CTS test for Android security b/170583712 am: 6261455f92 am: d8ee0928b3 am: b876001e76
Original change: https://googleplex-android-review.googlesource.com/c/platform/cts/+/13188214
MUST ONLY BE SUBMITTED BY AUTOMERGER
Change-Id: I71bb528c800b49492a11597365a315d11ad8f596
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 7b9c427..2572b01 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -36,6 +36,9 @@
tests/tests/view/
tests/tests/widget/
common/device-side/util/
+ hostsidetests/car/
+ hostsidetests/multiuser/
+ hostsidetests/scopedstorage/
hostsidetests/stagedinstall/
hostsidetests/userspacereboot/
tests/tests/packageinstaller/atomicinstall/
diff --git a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
index 9f984d6..f5061fc 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -78,6 +78,7 @@
"Landroid/annotation/SdkConstant;",
"Landroid/annotation/SdkConstant$SdkConstantType;",
"Landroid/annotation/StringDef;",
+ "Landroid/annotation/SuppressLint;",
"Landroid/annotation/SystemApi;",
"Landroid/annotation/SystemApi$Client;",
"Landroid/annotation/SystemApi$Container;",
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index 2a087dc..fe0dd12 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -514,6 +514,42 @@
}
}
+
+ @Test
+ public void testGrantUriPermission() throws Exception {
+ doGrantUriPermission(MEDIA, "testGrantUriPermission", new String[]{},
+ new String[]{PERM_READ_EXTERNAL_STORAGE, PERM_WRITE_EXTERNAL_STORAGE});
+ doGrantUriPermission(MEDIA, "testGrantUriPermission",
+ new String[]{PERM_READ_EXTERNAL_STORAGE},
+ new String[]{PERM_WRITE_EXTERNAL_STORAGE});
+ doGrantUriPermission(MEDIA, "testGrantUriPermission",
+ new String[]{PERM_READ_EXTERNAL_STORAGE, PERM_WRITE_EXTERNAL_STORAGE},
+ new String[] {});
+ }
+
+ @Test
+ public void testGrantUriPermission29() throws Exception {
+ doGrantUriPermission(MEDIA_29, "testGrantUriPermission", new String[]{},
+ new String[]{PERM_READ_EXTERNAL_STORAGE, PERM_WRITE_EXTERNAL_STORAGE});
+ doGrantUriPermission(MEDIA_29, "testGrantUriPermission",
+ new String[]{PERM_READ_EXTERNAL_STORAGE},
+ new String[]{PERM_WRITE_EXTERNAL_STORAGE});
+ doGrantUriPermission(MEDIA_29, "testGrantUriPermission",
+ new String[]{PERM_READ_EXTERNAL_STORAGE, PERM_WRITE_EXTERNAL_STORAGE},
+ new String[] {});
+ }
+
+ private void doGrantUriPermission(Config config, String method, String[] grantPermissions,
+ String[] revokePermissions) throws Exception {
+ uninstallPackage(config.apk);
+ installPackage(config.apk);
+ for (int user : mUsers) {
+ updatePermissions(config.pkg, user, grantPermissions, true);
+ updatePermissions(config.pkg, user, revokePermissions, false);
+ runDeviceTests(config.pkg, config.clazz, method, user);
+ }
+ }
+
@Test
public void testMediaNone() throws Exception {
doMediaNone(MEDIA);
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
index 3f32db4..cf1d888 100644
--- a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
@@ -212,6 +212,47 @@
}
}
+ /**
+ * Test prefix and non-prefix uri grant for all packages
+ */
+ @Test
+ public void testGrantUriPermission() {
+ final int flagGrantRead = Intent.FLAG_GRANT_READ_URI_PERMISSION;
+ final int flagGrantWrite = Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+ final int flagGrantReadPrefix =
+ Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
+ final int flagGrantWritePrefix =
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
+
+ for (Uri uri : new Uri[] {
+ MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+ MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+ MediaStore.Downloads.EXTERNAL_CONTENT_URI,
+ MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL)
+ }) {
+ // Non-prefix grant
+ checkGrantUriPermission(uri, flagGrantRead, true);
+ checkGrantUriPermission(uri, flagGrantWrite, true);
+
+ // Prefix grant
+ checkGrantUriPermission(uri, flagGrantReadPrefix, false);
+ checkGrantUriPermission(uri, flagGrantWritePrefix, false);
+ }
+ }
+
+ private void checkGrantUriPermission(Uri uri, int mode, boolean isGrantAllowed) {
+ if (isGrantAllowed) {
+ mContext.grantUriPermission(mContext.getPackageName(), uri, mode);
+ } else {
+ try {
+ mContext.grantUriPermission(mContext.getPackageName(), uri, mode);
+ fail("Expected granting to be blocked for flag 0x" + Integer.toHexString(mode));
+ } catch (SecurityException expected) {
+ }
+ }
+ }
+
@Test
public void testMediaRead() throws Exception {
doMediaRead(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MediaStorageTest::createAudio);
@@ -367,6 +408,8 @@
doMediaEscalation_RequestWrite(MediaStorageTest::createAudio);
doMediaEscalation_RequestWrite(MediaStorageTest::createVideo);
doMediaEscalation_RequestWrite(MediaStorageTest::createImage);
+ doMediaEscalation_RequestWrite(MediaStorageTest::createPlaylist);
+ doMediaEscalation_RequestWrite(MediaStorageTest::createSubtitle);
}
private void doMediaEscalation_RequestWrite(Callable<Uri> create) throws Exception {
@@ -375,7 +418,7 @@
try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(red, "w")) {
fail("Expected write access to be blocked");
- } catch (RecoverableSecurityException expected) {
+ } catch (SecurityException expected) {
}
doEscalation(MediaStore.createWriteRequest(mContentResolver, Arrays.asList(red)));
@@ -389,6 +432,8 @@
doMediaEscalation_RequestTrash(MediaStorageTest::createAudio);
doMediaEscalation_RequestTrash(MediaStorageTest::createVideo);
doMediaEscalation_RequestTrash(MediaStorageTest::createImage);
+ doMediaEscalation_RequestTrash(MediaStorageTest::createPlaylist);
+ doMediaEscalation_RequestTrash(MediaStorageTest::createSubtitle);
}
private void doMediaEscalation_RequestTrash(Callable<Uri> create) throws Exception {
@@ -407,6 +452,8 @@
doMediaEscalation_RequestFavorite(MediaStorageTest::createAudio);
doMediaEscalation_RequestFavorite(MediaStorageTest::createVideo);
doMediaEscalation_RequestFavorite(MediaStorageTest::createImage);
+ doMediaEscalation_RequestFavorite(MediaStorageTest::createPlaylist);
+ doMediaEscalation_RequestFavorite(MediaStorageTest::createSubtitle);
}
private void doMediaEscalation_RequestFavorite(Callable<Uri> create) throws Exception {
@@ -425,6 +472,8 @@
doMediaEscalation_RequestDelete(MediaStorageTest::createAudio);
doMediaEscalation_RequestDelete(MediaStorageTest::createVideo);
doMediaEscalation_RequestDelete(MediaStorageTest::createImage);
+ doMediaEscalation_RequestDelete(MediaStorageTest::createPlaylist);
+ doMediaEscalation_RequestDelete(MediaStorageTest::createSubtitle);
}
private void doMediaEscalation_RequestDelete(Callable<Uri> create) throws Exception {
@@ -519,6 +568,33 @@
}
}
+ private static Uri createPlaylist() throws IOException {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ final String displayName = "cts" + System.nanoTime();
+ final PendingParams params = new PendingParams(
+ MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, displayName, "audio/mpegurl");
+ final Uri pendingUri = MediaStoreUtils.createPending(context, params);
+ try (PendingSession session = MediaStoreUtils.openPending(context, pendingUri)) {
+ return session.publish();
+ }
+ }
+
+ private static Uri createSubtitle() throws IOException {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ final String displayName = "cts" + System.nanoTime();
+ final PendingParams params = new PendingParams(
+ MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL), displayName,
+ "application/x-subrip");
+ final Uri pendingUri = MediaStoreUtils.createPending(context, params);
+ try (PendingSession session = MediaStoreUtils.openPending(context, pendingUri)) {
+ try (InputStream in = context.getResources().getAssets().open("testmp3.mp3");
+ OutputStream out = session.openOutputStream()) {
+ FileUtils.copy(in, out);
+ }
+ return session.publish();
+ }
+ }
+
private static String queryForSingleColumn(Uri uri, String column) throws Exception {
final ContentResolver resolver = InstrumentationRegistry.getTargetContext()
.getContentResolver();
diff --git a/hostsidetests/backup/Android.bp b/hostsidetests/backup/Android.bp
index 598c357..1ca478c 100644
--- a/hostsidetests/backup/Android.bp
+++ b/hostsidetests/backup/Android.bp
@@ -21,6 +21,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
libs: [
"cts-tradefed",
diff --git a/hostsidetests/devicepolicy/Android.bp b/hostsidetests/devicepolicy/Android.bp
index 0e89a22..f832299 100644
--- a/hostsidetests/devicepolicy/Android.bp
+++ b/hostsidetests/devicepolicy/Android.bp
@@ -31,6 +31,7 @@
"cts",
"general-tests",
"vts10",
+ "mts",
],
java_resource_dirs: ["res"],
data: [":current-api-xml"],
diff --git a/hostsidetests/devicepolicy/app/AccountCheck/Android.bp b/hostsidetests/devicepolicy/app/AccountCheck/Android.bp
index 45d374f..fca1416 100644
--- a/hostsidetests/devicepolicy/app/AccountCheck/Android.bp
+++ b/hostsidetests/devicepolicy/app/AccountCheck/Android.bp
@@ -20,6 +20,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
srcs: ["src-owner/**/*.java"],
resource_dirs: ["TestOnlyOwner/res"],
@@ -41,6 +42,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
srcs: ["src-owner/**/*.java"],
resource_dirs: ["NonTestOnlyOwner/res"],
@@ -62,6 +64,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
srcs: ["src-owner/**/*.java"],
resource_dirs: ["TestOnlyOwnerUpdate/res"],
diff --git a/hostsidetests/devicepolicy/app/AccountCheck/Auth/Android.bp b/hostsidetests/devicepolicy/app/AccountCheck/Auth/Android.bp
index b31afea..687819e 100644
--- a/hostsidetests/devicepolicy/app/AccountCheck/Auth/Android.bp
+++ b/hostsidetests/devicepolicy/app/AccountCheck/Auth/Android.bp
@@ -20,6 +20,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
srcs: ["src/**/*.java"],
static_libs: [
diff --git a/hostsidetests/devicepolicy/app/AccountCheck/Tester/Android.bp b/hostsidetests/devicepolicy/app/AccountCheck/Tester/Android.bp
index d40d04c..2533108 100644
--- a/hostsidetests/devicepolicy/app/AccountCheck/Tester/Android.bp
+++ b/hostsidetests/devicepolicy/app/AccountCheck/Tester/Android.bp
@@ -20,6 +20,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
srcs: ["src/**/*.java"],
static_libs: [
diff --git a/hostsidetests/devicepolicy/app/AccountManagement/Android.bp b/hostsidetests/devicepolicy/app/AccountManagement/Android.bp
index 69dcbb5..f10dcbb 100644
--- a/hostsidetests/devicepolicy/app/AccountManagement/Android.bp
+++ b/hostsidetests/devicepolicy/app/AccountManagement/Android.bp
@@ -21,6 +21,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
srcs: ["src/**/*.java"],
static_libs: [
diff --git a/hostsidetests/devicepolicy/app/AppRestrictionsTargetApp/Android.bp b/hostsidetests/devicepolicy/app/AppRestrictionsTargetApp/Android.bp
index 9b35a75..37cc042 100644
--- a/hostsidetests/devicepolicy/app/AppRestrictionsTargetApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/AppRestrictionsTargetApp/Android.bp
@@ -24,5 +24,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/Assistant/Android.bp b/hostsidetests/devicepolicy/app/Assistant/Android.bp
index 5e1bb88..8feee05 100644
--- a/hostsidetests/devicepolicy/app/Assistant/Android.bp
+++ b/hostsidetests/devicepolicy/app/Assistant/Android.bp
@@ -24,6 +24,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
static_libs: [
"androidx.legacy_legacy-support-v4",
diff --git a/hostsidetests/devicepolicy/app/AutofillApp/Android.bp b/hostsidetests/devicepolicy/app/AutofillApp/Android.bp
index c79c0a5..664d890 100644
--- a/hostsidetests/devicepolicy/app/AutofillApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/AutofillApp/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
sdk_version: "current",
}
diff --git a/hostsidetests/devicepolicy/app/CertInstaller/Android.bp b/hostsidetests/devicepolicy/app/CertInstaller/Android.bp
index bee8617..e9b38d9 100644
--- a/hostsidetests/devicepolicy/app/CertInstaller/Android.bp
+++ b/hostsidetests/devicepolicy/app/CertInstaller/Android.bp
@@ -35,5 +35,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/ContactDirectoryProvider/Android.bp b/hostsidetests/devicepolicy/app/ContactDirectoryProvider/Android.bp
index ca9d9dd..200a6d2 100644
--- a/hostsidetests/devicepolicy/app/ContactDirectoryProvider/Android.bp
+++ b/hostsidetests/devicepolicy/app/ContactDirectoryProvider/Android.bp
@@ -21,6 +21,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
sdk_version: "current",
}
diff --git a/hostsidetests/devicepolicy/app/ContentCaptureApp/Android.bp b/hostsidetests/devicepolicy/app/ContentCaptureApp/Android.bp
index 3ed0a7f..6880174 100644
--- a/hostsidetests/devicepolicy/app/ContentCaptureApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/ContentCaptureApp/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
sdk_version: "system_current",
}
diff --git a/hostsidetests/devicepolicy/app/ContentCaptureService/Android.bp b/hostsidetests/devicepolicy/app/ContentCaptureService/Android.bp
index c50418d..cfe06d6 100644
--- a/hostsidetests/devicepolicy/app/ContentCaptureService/Android.bp
+++ b/hostsidetests/devicepolicy/app/ContentCaptureService/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
sdk_version: "system_current",
}
diff --git a/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp b/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp
index 590a7d1..cc34b43 100644
--- a/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
sdk_version: "system_current",
}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.bp b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.bp
index d447937..00940df 100644
--- a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.bp
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.bp
@@ -43,6 +43,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
@@ -72,6 +73,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
aaptflags: [
"--rename-manifest-package",
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/Android.bp b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/Android.bp
index 2d74684..a3e8766 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/Android.bp
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/Android.bp
@@ -31,5 +31,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsWithNoPermissionTest/Android.bp b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsWithNoPermissionTest/Android.bp
index 24aafd4..aa79d3d 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsWithNoPermissionTest/Android.bp
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsWithNoPermissionTest/Android.bp
@@ -31,5 +31,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/Android.bp b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/Android.bp
index 8643aa6..da26cee 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/Android.bp
@@ -31,5 +31,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/Android.bp b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/Android.bp
index 89476ed..19b788b 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/Android.bp
@@ -31,5 +31,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/Android.bp b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/Android.bp
index c27b134..acc77ac 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/Android.bp
@@ -31,5 +31,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/Android.bp b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/Android.bp
index ec9ae62..5786981 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/Android.bp
@@ -31,5 +31,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/Android.bp b/hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/Android.bp
index a33eec5..7383a9e 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/Android.bp
@@ -31,5 +31,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/CustomizationApp/Android.bp b/hostsidetests/devicepolicy/app/CustomizationApp/Android.bp
index 1a57839..bf00089 100644
--- a/hostsidetests/devicepolicy/app/CustomizationApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/CustomizationApp/Android.bp
@@ -20,6 +20,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
srcs: ["src/**/*.java"],
static_libs: [
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/Android.bp b/hostsidetests/devicepolicy/app/DelegateApp/Android.bp
index fe7eaf7..14bea7d 100644
--- a/hostsidetests/devicepolicy/app/DelegateApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/DelegateApp/Android.bp
@@ -35,5 +35,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAdmin/Android.bp b/hostsidetests/devicepolicy/app/DeviceAdmin/Android.bp
index 49be1dc..4a587f7 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdmin/Android.bp
+++ b/hostsidetests/devicepolicy/app/DeviceAdmin/Android.bp
@@ -32,6 +32,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "api23/AndroidManifest.xml",
}
@@ -58,6 +59,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "api24/AndroidManifest.xml",
}
@@ -82,6 +84,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "api29/AndroidManifest.xml",
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAdminService/Android.bp b/hostsidetests/devicepolicy/app/DeviceAdminService/Android.bp
index 79d091d..aaacefa 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdminService/Android.bp
+++ b/hostsidetests/devicepolicy/app/DeviceAdminService/Android.bp
@@ -28,6 +28,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "package1/AndroidManifest.xml",
}
@@ -48,6 +49,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "package2/AndroidManifest.xml",
}
@@ -68,6 +70,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "package3/AndroidManifest.xml",
}
@@ -88,6 +91,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "package4/AndroidManifest.xml",
}
@@ -108,6 +112,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "packageb/AndroidManifest.xml",
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp
index a61153d..e32c4ae 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp
@@ -36,6 +36,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "api23/AndroidManifest.xml",
}
@@ -65,6 +66,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "api25/AndroidManifest.xml",
}
@@ -94,6 +96,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "latest/AndroidManifest.xml",
}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.bp b/hostsidetests/devicepolicy/app/DeviceOwner/Android.bp
index cfd7e25..48826af 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.bp
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.bp
@@ -45,5 +45,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/DummyApps/Android.bp b/hostsidetests/devicepolicy/app/DummyApps/Android.bp
index 14338fb..869a908 100644
--- a/hostsidetests/devicepolicy/app/DummyApps/Android.bp
+++ b/hostsidetests/devicepolicy/app/DummyApps/Android.bp
@@ -34,6 +34,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "dummyapp1/AndroidManifest.xml",
}
@@ -60,6 +61,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "dummyapp2/AndroidManifest.xml",
}
@@ -86,6 +88,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "dummyapp3/AndroidManifest.xml",
}
@@ -112,6 +115,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "dummyapp4/AndroidManifest.xml",
}
diff --git a/hostsidetests/devicepolicy/app/DummyIme/Android.bp b/hostsidetests/devicepolicy/app/DummyIme/Android.bp
index 7f817cd..7955f42 100644
--- a/hostsidetests/devicepolicy/app/DummyIme/Android.bp
+++ b/hostsidetests/devicepolicy/app/DummyIme/Android.bp
@@ -25,5 +25,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/DummyLauncher/Android.bp b/hostsidetests/devicepolicy/app/DummyLauncher/Android.bp
index 36e0971..e0d39d3 100644
--- a/hostsidetests/devicepolicy/app/DummyLauncher/Android.bp
+++ b/hostsidetests/devicepolicy/app/DummyLauncher/Android.bp
@@ -24,5 +24,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp
index 6ffd45a..825bb12 100644
--- a/hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp
@@ -29,6 +29,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
sdk_version: "current",
}
@@ -49,6 +50,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "no_launcher_activity_AndroidManifest.xml",
sdk_version: "current",
@@ -70,6 +72,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "no_permission_AndroidManifest.xml",
sdk_version: "current",
diff --git a/hostsidetests/devicepolicy/app/IntentReceiver/Android.bp b/hostsidetests/devicepolicy/app/IntentReceiver/Android.bp
index b809bd1..d807701 100644
--- a/hostsidetests/devicepolicy/app/IntentReceiver/Android.bp
+++ b/hostsidetests/devicepolicy/app/IntentReceiver/Android.bp
@@ -32,5 +32,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/IntentSender/Android.bp b/hostsidetests/devicepolicy/app/IntentSender/Android.bp
index eb92ff4..8e6a7f0 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/Android.bp
+++ b/hostsidetests/devicepolicy/app/IntentSender/Android.bp
@@ -32,5 +32,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.bp b/hostsidetests/devicepolicy/app/LauncherTests/Android.bp
index ac11845..3aad240 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/Android.bp
+++ b/hostsidetests/devicepolicy/app/LauncherTests/Android.bp
@@ -33,5 +33,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.bp b/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.bp
index 13bc061..3263267 100644
--- a/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.bp
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.bp
@@ -25,5 +25,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp b/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp
index 372eac7..c5a56e1 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp
@@ -38,6 +38,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
platform_apis: true,
}
diff --git a/hostsidetests/devicepolicy/app/MeteredDataTestApp/Android.bp b/hostsidetests/devicepolicy/app/MeteredDataTestApp/Android.bp
index c3ae579..94f9784 100644
--- a/hostsidetests/devicepolicy/app/MeteredDataTestApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/MeteredDataTestApp/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
sdk_version: "current",
}
diff --git a/hostsidetests/devicepolicy/app/NotificationSender/Android.bp b/hostsidetests/devicepolicy/app/NotificationSender/Android.bp
index e8fe0e4..a10f627 100644
--- a/hostsidetests/devicepolicy/app/NotificationSender/Android.bp
+++ b/hostsidetests/devicepolicy/app/NotificationSender/Android.bp
@@ -21,6 +21,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
sdk_version: "current",
}
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/Android.bp b/hostsidetests/devicepolicy/app/PackageInstaller/Android.bp
index beb0c3a..d0de5a7 100644
--- a/hostsidetests/devicepolicy/app/PackageInstaller/Android.bp
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/Android.bp
@@ -33,5 +33,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/PasswordComplexity/Android.bp b/hostsidetests/devicepolicy/app/PasswordComplexity/Android.bp
index f91677e..7c9fb37 100644
--- a/hostsidetests/devicepolicy/app/PasswordComplexity/Android.bp
+++ b/hostsidetests/devicepolicy/app/PasswordComplexity/Android.bp
@@ -31,5 +31,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/PrintingApp/Android.bp b/hostsidetests/devicepolicy/app/PrintingApp/Android.bp
index 7d30624..8b54d28 100644
--- a/hostsidetests/devicepolicy/app/PrintingApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/PrintingApp/Android.bp
@@ -23,5 +23,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/ProfileOwner/Android.bp b/hostsidetests/devicepolicy/app/ProfileOwner/Android.bp
index 5728315..3895dab 100644
--- a/hostsidetests/devicepolicy/app/ProfileOwner/Android.bp
+++ b/hostsidetests/devicepolicy/app/ProfileOwner/Android.bp
@@ -33,5 +33,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/SeparateProfileChallenge/Android.bp b/hostsidetests/devicepolicy/app/SeparateProfileChallenge/Android.bp
index ab5465e..d0ed2e7 100644
--- a/hostsidetests/devicepolicy/app/SeparateProfileChallenge/Android.bp
+++ b/hostsidetests/devicepolicy/app/SeparateProfileChallenge/Android.bp
@@ -34,5 +34,6 @@
"vts10",
"general-tests",
"sts",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/SharingApps/Android.bp b/hostsidetests/devicepolicy/app/SharingApps/Android.bp
index 460fe55..0ba93e0 100644
--- a/hostsidetests/devicepolicy/app/SharingApps/Android.bp
+++ b/hostsidetests/devicepolicy/app/SharingApps/Android.bp
@@ -34,6 +34,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "sharingapp1/AndroidManifest.xml",
}
@@ -60,6 +61,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
manifest: "sharingapp2/AndroidManifest.xml",
}
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/Android.bp b/hostsidetests/devicepolicy/app/SimpleApp/Android.bp
index 1a6ebf8..32a9c79 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/SimpleApp/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
sdk_version: "current",
}
diff --git a/hostsidetests/devicepolicy/app/SimplePreMApp/Android.bp b/hostsidetests/devicepolicy/app/SimplePreMApp/Android.bp
index b9b6f8d..76fd05d 100644
--- a/hostsidetests/devicepolicy/app/SimplePreMApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/SimplePreMApp/Android.bp
@@ -25,5 +25,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp b/hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp
index f6ad171..cc3538b 100644
--- a/hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp
@@ -25,5 +25,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/SingleAdminApp/Android.bp b/hostsidetests/devicepolicy/app/SingleAdminApp/Android.bp
index 0f89feb..6d278cc 100644
--- a/hostsidetests/devicepolicy/app/SingleAdminApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/SingleAdminApp/Android.bp
@@ -33,5 +33,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/Android.bp b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/Android.bp
index 18c5f58..7d3689a 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/Android.bp
@@ -35,5 +35,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/Android.bp b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/Android.bp
index 38b4991..5c62f0b 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/Android.bp
@@ -35,5 +35,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/WidgetProvider/Android.bp b/hostsidetests/devicepolicy/app/WidgetProvider/Android.bp
index 5066bc2..b6a608d 100644
--- a/hostsidetests/devicepolicy/app/WidgetProvider/Android.bp
+++ b/hostsidetests/devicepolicy/app/WidgetProvider/Android.bp
@@ -22,5 +22,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.bp b/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.bp
index 4ce52a1..fa1b793 100644
--- a/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.bp
+++ b/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.bp
@@ -25,5 +25,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/net/Android.bp b/hostsidetests/mediaparser/Android.bp
similarity index 72%
rename from hostsidetests/net/Android.bp
rename to hostsidetests/mediaparser/Android.bp
index 741c961..87c9621 100644
--- a/hostsidetests/net/Android.bp
+++ b/hostsidetests/mediaparser/Android.bp
@@ -1,4 +1,5 @@
-// Copyright (C) 2014 The Android Open Source Project
+//
+// Copyright 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -11,20 +12,28 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+//
java_test_host {
- name: "CtsHostsideNetworkTests",
+ name: "CtsMediaParserHostTestCases",
defaults: ["cts_defaults"],
- // Only compile source java files in this apk.
- srcs: ["src/**/*.java"],
- libs: [
- "cts-tradefed",
- "tradefed",
+ srcs: [
+ "src/**/*.java",
],
- // Tag this module as a cts test artifact
test_suites: [
"cts",
"vts10",
"general-tests",
],
+ libs: [
+ "cts-tradefed",
+ "tradefed",
+ "compatibility-host-util",
+ ],
+ static_libs: [
+ "cts-host-utils",
+ ],
+ data: [
+ ":CtsMediaParserTestCasesApp",
+ ]
}
diff --git a/hostsidetests/mediaparser/AndroidTest.xml b/hostsidetests/mediaparser/AndroidTest.xml
new file mode 100644
index 0000000..7d53939
--- /dev/null
+++ b/hostsidetests/mediaparser/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS media host test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="media" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsMediaParserHostTestCases.jar" />
+ <option name="runtime-hint" value="3m" />
+ </test>
+</configuration>
+
diff --git a/hostsidetests/mediaparser/OWNERS b/hostsidetests/mediaparser/OWNERS
new file mode 100644
index 0000000..51256bf
--- /dev/null
+++ b/hostsidetests/mediaparser/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 817235
+aquilescanta@google.com
+andrewlewis@google.com
+essick@google.com
+marcone@google.com
diff --git a/hostsidetests/mediaparser/src/android/media/mediaparser/cts/MediaParserHostSideTest.java b/hostsidetests/mediaparser/src/android/media/mediaparser/cts/MediaParserHostSideTest.java
new file mode 100644
index 0000000..e5797ce
--- /dev/null
+++ b/hostsidetests/mediaparser/src/android/media/mediaparser/cts/MediaParserHostSideTest.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.mediaparser.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.internal.os.StatsdConfigProto;
+import com.android.internal.os.StatsdConfigProto.AtomMatcher;
+import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
+import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.os.AtomsProto;
+import com.android.os.AtomsProto.MediametricsMediaParserReported;
+import com.android.os.StatsLog;
+import com.android.os.StatsLog.ConfigMetricsReportList;
+import com.android.os.StatsLog.EventMetricData;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.CollectingByteOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.TestRunResult;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import com.google.common.io.Files;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Test for checking that the MediaParser CTS tests produce the expected media metrics. */
+public class MediaParserHostSideTest extends DeviceTestCase implements IBuildReceiver {
+
+ private static final String MEDIAPARSER_TEST_APK = "CtsMediaParserTestCasesApp.apk";
+ private static final String MEDIAPARSER_TEST_APP_PACKAGE = "android.media.mediaparser.cts";
+ private static final String MEDIAPARSER_TEST_CLASS_NAME =
+ "android.media.mediaparser.cts.MediaParserTest";
+ private static final String TEST_RUNNER = "androidx.test.runner.AndroidJUnitRunner";
+
+ private static final long CONFIG_ID = "cts_config".hashCode();
+ private static final String MEDIAPARSER_METRICS_SEPARATOR = "\\|";
+ private static final double MEDIAPARSER_METRICS_DITHER_VALUE = .02f;
+
+ private IBuildInfo mCtsBuildInfo;
+
+ // Resource management.
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuildInfo = buildInfo;
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ File apk = new CompatibilityBuildHelper(mCtsBuildInfo).getTestFile(MEDIAPARSER_TEST_APK);
+ assertThat(getDevice().installPackage(apk, /* reinstall= */ true)).isNull();
+ removeConfig();
+ createAndUploadConfig();
+ getAndClearReportList(); // Clear existing reports.
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ removeConfig();
+ getDevice().uninstallPackage(MEDIAPARSER_TEST_APP_PACKAGE);
+ }
+
+ // Tests.
+
+ public void testCreationByNameMetrics() throws Exception {
+ String[] expectedParserNames = {
+ "android.media.mediaparser.MatroskaParser",
+ "android.media.mediaparser.FragmentedMp4Parser",
+ "android.media.mediaparser.Mp4Parser",
+ "android.media.mediaparser.Mp3Parser",
+ "android.media.mediaparser.AdtsParser",
+ "android.media.mediaparser.Ac3Parser",
+ "android.media.mediaparser.TsParser",
+ "android.media.mediaparser.FlvParser",
+ "android.media.mediaparser.OggParser",
+ "android.media.mediaparser.PsParser",
+ "android.media.mediaparser.WavParser",
+ "android.media.mediaparser.AmrParser",
+ "android.media.mediaparser.Ac4Parser",
+ "android.media.mediaparser.FlacParser",
+ };
+ // All of the above are created by name.
+ int[] expectedCreatedByName =
+ Arrays.stream(expectedParserNames).mapToInt(unusedArgument -> 1).toArray();
+ runDeviceTest("testCreationByName");
+ List<MediametricsMediaParserReported> mediaParserReportedEvents =
+ getMediaParserReportedEvents();
+ String[] observedParserNames =
+ mediaParserReportedEvents.stream()
+ .map(MediametricsMediaParserReported::getParserName)
+ .toArray(String[]::new);
+ int[] observedCreatedByName =
+ mediaParserReportedEvents.stream()
+ .mapToInt(MediametricsMediaParserReported::getCreatedByName)
+ .toArray();
+ assertThat(observedParserNames).isEqualTo(expectedParserNames);
+ assertThat(observedCreatedByName).isEqualTo(expectedCreatedByName);
+ }
+
+ public void testParserPool() throws Exception {
+ runDeviceTest("testMp4");
+ String[] expectedParserNamesInPool = {
+ "android.media.mediaparser.MatroskaParser",
+ "android.media.mediaparser.FragmentedMp4Parser",
+ "android.media.mediaparser.Mp4Parser",
+ "android.media.mediaparser.Mp3Parser",
+ "android.media.mediaparser.AdtsParser",
+ "android.media.mediaparser.Ac3Parser",
+ "android.media.mediaparser.TsParser",
+ "android.media.mediaparser.FlvParser",
+ "android.media.mediaparser.OggParser",
+ "android.media.mediaparser.PsParser",
+ "android.media.mediaparser.WavParser",
+ "android.media.mediaparser.AmrParser",
+ "android.media.mediaparser.Ac4Parser",
+ "android.media.mediaparser.FlacParser",
+ };
+ String parserPool = getSingleMediaParserReportedEvent().getParserPool();
+ List<String> parserNamesInParserPool =
+ Arrays.asList(parserPool.split(MEDIAPARSER_METRICS_SEPARATOR));
+ // We do not assert the order in the pool in order to allow test robustness against future
+ // mainline changes.
+ assertThat(parserNamesInParserPool).containsExactlyElementsIn(expectedParserNamesInPool);
+ }
+
+ public void testLastException() throws Exception {
+ runDeviceTest("testOggInvalidHeaderSniff");
+ List<MediametricsMediaParserReported> mediaParserReportedEvents =
+ getMediaParserReportedEvents();
+ assertThat(mediaParserReportedEvents).hasSize(2);
+ for (MediametricsMediaParserReported event : mediaParserReportedEvents) {
+ assertThat(event.getLastException())
+ .isEqualTo("android.media.MediaParser$UnrecognizedInputFormatException");
+ }
+ }
+
+ public void testResourceByteCount() throws Exception {
+ long actualInputSize = 101597;
+ long minimumExpectedResourceByteCount =
+ (long) (actualInputSize * (1 - MEDIAPARSER_METRICS_DITHER_VALUE));
+ long maximumExpectedResourceByteCount =
+ (long) (actualInputSize * (1 + MEDIAPARSER_METRICS_DITHER_VALUE));
+ runDeviceTest("testMp4");
+ long reportedByteCount = getSingleMediaParserReportedEvent().getResourceByteCount();
+ assertThat(reportedByteCount).isAtLeast(minimumExpectedResourceByteCount);
+ assertThat(reportedByteCount).isAtMost(maximumExpectedResourceByteCount);
+ }
+
+ public void testDurationMillis() throws Exception {
+ long actualDurationMillis = 1024;
+ long minimumExpectedResourceByteCount =
+ (long) (actualDurationMillis * (1 - MEDIAPARSER_METRICS_DITHER_VALUE));
+ long maximumExpectedResourceByteCount =
+ (long) (actualDurationMillis * (1 + MEDIAPARSER_METRICS_DITHER_VALUE));
+ runDeviceTest("testMp4");
+ long reportedDurationMillis = getSingleMediaParserReportedEvent().getDurationMillis();
+ assertThat(reportedDurationMillis).isAtLeast(minimumExpectedResourceByteCount);
+ assertThat(reportedDurationMillis).isAtMost(maximumExpectedResourceByteCount);
+ }
+
+ public void testTrackMimeTypes() throws Exception {
+ String[] expectedTrackMimeTypes = new String[] {"video/avc", "audio/mp4a-latm"};
+ runDeviceTest("testMp4");
+ String trackMimeTypesField = getSingleMediaParserReportedEvent().getTrackMimeTypes();
+ List<String> actualTrackMimeTypes =
+ Arrays.asList(trackMimeTypesField.split(MEDIAPARSER_METRICS_SEPARATOR));
+ assertThat(actualTrackMimeTypes).containsExactlyElementsIn(expectedTrackMimeTypes);
+ }
+
+ public void testTrackCodecs() throws Exception {
+ String[] expectedCodecs = new String[] {"", "mp4a.40.2"};
+ runDeviceTest("testMp4");
+ String trackMimeTypesField = getSingleMediaParserReportedEvent().getTrackCodecs();
+ List<String> actualTrackMimeTypes =
+ Arrays.asList(trackMimeTypesField.split(MEDIAPARSER_METRICS_SEPARATOR));
+ assertThat(actualTrackMimeTypes).containsExactlyElementsIn(expectedCodecs);
+ }
+
+ public void testAlteredParameters() throws Exception {
+ runDeviceTest("testTsWithH264DtsAudio");
+ assertThat(getSingleMediaParserReportedEvent().getAlteredParameters())
+ .isEqualTo("android.media.mediaparser.ts.enableHdmvDtsAudioStreams");
+ }
+
+ public void testVideoSize() throws Exception {
+ runDeviceTest("testMp4");
+ MediametricsMediaParserReported reportedEvent = getSingleMediaParserReportedEvent();
+ assertThat(reportedEvent.getVideoWidth()).isEqualTo(1080);
+ assertThat(reportedEvent.getVideoHeight()).isEqualTo(720);
+ }
+
+ // Internal methods.
+
+ /** Creates the statsd config and passes it to statsd. */
+ private void createAndUploadConfig() throws Exception {
+ StatsdConfig.Builder configBuilder =
+ StatsdConfigProto.StatsdConfig.newBuilder()
+ .setId(CONFIG_ID)
+ .addAllowedLogSource(MEDIAPARSER_TEST_APP_PACKAGE)
+ .addWhitelistedAtomIds(
+ AtomsProto.Atom.MEDIAMETRICS_MEDIAPARSER_REPORTED_FIELD_NUMBER);
+ addAtomEvent(configBuilder);
+ uploadConfig(configBuilder.build());
+ }
+
+ /** Removes any existing config with id {@link #CONFIG_ID}. */
+ private void removeConfig() throws Exception {
+ getDevice().executeShellCommand("cmd stats config remove " + CONFIG_ID);
+ }
+
+ /** Writes the given config into a file and passes is to statsd via standard input. */
+ private void uploadConfig(StatsdConfig config) throws Exception {
+ File configFile = File.createTempFile("statsdconfig", ".config");
+ configFile.deleteOnExit();
+ Files.write(config.toByteArray(), configFile);
+ String remotePath = "/data/local/tmp/" + configFile.getName();
+ // Make sure a config file with the same name doesn't exist already.
+ getDevice().deleteFile(remotePath);
+ assertThat(getDevice().pushFile(configFile, remotePath)).isTrue();
+ getDevice()
+ .executeShellCommand(
+ "cat " + remotePath + " | cmd stats config update " + CONFIG_ID);
+ getDevice().deleteFile(remotePath);
+ }
+
+ /**
+ * Asserts that there is only one MediaParser reported metric event, and returns it.
+ *
+ * <p>Note: Calls {@link #getAndClearReportList()} to obtain the statsd report.
+ */
+ private MediametricsMediaParserReported getSingleMediaParserReportedEvent() throws Exception {
+ List<MediametricsMediaParserReported> mediaParserReportedEvents =
+ getMediaParserReportedEvents();
+ assertThat(mediaParserReportedEvents).hasSize(1);
+ return mediaParserReportedEvents.get(0);
+ }
+
+ /**
+ * Returns all MediaParser reported metric events sorted by timestamp.
+ *
+ * <p>Note: Calls {@link #getAndClearReportList()} to obtain the statsd report.
+ */
+ private List<MediametricsMediaParserReported> getMediaParserReportedEvents() throws Exception {
+ ConfigMetricsReportList reportList = getAndClearReportList();
+ assertThat(reportList.getReportsCount()).isEqualTo(1);
+ StatsLog.ConfigMetricsReport report = reportList.getReports(0);
+ ArrayList<EventMetricData> data = new ArrayList<>();
+ report.getMetricsList()
+ .forEach(
+ statsLogReport ->
+ data.addAll(statsLogReport.getEventMetrics().getDataList()));
+ // We sort the reported events by the elapsed timestamp so as to ensure they are returned
+ // in the same order as they were generated by the CTS tests.
+ return data.stream()
+ .sorted(Comparator.comparing(EventMetricData::getElapsedTimestampNanos))
+ .map(event -> event.getAtom().getMediametricsMediaparserReported())
+ .collect(Collectors.toList());
+ }
+
+ /** Gets a statsd report and removes it from the device. */
+ private ConfigMetricsReportList getAndClearReportList() throws Exception {
+ CollectingByteOutputReceiver receiver = new CollectingByteOutputReceiver();
+ getDevice()
+ .executeShellCommand(
+ "cmd stats dump-report " + CONFIG_ID + " --include_current_bucket --proto",
+ receiver);
+ return ConfigMetricsReportList.parser().parseFrom(receiver.getOutput());
+ }
+
+ /** Runs the test with the given name from the MediaParser CTS apk. */
+ private void runDeviceTest(String testMethodName) throws DeviceNotAvailableException {
+ RemoteAndroidTestRunner testRunner =
+ new RemoteAndroidTestRunner(
+ MEDIAPARSER_TEST_APP_PACKAGE, TEST_RUNNER, getDevice().getIDevice());
+ testRunner.setMethodName(MEDIAPARSER_TEST_CLASS_NAME, testMethodName);
+ CollectingTestListener listener = new CollectingTestListener();
+ assertThat(getDevice().runInstrumentationTests(testRunner, listener)).isTrue();
+ TestRunResult result = listener.getCurrentRunResults();
+ assertThat(result.isRunFailure()).isFalse();
+ assertThat(result.getNumTests()).isEqualTo(1);
+ assertThat(result.hasFailedTests()).isFalse();
+ }
+
+ /** Adds an event to the config in order to match MediaParser reported atoms. */
+ private static void addAtomEvent(StatsdConfig.Builder config) {
+ String atomName = "Atom" + System.nanoTime();
+ String eventName = "Event" + System.nanoTime();
+ SimpleAtomMatcher.Builder sam =
+ SimpleAtomMatcher.newBuilder()
+ .setAtomId(AtomsProto.Atom.MEDIAMETRICS_MEDIAPARSER_REPORTED_FIELD_NUMBER);
+ config.addAtomMatcher(
+ AtomMatcher.newBuilder().setId(atomName.hashCode()).setSimpleAtomMatcher(sam));
+ config.addEventMetric(
+ StatsdConfigProto.EventMetric.newBuilder()
+ .setId(eventName.hashCode())
+ .setWhat(atomName.hashCode()));
+ }
+}
diff --git a/hostsidetests/net/AndroidTest.xml b/hostsidetests/net/AndroidTest.xml
deleted file mode 100644
index b7fefaf..0000000
--- a/hostsidetests/net/AndroidTest.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for CTS net host test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="networking" />
- <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
-
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
- <target_preparer class="com.android.cts.net.NetworkPolicyTestsPreparer" />
-
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="teardown-command" value="cmd power set-mode 0" />
- <option name="teardown-command" value="cmd battery reset" />
- <option name="teardown-command" value="cmd netpolicy stop-watching" />
- </target_preparer>
-
- <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
- <option name="jar" value="CtsHostsideNetworkTests.jar" />
- <option name="runtime-hint" value="3m56s" />
- </test>
-
- <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
- <option name="directory-keys" value="/sdcard/CtsHostsideNetworkTests" />
- <option name="collect-on-run-ended-only" value="true" />
- </metrics_collector>
-</configuration>
diff --git a/hostsidetests/net/OWNERS b/hostsidetests/net/OWNERS
deleted file mode 100644
index 52c8053..0000000
--- a/hostsidetests/net/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 61373
-sudheersai@google.com
-lorenzo@google.com
-jchalard@google.com
diff --git a/hostsidetests/net/aidl/Android.bp b/hostsidetests/net/aidl/Android.bp
deleted file mode 100644
index 320a1fa..0000000
--- a/hostsidetests/net/aidl/Android.bp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-java_test_helper_library {
- name: "CtsHostsideNetworkTestsAidl",
- sdk_version: "current",
- srcs: [
- "com/android/cts/net/hostside/IMyService.aidl",
- "com/android/cts/net/hostside/INetworkCallback.aidl",
- "com/android/cts/net/hostside/INetworkStateObserver.aidl",
- "com/android/cts/net/hostside/IRemoteSocketFactory.aidl",
- ],
-}
diff --git a/hostsidetests/net/aidl/com/android/cts/net/hostside/IMyService.aidl b/hostsidetests/net/aidl/com/android/cts/net/hostside/IMyService.aidl
deleted file mode 100644
index 5aafdf0..0000000
--- a/hostsidetests/net/aidl/com/android/cts/net/hostside/IMyService.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import com.android.cts.net.hostside.INetworkCallback;
-
-interface IMyService {
- void registerBroadcastReceiver();
- int getCounters(String receiverName, String action);
- String checkNetworkStatus();
- String getRestrictBackgroundStatus();
- void sendNotification(int notificationId, String notificationType);
- void registerNetworkCallback(in INetworkCallback cb);
- void unregisterNetworkCallback();
-}
diff --git a/hostsidetests/net/aidl/com/android/cts/net/hostside/INetworkCallback.aidl b/hostsidetests/net/aidl/com/android/cts/net/hostside/INetworkCallback.aidl
deleted file mode 100644
index 2048bab..0000000
--- a/hostsidetests/net/aidl/com/android/cts/net/hostside/INetworkCallback.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import android.net.Network;
-import android.net.NetworkCapabilities;
-
-interface INetworkCallback {
- void onBlockedStatusChanged(in Network network, boolean blocked);
- void onAvailable(in Network network);
- void onLost(in Network network);
- void onCapabilitiesChanged(in Network network, in NetworkCapabilities cap);
-}
diff --git a/hostsidetests/net/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl b/hostsidetests/net/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl
deleted file mode 100644
index 165f530..0000000
--- a/hostsidetests/net/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-interface INetworkStateObserver {
- boolean isForeground();
- void onNetworkStateChecked(String resultData);
-}
\ No newline at end of file
diff --git a/hostsidetests/net/aidl/com/android/cts/net/hostside/IRemoteSocketFactory.aidl b/hostsidetests/net/aidl/com/android/cts/net/hostside/IRemoteSocketFactory.aidl
deleted file mode 100644
index 68176ad..0000000
--- a/hostsidetests/net/aidl/com/android/cts/net/hostside/IRemoteSocketFactory.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import android.os.ParcelFileDescriptor;
-
-interface IRemoteSocketFactory {
- ParcelFileDescriptor openSocketFd(String host, int port, int timeoutMs);
- String getPackageName();
- int getUid();
-}
diff --git a/hostsidetests/net/app/Android.bp b/hostsidetests/net/app/Android.bp
deleted file mode 100644
index 7a11456..0000000
--- a/hostsidetests/net/app/Android.bp
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// Copyright (C) 2014 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-android_test_helper_app {
- name: "CtsHostsideNetworkTestsApp",
- defaults: ["cts_support_defaults"],
- //sdk_version: "current",
- platform_apis: true,
- static_libs: [
- "androidx.test.rules",
- "androidx.test.ext.junit",
- "compatibility-device-util-axt",
- "ctstestrunner-axt",
- "ub-uiautomator",
- "CtsHostsideNetworkTestsAidl",
- ],
- libs: [
- "android.test.runner.stubs",
- "android.test.base.stubs",
- ],
- srcs: ["src/**/*.java"],
- // Tag this module as a cts test artifact
- test_suites: [
- "cts",
- "vts10",
- "general-tests",
- ],
-}
diff --git a/hostsidetests/net/app/AndroidManifest.xml b/hostsidetests/net/app/AndroidManifest.xml
deleted file mode 100644
index 3940de4..0000000
--- a/hostsidetests/net/app/AndroidManifest.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.net.hostside">
-
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
- <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
-
- <application android:requestLegacyExternalStorage="true" >
- <uses-library android:name="android.test.runner" />
- <activity android:name=".MyActivity" />
- <service android:name=".MyVpnService"
- android:permission="android.permission.BIND_VPN_SERVICE">
- <intent-filter>
- <action android:name="android.net.VpnService"/>
- </intent-filter>
- </service>
- <service
- android:name=".MyNotificationListenerService"
- android:label="MyNotificationListenerService"
- android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
- <intent-filter>
- <action android:name="android.service.notification.NotificationListenerService" />
- </intent-filter>
- </service>
- </application>
-
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.cts.net.hostside" />
-
-</manifest>
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
deleted file mode 100644
index 219cc3d..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE;
-import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.SystemClock;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Base class for metered and non-metered tests on idle apps.
- */
-@RequiredProperties({APP_STANDBY_MODE})
-abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetworkTestCase {
-
- @Before
- public final void setUp() throws Exception {
- super.setUp();
-
- // Set initial state.
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- setAppIdle(false);
- turnBatteryOn();
-
- registerBroadcastReceiver();
- }
-
- @After
- public final void tearDown() throws Exception {
- super.tearDown();
-
- executeSilentShellCommand("cmd battery reset");
- setAppIdle(false);
- }
-
- @Test
- public void testBackgroundNetworkAccess_enabled() throws Exception {
- setAppIdle(true);
- assertBackgroundNetworkAccess(false);
-
- assertsForegroundAlwaysHasNetworkAccess();
- setAppIdle(true);
- assertBackgroundNetworkAccess(false);
-
- // Make sure foreground app doesn't lose access upon enabling it.
- setAppIdle(true);
- launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY);
- finishActivity();
- assertAppIdle(false); // Sanity check - not idle anymore, since activity was launched...
- assertBackgroundNetworkAccess(true);
- setAppIdle(true);
- assertBackgroundNetworkAccess(false);
-
- // Same for foreground service.
- setAppIdle(true);
- launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
- stopForegroundService();
- assertAppIdle(true);
- assertBackgroundNetworkAccess(false);
- }
-
- @Test
- public void testBackgroundNetworkAccess_whitelisted() throws Exception {
- setAppIdle(true);
- assertBackgroundNetworkAccess(false);
-
- addPowerSaveModeWhitelist(TEST_APP2_PKG);
- assertAppIdle(false); // Sanity check - not idle anymore, since whitelisted
- assertBackgroundNetworkAccess(true);
-
- setAppIdleNoAssert(true);
- assertAppIdle(false); // app is still whitelisted
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- assertAppIdle(true); // Sanity check - idle again, once whitelisted was removed
- assertBackgroundNetworkAccess(false);
-
- setAppIdle(true);
- addPowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- assertAppIdle(false); // Sanity check - not idle anymore, since whitelisted
- assertBackgroundNetworkAccess(true);
-
- setAppIdleNoAssert(true);
- assertAppIdle(false); // app is still whitelisted
- removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- assertAppIdle(true); // Sanity check - idle again, once whitelisted was removed
- assertBackgroundNetworkAccess(false);
-
- assertsForegroundAlwaysHasNetworkAccess();
-
- // Sanity check - no whitelist, no access!
- setAppIdle(true);
- assertBackgroundNetworkAccess(false);
- }
-
- @Test
- public void testBackgroundNetworkAccess_tempWhitelisted() throws Exception {
- setAppIdle(true);
- assertBackgroundNetworkAccess(false);
-
- addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
- assertBackgroundNetworkAccess(true);
- // Wait until the whitelist duration is expired.
- SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
- assertBackgroundNetworkAccess(false);
- }
-
- @Test
- public void testBackgroundNetworkAccess_disabled() throws Exception {
- assertBackgroundNetworkAccess(true);
-
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(true);
- }
-
- @RequiredProperties({BATTERY_SAVER_MODE})
- @Test
- public void testAppIdleNetworkAccess_whenCharging() throws Exception {
- // Check that app is paroled when charging
- setAppIdle(true);
- assertBackgroundNetworkAccess(false);
- turnBatteryOff();
- assertBackgroundNetworkAccess(true);
- turnBatteryOn();
- assertBackgroundNetworkAccess(false);
-
- // Check that app is restricted when not idle but power-save is on
- setAppIdle(false);
- assertBackgroundNetworkAccess(true);
- setBatterySaverMode(true);
- assertBackgroundNetworkAccess(false);
- // Use setBatterySaverMode API to leave power-save mode instead of plugging in charger
- setBatterySaverMode(false);
- turnBatteryOff();
- assertBackgroundNetworkAccess(true);
-
- // And when no longer charging, it still has network access, since it's not idle
- turnBatteryOn();
- assertBackgroundNetworkAccess(true);
- }
-
- @Test
- public void testAppIdleNetworkAccess_idleWhitelisted() throws Exception {
- setAppIdle(true);
- assertAppIdle(true);
- assertBackgroundNetworkAccess(false);
-
- addAppIdleWhitelist(mUid);
- assertBackgroundNetworkAccess(true);
-
- removeAppIdleWhitelist(mUid);
- assertBackgroundNetworkAccess(false);
-
- // Make sure whitelisting a random app doesn't affect the tested app.
- addAppIdleWhitelist(mUid + 1);
- assertBackgroundNetworkAccess(false);
- removeAppIdleWhitelist(mUid + 1);
- }
-
- @Test
- public void testAppIdle_toast() throws Exception {
- setAppIdle(true);
- assertAppIdle(true);
- assertEquals("Shown", showToast());
- assertAppIdle(true);
- // Wait for a couple of seconds for the toast to actually be shown
- SystemClock.sleep(2000);
- assertAppIdle(true);
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java
deleted file mode 100644
index 04d054d..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Base class for metered and non-metered Battery Saver Mode tests.
- */
-@RequiredProperties({BATTERY_SAVER_MODE})
-abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgroundNetworkTestCase {
-
- @Before
- public final void setUp() throws Exception {
- super.setUp();
-
- // Set initial state.
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- setBatterySaverMode(false);
-
- registerBroadcastReceiver();
- }
-
- @After
- public final void tearDown() throws Exception {
- super.tearDown();
-
- setBatterySaverMode(false);
- }
-
- @Test
- public void testBackgroundNetworkAccess_enabled() throws Exception {
- setBatterySaverMode(true);
- assertBackgroundNetworkAccess(false);
-
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(false);
-
- // Make sure foreground app doesn't lose access upon Battery Saver.
- setBatterySaverMode(false);
- launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY);
- setBatterySaverMode(true);
- assertForegroundNetworkAccess();
-
- // Although it should not have access while the screen is off.
- turnScreenOff();
- assertBackgroundNetworkAccess(false);
- turnScreenOn();
- assertForegroundNetworkAccess();
-
- // Goes back to background state.
- finishActivity();
- assertBackgroundNetworkAccess(false);
-
- // Make sure foreground service doesn't lose access upon enabling Battery Saver.
- setBatterySaverMode(false);
- launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
- setBatterySaverMode(true);
- assertForegroundNetworkAccess();
- stopForegroundService();
- assertBackgroundNetworkAccess(false);
- }
-
- @Test
- public void testBackgroundNetworkAccess_whitelisted() throws Exception {
- setBatterySaverMode(true);
- assertBackgroundNetworkAccess(false);
-
- addPowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(true);
-
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
-
- addPowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(true);
-
- removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
-
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(false);
- }
-
- @Test
- public void testBackgroundNetworkAccess_disabled() throws Exception {
- assertBackgroundNetworkAccess(true);
-
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(true);
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java
deleted file mode 100644
index 6f32c56..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.Property.DOZE_MODE;
-import static com.android.cts.net.hostside.Property.NOT_LOW_RAM_DEVICE;
-
-import android.os.SystemClock;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Base class for metered and non-metered Doze Mode tests.
- */
-@RequiredProperties({DOZE_MODE})
-abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetworkTestCase {
-
- @Before
- public final void setUp() throws Exception {
- super.setUp();
-
- // Set initial state.
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- setDozeMode(false);
-
- registerBroadcastReceiver();
- }
-
- @After
- public final void tearDown() throws Exception {
- super.tearDown();
-
- setDozeMode(false);
- }
-
- @Test
- public void testBackgroundNetworkAccess_enabled() throws Exception {
- setDozeMode(true);
- assertBackgroundNetworkAccess(false);
-
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(false);
-
- // Make sure foreground service doesn't lose network access upon enabling doze.
- setDozeMode(false);
- launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
- setDozeMode(true);
- assertForegroundNetworkAccess();
- stopForegroundService();
- assertBackgroundState();
- assertBackgroundNetworkAccess(false);
- }
-
- @Test
- public void testBackgroundNetworkAccess_whitelisted() throws Exception {
- setDozeMode(true);
- assertBackgroundNetworkAccess(false);
-
- addPowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(true);
-
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
-
- addPowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
-
- removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
-
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(false);
- }
-
- @Test
- public void testBackgroundNetworkAccess_disabled() throws Exception {
- assertBackgroundNetworkAccess(true);
-
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(true);
- }
-
- @RequiredProperties({NOT_LOW_RAM_DEVICE})
- @Test
- public void testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction()
- throws Exception {
- setPendingIntentWhitelistDuration(NETWORK_TIMEOUT_MS);
- try {
- registerNotificationListenerService();
- setDozeMode(true);
- assertBackgroundNetworkAccess(false);
-
- testNotification(4, NOTIFICATION_TYPE_CONTENT);
- testNotification(8, NOTIFICATION_TYPE_DELETE);
- testNotification(15, NOTIFICATION_TYPE_FULL_SCREEN);
- testNotification(16, NOTIFICATION_TYPE_BUNDLE);
- testNotification(23, NOTIFICATION_TYPE_ACTION);
- testNotification(42, NOTIFICATION_TYPE_ACTION_BUNDLE);
- testNotification(108, NOTIFICATION_TYPE_ACTION_REMOTE_INPUT);
- } finally {
- resetDeviceIdleSettings();
- }
- }
-
- private void testNotification(int id, String type) throws Exception {
- sendNotification(id, type);
- assertBackgroundNetworkAccess(true);
- if (type.equals(NOTIFICATION_TYPE_ACTION)) {
- // Make sure access is disabled after it expires. Since this check considerably slows
- // downs the CTS tests, do it just once.
- SystemClock.sleep(NETWORK_TIMEOUT_MS);
- assertBackgroundNetworkAccess(false);
- }
- }
-
- // Must override so it only tests foreground service - once an app goes to foreground, device
- // leaves Doze Mode.
- @Override
- protected void assertsForegroundAlwaysHasNetworkAccess() throws Exception {
- launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
- stopForegroundService();
- assertBackgroundState();
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
deleted file mode 100644
index e5fd149..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ /dev/null
@@ -1,881 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
-import static android.os.BatteryManager.BATTERY_PLUGGED_AC;
-import static android.os.BatteryManager.BATTERY_PLUGGED_USB;
-import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS;
-
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.executeShellCommand;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getConnectivityManager;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getContext;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getInstrumentation;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getWifiManager;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.app.ActivityManager;
-import android.app.Instrumentation;
-import android.app.NotificationManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkInfo.State;
-import android.net.wifi.WifiManager;
-import android.os.BatteryManager;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.service.notification.NotificationListenerService;
-import android.util.Log;
-
-import org.junit.Rule;
-import org.junit.rules.RuleChain;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Superclass for tests related to background network restrictions.
- */
-@RunWith(NetworkPolicyTestRunner.class)
-public abstract class AbstractRestrictBackgroundNetworkTestCase {
- public static final String TAG = "RestrictBackgroundNetworkTests";
-
- protected static final String TEST_PKG = "com.android.cts.net.hostside";
- protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2";
-
- private static final String TEST_APP2_ACTIVITY_CLASS = TEST_APP2_PKG + ".MyActivity";
- private static final String TEST_APP2_SERVICE_CLASS = TEST_APP2_PKG + ".MyForegroundService";
-
- private static final int SLEEP_TIME_SEC = 1;
-
- // Constants below must match values defined on app2's Common.java
- private static final String MANIFEST_RECEIVER = "ManifestReceiver";
- private static final String DYNAMIC_RECEIVER = "DynamicReceiver";
-
- private static final String ACTION_RECEIVER_READY =
- "com.android.cts.net.hostside.app2.action.RECEIVER_READY";
- static final String ACTION_SHOW_TOAST =
- "com.android.cts.net.hostside.app2.action.SHOW_TOAST";
-
- protected static final String NOTIFICATION_TYPE_CONTENT = "CONTENT";
- protected static final String NOTIFICATION_TYPE_DELETE = "DELETE";
- protected static final String NOTIFICATION_TYPE_FULL_SCREEN = "FULL_SCREEN";
- protected static final String NOTIFICATION_TYPE_BUNDLE = "BUNDLE";
- protected static final String NOTIFICATION_TYPE_ACTION = "ACTION";
- protected static final String NOTIFICATION_TYPE_ACTION_BUNDLE = "ACTION_BUNDLE";
- protected static final String NOTIFICATION_TYPE_ACTION_REMOTE_INPUT = "ACTION_REMOTE_INPUT";
-
- // TODO: Update BatteryManager.BATTERY_PLUGGED_ANY as @TestApi
- public static final int BATTERY_PLUGGED_ANY =
- BATTERY_PLUGGED_AC | BATTERY_PLUGGED_USB | BATTERY_PLUGGED_WIRELESS;
-
- private static final String NETWORK_STATUS_SEPARATOR = "\\|";
- private static final int SECOND_IN_MS = 1000;
- static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS;
- private static int PROCESS_STATE_FOREGROUND_SERVICE;
-
- private static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
-
- protected static final int TYPE_COMPONENT_ACTIVTIY = 0;
- protected static final int TYPE_COMPONENT_FOREGROUND_SERVICE = 1;
-
- private static final int BATTERY_STATE_TIMEOUT_MS = 5000;
- private static final int BATTERY_STATE_CHECK_INTERVAL_MS = 500;
-
- private static final int FOREGROUND_PROC_NETWORK_TIMEOUT_MS = 6000;
-
- // Must be higher than NETWORK_TIMEOUT_MS
- private static final int ORDERED_BROADCAST_TIMEOUT_MS = NETWORK_TIMEOUT_MS * 4;
-
- private static final IntentFilter BATTERY_CHANGED_FILTER =
- new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
-
- private static final String APP_NOT_FOREGROUND_ERROR = "app_not_fg";
-
- protected static final long TEMP_POWERSAVE_WHITELIST_DURATION_MS = 5_000; // 5 sec
-
- protected Context mContext;
- protected Instrumentation mInstrumentation;
- protected ConnectivityManager mCm;
- protected int mUid;
- private int mMyUid;
- private MyServiceClient mServiceClient;
- private String mDeviceIdleConstantsSetting;
-
- @Rule
- public final RuleChain mRuleChain = RuleChain.outerRule(new RequiredPropertiesRule())
- .around(new MeterednessConfigurationRule());
-
- protected void setUp() throws Exception {
-
- PROCESS_STATE_FOREGROUND_SERVICE = (Integer) ActivityManager.class
- .getDeclaredField("PROCESS_STATE_FOREGROUND_SERVICE").get(null);
- mInstrumentation = getInstrumentation();
- mContext = getContext();
- mCm = getConnectivityManager();
- mUid = getUid(TEST_APP2_PKG);
- mMyUid = getUid(mContext.getPackageName());
- mServiceClient = new MyServiceClient(mContext);
- mServiceClient.bind();
- mDeviceIdleConstantsSetting = "device_idle_constants";
- executeShellCommand("cmd netpolicy start-watching " + mUid);
- setAppIdle(false);
-
- Log.i(TAG, "Apps status:\n"
- + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n"
- + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid));
- }
-
- protected void tearDown() throws Exception {
- executeShellCommand("cmd netpolicy stop-watching");
- mServiceClient.unbind();
- }
-
- protected int getUid(String packageName) throws Exception {
- return mContext.getPackageManager().getPackageUid(packageName, 0);
- }
-
- protected void assertRestrictBackgroundChangedReceived(int expectedCount) throws Exception {
- assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, expectedCount);
- assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0);
- }
-
- protected void assertRestrictBackgroundChangedReceived(String receiverName, int expectedCount)
- throws Exception {
- int attempts = 0;
- int count = 0;
- final int maxAttempts = 5;
- do {
- attempts++;
- count = getNumberBroadcastsReceived(receiverName, ACTION_RESTRICT_BACKGROUND_CHANGED);
- assertFalse("Expected count " + expectedCount + " but actual is " + count,
- count > expectedCount);
- if (count == expectedCount) {
- break;
- }
- Log.d(TAG, "Expecting count " + expectedCount + " but actual is " + count + " after "
- + attempts + " attempts; sleeping "
- + SLEEP_TIME_SEC + " seconds before trying again");
- SystemClock.sleep(SLEEP_TIME_SEC * SECOND_IN_MS);
- } while (attempts <= maxAttempts);
- assertEquals("Number of expected broadcasts for " + receiverName + " not reached after "
- + maxAttempts * SLEEP_TIME_SEC + " seconds", expectedCount, count);
- }
-
- protected String sendOrderedBroadcast(Intent intent) throws Exception {
- return sendOrderedBroadcast(intent, ORDERED_BROADCAST_TIMEOUT_MS);
- }
-
- protected String sendOrderedBroadcast(Intent intent, int timeoutMs) throws Exception {
- final LinkedBlockingQueue<String> result = new LinkedBlockingQueue<>(1);
- Log.d(TAG, "Sending ordered broadcast: " + intent);
- mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String resultData = getResultData();
- if (resultData == null) {
- Log.e(TAG, "Received null data from ordered intent");
- return;
- }
- result.offer(resultData);
- }
- }, null, 0, null, null);
-
- final String resultData = result.poll(timeoutMs, TimeUnit.MILLISECONDS);
- Log.d(TAG, "Ordered broadcast response after " + timeoutMs + "ms: " + resultData );
- return resultData;
- }
-
- protected int getNumberBroadcastsReceived(String receiverName, String action) throws Exception {
- return mServiceClient.getCounters(receiverName, action);
- }
-
- protected void assertRestrictBackgroundStatus(int expectedStatus) throws Exception {
- final String status = mServiceClient.getRestrictBackgroundStatus();
- assertNotNull("didn't get API status from app2", status);
- assertEquals(restrictBackgroundValueToString(expectedStatus),
- restrictBackgroundValueToString(Integer.parseInt(status)));
- }
-
- protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception {
- assertBackgroundState(); // Sanity check.
- assertNetworkAccess(expectAllowed /* expectAvailable */, false /* needScreenOn */);
- }
-
- protected void assertForegroundNetworkAccess() throws Exception {
- assertForegroundState(); // Sanity check.
- // We verified that app is in foreground state but if the screen turns-off while
- // verifying for network access, the app will go into background state (in case app's
- // foreground status was due to top activity). So, turn the screen on when verifying
- // network connectivity.
- assertNetworkAccess(true /* expectAvailable */, true /* needScreenOn */);
- }
-
- protected void assertForegroundServiceNetworkAccess() throws Exception {
- assertForegroundServiceState(); // Sanity check.
- assertNetworkAccess(true /* expectAvailable */, false /* needScreenOn */);
- }
-
- /**
- * Asserts that an app always have access while on foreground or running a foreground service.
- *
- * <p>This method will launch an activity and a foreground service to make the assertion, but
- * will finish the activity / stop the service afterwards.
- */
- protected void assertsForegroundAlwaysHasNetworkAccess() throws Exception{
- // Checks foreground first.
- launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY);
- finishActivity();
-
- // Then foreground service
- launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
- stopForegroundService();
- }
-
- protected final void assertBackgroundState() throws Exception {
- final int maxTries = 30;
- ProcessState state = null;
- for (int i = 1; i <= maxTries; i++) {
- state = getProcessStateByUid(mUid);
- Log.v(TAG, "assertBackgroundState(): status for app2 (" + mUid + ") on attempt #" + i
- + ": " + state);
- if (isBackground(state.state)) {
- return;
- }
- Log.d(TAG, "App not on background state (" + state + ") on attempt #" + i
- + "; sleeping 1s before trying again");
- SystemClock.sleep(SECOND_IN_MS);
- }
- fail("App2 is not on background state after " + maxTries + " attempts: " + state );
- }
-
- protected final void assertForegroundState() throws Exception {
- final int maxTries = 30;
- ProcessState state = null;
- for (int i = 1; i <= maxTries; i++) {
- state = getProcessStateByUid(mUid);
- Log.v(TAG, "assertForegroundState(): status for app2 (" + mUid + ") on attempt #" + i
- + ": " + state);
- if (!isBackground(state.state)) {
- return;
- }
- Log.d(TAG, "App not on foreground state on attempt #" + i
- + "; sleeping 1s before trying again");
- turnScreenOn();
- SystemClock.sleep(SECOND_IN_MS);
- }
- fail("App2 is not on foreground state after " + maxTries + " attempts: " + state );
- }
-
- protected final void assertForegroundServiceState() throws Exception {
- final int maxTries = 30;
- ProcessState state = null;
- for (int i = 1; i <= maxTries; i++) {
- state = getProcessStateByUid(mUid);
- Log.v(TAG, "assertForegroundServiceState(): status for app2 (" + mUid + ") on attempt #"
- + i + ": " + state);
- if (state.state == PROCESS_STATE_FOREGROUND_SERVICE) {
- return;
- }
- Log.d(TAG, "App not on foreground service state on attempt #" + i
- + "; sleeping 1s before trying again");
- SystemClock.sleep(SECOND_IN_MS);
- }
- fail("App2 is not on foreground service state after " + maxTries + " attempts: " + state );
- }
-
- /**
- * Returns whether an app state should be considered "background" for restriction purposes.
- */
- protected boolean isBackground(int state) {
- return state > PROCESS_STATE_FOREGROUND_SERVICE;
- }
-
- /**
- * Asserts whether the active network is available or not.
- */
- private void assertNetworkAccess(boolean expectAvailable, boolean needScreenOn)
- throws Exception {
- final int maxTries = 5;
- String error = null;
- int timeoutMs = 500;
-
- for (int i = 1; i <= maxTries; i++) {
- error = checkNetworkAccess(expectAvailable);
-
- if (error.isEmpty()) return;
-
- // TODO: ideally, it should retry only when it cannot connect to an external site,
- // or no retry at all! But, currently, the initial change fails almost always on
- // battery saver tests because the netd changes are made asynchronously.
- // Once b/27803922 is fixed, this retry mechanism should be revisited.
-
- Log.w(TAG, "Network status didn't match for expectAvailable=" + expectAvailable
- + " on attempt #" + i + ": " + error + "\n"
- + "Sleeping " + timeoutMs + "ms before trying again");
- if (needScreenOn) {
- turnScreenOn();
- }
- // No sleep after the last turn
- if (i < maxTries) {
- SystemClock.sleep(timeoutMs);
- }
- // Exponential back-off.
- timeoutMs = Math.min(timeoutMs*2, NETWORK_TIMEOUT_MS);
- }
- fail("Invalid state for expectAvailable=" + expectAvailable + " after " + maxTries
- + " attempts.\nLast error: " + error);
- }
-
- /**
- * Checks whether the network is available as expected.
- *
- * @return error message with the mismatch (or empty if assertion passed).
- */
- private String checkNetworkAccess(boolean expectAvailable) throws Exception {
- final String resultData = mServiceClient.checkNetworkStatus();
- return checkForAvailabilityInResultData(resultData, expectAvailable);
- }
-
- private String checkForAvailabilityInResultData(String resultData, boolean expectAvailable) {
- if (resultData == null) {
- assertNotNull("Network status from app2 is null", resultData);
- }
- // Network status format is described on MyBroadcastReceiver.checkNetworkStatus()
- final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR);
- assertEquals("Wrong network status: " + resultData, 5, parts.length); // Sanity check
- final State state = parts[0].equals("null") ? null : State.valueOf(parts[0]);
- final DetailedState detailedState = parts[1].equals("null")
- ? null : DetailedState.valueOf(parts[1]);
- final boolean connected = Boolean.valueOf(parts[2]);
- final String connectionCheckDetails = parts[3];
- final String networkInfo = parts[4];
-
- final StringBuilder errors = new StringBuilder();
- final State expectedState;
- final DetailedState expectedDetailedState;
- if (expectAvailable) {
- expectedState = State.CONNECTED;
- expectedDetailedState = DetailedState.CONNECTED;
- } else {
- expectedState = State.DISCONNECTED;
- expectedDetailedState = DetailedState.BLOCKED;
- }
-
- if (expectAvailable != connected) {
- errors.append(String.format("External site connection failed: expected %s, got %s\n",
- expectAvailable, connected));
- }
- if (expectedState != state || expectedDetailedState != detailedState) {
- errors.append(String.format("Connection state mismatch: expected %s/%s, got %s/%s\n",
- expectedState, expectedDetailedState, state, detailedState));
- }
-
- if (errors.length() > 0) {
- errors.append("\tnetworkInfo: " + networkInfo + "\n");
- errors.append("\tconnectionCheckDetails: " + connectionCheckDetails + "\n");
- }
- return errors.toString();
- }
-
- /**
- * Runs a Shell command which is not expected to generate output.
- */
- protected void executeSilentShellCommand(String command) {
- final String result = executeShellCommand(command);
- assertTrue("Command '" + command + "' failed: " + result, result.trim().isEmpty());
- }
-
- /**
- * Asserts the result of a command, wait and re-running it a couple times if necessary.
- */
- protected void assertDelayedShellCommand(String command, final String expectedResult)
- throws Exception {
- assertDelayedShellCommand(command, 5, 1, expectedResult);
- }
-
- protected void assertDelayedShellCommand(String command, int maxTries, int napTimeSeconds,
- final String expectedResult) throws Exception {
- assertDelayedShellCommand(command, maxTries, napTimeSeconds, new ExpectResultChecker() {
-
- @Override
- public boolean isExpected(String result) {
- return expectedResult.equals(result);
- }
-
- @Override
- public String getExpected() {
- return expectedResult;
- }
- });
- }
-
- protected void assertDelayedShellCommand(String command, int maxTries, int napTimeSeconds,
- ExpectResultChecker checker) throws Exception {
- String result = "";
- for (int i = 1; i <= maxTries; i++) {
- result = executeShellCommand(command).trim();
- if (checker.isExpected(result)) return;
- Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '"
- + checker.getExpected() + "' on attempt #" + i
- + "; sleeping " + napTimeSeconds + "s before trying again");
- SystemClock.sleep(napTimeSeconds * SECOND_IN_MS);
- }
- fail("Command '" + command + "' did not return '" + checker.getExpected() + "' after "
- + maxTries
- + " attempts. Last result: '" + result + "'");
- }
-
- protected void addRestrictBackgroundWhitelist(int uid) throws Exception {
- executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid);
- assertRestrictBackgroundWhitelist(uid, true);
- // UID policies live by the Highlander rule: "There can be only one".
- // Hence, if app is whitelisted, it should not be blacklisted.
- assertRestrictBackgroundBlacklist(uid, false);
- }
-
- protected void removeRestrictBackgroundWhitelist(int uid) throws Exception {
- executeShellCommand("cmd netpolicy remove restrict-background-whitelist " + uid);
- assertRestrictBackgroundWhitelist(uid, false);
- }
-
- protected void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception {
- assertRestrictBackground("restrict-background-whitelist", uid, expected);
- }
-
- protected void addRestrictBackgroundBlacklist(int uid) throws Exception {
- executeShellCommand("cmd netpolicy add restrict-background-blacklist " + uid);
- assertRestrictBackgroundBlacklist(uid, true);
- // UID policies live by the Highlander rule: "There can be only one".
- // Hence, if app is blacklisted, it should not be whitelisted.
- assertRestrictBackgroundWhitelist(uid, false);
- }
-
- protected void removeRestrictBackgroundBlacklist(int uid) throws Exception {
- executeShellCommand("cmd netpolicy remove restrict-background-blacklist " + uid);
- assertRestrictBackgroundBlacklist(uid, false);
- }
-
- protected void assertRestrictBackgroundBlacklist(int uid, boolean expected) throws Exception {
- assertRestrictBackground("restrict-background-blacklist", uid, expected);
- }
-
- protected void addAppIdleWhitelist(int uid) throws Exception {
- executeShellCommand("cmd netpolicy add app-idle-whitelist " + uid);
- assertAppIdleWhitelist(uid, true);
- }
-
- protected void removeAppIdleWhitelist(int uid) throws Exception {
- executeShellCommand("cmd netpolicy remove app-idle-whitelist " + uid);
- assertAppIdleWhitelist(uid, false);
- }
-
- protected void assertAppIdleWhitelist(int uid, boolean expected) throws Exception {
- assertRestrictBackground("app-idle-whitelist", uid, expected);
- }
-
- private void assertRestrictBackground(String list, int uid, boolean expected) throws Exception {
- final int maxTries = 5;
- boolean actual = false;
- final String expectedUid = Integer.toString(uid);
- String uids = "";
- for (int i = 1; i <= maxTries; i++) {
- final String output =
- executeShellCommand("cmd netpolicy list " + list);
- uids = output.split(":")[1];
- for (String candidate : uids.split(" ")) {
- actual = candidate.trim().equals(expectedUid);
- if (expected == actual) {
- return;
- }
- }
- Log.v(TAG, list + " check for uid " + uid + " doesn't match yet (expected "
- + expected + ", got " + actual + "); sleeping 1s before polling again");
- SystemClock.sleep(SECOND_IN_MS);
- }
- fail(list + " check for uid " + uid + " failed: expected " + expected + ", got " + actual
- + ". Full list: " + uids);
- }
-
- protected void addTempPowerSaveModeWhitelist(String packageName, long duration)
- throws Exception {
- Log.i(TAG, "Adding pkg " + packageName + " to temp-power-save-mode whitelist");
- executeShellCommand("dumpsys deviceidle tempwhitelist -d " + duration + " " + packageName);
- }
-
- protected void assertPowerSaveModeWhitelist(String packageName, boolean expected)
- throws Exception {
- // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
- // need to use netpolicy for whitelisting
- assertDelayedShellCommand("dumpsys deviceidle whitelist =" + packageName,
- Boolean.toString(expected));
- }
-
- protected void addPowerSaveModeWhitelist(String packageName) throws Exception {
- Log.i(TAG, "Adding package " + packageName + " to power-save-mode whitelist");
- // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
- // need to use netpolicy for whitelisting
- executeShellCommand("dumpsys deviceidle whitelist +" + packageName);
- assertPowerSaveModeWhitelist(packageName, true); // Sanity check
- }
-
- protected void removePowerSaveModeWhitelist(String packageName) throws Exception {
- Log.i(TAG, "Removing package " + packageName + " from power-save-mode whitelist");
- // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
- // need to use netpolicy for whitelisting
- executeShellCommand("dumpsys deviceidle whitelist -" + packageName);
- assertPowerSaveModeWhitelist(packageName, false); // Sanity check
- }
-
- protected void assertPowerSaveModeExceptIdleWhitelist(String packageName, boolean expected)
- throws Exception {
- // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
- // need to use netpolicy for whitelisting
- assertDelayedShellCommand("dumpsys deviceidle except-idle-whitelist =" + packageName,
- Boolean.toString(expected));
- }
-
- protected void addPowerSaveModeExceptIdleWhitelist(String packageName) throws Exception {
- Log.i(TAG, "Adding package " + packageName + " to power-save-mode-except-idle whitelist");
- // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
- // need to use netpolicy for whitelisting
- executeShellCommand("dumpsys deviceidle except-idle-whitelist +" + packageName);
- assertPowerSaveModeExceptIdleWhitelist(packageName, true); // Sanity check
- }
-
- protected void removePowerSaveModeExceptIdleWhitelist(String packageName) throws Exception {
- Log.i(TAG, "Removing package " + packageName
- + " from power-save-mode-except-idle whitelist");
- // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
- // need to use netpolicy for whitelisting
- executeShellCommand("dumpsys deviceidle except-idle-whitelist reset");
- assertPowerSaveModeExceptIdleWhitelist(packageName, false); // Sanity check
- }
-
- protected void turnBatteryOn() throws Exception {
- executeSilentShellCommand("cmd battery unplug");
- executeSilentShellCommand("cmd battery set status "
- + BatteryManager.BATTERY_STATUS_DISCHARGING);
- assertBatteryState(false);
- }
-
- protected void turnBatteryOff() throws Exception {
- executeSilentShellCommand("cmd battery set ac " + BATTERY_PLUGGED_ANY);
- executeSilentShellCommand("cmd battery set level 100");
- executeSilentShellCommand("cmd battery set status "
- + BatteryManager.BATTERY_STATUS_CHARGING);
- assertBatteryState(true);
- }
-
- private void assertBatteryState(boolean pluggedIn) throws Exception {
- final long endTime = SystemClock.elapsedRealtime() + BATTERY_STATE_TIMEOUT_MS;
- while (isDevicePluggedIn() != pluggedIn && SystemClock.elapsedRealtime() <= endTime) {
- Thread.sleep(BATTERY_STATE_CHECK_INTERVAL_MS);
- }
- if (isDevicePluggedIn() != pluggedIn) {
- fail("Timed out waiting for the plugged-in state to change,"
- + " expected pluggedIn: " + pluggedIn);
- }
- }
-
- private boolean isDevicePluggedIn() {
- final Intent batteryIntent = mContext.registerReceiver(null, BATTERY_CHANGED_FILTER);
- return batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) > 0;
- }
-
- protected void turnScreenOff() throws Exception {
- executeSilentShellCommand("input keyevent KEYCODE_SLEEP");
- }
-
- protected void turnScreenOn() throws Exception {
- executeSilentShellCommand("input keyevent KEYCODE_WAKEUP");
- executeSilentShellCommand("wm dismiss-keyguard");
- }
-
- protected void setBatterySaverMode(boolean enabled) throws Exception {
- Log.i(TAG, "Setting Battery Saver Mode to " + enabled);
- if (enabled) {
- turnBatteryOn();
- executeSilentShellCommand("cmd power set-mode 1");
- } else {
- executeSilentShellCommand("cmd power set-mode 0");
- turnBatteryOff();
- }
- }
-
- protected void setDozeMode(boolean enabled) throws Exception {
- // Sanity check, since tests should check beforehand....
- assertTrue("Device does not support Doze Mode", isDozeModeSupported());
-
- Log.i(TAG, "Setting Doze Mode to " + enabled);
- if (enabled) {
- turnBatteryOn();
- turnScreenOff();
- executeShellCommand("dumpsys deviceidle force-idle deep");
- } else {
- turnScreenOn();
- turnBatteryOff();
- executeShellCommand("dumpsys deviceidle unforce");
- }
- // Sanity check.
- assertDozeMode(enabled);
- }
-
- protected void assertDozeMode(boolean enabled) throws Exception {
- assertDelayedShellCommand("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE");
- }
-
- protected void setAppIdle(boolean enabled) throws Exception {
- Log.i(TAG, "Setting app idle to " + enabled);
- executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled );
- assertAppIdle(enabled); // Sanity check
- }
-
- protected void setAppIdleNoAssert(boolean enabled) throws Exception {
- Log.i(TAG, "Setting app idle to " + enabled);
- executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled );
- }
-
- protected void assertAppIdle(boolean enabled) throws Exception {
- try {
- assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 15, 2, "Idle=" + enabled);
- } catch (Throwable e) {
- throw e;
- }
- }
-
- /**
- * Starts a service that will register a broadcast receiver to receive
- * {@code RESTRICT_BACKGROUND_CHANGE} intents.
- * <p>
- * The service must run in a separate app because otherwise it would be killed every time
- * {@link #runDeviceTests(String, String)} is executed.
- */
- protected void registerBroadcastReceiver() throws Exception {
- mServiceClient.registerBroadcastReceiver();
-
- final Intent intent = new Intent(ACTION_RECEIVER_READY)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- // Wait until receiver is ready.
- final int maxTries = 10;
- for (int i = 1; i <= maxTries; i++) {
- final String message = sendOrderedBroadcast(intent, SECOND_IN_MS * 4);
- Log.d(TAG, "app2 receiver acked: " + message);
- if (message != null) {
- return;
- }
- Log.v(TAG, "app2 receiver is not ready yet; sleeping 1s before polling again");
- SystemClock.sleep(SECOND_IN_MS);
- }
- fail("app2 receiver is not ready");
- }
-
- protected void registerNetworkCallback(INetworkCallback cb) throws Exception {
- mServiceClient.registerNetworkCallback(cb);
- }
-
- protected void unregisterNetworkCallback() throws Exception {
- mServiceClient.unregisterNetworkCallback();
- }
-
- /**
- * Registers a {@link NotificationListenerService} implementation that will execute the
- * notification actions right after the notification is sent.
- */
- protected void registerNotificationListenerService() throws Exception {
- executeShellCommand("cmd notification allow_listener "
- + MyNotificationListenerService.getId());
- final NotificationManager nm = mContext.getSystemService(NotificationManager.class);
- final ComponentName listenerComponent = MyNotificationListenerService.getComponentName();
- assertTrue(listenerComponent + " has not been granted access",
- nm.isNotificationListenerAccessGranted(listenerComponent));
- }
-
- protected void setPendingIntentWhitelistDuration(int durationMs) throws Exception {
- executeSilentShellCommand(String.format(
- "settings put global %s %s=%d", mDeviceIdleConstantsSetting,
- "notification_whitelist_duration", durationMs));
- }
-
- protected void resetDeviceIdleSettings() throws Exception {
- executeShellCommand(String.format("settings delete global %s",
- mDeviceIdleConstantsSetting));
- }
-
- protected void launchComponentAndAssertNetworkAccess(int type) throws Exception {
- if (type == TYPE_COMPONENT_FOREGROUND_SERVICE) {
- startForegroundService();
- assertForegroundServiceNetworkAccess();
- return;
- } else if (type == TYPE_COMPONENT_ACTIVTIY) {
- turnScreenOn();
- // Wait for screen-on state to propagate through the system.
- SystemClock.sleep(2000);
- final CountDownLatch latch = new CountDownLatch(1);
- final Intent launchIntent = getIntentForComponent(type);
- final Bundle extras = new Bundle();
- final String[] errors = new String[]{null};
- extras.putBinder(KEY_NETWORK_STATE_OBSERVER, getNewNetworkStateObserver(latch, errors));
- launchIntent.putExtras(extras);
- mContext.startActivity(launchIntent);
- if (latch.await(FOREGROUND_PROC_NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- if (!errors[0].isEmpty()) {
- if (errors[0] == APP_NOT_FOREGROUND_ERROR) {
- // App didn't come to foreground when the activity is started, so try again.
- assertForegroundNetworkAccess();
- } else {
- fail("Network is not available for app2 (" + mUid + "): " + errors[0]);
- }
- }
- } else {
- fail("Timed out waiting for network availability status from app2 (" + mUid + ")");
- }
- } else {
- throw new IllegalArgumentException("Unknown type: " + type);
- }
- }
-
- private void startForegroundService() throws Exception {
- final Intent launchIntent = getIntentForComponent(TYPE_COMPONENT_FOREGROUND_SERVICE);
- mContext.startForegroundService(launchIntent);
- assertForegroundServiceState();
- }
-
- private Intent getIntentForComponent(int type) {
- final Intent intent = new Intent();
- if (type == TYPE_COMPONENT_ACTIVTIY) {
- intent.setComponent(new ComponentName(TEST_APP2_PKG, TEST_APP2_ACTIVITY_CLASS))
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- } else if (type == TYPE_COMPONENT_FOREGROUND_SERVICE) {
- intent.setComponent(new ComponentName(TEST_APP2_PKG, TEST_APP2_SERVICE_CLASS))
- .setFlags(1);
- } else {
- fail("Unknown type: " + type);
- }
- return intent;
- }
-
- protected void stopForegroundService() throws Exception {
- executeShellCommand(String.format("am startservice -f 2 %s/%s",
- TEST_APP2_PKG, TEST_APP2_SERVICE_CLASS));
- // NOTE: cannot assert state because it depends on whether activity was on top before.
- }
-
- private Binder getNewNetworkStateObserver(final CountDownLatch latch,
- final String[] errors) {
- return new INetworkStateObserver.Stub() {
- @Override
- public boolean isForeground() {
- try {
- final ProcessState state = getProcessStateByUid(mUid);
- return !isBackground(state.state);
- } catch (Exception e) {
- Log.d(TAG, "Error while reading the proc state for " + mUid + ": " + e);
- return false;
- }
- }
-
- @Override
- public void onNetworkStateChecked(String resultData) {
- errors[0] = resultData == null
- ? APP_NOT_FOREGROUND_ERROR
- : checkForAvailabilityInResultData(resultData, true);
- latch.countDown();
- }
- };
- }
-
- /**
- * Finishes an activity on app2 so its process is demoted fromforeground status.
- */
- protected void finishActivity() throws Exception {
- executeShellCommand("am broadcast -a "
- + " com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY "
- + "--receiver-foreground --receiver-registered-only");
- }
-
- protected void sendNotification(int notificationId, String notificationType) throws Exception {
- Log.d(TAG, "Sending notification broadcast (id=" + notificationId
- + ", type=" + notificationType);
- mServiceClient.sendNotification(notificationId, notificationType);
- }
-
- protected String showToast() {
- final Intent intent = new Intent(ACTION_SHOW_TOAST);
- intent.setPackage(TEST_APP2_PKG);
- Log.d(TAG, "Sending request to show toast");
- try {
- return sendOrderedBroadcast(intent, 3 * SECOND_IN_MS);
- } catch (Exception e) {
- return "";
- }
- }
-
- private ProcessState getProcessStateByUid(int uid) throws Exception {
- return new ProcessState(executeShellCommand("cmd activity get-uid-state " + uid));
- }
-
- private static class ProcessState {
- private final String fullState;
- final int state;
-
- ProcessState(String fullState) {
- this.fullState = fullState;
- try {
- this.state = Integer.parseInt(fullState.split(" ")[0]);
- } catch (Exception e) {
- throw new IllegalArgumentException("Could not parse " + fullState);
- }
- }
-
- @Override
- public String toString() {
- return fullState;
- }
- }
-
- /**
- * Helper class used to assert the result of a Shell command.
- */
- protected static interface ExpectResultChecker {
- /**
- * Checkes whether the result of the command matched the expectation.
- */
- boolean isExpected(String result);
- /**
- * Gets the expected result so it's displayed on log and failure messages.
- */
- String getExpected();
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java
deleted file mode 100644
index f1858d6..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-
-@RequiredProperties({METERED_NETWORK})
-public class AppIdleMeteredTest extends AbstractAppIdleTestCase {
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java
deleted file mode 100644
index e737a6d..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
-
-@RequiredProperties({NON_METERED_NETWORK})
-public class AppIdleNonMeteredTest extends AbstractAppIdleTestCase {
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java
deleted file mode 100644
index c78ca2e..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-
-@RequiredProperties({METERED_NETWORK})
-public class BatterySaverModeMeteredTest extends AbstractBatterySaverModeTestCase {
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
deleted file mode 100644
index fb52a54..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
-
-@RequiredProperties({NON_METERED_NETWORK})
-public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase {
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
deleted file mode 100644
index aa2c914..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
-import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
-import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
-
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
-import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-import static com.android.cts.net.hostside.Property.NO_DATA_SAVER_MODE;
-
-import static org.junit.Assert.fail;
-
-import com.android.compatibility.common.util.CddTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import androidx.test.filters.LargeTest;
-
-@RequiredProperties({DATA_SAVER_MODE, METERED_NETWORK})
-@LargeTest
-public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase {
-
- private static final String[] REQUIRED_WHITELISTED_PACKAGES = {
- "com.android.providers.downloads"
- };
-
- @Before
- public void setUp() throws Exception {
- super.setUp();
-
- // Set initial state.
- setRestrictBackground(false);
- removeRestrictBackgroundWhitelist(mUid);
- removeRestrictBackgroundBlacklist(mUid);
-
- registerBroadcastReceiver();
- assertRestrictBackgroundChangedReceived(0);
- }
-
- @After
- public void tearDown() throws Exception {
- super.tearDown();
-
- setRestrictBackground(false);
- }
-
- @Test
- public void testGetRestrictBackgroundStatus_disabled() throws Exception {
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
-
- // Sanity check: make sure status is always disabled, never whitelisted
- addRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundChangedReceived(0);
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
-
- assertsForegroundAlwaysHasNetworkAccess();
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
- }
-
- @Test
- public void testGetRestrictBackgroundStatus_whitelisted() throws Exception {
- setRestrictBackground(true);
- assertRestrictBackgroundChangedReceived(1);
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
-
- addRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundChangedReceived(2);
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_WHITELISTED);
-
- removeRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundChangedReceived(3);
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
-
- assertsForegroundAlwaysHasNetworkAccess();
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
- }
-
- @Test
- public void testGetRestrictBackgroundStatus_enabled() throws Exception {
- setRestrictBackground(true);
- assertRestrictBackgroundChangedReceived(1);
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
-
- assertsForegroundAlwaysHasNetworkAccess();
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
-
- // Make sure foreground app doesn't lose access upon enabling Data Saver.
- setRestrictBackground(false);
- launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY);
- setRestrictBackground(true);
- assertForegroundNetworkAccess();
-
- // Although it should not have access while the screen is off.
- turnScreenOff();
- assertBackgroundNetworkAccess(false);
- turnScreenOn();
- assertForegroundNetworkAccess();
-
- // Goes back to background state.
- finishActivity();
- assertBackgroundNetworkAccess(false);
-
- // Make sure foreground service doesn't lose access upon enabling Data Saver.
- setRestrictBackground(false);
- launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
- setRestrictBackground(true);
- assertForegroundNetworkAccess();
- stopForegroundService();
- assertBackgroundNetworkAccess(false);
- }
-
- @Test
- public void testGetRestrictBackgroundStatus_blacklisted() throws Exception {
- addRestrictBackgroundBlacklist(mUid);
- assertRestrictBackgroundChangedReceived(1);
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
-
- assertsForegroundAlwaysHasNetworkAccess();
- assertRestrictBackgroundChangedReceived(1);
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
-
- // UID policies live by the Highlander rule: "There can be only one".
- // Hence, if app is whitelisted, it should not be blacklisted anymore.
- setRestrictBackground(true);
- assertRestrictBackgroundChangedReceived(2);
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
- addRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundChangedReceived(3);
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_WHITELISTED);
-
- // Check status after removing blacklist.
- // ...re-enables first
- addRestrictBackgroundBlacklist(mUid);
- assertRestrictBackgroundChangedReceived(4);
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
- assertsForegroundAlwaysHasNetworkAccess();
- // ... remove blacklist - access's still rejected because Data Saver is on
- removeRestrictBackgroundBlacklist(mUid);
- assertRestrictBackgroundChangedReceived(4);
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
- assertsForegroundAlwaysHasNetworkAccess();
- // ... finally, disable Data Saver
- setRestrictBackground(false);
- assertRestrictBackgroundChangedReceived(5);
- assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
- assertsForegroundAlwaysHasNetworkAccess();
- }
-
- @Test
- public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception {
- final StringBuilder error = new StringBuilder();
- for (String packageName : REQUIRED_WHITELISTED_PACKAGES) {
- int uid = -1;
- try {
- uid = getUid(packageName);
- assertRestrictBackgroundWhitelist(uid, true);
- } catch (Throwable t) {
- error.append("\nFailed for '").append(packageName).append("'");
- if (uid > 0) {
- error.append(" (uid ").append(uid).append(")");
- }
- error.append(": ").append(t).append("\n");
- }
- }
- if (error.length() > 0) {
- fail(error.toString());
- }
- }
-
- @RequiredProperties({NO_DATA_SAVER_MODE})
- @CddTest(requirement="7.4.7/C-2-2")
- @Test
- public void testBroadcastNotSentOnUnsupportedDevices() throws Exception {
- setRestrictBackground(true);
- assertRestrictBackgroundChangedReceived(0);
-
- setRestrictBackground(false);
- assertRestrictBackgroundChangedReceived(0);
-
- setRestrictBackground(true);
- assertRestrictBackgroundChangedReceived(0);
- }
-
- private void assertDataSaverStatusOnBackground(int expectedStatus) throws Exception {
- assertRestrictBackgroundStatus(expectedStatus);
- assertBackgroundNetworkAccess(expectedStatus != RESTRICT_BACKGROUND_STATUS_ENABLED);
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java
deleted file mode 100644
index 4306c99..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-
-@RequiredProperties({METERED_NETWORK})
-public class DozeModeMeteredTest extends AbstractDozeModeTestCase {
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java
deleted file mode 100644
index 1e89f15..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
-
-@RequiredProperties({NON_METERED_NETWORK})
-public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase {
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java
deleted file mode 100644
index 5ecb399..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG;
-import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_APP2_PKG;
-import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_PKG;
-
-import android.os.Environment;
-import android.os.FileUtils;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import com.android.compatibility.common.util.OnFailureRule;
-
-import org.junit.AssumptionViolatedException;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-
-public class DumpOnFailureRule extends OnFailureRule {
- private File mDumpDir = new File(Environment.getExternalStorageDirectory(),
- "CtsHostsideNetworkTests");
-
- @Override
- public void onTestFailure(Statement base, Description description, Throwable throwable) {
- final String testName = description.getClassName() + "_" + description.getMethodName();
-
- if (throwable instanceof AssumptionViolatedException) {
- Log.d(TAG, "Skipping test " + testName + ": " + throwable);
- return;
- }
-
- prepareDumpRootDir();
- final File dumpFile = new File(mDumpDir, "dump-" + testName);
- Log.i(TAG, "Dumping debug info for " + description + ": " + dumpFile.getPath());
- try (FileOutputStream out = new FileOutputStream(dumpFile)) {
- for (String cmd : new String[] {
- "dumpsys netpolicy",
- "dumpsys network_management",
- "dumpsys usagestats " + TEST_PKG + " " + TEST_APP2_PKG,
- "dumpsys usagestats appstandby",
- }) {
- dumpCommandOutput(out, cmd);
- }
- } catch (FileNotFoundException e) {
- Log.e(TAG, "Error opening file: " + dumpFile, e);
- } catch (IOException e) {
- Log.e(TAG, "Error closing file: " + dumpFile, e);
- }
- }
-
- void dumpCommandOutput(FileOutputStream out, String cmd) {
- final ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation()
- .getUiAutomation().executeShellCommand(cmd);
- try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
- out.write(("Output of '" + cmd + "':\n").getBytes(StandardCharsets.UTF_8));
- FileUtils.copy(in, out);
- out.write("\n\n=================================================================\n\n"
- .getBytes(StandardCharsets.UTF_8));
- } catch (IOException e) {
- Log.e(TAG, "Error dumping '" + cmd + "'", e);
- }
- }
-
- void prepareDumpRootDir() {
- if (!mDumpDir.exists() && !mDumpDir.mkdir()) {
- Log.e(TAG, "Error creating " + mDumpDir);
- }
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java
deleted file mode 100644
index 8fadf9e..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.resetMeteredNetwork;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setupMeteredNetwork;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
-
-import android.util.ArraySet;
-import android.util.Pair;
-
-import com.android.compatibility.common.util.BeforeAfterRule;
-
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-public class MeterednessConfigurationRule extends BeforeAfterRule {
- private Pair<String, Boolean> mSsidAndInitialMeteredness;
-
- @Override
- public void onBefore(Statement base, Description description) throws Throwable {
- final ArraySet<Property> requiredProperties
- = RequiredPropertiesRule.getRequiredProperties();
- if (requiredProperties.contains(METERED_NETWORK)) {
- configureNetworkMeteredness(true);
- } else if (requiredProperties.contains(NON_METERED_NETWORK)) {
- configureNetworkMeteredness(false);
- }
- }
-
- @Override
- public void onAfter(Statement base, Description description) throws Throwable {
- resetNetworkMeteredness();
- }
-
- public void configureNetworkMeteredness(boolean metered) throws Exception {
- mSsidAndInitialMeteredness = setupMeteredNetwork(metered);
- }
-
- public void resetNetworkMeteredness() throws Exception {
- if (mSsidAndInitialMeteredness != null) {
- resetMeteredNetwork(mSsidAndInitialMeteredness.first,
- mSsidAndInitialMeteredness.second);
- }
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java
deleted file mode 100644
index c9edda6..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
-import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE;
-import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.DOZE_MODE;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
-
-import android.os.SystemClock;
-import android.util.Log;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Test cases for the more complex scenarios where multiple restrictions (like Battery Saver Mode
- * and Data Saver Mode) are applied simultaneously.
- * <p>
- * <strong>NOTE: </strong>it might sound like the test methods on this class are testing too much,
- * which would make it harder to diagnose individual failures, but the assumption is that such
- * failure most likely will happen when the restriction is tested individually as well.
- */
-public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase {
- private static final String TAG = "MixedModesTest";
-
- @Before
- public void setUp() throws Exception {
- super.setUp();
-
- // Set initial state.
- removeRestrictBackgroundWhitelist(mUid);
- removeRestrictBackgroundBlacklist(mUid);
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
-
- registerBroadcastReceiver();
- }
-
- @After
- public void tearDown() throws Exception {
- super.tearDown();
-
- try {
- setRestrictBackground(false);
- } finally {
- setBatterySaverMode(false);
- }
- }
-
- /**
- * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks.
- */
- @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, METERED_NETWORK})
- @Test
- public void testDataAndBatterySaverModes_meteredNetwork() throws Exception {
- final MeterednessConfigurationRule meterednessConfiguration
- = new MeterednessConfigurationRule();
- meterednessConfiguration.configureNetworkMeteredness(true);
- try {
- setRestrictBackground(true);
- setBatterySaverMode(true);
-
- Log.v(TAG, "Not whitelisted for any.");
- assertBackgroundNetworkAccess(false);
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(false);
-
- Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver.");
- addRestrictBackgroundWhitelist(mUid);
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(false);
- removeRestrictBackgroundWhitelist(mUid);
-
- Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver.");
- addPowerSaveModeWhitelist(TEST_APP2_PKG);
- removeRestrictBackgroundWhitelist(mUid);
- assertBackgroundNetworkAccess(false);
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(false);
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
-
- Log.v(TAG, "Whitelisted for both.");
- addRestrictBackgroundWhitelist(mUid);
- addPowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(true);
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(true);
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
- removeRestrictBackgroundWhitelist(mUid);
-
- Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver.");
- addRestrictBackgroundBlacklist(mUid);
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(false);
- removeRestrictBackgroundBlacklist(mUid);
-
- Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver.");
- addRestrictBackgroundBlacklist(mUid);
- addPowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(false);
- removeRestrictBackgroundBlacklist(mUid);
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- } finally {
- meterednessConfiguration.resetNetworkMeteredness();
- }
- }
-
- /**
- * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on non-metered
- * networks.
- */
- @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE, NON_METERED_NETWORK})
- @Test
- public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception {
- final MeterednessConfigurationRule meterednessConfiguration
- = new MeterednessConfigurationRule();
- meterednessConfiguration.configureNetworkMeteredness(false);
- try {
- setRestrictBackground(true);
- setBatterySaverMode(true);
-
- Log.v(TAG, "Not whitelisted for any.");
- assertBackgroundNetworkAccess(false);
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(false);
-
- Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver.");
- addRestrictBackgroundWhitelist(mUid);
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(false);
- removeRestrictBackgroundWhitelist(mUid);
-
- Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver.");
- addPowerSaveModeWhitelist(TEST_APP2_PKG);
- removeRestrictBackgroundWhitelist(mUid);
- assertBackgroundNetworkAccess(true);
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(true);
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
-
- Log.v(TAG, "Whitelisted for both.");
- addRestrictBackgroundWhitelist(mUid);
- addPowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(true);
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(true);
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
- removeRestrictBackgroundWhitelist(mUid);
-
- Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver.");
- addRestrictBackgroundBlacklist(mUid);
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(false);
- removeRestrictBackgroundBlacklist(mUid);
-
- Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver.");
- addRestrictBackgroundBlacklist(mUid);
- addPowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(true);
- assertsForegroundAlwaysHasNetworkAccess();
- assertBackgroundNetworkAccess(true);
- removeRestrictBackgroundBlacklist(mUid);
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- } finally {
- meterednessConfiguration.resetNetworkMeteredness();
- }
- }
-
- /**
- * Tests that powersave whitelists works as expected when doze and battery saver modes
- * are enabled.
- */
- @RequiredProperties({DOZE_MODE, BATTERY_SAVER_MODE})
- @Test
- public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception {
- setBatterySaverMode(true);
- setDozeMode(true);
-
- try {
- addPowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(true);
-
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
-
- addPowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
-
- removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
- } finally {
- setBatterySaverMode(false);
- setDozeMode(false);
- }
- }
-
- /**
- * Tests that powersave whitelists works as expected when doze and appIdle modes
- * are enabled.
- */
- @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE})
- @Test
- public void testDozeAndAppIdle_powerSaveWhitelists() throws Exception {
- setDozeMode(true);
- setAppIdle(true);
-
- try {
- addPowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(true);
-
- removePowerSaveModeWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
-
- addPowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
-
- removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- assertBackgroundNetworkAccess(false);
- } finally {
- setAppIdle(false);
- setDozeMode(false);
- }
- }
-
- @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE})
- @Test
- public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception {
- setDozeMode(true);
- setAppIdle(true);
-
- try {
- assertBackgroundNetworkAccess(false);
-
- addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
- assertBackgroundNetworkAccess(true);
-
- // Wait until the whitelist duration is expired.
- SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
- assertBackgroundNetworkAccess(false);
- } finally {
- setAppIdle(false);
- setDozeMode(false);
- }
- }
-
- @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE})
- @Test
- public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception {
- setBatterySaverMode(true);
- setAppIdle(true);
-
- try {
- assertBackgroundNetworkAccess(false);
-
- addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
- assertBackgroundNetworkAccess(true);
-
- // Wait until the whitelist duration is expired.
- SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
- assertBackgroundNetworkAccess(false);
- } finally {
- setAppIdle(false);
- setBatterySaverMode(false);
- }
- }
-
- /**
- * Tests that the app idle whitelist works as expected when doze and appIdle mode are enabled.
- */
- @RequiredProperties({DOZE_MODE, APP_STANDBY_MODE})
- @Test
- public void testDozeAndAppIdle_appIdleWhitelist() throws Exception {
- setDozeMode(true);
- setAppIdle(true);
-
- try {
- assertBackgroundNetworkAccess(false);
-
- // UID still shouldn't have access because of Doze.
- addAppIdleWhitelist(mUid);
- assertBackgroundNetworkAccess(false);
-
- removeAppIdleWhitelist(mUid);
- assertBackgroundNetworkAccess(false);
- } finally {
- setAppIdle(false);
- setDozeMode(false);
- }
- }
-
- @RequiredProperties({APP_STANDBY_MODE, DOZE_MODE})
- @Test
- public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception {
- setDozeMode(true);
- setAppIdle(true);
-
- try {
- assertBackgroundNetworkAccess(false);
-
- addAppIdleWhitelist(mUid);
- assertBackgroundNetworkAccess(false);
-
- addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
- assertBackgroundNetworkAccess(true);
-
- // Wait until the whitelist duration is expired.
- SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
- assertBackgroundNetworkAccess(false);
- } finally {
- setAppIdle(false);
- setDozeMode(false);
- removeAppIdleWhitelist(mUid);
- }
- }
-
- @RequiredProperties({APP_STANDBY_MODE, BATTERY_SAVER_MODE})
- @Test
- public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception {
- setBatterySaverMode(true);
- setAppIdle(true);
-
- try {
- assertBackgroundNetworkAccess(false);
-
- addAppIdleWhitelist(mUid);
- assertBackgroundNetworkAccess(false);
-
- addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
- assertBackgroundNetworkAccess(true);
-
- // Wait until the whitelist duration is expired.
- SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
- assertBackgroundNetworkAccess(false);
- } finally {
- setAppIdle(false);
- setBatterySaverMode(false);
- removeAppIdleWhitelist(mUid);
- }
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/MyActivity.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/MyActivity.java
deleted file mode 100644
index 0d0bc58..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/MyActivity.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.WindowManager;
-
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-public class MyActivity extends Activity {
- private final LinkedBlockingQueue<Integer> mResult = new LinkedBlockingQueue<>(1);
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
- | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
- | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (mResult.offer(resultCode) == false) {
- throw new RuntimeException("Queue is full! This should never happen");
- }
- }
-
- public Integer getResult(int timeoutMs) throws InterruptedException {
- return mResult.poll(timeoutMs, TimeUnit.MILLISECONDS);
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java
deleted file mode 100644
index 0132536..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.net.hostside;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.app.RemoteInput;
-import android.content.ComponentName;
-import android.os.Bundle;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
-import android.util.Log;
-
-/**
- * NotificationListenerService implementation that executes the notification actions once they're
- * created.
- */
-public class MyNotificationListenerService extends NotificationListenerService {
- private static final String TAG = "MyNotificationListenerService";
-
- @Override
- public void onListenerConnected() {
- Log.d(TAG, "onListenerConnected()");
- }
-
- @Override
- public void onNotificationPosted(StatusBarNotification sbn) {
- Log.d(TAG, "onNotificationPosted(): " + sbn);
- if (!sbn.getPackageName().startsWith(getPackageName())) {
- Log.v(TAG, "ignoring notification from a different package");
- return;
- }
- final PendingIntentSender sender = new PendingIntentSender();
- final Notification notification = sbn.getNotification();
- if (notification.contentIntent != null) {
- sender.send("content", notification.contentIntent);
- }
- if (notification.deleteIntent != null) {
- sender.send("delete", notification.deleteIntent);
- }
- if (notification.fullScreenIntent != null) {
- sender.send("full screen", notification.fullScreenIntent);
- }
- if (notification.actions != null) {
- for (Notification.Action action : notification.actions) {
- sender.send("action", action.actionIntent);
- sender.send("action extras", action.getExtras());
- final RemoteInput[] remoteInputs = action.getRemoteInputs();
- if (remoteInputs != null && remoteInputs.length > 0) {
- for (RemoteInput remoteInput : remoteInputs) {
- sender.send("remote input extras", remoteInput.getExtras());
- }
- }
- }
- }
- sender.send("notification extras", notification.extras);
- }
-
- static String getId() {
- return String.format("%s/%s", MyNotificationListenerService.class.getPackage().getName(),
- MyNotificationListenerService.class.getName());
- }
-
- static ComponentName getComponentName() {
- return new ComponentName(MyNotificationListenerService.class.getPackage().getName(),
- MyNotificationListenerService.class.getName());
- }
-
- private static final class PendingIntentSender {
- private PendingIntent mSentIntent = null;
- private String mReason = null;
-
- private void send(String reason, PendingIntent pendingIntent) {
- if (pendingIntent == null) {
- // Could happen on action that only has extras
- Log.v(TAG, "Not sending null pending intent for " + reason);
- return;
- }
- if (mSentIntent != null || mReason != null) {
- // Sanity check: make sure test case set up just one pending intent in the
- // notification, otherwise it could pass because another pending intent caused the
- // whitelisting.
- throw new IllegalStateException("Already sent a PendingIntent (" + mSentIntent
- + ") for reason '" + mReason + "' when requested another for '" + reason
- + "' (" + pendingIntent + ")");
- }
- Log.i(TAG, "Sending pending intent for " + reason + ":" + pendingIntent);
- try {
- pendingIntent.send();
- mSentIntent = pendingIntent;
- mReason = reason;
- } catch (CanceledException e) {
- Log.w(TAG, "Pending intent " + pendingIntent + " canceled");
- }
- }
-
- private void send(String reason, Bundle extras) {
- if (extras != null) {
- for (String key : extras.keySet()) {
- Object value = extras.get(key);
- if (value instanceof PendingIntent) {
- send(reason + " with key '" + key + "'", (PendingIntent) value);
- }
- }
- }
- }
-
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/MyServiceClient.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/MyServiceClient.java
deleted file mode 100644
index 6546e26..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/MyServiceClient.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.ConditionVariable;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import com.android.cts.net.hostside.IMyService;
-
-public class MyServiceClient {
- private static final int TIMEOUT_MS = 5000;
- private static final String PACKAGE = MyServiceClient.class.getPackage().getName();
- private static final String APP2_PACKAGE = PACKAGE + ".app2";
- private static final String SERVICE_NAME = APP2_PACKAGE + ".MyService";
-
- private Context mContext;
- private ServiceConnection mServiceConnection;
- private IMyService mService;
-
- public MyServiceClient(Context context) {
- mContext = context;
- }
-
- public void bind() {
- if (mService != null) {
- throw new IllegalStateException("Already bound");
- }
-
- final ConditionVariable cv = new ConditionVariable();
- mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- mService = IMyService.Stub.asInterface(service);
- cv.open();
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
- }
- };
-
- final Intent intent = new Intent();
- intent.setComponent(new ComponentName(APP2_PACKAGE, SERVICE_NAME));
- // Needs to use BIND_NOT_FOREGROUND so app2 does not run in
- // the same process state as app
- mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE
- | Context.BIND_NOT_FOREGROUND);
- cv.block(TIMEOUT_MS);
- if (mService == null) {
- throw new IllegalStateException(
- "Could not bind to MyService service after " + TIMEOUT_MS + "ms");
- }
- }
-
- public void unbind() {
- if (mService != null) {
- mContext.unbindService(mServiceConnection);
- }
- }
-
- public void registerBroadcastReceiver() throws RemoteException {
- mService.registerBroadcastReceiver();
- }
-
- public int getCounters(String receiverName, String action) throws RemoteException {
- return mService.getCounters(receiverName, action);
- }
-
- public String checkNetworkStatus() throws RemoteException {
- return mService.checkNetworkStatus();
- }
-
- public String getRestrictBackgroundStatus() throws RemoteException {
- return mService.getRestrictBackgroundStatus();
- }
-
- public void sendNotification(int notificationId, String notificationType) throws RemoteException {
- mService.sendNotification(notificationId, notificationType);
- }
-
- public void registerNetworkCallback(INetworkCallback cb) throws RemoteException {
- mService.registerNetworkCallback(cb);
- }
-
- public void unregisterNetworkCallback() throws RemoteException {
- mService.unregisterNetworkCallback();
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/MyVpnService.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/MyVpnService.java
deleted file mode 100644
index 7d3d4fc..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/MyVpnService.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import android.content.Intent;
-import android.net.Network;
-import android.net.ProxyInfo;
-import android.net.VpnService;
-import android.os.ParcelFileDescriptor;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-
-public class MyVpnService extends VpnService {
-
- private static String TAG = "MyVpnService";
- private static int MTU = 1799;
-
- public static final String ACTION_ESTABLISHED = "com.android.cts.net.hostside.ESTABNLISHED";
- public static final String EXTRA_ALWAYS_ON = "is-always-on";
- public static final String EXTRA_LOCKDOWN_ENABLED = "is-lockdown-enabled";
-
- private ParcelFileDescriptor mFd = null;
- private PacketReflector mPacketReflector = null;
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- String packageName = getPackageName();
- String cmd = intent.getStringExtra(packageName + ".cmd");
- if ("disconnect".equals(cmd)) {
- stop();
- } else if ("connect".equals(cmd)) {
- start(packageName, intent);
- }
-
- return START_NOT_STICKY;
- }
-
- private void start(String packageName, Intent intent) {
- Builder builder = new Builder();
-
- String addresses = intent.getStringExtra(packageName + ".addresses");
- if (addresses != null) {
- String[] addressArray = addresses.split(",");
- for (int i = 0; i < addressArray.length; i++) {
- String[] prefixAndMask = addressArray[i].split("/");
- try {
- InetAddress address = InetAddress.getByName(prefixAndMask[0]);
- int prefixLength = Integer.parseInt(prefixAndMask[1]);
- builder.addAddress(address, prefixLength);
- } catch (UnknownHostException|NumberFormatException|
- ArrayIndexOutOfBoundsException e) {
- continue;
- }
- }
- }
-
- String routes = intent.getStringExtra(packageName + ".routes");
- if (routes != null) {
- String[] routeArray = routes.split(",");
- for (int i = 0; i < routeArray.length; i++) {
- String[] prefixAndMask = routeArray[i].split("/");
- try {
- InetAddress address = InetAddress.getByName(prefixAndMask[0]);
- int prefixLength = Integer.parseInt(prefixAndMask[1]);
- builder.addRoute(address, prefixLength);
- } catch (UnknownHostException|NumberFormatException|
- ArrayIndexOutOfBoundsException e) {
- continue;
- }
- }
- }
-
- String allowed = intent.getStringExtra(packageName + ".allowedapplications");
- if (allowed != null) {
- String[] packageArray = allowed.split(",");
- for (int i = 0; i < packageArray.length; i++) {
- String allowedPackage = packageArray[i];
- if (!TextUtils.isEmpty(allowedPackage)) {
- try {
- builder.addAllowedApplication(allowedPackage);
- } catch(NameNotFoundException e) {
- continue;
- }
- }
- }
- }
-
- String disallowed = intent.getStringExtra(packageName + ".disallowedapplications");
- if (disallowed != null) {
- String[] packageArray = disallowed.split(",");
- for (int i = 0; i < packageArray.length; i++) {
- String disallowedPackage = packageArray[i];
- if (!TextUtils.isEmpty(disallowedPackage)) {
- try {
- builder.addDisallowedApplication(disallowedPackage);
- } catch(NameNotFoundException e) {
- continue;
- }
- }
- }
- }
-
- ArrayList<Network> underlyingNetworks =
- intent.getParcelableArrayListExtra(packageName + ".underlyingNetworks");
- if (underlyingNetworks == null) {
- // VPN tracks default network
- builder.setUnderlyingNetworks(null);
- } else {
- builder.setUnderlyingNetworks(underlyingNetworks.toArray(new Network[0]));
- }
-
- boolean isAlwaysMetered = intent.getBooleanExtra(packageName + ".isAlwaysMetered", false);
- builder.setMetered(isAlwaysMetered);
-
- ProxyInfo vpnProxy = intent.getParcelableExtra(packageName + ".httpProxy");
- builder.setHttpProxy(vpnProxy);
- builder.setMtu(MTU);
- builder.setBlocking(true);
- builder.setSession("MyVpnService");
-
- Log.i(TAG, "Establishing VPN,"
- + " addresses=" + addresses
- + " routes=" + routes
- + " allowedApplications=" + allowed
- + " disallowedApplications=" + disallowed);
-
- mFd = builder.establish();
- Log.i(TAG, "Established, fd=" + (mFd == null ? "null" : mFd.getFd()));
-
- broadcastEstablished();
-
- mPacketReflector = new PacketReflector(mFd.getFileDescriptor(), MTU);
- mPacketReflector.start();
- }
-
- private void broadcastEstablished() {
- final Intent bcIntent = new Intent(ACTION_ESTABLISHED);
- bcIntent.putExtra(EXTRA_ALWAYS_ON, isAlwaysOn());
- bcIntent.putExtra(EXTRA_LOCKDOWN_ENABLED, isLockdownEnabled());
- sendBroadcast(bcIntent);
- }
-
- private void stop() {
- if (mPacketReflector != null) {
- mPacketReflector.interrupt();
- mPacketReflector = null;
- }
- try {
- if (mFd != null) {
- Log.i(TAG, "Closing filedescriptor");
- mFd.close();
- }
- } catch(IOException e) {
- } finally {
- mFd = null;
- }
- }
-
- @Override
- public void onDestroy() {
- stop();
- super.onDestroy();
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java
deleted file mode 100644
index 2ac29e7..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered;
-import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-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.net.Network;
-import android.net.NetworkCapabilities;
-import android.util.Log;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import java.util.Objects;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCase {
- private Network mNetwork;
- private final TestNetworkCallback mTestNetworkCallback = new TestNetworkCallback();
- @Rule
- public final MeterednessConfigurationRule mMeterednessConfiguration
- = new MeterednessConfigurationRule();
-
- enum CallbackState {
- NONE,
- AVAILABLE,
- LOST,
- BLOCKED_STATUS,
- CAPABILITIES
- }
-
- private static class CallbackInfo {
- public final CallbackState state;
- public final Network network;
- public final Object arg;
-
- CallbackInfo(CallbackState s, Network n, Object o) {
- state = s; network = n; arg = o;
- }
-
- public String toString() {
- return String.format("%s (%s) (%s)", state, network, arg);
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof CallbackInfo)) return false;
- // Ignore timeMs, since it's unpredictable.
- final CallbackInfo other = (CallbackInfo) o;
- return (state == other.state) && Objects.equals(network, other.network)
- && Objects.equals(arg, other.arg);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(state, network, arg);
- }
- }
-
- private class TestNetworkCallback extends INetworkCallback.Stub {
- private static final int TEST_CONNECT_TIMEOUT_MS = 30_000;
- private static final int TEST_CALLBACK_TIMEOUT_MS = 5_000;
-
- private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
-
- protected void setLastCallback(CallbackState state, Network network, Object o) {
- mCallbacks.offer(new CallbackInfo(state, network, o));
- }
-
- CallbackInfo nextCallback(int timeoutMs) {
- CallbackInfo cb = null;
- try {
- cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- }
- if (cb == null) {
- fail("Did not receive callback after " + timeoutMs + "ms");
- }
- return cb;
- }
-
- CallbackInfo expectCallback(CallbackState state, Network expectedNetwork, Object o) {
- final CallbackInfo expected = new CallbackInfo(state, expectedNetwork, o);
- final CallbackInfo actual = nextCallback(TEST_CALLBACK_TIMEOUT_MS);
- assertEquals("Unexpected callback:", expected, actual);
- return actual;
- }
-
- @Override
- public void onAvailable(Network network) {
- setLastCallback(CallbackState.AVAILABLE, network, null);
- }
-
- @Override
- public void onLost(Network network) {
- setLastCallback(CallbackState.LOST, network, null);
- }
-
- @Override
- public void onBlockedStatusChanged(Network network, boolean blocked) {
- setLastCallback(CallbackState.BLOCKED_STATUS, network, blocked);
- }
-
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities cap) {
- setLastCallback(CallbackState.CAPABILITIES, network, cap);
- }
-
- public Network expectAvailableCallbackAndGetNetwork() {
- final CallbackInfo cb = nextCallback(TEST_CONNECT_TIMEOUT_MS);
- if (cb.state != CallbackState.AVAILABLE) {
- fail("Network is not available. Instead obtained the following callback :"
- + cb);
- }
- return cb.network;
- }
-
- public void expectBlockedStatusCallback(Network expectedNetwork, boolean expectBlocked) {
- expectCallback(CallbackState.BLOCKED_STATUS, expectedNetwork, expectBlocked);
- }
-
- public void expectBlockedStatusCallbackEventually(Network expectedNetwork,
- boolean expectBlocked) {
- final long deadline = System.currentTimeMillis() + TEST_CALLBACK_TIMEOUT_MS;
- do {
- final CallbackInfo cb = nextCallback((int) (deadline - System.currentTimeMillis()));
- if (cb.state == CallbackState.BLOCKED_STATUS
- && cb.network.equals(expectedNetwork)) {
- assertEquals(expectBlocked, cb.arg);
- return;
- }
- } while (System.currentTimeMillis() <= deadline);
- fail("Didn't receive onBlockedStatusChanged()");
- }
-
- public void expectCapabilitiesCallbackEventually(Network expectedNetwork, boolean hasCap,
- int cap) {
- final long deadline = System.currentTimeMillis() + TEST_CALLBACK_TIMEOUT_MS;
- do {
- final CallbackInfo cb = nextCallback((int) (deadline - System.currentTimeMillis()));
- if (cb.state != CallbackState.CAPABILITIES
- || !expectedNetwork.equals(cb.network)
- || (hasCap != ((NetworkCapabilities) cb.arg).hasCapability(cap))) {
- Log.i("NetworkCallbackTest#expectCapabilitiesCallback",
- "Ignoring non-matching callback : " + cb);
- continue;
- }
- // Found a match, return
- return;
- } while (System.currentTimeMillis() <= deadline);
- fail("Didn't receive the expected callback to onCapabilitiesChanged(). Check the "
- + "log for a list of received callbacks, if any.");
- }
- }
-
- @Before
- public void setUp() throws Exception {
- super.setUp();
-
- assumeTrue(isActiveNetworkMetered(true) || canChangeActiveNetworkMeteredness());
-
- registerBroadcastReceiver();
-
- removeRestrictBackgroundWhitelist(mUid);
- removeRestrictBackgroundBlacklist(mUid);
- assertRestrictBackgroundChangedReceived(0);
-
- // Initial state
- setBatterySaverMode(false);
- setRestrictBackground(false);
-
- // Make wifi a metered network.
- mMeterednessConfiguration.configureNetworkMeteredness(true);
-
- // Register callback
- registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback);
- // Once the wifi is marked as metered, the wifi will reconnect. Wait for onAvailable()
- // callback to ensure wifi is connected before the test and store the default network.
- mNetwork = mTestNetworkCallback.expectAvailableCallbackAndGetNetwork();
- // Check that the network is metered.
- mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
- false /* hasCapability */, NET_CAPABILITY_NOT_METERED);
- mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false);
- }
-
- @After
- public void tearDown() throws Exception {
- super.tearDown();
-
- setRestrictBackground(false);
- setBatterySaverMode(false);
- unregisterNetworkCallback();
- }
-
- @RequiredProperties({DATA_SAVER_MODE})
- @Test
- public void testOnBlockedStatusChanged_dataSaver() throws Exception {
- try {
- // Enable restrict background
- setRestrictBackground(true);
- assertBackgroundNetworkAccess(false);
- mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
-
- // Add to whitelist
- addRestrictBackgroundWhitelist(mUid);
- assertBackgroundNetworkAccess(true);
- mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
-
- // Remove from whitelist
- removeRestrictBackgroundWhitelist(mUid);
- assertBackgroundNetworkAccess(false);
- mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
- } finally {
- mMeterednessConfiguration.resetNetworkMeteredness();
- }
-
- // Set to non-metered network
- mMeterednessConfiguration.configureNetworkMeteredness(false);
- mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
- true /* hasCapability */, NET_CAPABILITY_NOT_METERED);
- try {
- assertBackgroundNetworkAccess(true);
- mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
-
- // Disable restrict background, should not trigger callback
- setRestrictBackground(false);
- assertBackgroundNetworkAccess(true);
- } finally {
- mMeterednessConfiguration.resetNetworkMeteredness();
- }
- }
-
- @RequiredProperties({BATTERY_SAVER_MODE})
- @Test
- public void testOnBlockedStatusChanged_powerSaver() throws Exception {
- try {
- // Enable Power Saver
- setBatterySaverMode(true);
- assertBackgroundNetworkAccess(false);
- mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
-
- // Disable Power Saver
- setBatterySaverMode(false);
- assertBackgroundNetworkAccess(true);
- mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
- } finally {
- mMeterednessConfiguration.resetNetworkMeteredness();
- }
-
- // Set to non-metered network
- mMeterednessConfiguration.configureNetworkMeteredness(false);
- mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
- true /* hasCapability */, NET_CAPABILITY_NOT_METERED);
- try {
- // Enable Power Saver
- setBatterySaverMode(true);
- assertBackgroundNetworkAccess(false);
- mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
-
- // Disable Power Saver
- setBatterySaverMode(false);
- assertBackgroundNetworkAccess(true);
- mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
- } finally {
- mMeterednessConfiguration.resetNetworkMeteredness();
- }
- }
-
- // TODO: 1. test against VPN lockdown.
- // 2. test against multiple networks.
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java
deleted file mode 100644
index f340907..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
-
-import org.junit.rules.RunRules;
-import org.junit.rules.TestRule;
-import org.junit.runners.model.FrameworkMethod;
-import org.junit.runners.model.InitializationError;
-import org.junit.runners.model.Statement;
-
-import java.util.List;
-
-/**
- * Custom runner to allow dumping logs after a test failure before the @After methods get to run.
- */
-public class NetworkPolicyTestRunner extends AndroidJUnit4ClassRunner {
- private TestRule mDumpOnFailureRule = new DumpOnFailureRule();
-
- public NetworkPolicyTestRunner(Class<?> klass) throws InitializationError {
- super(klass);
- }
-
- @Override
- public Statement methodInvoker(FrameworkMethod method, Object test) {
- return new RunRules(super.methodInvoker(method, test), List.of(mDumpOnFailureRule),
- describeChild(method));
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java
deleted file mode 100644
index 3807d79..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
-import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
-import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-
-import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
-import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.app.ActivityManager;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.location.LocationManager;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.wifi.WifiManager;
-import android.os.Process;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.compatibility.common.util.AppStandbyUtils;
-import com.android.compatibility.common.util.BatteryUtils;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-
-public class NetworkPolicyTestUtils {
-
- private static final int TIMEOUT_CHANGE_METEREDNESS_MS = 5000;
-
- private static ConnectivityManager mCm;
- private static WifiManager mWm;
-
- private static Boolean mBatterySaverSupported;
- private static Boolean mDataSaverSupported;
- private static Boolean mDozeModeSupported;
- private static Boolean mAppStandbySupported;
-
- private NetworkPolicyTestUtils() {}
-
- public static boolean isBatterySaverSupported() {
- if (mBatterySaverSupported == null) {
- mBatterySaverSupported = BatteryUtils.isBatterySaverSupported();
- }
- return mBatterySaverSupported;
- }
-
- /**
- * As per CDD requirements, if the device doesn't support data saver mode then
- * ConnectivityManager.getRestrictBackgroundStatus() will always return
- * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if
- * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns
- * RESTRICT_BACKGROUND_STATUS_DISABLED or not.
- */
- public static boolean isDataSaverSupported() {
- if (mDataSaverSupported == null) {
- assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
- try {
- setRestrictBackground(true);
- mDataSaverSupported = !isMyRestrictBackgroundStatus(
- RESTRICT_BACKGROUND_STATUS_DISABLED);
- } finally {
- setRestrictBackground(false);
- }
- }
- return mDataSaverSupported;
- }
-
- public static boolean isDozeModeSupported() {
- if (mDozeModeSupported == null) {
- final String result = executeShellCommand("cmd deviceidle enabled deep");
- mDozeModeSupported = result.equals("1");
- }
- return mDozeModeSupported;
- }
-
- public static boolean isAppStandbySupported() {
- if (mAppStandbySupported == null) {
- mAppStandbySupported = AppStandbyUtils.isAppStandbyEnabled();
- }
- return mAppStandbySupported;
- }
-
- public static boolean isLowRamDevice() {
- final ActivityManager am = (ActivityManager) getContext().getSystemService(
- Context.ACTIVITY_SERVICE);
- return am.isLowRamDevice();
- }
-
- public static boolean isLocationEnabled() {
- final LocationManager lm = (LocationManager) getContext().getSystemService(
- Context.LOCATION_SERVICE);
- return lm.isLocationEnabled();
- }
-
- public static void setLocationEnabled(boolean enabled) {
- final LocationManager lm = (LocationManager) getContext().getSystemService(
- Context.LOCATION_SERVICE);
- lm.setLocationEnabledForUser(enabled, Process.myUserHandle());
- assertEquals("Couldn't change location enabled state", lm.isLocationEnabled(), enabled);
- Log.d(TAG, "Changed location enabled state to " + enabled);
- }
-
- public static boolean isActiveNetworkMetered(boolean metered) {
- return getConnectivityManager().isActiveNetworkMetered() == metered;
- }
-
- public static boolean canChangeActiveNetworkMeteredness() {
- final Network activeNetwork = getConnectivityManager().getActiveNetwork();
- final NetworkCapabilities networkCapabilities
- = getConnectivityManager().getNetworkCapabilities(activeNetwork);
- return networkCapabilities.hasTransport(TRANSPORT_WIFI);
- }
-
- public static Pair<String, Boolean> setupMeteredNetwork(boolean metered) throws Exception {
- if (isActiveNetworkMetered(metered)) {
- return null;
- }
- final boolean isLocationEnabled = isLocationEnabled();
- try {
- if (!isLocationEnabled) {
- setLocationEnabled(true);
- }
- final String ssid = unquoteSSID(getWifiManager().getConnectionInfo().getSSID());
- assertNotEquals(WifiManager.UNKNOWN_SSID, ssid);
- setWifiMeteredStatus(ssid, metered);
- return Pair.create(ssid, !metered);
- } finally {
- // Reset the location enabled state
- if (!isLocationEnabled) {
- setLocationEnabled(false);
- }
- }
- }
-
- public static void resetMeteredNetwork(String ssid, boolean metered) throws Exception {
- setWifiMeteredStatus(ssid, metered);
- }
-
- public static void setWifiMeteredStatus(String ssid, boolean metered) throws Exception {
- assertFalse("SSID should not be empty", TextUtils.isEmpty(ssid));
- final String cmd = "cmd netpolicy set metered-network " + ssid + " " + metered;
- executeShellCommand(cmd);
- assertWifiMeteredStatus(ssid, metered);
- assertActiveNetworkMetered(metered);
- }
-
- public static void assertWifiMeteredStatus(String ssid, boolean expectedMeteredStatus) {
- final String result = executeShellCommand("cmd netpolicy list wifi-networks");
- final String expectedLine = ssid + ";" + expectedMeteredStatus;
- assertTrue("Expected line: " + expectedLine + "; Actual result: " + result,
- result.contains(expectedLine));
- }
-
- // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
- public static void assertActiveNetworkMetered(boolean expectedMeteredStatus) throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
- final NetworkCallback networkCallback = new NetworkCallback() {
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
- final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
- if (metered == expectedMeteredStatus) {
- latch.countDown();
- }
- }
- };
- // Registering a callback here guarantees onCapabilitiesChanged is called immediately
- // with the current setting. Therefore, if the setting has already been changed,
- // this method will return right away, and if not it will wait for the setting to change.
- getConnectivityManager().registerDefaultNetworkCallback(networkCallback);
- if (!latch.await(TIMEOUT_CHANGE_METEREDNESS_MS, TimeUnit.MILLISECONDS)) {
- fail("Timed out waiting for active network metered status to change to "
- + expectedMeteredStatus + " ; network = "
- + getConnectivityManager().getActiveNetwork());
- }
- getConnectivityManager().unregisterNetworkCallback(networkCallback);
- }
-
- public static void setRestrictBackground(boolean enabled) {
- executeShellCommand("cmd netpolicy set restrict-background " + enabled);
- final String output = executeShellCommand("cmd netpolicy get restrict-background");
- final String expectedSuffix = enabled ? "enabled" : "disabled";
- assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'",
- output.endsWith(expectedSuffix));
- }
-
- public static boolean isMyRestrictBackgroundStatus(int expectedStatus) {
- final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus();
- if (expectedStatus != actualStatus) {
- Log.d(TAG, "MyRestrictBackgroundStatus: "
- + "Expected: " + restrictBackgroundValueToString(expectedStatus)
- + "; Actual: " + restrictBackgroundValueToString(actualStatus));
- return false;
- }
- return true;
- }
-
- // Copied from cts/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
- private static String unquoteSSID(String ssid) {
- // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
- // Otherwise it's guaranteed not to start with a quote.
- if (ssid.charAt(0) == '"') {
- return ssid.substring(1, ssid.length() - 1);
- } else {
- return ssid;
- }
- }
-
- public static String restrictBackgroundValueToString(int status) {
- switch (status) {
- case RESTRICT_BACKGROUND_STATUS_DISABLED:
- return "DISABLED";
- case RESTRICT_BACKGROUND_STATUS_WHITELISTED:
- return "WHITELISTED";
- case RESTRICT_BACKGROUND_STATUS_ENABLED:
- return "ENABLED";
- default:
- return "UNKNOWN_STATUS_" + status;
- }
- }
-
- public static String executeShellCommand(String command) {
- final String result = runShellCommand(command).trim();
- Log.d(TAG, "Output of '" + command + "': '" + result + "'");
- return result;
- }
-
- public static void assertMyRestrictBackgroundStatus(int expectedStatus) {
- final int actualStatus = getConnectivityManager().getRestrictBackgroundStatus();
- assertEquals(restrictBackgroundValueToString(expectedStatus),
- restrictBackgroundValueToString(actualStatus));
- }
-
- public static ConnectivityManager getConnectivityManager() {
- if (mCm == null) {
- mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
- }
- return mCm;
- }
-
- public static WifiManager getWifiManager() {
- if (mWm == null) {
- mWm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
- }
- return mWm;
- }
-
- public static Context getContext() {
- return getInstrumentation().getContext();
- }
-
- public static Instrumentation getInstrumentation() {
- return InstrumentationRegistry.getInstrumentation();
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/PacketReflector.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/PacketReflector.java
deleted file mode 100644
index 124c2c3..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/PacketReflector.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static android.system.OsConstants.ICMP6_ECHO_REPLY;
-import static android.system.OsConstants.ICMP6_ECHO_REQUEST;
-import static android.system.OsConstants.ICMP_ECHO;
-import static android.system.OsConstants.ICMP_ECHOREPLY;
-
-import android.system.ErrnoException;
-import android.system.Os;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-public class PacketReflector extends Thread {
-
- private static int IPV4_HEADER_LENGTH = 20;
- private static int IPV6_HEADER_LENGTH = 40;
-
- private static int IPV4_ADDR_OFFSET = 12;
- private static int IPV6_ADDR_OFFSET = 8;
- private static int IPV4_ADDR_LENGTH = 4;
- private static int IPV6_ADDR_LENGTH = 16;
-
- private static int IPV4_PROTO_OFFSET = 9;
- private static int IPV6_PROTO_OFFSET = 6;
-
- private static final byte IPPROTO_ICMP = 1;
- private static final byte IPPROTO_TCP = 6;
- private static final byte IPPROTO_UDP = 17;
- private static final byte IPPROTO_ICMPV6 = 58;
-
- private static int ICMP_HEADER_LENGTH = 8;
- private static int TCP_HEADER_LENGTH = 20;
- private static int UDP_HEADER_LENGTH = 8;
-
- private static final byte ICMP_ECHO = 8;
- private static final byte ICMP_ECHOREPLY = 0;
-
- private static String TAG = "PacketReflector";
-
- private FileDescriptor mFd;
- private byte[] mBuf;
-
- public PacketReflector(FileDescriptor fd, int mtu) {
- super("PacketReflector");
- mFd = fd;
- mBuf = new byte[mtu];
- }
-
- private static void swapBytes(byte[] buf, int pos1, int pos2, int len) {
- for (int i = 0; i < len; i++) {
- byte b = buf[pos1 + i];
- buf[pos1 + i] = buf[pos2 + i];
- buf[pos2 + i] = b;
- }
- }
-
- private static void swapAddresses(byte[] buf, int version) {
- int addrPos, addrLen;
- switch(version) {
- case 4:
- addrPos = IPV4_ADDR_OFFSET;
- addrLen = IPV4_ADDR_LENGTH;
- break;
- case 6:
- addrPos = IPV6_ADDR_OFFSET;
- addrLen = IPV6_ADDR_LENGTH;
- break;
- default:
- throw new IllegalArgumentException();
- }
- swapBytes(buf, addrPos, addrPos + addrLen, addrLen);
- }
-
- // Reflect TCP packets: swap the source and destination addresses, but don't change the ports.
- // This is used by the test to "connect to itself" through the VPN.
- private void processTcpPacket(byte[] buf, int version, int len, int hdrLen) {
- if (len < hdrLen + TCP_HEADER_LENGTH) {
- return;
- }
-
- // Swap src and dst IP addresses.
- swapAddresses(buf, version);
-
- // Send the packet back.
- writePacket(buf, len);
- }
-
- // Echo UDP packets: swap source and destination addresses, and source and destination ports.
- // This is used by the test to check that the bytes it sends are echoed back.
- private void processUdpPacket(byte[] buf, int version, int len, int hdrLen) {
- if (len < hdrLen + UDP_HEADER_LENGTH) {
- return;
- }
-
- // Swap src and dst IP addresses.
- swapAddresses(buf, version);
-
- // Swap dst and src ports.
- int portOffset = hdrLen;
- swapBytes(buf, portOffset, portOffset + 2, 2);
-
- // Send the packet back.
- writePacket(buf, len);
- }
-
- private void processIcmpPacket(byte[] buf, int version, int len, int hdrLen) {
- if (len < hdrLen + ICMP_HEADER_LENGTH) {
- return;
- }
-
- byte type = buf[hdrLen];
- if (!(version == 4 && type == ICMP_ECHO) &&
- !(version == 6 && type == (byte) ICMP6_ECHO_REQUEST)) {
- return;
- }
-
- // Save the ping packet we received.
- byte[] request = buf.clone();
-
- // Swap src and dst IP addresses, and send the packet back.
- // This effectively pings the device to see if it replies.
- swapAddresses(buf, version);
- writePacket(buf, len);
-
- // The device should have replied, and buf should now contain a ping response.
- int received = readPacket(buf);
- if (received != len) {
- Log.i(TAG, "Reflecting ping did not result in ping response: " +
- "read=" + received + " expected=" + len);
- return;
- }
-
- byte replyType = buf[hdrLen];
- if ((type == ICMP_ECHO && replyType != ICMP_ECHOREPLY)
- || (type == (byte) ICMP6_ECHO_REQUEST && replyType != (byte) ICMP6_ECHO_REPLY)) {
- Log.i(TAG, "Received unexpected ICMP reply: original " + type
- + ", reply " + replyType);
- return;
- }
-
- // Compare the response we got with the original packet.
- // The only thing that should have changed are addresses, type and checksum.
- // Overwrite them with the received bytes and see if the packet is otherwise identical.
- request[hdrLen] = buf[hdrLen]; // Type
- request[hdrLen + 2] = buf[hdrLen + 2]; // Checksum byte 1.
- request[hdrLen + 3] = buf[hdrLen + 3]; // Checksum byte 2.
-
- // Since Linux kernel 4.2, net.ipv6.auto_flowlabels is set by default, and therefore
- // the request and reply may have different IPv6 flow label: ignore that as well.
- if (version == 6) {
- request[1] = (byte)(request[1] & 0xf0 | buf[1] & 0x0f);
- request[2] = buf[2];
- request[3] = buf[3];
- }
-
- for (int i = 0; i < len; i++) {
- if (buf[i] != request[i]) {
- Log.i(TAG, "Received non-matching packet when expecting ping response.");
- return;
- }
- }
-
- // Now swap the addresses again and reflect the packet. This sends a ping reply.
- swapAddresses(buf, version);
- writePacket(buf, len);
- }
-
- private void writePacket(byte[] buf, int len) {
- try {
- Os.write(mFd, buf, 0, len);
- } catch (ErrnoException|IOException e) {
- Log.e(TAG, "Error writing packet: " + e.getMessage());
- }
- }
-
- private int readPacket(byte[] buf) {
- int len;
- try {
- len = Os.read(mFd, buf, 0, buf.length);
- } catch (ErrnoException|IOException e) {
- Log.e(TAG, "Error reading packet: " + e.getMessage());
- len = -1;
- }
- return len;
- }
-
- // Reads one packet from our mFd, and possibly writes the packet back.
- private void processPacket() {
- int len = readPacket(mBuf);
- if (len < 1) {
- return;
- }
-
- int version = mBuf[0] >> 4;
- int addrPos, protoPos, hdrLen, addrLen;
- if (version == 4) {
- hdrLen = IPV4_HEADER_LENGTH;
- protoPos = IPV4_PROTO_OFFSET;
- addrPos = IPV4_ADDR_OFFSET;
- addrLen = IPV4_ADDR_LENGTH;
- } else if (version == 6) {
- hdrLen = IPV6_HEADER_LENGTH;
- protoPos = IPV6_PROTO_OFFSET;
- addrPos = IPV6_ADDR_OFFSET;
- addrLen = IPV6_ADDR_LENGTH;
- } else {
- return;
- }
-
- if (len < hdrLen) {
- return;
- }
-
- byte proto = mBuf[protoPos];
- switch (proto) {
- case IPPROTO_ICMP:
- case IPPROTO_ICMPV6:
- processIcmpPacket(mBuf, version, len, hdrLen);
- break;
- case IPPROTO_TCP:
- processTcpPacket(mBuf, version, len, hdrLen);
- break;
- case IPPROTO_UDP:
- processUdpPacket(mBuf, version, len, hdrLen);
- break;
- }
- }
-
- public void run() {
- Log.i(TAG, "PacketReflector starting fd=" + mFd + " valid=" + mFd.valid());
- while (!interrupted() && mFd.valid()) {
- processPacket();
- }
- Log.i(TAG, "PacketReflector exiting fd=" + mFd + " valid=" + mFd.valid());
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/Property.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/Property.java
deleted file mode 100644
index 18805f9..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/Property.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isAppStandbySupported;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isBatterySaverSupported;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDataSaverSupported;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isLowRamDevice;
-
-public enum Property {
- BATTERY_SAVER_MODE(1 << 0) {
- public boolean isSupported() { return isBatterySaverSupported(); }
- },
-
- DATA_SAVER_MODE(1 << 1) {
- public boolean isSupported() { return isDataSaverSupported(); }
- },
-
- NO_DATA_SAVER_MODE(~DATA_SAVER_MODE.getValue()) {
- public boolean isSupported() { return !isDataSaverSupported(); }
- },
-
- DOZE_MODE(1 << 2) {
- public boolean isSupported() { return isDozeModeSupported(); }
- },
-
- APP_STANDBY_MODE(1 << 3) {
- public boolean isSupported() { return isAppStandbySupported(); }
- },
-
- NOT_LOW_RAM_DEVICE(1 << 4) {
- public boolean isSupported() { return !isLowRamDevice(); }
- },
-
- METERED_NETWORK(1 << 5) {
- public boolean isSupported() {
- return isActiveNetworkMetered(true) || canChangeActiveNetworkMeteredness();
- }
- },
-
- NON_METERED_NETWORK(~METERED_NETWORK.getValue()) {
- public boolean isSupported() {
- return isActiveNetworkMetered(false) || canChangeActiveNetworkMeteredness();
- }
- };
-
- private int mValue;
-
- Property(int value) { mValue = value; }
-
- public int getValue() { return mValue; }
-
- abstract boolean isSupported();
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java
deleted file mode 100644
index 80f99b6..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/RemoteSocketFactoryClient.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.ConditionVariable;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.system.ErrnoException;
-import android.system.Os;
-
-import com.android.cts.net.hostside.IRemoteSocketFactory;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-public class RemoteSocketFactoryClient {
- private static final int TIMEOUT_MS = 5000;
- private static final String PACKAGE = RemoteSocketFactoryClient.class.getPackage().getName();
- private static final String APP2_PACKAGE = PACKAGE + ".app2";
- private static final String SERVICE_NAME = APP2_PACKAGE + ".RemoteSocketFactoryService";
-
- private Context mContext;
- private ServiceConnection mServiceConnection;
- private IRemoteSocketFactory mService;
-
- public RemoteSocketFactoryClient(Context context) {
- mContext = context;
- }
-
- public void bind() {
- if (mService != null) {
- throw new IllegalStateException("Already bound");
- }
-
- final ConditionVariable cv = new ConditionVariable();
- mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- mService = IRemoteSocketFactory.Stub.asInterface(service);
- cv.open();
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
- }
- };
-
- final Intent intent = new Intent();
- intent.setComponent(new ComponentName(APP2_PACKAGE, SERVICE_NAME));
- mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
- cv.block(TIMEOUT_MS);
- if (mService == null) {
- throw new IllegalStateException(
- "Could not bind to RemoteSocketFactory service after " + TIMEOUT_MS + "ms");
- }
- }
-
- public void unbind() {
- if (mService != null) {
- mContext.unbindService(mServiceConnection);
- }
- }
-
- public FileDescriptor openSocketFd(String host, int port, int timeoutMs)
- throws RemoteException, ErrnoException, IOException {
- // Dup the filedescriptor so ParcelFileDescriptor's finalizer doesn't garbage collect it
- // and cause our fd to become invalid. http://b/35927643 .
- ParcelFileDescriptor pfd = mService.openSocketFd(host, port, timeoutMs);
- FileDescriptor fd = Os.dup(pfd.getFileDescriptor());
- pfd.close();
- return fd;
- }
-
- public String getPackageName() throws RemoteException {
- return mService.getPackageName();
- }
-
- public int getUid() throws RemoteException {
- return mService.getUid();
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java
deleted file mode 100644
index 01f9f3e..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG;
-
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.Log;
-
-import com.android.compatibility.common.util.BeforeAfterRule;
-
-import org.junit.Assume;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-public class RequiredPropertiesRule extends BeforeAfterRule {
-
- private static ArraySet<Property> mRequiredProperties;
-
- @Override
- public void onBefore(Statement base, Description description) {
- mRequiredProperties = getAllRequiredProperties(description);
-
- final String testName = description.getClassName() + "#" + description.getMethodName();
- assertTestIsValid(testName, mRequiredProperties);
- Log.i(TAG, "Running test " + testName + " with required properties: "
- + propertiesToString(mRequiredProperties));
- }
-
- private ArraySet<Property> getAllRequiredProperties(Description description) {
- final ArraySet<Property> allRequiredProperties = new ArraySet<>();
- RequiredProperties requiredProperties = description.getAnnotation(RequiredProperties.class);
- if (requiredProperties != null) {
- Collections.addAll(allRequiredProperties, requiredProperties.value());
- }
-
- for (Class<?> clazz = description.getTestClass();
- clazz != null; clazz = clazz.getSuperclass()) {
- requiredProperties = clazz.getDeclaredAnnotation(RequiredProperties.class);
- if (requiredProperties == null) {
- continue;
- }
- for (Property requiredProperty : requiredProperties.value()) {
- for (Property p : Property.values()) {
- if (p.getValue() == ~requiredProperty.getValue()
- && allRequiredProperties.contains(p)) {
- continue;
- }
- }
- allRequiredProperties.add(requiredProperty);
- }
- }
- return allRequiredProperties;
- }
-
- private void assertTestIsValid(String testName, ArraySet<Property> requiredProperies) {
- if (requiredProperies == null) {
- return;
- }
- final ArrayList<Property> unsupportedProperties = new ArrayList<>();
- for (Property property : requiredProperies) {
- if (!property.isSupported()) {
- unsupportedProperties.add(property);
- }
- }
- Assume.assumeTrue("Unsupported properties: "
- + propertiesToString(unsupportedProperties), unsupportedProperties.isEmpty());
- }
-
- public static ArraySet<Property> getRequiredProperties() {
- return mRequiredProperties;
- }
-
- private static String propertiesToString(Iterable<Property> properties) {
- return "[" + TextUtils.join(",", properties) + "]";
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java
deleted file mode 100755
index a451ea8..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java
+++ /dev/null
@@ -1,1090 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside;
-
-import static android.os.Process.INVALID_UID;
-import static android.system.OsConstants.*;
-
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.net.Proxy;
-import android.net.ProxyInfo;
-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.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiSelector;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-import android.system.StructPollfd;
-import android.test.InstrumentationTestCase;
-import android.test.MoreAsserts;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.compatibility.common.util.BlockingBroadcastReceiver;
-
-import java.io.Closeable;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-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.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Tests for the VpnService API.
- *
- * These tests establish a VPN via the VpnService API, and have the service reflect the packets back
- * to the device without causing any network traffic. This allows testing the local VPN data path
- * without a network connection or a VPN server.
- *
- * Note: in Lollipop, VPN functionality relies on kernel support for UID-based routing. If these
- * tests fail, it may be due to the lack of kernel support. The necessary patches can be
- * cherry-picked from the Android common kernel trees:
- *
- * android-3.10:
- * https://android-review.googlesource.com/#/c/99220/
- * https://android-review.googlesource.com/#/c/100545/
- *
- * android-3.4:
- * https://android-review.googlesource.com/#/c/99225/
- * https://android-review.googlesource.com/#/c/100557/
- *
- * To ensure that the kernel has the required commits, run the kernel unit
- * tests described at:
- *
- * https://source.android.com/devices/tech/config/kernel_network_tests.html
- *
- */
-public class VpnTest extends InstrumentationTestCase {
-
- // These are neither public nor @TestApi.
- // TODO: add them to @TestApi.
- private static final String PRIVATE_DNS_MODE_SETTING = "private_dns_mode";
- private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
- private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
- private static final String PRIVATE_DNS_SPECIFIER_SETTING = "private_dns_specifier";
-
- public static String TAG = "VpnTest";
- public static int TIMEOUT_MS = 3 * 1000;
- public static int SOCKET_TIMEOUT_MS = 100;
- public static String TEST_HOST = "connectivitycheck.gstatic.com";
-
- private UiDevice mDevice;
- private MyActivity mActivity;
- private String mPackageName;
- private ConnectivityManager mCM;
- private WifiManager mWifiManager;
- private RemoteSocketFactoryClient mRemoteSocketFactoryClient;
-
- Network mNetwork;
- NetworkCallback mCallback;
- final Object mLock = new Object();
- final Object mLockShutdown = new Object();
-
- private String mOldPrivateDnsMode;
- private String mOldPrivateDnsSpecifier;
-
- private boolean supportedHardware() {
- final PackageManager pm = getInstrumentation().getContext().getPackageManager();
- return !pm.hasSystemFeature("android.hardware.type.watch");
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- mNetwork = null;
- mCallback = null;
- storePrivateDnsSetting();
-
- mDevice = UiDevice.getInstance(getInstrumentation());
- mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
- MyActivity.class, null);
- mPackageName = mActivity.getPackageName();
- mCM = (ConnectivityManager) mActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
- mWifiManager = (WifiManager) mActivity.getSystemService(Context.WIFI_SERVICE);
- mRemoteSocketFactoryClient = new RemoteSocketFactoryClient(mActivity);
- mRemoteSocketFactoryClient.bind();
- mDevice.waitForIdle();
- }
-
- @Override
- public void tearDown() throws Exception {
- restorePrivateDnsSetting();
- mRemoteSocketFactoryClient.unbind();
- if (mCallback != null) {
- mCM.unregisterNetworkCallback(mCallback);
- }
- Log.i(TAG, "Stopping VPN");
- stopVpn();
- mActivity.finish();
- super.tearDown();
- }
-
- private void prepareVpn() throws Exception {
- final int REQUEST_ID = 42;
-
- // Attempt to prepare.
- Log.i(TAG, "Preparing VPN");
- Intent intent = VpnService.prepare(mActivity);
-
- if (intent != null) {
- // Start the confirmation dialog and click OK.
- mActivity.startActivityForResult(intent, REQUEST_ID);
- mDevice.waitForIdle();
-
- String packageName = intent.getComponent().getPackageName();
- String resourceIdRegex = "android:id/button1$|button_start_vpn";
- final UiObject okButton = new UiObject(new UiSelector()
- .className("android.widget.Button")
- .packageName(packageName)
- .resourceIdMatches(resourceIdRegex));
- if (okButton.waitForExists(TIMEOUT_MS) == false) {
- mActivity.finishActivity(REQUEST_ID);
- fail("VpnService.prepare returned an Intent for '" + intent.getComponent() + "' " +
- "to display the VPN confirmation dialog, but this test could not find the " +
- "button to allow the VPN application to connect. Please ensure that the " +
- "component displays a button with a resource ID matching the regexp: '" +
- resourceIdRegex + "'.");
- }
-
- // Click the button and wait for RESULT_OK.
- okButton.click();
- try {
- int result = mActivity.getResult(TIMEOUT_MS);
- if (result != MyActivity.RESULT_OK) {
- fail("The VPN confirmation dialog did not return RESULT_OK when clicking on " +
- "the button matching the regular expression '" + resourceIdRegex +
- "' of " + intent.getComponent() + "'. Please ensure that clicking on " +
- "that button allows the VPN application to connect. " +
- "Return value: " + result);
- }
- } catch (InterruptedException e) {
- fail("VPN confirmation dialog did not return after " + TIMEOUT_MS + "ms");
- }
-
- // Now we should be prepared.
- intent = VpnService.prepare(mActivity);
- if (intent != null) {
- fail("VpnService.prepare returned non-null even after the VPN dialog " +
- intent.getComponent() + "returned RESULT_OK.");
- }
- }
- }
-
- // TODO: Consider replacing arguments with a Builder.
- private void startVpn(
- String[] addresses, String[] routes, String allowedApplications,
- String disallowedApplications, @Nullable ProxyInfo proxyInfo,
- @Nullable ArrayList<Network> underlyingNetworks, boolean isAlwaysMetered) throws Exception {
- prepareVpn();
-
- // Register a callback so we will be notified when our VPN comes up.
- final NetworkRequest request = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build();
- mCallback = new NetworkCallback() {
- public void onAvailable(Network network) {
- synchronized (mLock) {
- Log.i(TAG, "Got available callback for network=" + network);
- mNetwork = network;
- mLock.notify();
- }
- }
- };
- mCM.registerNetworkCallback(request, mCallback); // Unregistered in tearDown.
-
- // Start the service and wait up for TIMEOUT_MS ms for the VPN to come up.
- Intent intent = new Intent(mActivity, MyVpnService.class)
- .putExtra(mPackageName + ".cmd", "connect")
- .putExtra(mPackageName + ".addresses", TextUtils.join(",", addresses))
- .putExtra(mPackageName + ".routes", TextUtils.join(",", routes))
- .putExtra(mPackageName + ".allowedapplications", allowedApplications)
- .putExtra(mPackageName + ".disallowedapplications", disallowedApplications)
- .putExtra(mPackageName + ".httpProxy", proxyInfo)
- .putParcelableArrayListExtra(
- mPackageName + ".underlyingNetworks", underlyingNetworks)
- .putExtra(mPackageName + ".isAlwaysMetered", isAlwaysMetered);
-
- mActivity.startService(intent);
- synchronized (mLock) {
- if (mNetwork == null) {
- Log.i(TAG, "bf mLock");
- mLock.wait(TIMEOUT_MS);
- Log.i(TAG, "af mLock");
- }
- }
-
- if (mNetwork == null) {
- fail("VPN did not become available after " + TIMEOUT_MS + "ms");
- }
-
- // Unfortunately, when the available callback fires, the VPN UID ranges are not yet
- // configured. Give the system some time to do so. http://b/18436087 .
- try { Thread.sleep(3000); } catch(InterruptedException e) {}
- }
-
- private void stopVpn() {
- // Register a callback so we will be notified when our VPN comes up.
- final NetworkRequest request = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build();
- mCallback = new NetworkCallback() {
- public void onLost(Network network) {
- synchronized (mLockShutdown) {
- Log.i(TAG, "Got lost callback for network=" + network
- + ",mNetwork = " + mNetwork);
- if( mNetwork == network){
- mLockShutdown.notify();
- }
- }
- }
- };
- mCM.registerNetworkCallback(request, mCallback); // Unregistered in tearDown.
- // Simply calling mActivity.stopService() won't stop the service, because the system binds
- // to the service for the purpose of sending it a revoke command if another VPN comes up,
- // and stopping a bound service has no effect. Instead, "start" the service again with an
- // Intent that tells it to disconnect.
- Intent intent = new Intent(mActivity, MyVpnService.class)
- .putExtra(mPackageName + ".cmd", "disconnect");
- mActivity.startService(intent);
- synchronized (mLockShutdown) {
- try {
- Log.i(TAG, "bf mLockShutdown");
- mLockShutdown.wait(TIMEOUT_MS);
- Log.i(TAG, "af mLockShutdown");
- } catch(InterruptedException e) {}
- }
- }
-
- private static void closeQuietly(Closeable c) {
- if (c != null) {
- try {
- c.close();
- } catch (IOException e) {
- }
- }
- }
-
- private static void checkPing(String to) throws IOException, ErrnoException {
- InetAddress address = InetAddress.getByName(to);
- FileDescriptor s;
- final int LENGTH = 64;
- byte[] packet = new byte[LENGTH];
- byte[] header;
-
- // Construct a ping packet.
- Random random = new Random();
- random.nextBytes(packet);
- if (address instanceof Inet6Address) {
- s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
- header = new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
- } else {
- // Note that this doesn't actually work due to http://b/18558481 .
- s = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
- header = new byte[] { (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
- }
- System.arraycopy(header, 0, packet, 0, header.length);
-
- // Send the packet.
- int port = random.nextInt(65534) + 1;
- Os.connect(s, address, port);
- Os.write(s, packet, 0, packet.length);
-
- // Expect a reply.
- StructPollfd pollfd = new StructPollfd();
- pollfd.events = (short) POLLIN; // "error: possible loss of precision"
- pollfd.fd = s;
- int ret = Os.poll(new StructPollfd[] { pollfd }, SOCKET_TIMEOUT_MS);
- assertEquals("Expected reply after sending ping", 1, ret);
-
- byte[] reply = new byte[LENGTH];
- int read = Os.read(s, reply, 0, LENGTH);
- assertEquals(LENGTH, read);
-
- // Find out what the kernel set the ICMP ID to.
- InetSocketAddress local = (InetSocketAddress) Os.getsockname(s);
- port = local.getPort();
- packet[4] = (byte) ((port >> 8) & 0xff);
- packet[5] = (byte) (port & 0xff);
-
- // Check the contents.
- if (packet[0] == (byte) 0x80) {
- packet[0] = (byte) 0x81;
- } else {
- packet[0] = 0;
- }
- // Zero out the checksum in the reply so it matches the uninitialized checksum in packet.
- reply[2] = reply[3] = 0;
- MoreAsserts.assertEquals(packet, reply);
- }
-
- // Writes data to out and checks that it appears identically on in.
- private static void writeAndCheckData(
- OutputStream out, InputStream in, byte[] data) throws IOException {
- out.write(data, 0, data.length);
- out.flush();
-
- byte[] read = new byte[data.length];
- int bytesRead = 0, totalRead = 0;
- do {
- bytesRead = in.read(read, totalRead, read.length - totalRead);
- totalRead += bytesRead;
- } while (bytesRead >= 0 && totalRead < data.length);
- assertEquals(totalRead, data.length);
- MoreAsserts.assertEquals(data, read);
- }
-
- private void checkTcpReflection(String to, String expectedFrom) throws IOException {
- // Exercise TCP over the VPN by "connecting to ourselves". We open a server socket and a
- // client socket, and connect the client socket to a remote host, with the port of the
- // server socket. The PacketReflector reflects the packets, changing the source addresses
- // but not the ports, so our client socket is connected to our server socket, though both
- // sockets think their peers are on the "remote" IP address.
-
- // Open a listening socket.
- ServerSocket listen = new ServerSocket(0, 10, InetAddress.getByName("::"));
-
- // Connect the client socket to it.
- InetAddress toAddr = InetAddress.getByName(to);
- Socket client = new Socket();
- try {
- client.connect(new InetSocketAddress(toAddr, listen.getLocalPort()), SOCKET_TIMEOUT_MS);
- if (expectedFrom == null) {
- closeQuietly(listen);
- closeQuietly(client);
- fail("Expected connection to fail, but it succeeded.");
- }
- } catch (IOException e) {
- if (expectedFrom != null) {
- closeQuietly(listen);
- fail("Expected connection to succeed, but it failed.");
- } else {
- // We expected the connection to fail, and it did, so there's nothing more to test.
- return;
- }
- }
-
- // The connection succeeded, and we expected it to succeed. Send some data; if things are
- // working, the data will be sent to the VPN, reflected by the PacketReflector, and arrive
- // at our server socket. For good measure, send some data in the other direction.
- Socket server = null;
- try {
- // Accept the connection on the server side.
- listen.setSoTimeout(SOCKET_TIMEOUT_MS);
- server = listen.accept();
- checkConnectionOwnerUidTcp(client);
- checkConnectionOwnerUidTcp(server);
- // Check that the source and peer addresses are as expected.
- assertEquals(expectedFrom, client.getLocalAddress().getHostAddress());
- assertEquals(expectedFrom, server.getLocalAddress().getHostAddress());
- assertEquals(
- new InetSocketAddress(toAddr, client.getLocalPort()),
- server.getRemoteSocketAddress());
- assertEquals(
- new InetSocketAddress(toAddr, server.getLocalPort()),
- client.getRemoteSocketAddress());
-
- // Now write some data.
- final int LENGTH = 32768;
- byte[] data = new byte[LENGTH];
- new Random().nextBytes(data);
-
- // Make sure our writes don't block or time out, because we're single-threaded and can't
- // read and write at the same time.
- server.setReceiveBufferSize(LENGTH * 2);
- client.setSendBufferSize(LENGTH * 2);
- client.setSoTimeout(SOCKET_TIMEOUT_MS);
- server.setSoTimeout(SOCKET_TIMEOUT_MS);
-
- // Send some data from client to server, then from server to client.
- writeAndCheckData(client.getOutputStream(), server.getInputStream(), data);
- writeAndCheckData(server.getOutputStream(), client.getInputStream(), data);
- } finally {
- closeQuietly(listen);
- closeQuietly(client);
- closeQuietly(server);
- }
- }
-
- private void checkConnectionOwnerUidUdp(DatagramSocket s, boolean expectSuccess) {
- final int expectedUid = expectSuccess ? Process.myUid() : INVALID_UID;
- InetSocketAddress loc = new InetSocketAddress(s.getLocalAddress(), s.getLocalPort());
- InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort());
- int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_UDP, loc, rem);
- assertEquals(expectedUid, uid);
- }
-
- private void checkConnectionOwnerUidTcp(Socket s) {
- final int expectedUid = Process.myUid();
- InetSocketAddress loc = new InetSocketAddress(s.getLocalAddress(), s.getLocalPort());
- InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort());
- int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_TCP, loc, rem);
- assertEquals(expectedUid, uid);
- }
-
- private void checkUdpEcho(String to, String expectedFrom) throws IOException {
- DatagramSocket s;
- InetAddress address = InetAddress.getByName(to);
- if (address instanceof Inet6Address) { // http://b/18094870
- s = new DatagramSocket(0, InetAddress.getByName("::"));
- } else {
- s = new DatagramSocket();
- }
- s.setSoTimeout(SOCKET_TIMEOUT_MS);
-
- Random random = new Random();
- byte[] data = new byte[random.nextInt(1650)];
- random.nextBytes(data);
- DatagramPacket p = new DatagramPacket(data, data.length);
- s.connect(address, 7);
-
- if (expectedFrom != null) {
- assertEquals("Unexpected source address: ",
- expectedFrom, s.getLocalAddress().getHostAddress());
- }
-
- try {
- if (expectedFrom != null) {
- s.send(p);
- checkConnectionOwnerUidUdp(s, true);
- s.receive(p);
- MoreAsserts.assertEquals(data, p.getData());
- } else {
- try {
- s.send(p);
- s.receive(p);
- fail("Received unexpected reply");
- } catch (IOException expected) {
- checkConnectionOwnerUidUdp(s, false);
- }
- }
- } finally {
- s.close();
- }
- }
-
- private void checkTrafficOnVpn() throws Exception {
- checkUdpEcho("192.0.2.251", "192.0.2.2");
- checkUdpEcho("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe");
- checkPing("2001:db8:dead:beef::f00");
- checkTcpReflection("192.0.2.252", "192.0.2.2");
- checkTcpReflection("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe");
- }
-
- private void checkNoTrafficOnVpn() throws Exception {
- checkUdpEcho("192.0.2.251", null);
- checkUdpEcho("2001:db8:dead:beef::f00", null);
- checkTcpReflection("192.0.2.252", null);
- checkTcpReflection("2001:db8:dead:beef::f00", null);
- }
-
- private FileDescriptor openSocketFd(String host, int port, int timeoutMs) throws Exception {
- Socket s = new Socket(host, port);
- s.setSoTimeout(timeoutMs);
- // Dup the filedescriptor so ParcelFileDescriptor's finalizer doesn't garbage collect it
- // and cause our fd to become invalid. http://b/35927643 .
- FileDescriptor fd = Os.dup(ParcelFileDescriptor.fromSocket(s).getFileDescriptor());
- s.close();
- return fd;
- }
-
- private FileDescriptor openSocketFdInOtherApp(
- String host, int port, int timeoutMs) throws Exception {
- Log.d(TAG, String.format("Creating test socket in UID=%d, my UID=%d",
- mRemoteSocketFactoryClient.getUid(), Os.getuid()));
- FileDescriptor fd = mRemoteSocketFactoryClient.openSocketFd(host, port, TIMEOUT_MS);
- return fd;
- }
-
- private void sendRequest(FileDescriptor fd, String host) throws Exception {
- String request = "GET /generate_204 HTTP/1.1\r\n" +
- "Host: " + host + "\r\n" +
- "Connection: keep-alive\r\n\r\n";
- byte[] requestBytes = request.getBytes(StandardCharsets.UTF_8);
- int ret = Os.write(fd, requestBytes, 0, requestBytes.length);
- Log.d(TAG, "Wrote " + ret + "bytes");
-
- String expected = "HTTP/1.1 204 No Content\r\n";
- byte[] response = new byte[expected.length()];
- Os.read(fd, response, 0, response.length);
-
- String actual = new String(response, StandardCharsets.UTF_8);
- assertEquals(expected, actual);
- Log.d(TAG, "Got response: " + actual);
- }
-
- private void assertSocketStillOpen(FileDescriptor fd, String host) throws Exception {
- try {
- assertTrue(fd.valid());
- sendRequest(fd, host);
- assertTrue(fd.valid());
- } finally {
- Os.close(fd);
- }
- }
-
- private void assertSocketClosed(FileDescriptor fd, String host) throws Exception {
- try {
- assertTrue(fd.valid());
- sendRequest(fd, host);
- fail("Socket opened before VPN connects should be closed when VPN connects");
- } catch (ErrnoException expected) {
- assertEquals(ECONNABORTED, expected.errno);
- assertTrue(fd.valid());
- } finally {
- Os.close(fd);
- }
- }
-
- private ContentResolver getContentResolver() {
- return getInstrumentation().getContext().getContentResolver();
- }
-
- private boolean isPrivateDnsInStrictMode() {
- return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(
- Settings.Global.getString(getContentResolver(), PRIVATE_DNS_MODE_SETTING));
- }
-
- private void storePrivateDnsSetting() {
- mOldPrivateDnsMode = Settings.Global.getString(getContentResolver(),
- PRIVATE_DNS_MODE_SETTING);
- mOldPrivateDnsSpecifier = Settings.Global.getString(getContentResolver(),
- PRIVATE_DNS_SPECIFIER_SETTING);
- }
-
- private void restorePrivateDnsSetting() {
- Settings.Global.putString(getContentResolver(), PRIVATE_DNS_MODE_SETTING,
- mOldPrivateDnsMode);
- Settings.Global.putString(getContentResolver(), PRIVATE_DNS_SPECIFIER_SETTING,
- mOldPrivateDnsSpecifier);
- }
-
- // TODO: replace with CtsNetUtils.awaitPrivateDnsSetting in Q or above.
- private void expectPrivateDnsHostname(final String hostname) throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder()
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .build();
- final CountDownLatch latch = new CountDownLatch(1);
- final NetworkCallback callback = new NetworkCallback() {
- @Override
- public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
- if (network.equals(mNetwork) &&
- Objects.equals(lp.getPrivateDnsServerName(), hostname)) {
- latch.countDown();
- }
- }
- };
-
- mCM.registerNetworkCallback(request, callback);
-
- try {
- assertTrue("Private DNS hostname was not " + hostname + " after " + TIMEOUT_MS + "ms",
- latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- } finally {
- mCM.unregisterNetworkCallback(callback);
- }
- }
-
- private void setAndVerifyPrivateDns(boolean strictMode) throws Exception {
- final ContentResolver cr = getInstrumentation().getContext().getContentResolver();
- String privateDnsHostname;
-
- if (strictMode) {
- privateDnsHostname = "vpncts-nx.metric.gstatic.com";
- Settings.Global.putString(cr, PRIVATE_DNS_SPECIFIER_SETTING, privateDnsHostname);
- Settings.Global.putString(cr, PRIVATE_DNS_MODE_SETTING,
- PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
- } else {
- Settings.Global.putString(cr, PRIVATE_DNS_MODE_SETTING, PRIVATE_DNS_MODE_OPPORTUNISTIC);
- privateDnsHostname = null;
- }
-
- expectPrivateDnsHostname(privateDnsHostname);
-
- String randomName = "vpncts-" + new Random().nextInt(1000000000) + "-ds.metric.gstatic.com";
- if (strictMode) {
- // Strict mode private DNS is enabled. DNS lookups should fail, because the private DNS
- // server name is invalid.
- try {
- InetAddress.getByName(randomName);
- fail("VPN DNS lookup should fail with private DNS enabled");
- } catch (UnknownHostException expected) {
- }
- } else {
- // Strict mode private DNS is disabled. DNS lookup should succeed, because the VPN
- // provides no DNS servers, and thus DNS falls through to the default network.
- assertNotNull("VPN DNS lookup should succeed with private DNS disabled",
- InetAddress.getByName(randomName));
- }
- }
-
- // Tests that strict mode private DNS is used on VPNs.
- private void checkStrictModePrivateDns() throws Exception {
- final boolean initialMode = isPrivateDnsInStrictMode();
- setAndVerifyPrivateDns(!initialMode);
- setAndVerifyPrivateDns(initialMode);
- }
-
- public void testDefault() throws Exception {
- if (!supportedHardware()) return;
- // If adb TCP port opened, this test may running by adb over network.
- // All of socket would be destroyed in this test. So this test don't
- // support adb over network, see b/119382723.
- if (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1
- || SystemProperties.getInt("service.adb.tcp.port", -1) > -1) {
- Log.i(TAG, "adb is running over the network, so skip this test");
- return;
- }
-
- final BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(
- getInstrumentation().getTargetContext(), MyVpnService.ACTION_ESTABLISHED);
- receiver.register();
-
- FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS);
-
- startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
- new String[] {"0.0.0.0/0", "::/0"},
- "", "", null, null /* underlyingNetworks */, false /* isAlwaysMetered */);
-
- final Intent intent = receiver.awaitForBroadcast(TimeUnit.MINUTES.toMillis(1));
- assertNotNull("Failed to receive broadcast from VPN service", intent);
- assertFalse("Wrong VpnService#isAlwaysOn",
- intent.getBooleanExtra(MyVpnService.EXTRA_ALWAYS_ON, true));
- assertFalse("Wrong VpnService#isLockdownEnabled",
- intent.getBooleanExtra(MyVpnService.EXTRA_LOCKDOWN_ENABLED, true));
-
- assertSocketClosed(fd, TEST_HOST);
-
- checkTrafficOnVpn();
-
- checkStrictModePrivateDns();
-
- receiver.unregisterQuietly();
- }
-
- public void testAppAllowed() throws Exception {
- if (!supportedHardware()) return;
-
- FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS);
-
- // Shell app must not be put in here or it would kill the ADB-over-network use case
- String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName;
- 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, "", null, null /* underlyingNetworks */, false /* isAlwaysMetered */);
-
- assertSocketClosed(fd, TEST_HOST);
-
- checkTrafficOnVpn();
-
- checkStrictModePrivateDns();
- }
-
- public void testAppDisallowed() throws Exception {
- if (!supportedHardware()) return;
-
- FileDescriptor localFd = openSocketFd(TEST_HOST, 80, TIMEOUT_MS);
- FileDescriptor remoteFd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS);
-
- String disallowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName;
- // If adb TCP port opened, this test may running by adb over TCP.
- // Add com.android.shell appllication into blacklist to exclude adb socket for VPN test,
- // see b/119382723.
- // Note: The test don't support running adb over network for root device
- disallowedApps = disallowedApps + ",com.android.shell";
- Log.i(TAG, "Append shell app to disallowedApps: " + disallowedApps);
- startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
- new String[] {"192.0.2.0/24", "2001:db8::/32"},
- "", disallowedApps, null, null /* underlyingNetworks */,
- false /* isAlwaysMetered */);
-
- assertSocketStillOpen(localFd, TEST_HOST);
- assertSocketStillOpen(remoteFd, TEST_HOST);
-
- checkNoTrafficOnVpn();
- }
-
- public void testGetConnectionOwnerUidSecurity() throws Exception {
- if (!supportedHardware()) return;
-
- DatagramSocket s;
- InetAddress address = InetAddress.getByName("localhost");
- s = new DatagramSocket();
- s.setSoTimeout(SOCKET_TIMEOUT_MS);
- s.connect(address, 7);
- InetSocketAddress loc = new InetSocketAddress(s.getLocalAddress(), s.getLocalPort());
- InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort());
- try {
- int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_TCP, loc, rem);
- fail("Only an active VPN app may call this API.");
- } catch (SecurityException expected) {
- return;
- }
- }
-
- public void testSetProxy() throws Exception {
- if (!supportedHardware()) return;
- ProxyInfo initialProxy = mCM.getDefaultProxy();
- // Receiver for the proxy change broadcast.
- BlockingBroadcastReceiver proxyBroadcastReceiver = new ProxyChangeBroadcastReceiver();
- proxyBroadcastReceiver.register();
-
- String allowedApps = mPackageName;
- ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("10.0.0.1", 8888);
- startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
- new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "",
- testProxyInfo, null /* underlyingNetworks */, false /* isAlwaysMetered */);
-
- // Check that the proxy change broadcast is received
- try {
- assertNotNull("No proxy change was broadcast when VPN is connected.",
- proxyBroadcastReceiver.awaitForBroadcast());
- } finally {
- proxyBroadcastReceiver.unregisterQuietly();
- }
-
- // Proxy is set correctly in network and in link properties.
- assertNetworkHasExpectedProxy(testProxyInfo, mNetwork);
- assertDefaultProxy(testProxyInfo);
-
- proxyBroadcastReceiver = new ProxyChangeBroadcastReceiver();
- proxyBroadcastReceiver.register();
- stopVpn();
- try {
- assertNotNull("No proxy change was broadcast when VPN was disconnected.",
- proxyBroadcastReceiver.awaitForBroadcast());
- } finally {
- proxyBroadcastReceiver.unregisterQuietly();
- }
-
- // After disconnecting from VPN, the proxy settings are the ones of the initial network.
- assertDefaultProxy(initialProxy);
- }
-
- public void testSetProxyDisallowedApps() throws Exception {
- if (!supportedHardware()) return;
- ProxyInfo initialProxy = mCM.getDefaultProxy();
-
- // If adb TCP port opened, this test may running by adb over TCP.
- // Add com.android.shell appllication into blacklist to exclude adb socket for VPN test,
- // see b/119382723.
- // Note: The test don't support running adb over network for root device
- String disallowedApps = mPackageName + ",com.android.shell";
- ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("10.0.0.1", 8888);
- startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
- new String[] {"0.0.0.0/0", "::/0"}, "", disallowedApps,
- testProxyInfo, null /* underlyingNetworks */, false /* isAlwaysMetered */);
-
- // The disallowed app does has the proxy configs of the default network.
- assertNetworkHasExpectedProxy(initialProxy, mCM.getActiveNetwork());
- assertDefaultProxy(initialProxy);
- }
-
- public void testNoProxy() throws Exception {
- if (!supportedHardware()) return;
- ProxyInfo initialProxy = mCM.getDefaultProxy();
- BlockingBroadcastReceiver proxyBroadcastReceiver = new ProxyChangeBroadcastReceiver();
- proxyBroadcastReceiver.register();
- String allowedApps = mPackageName;
- startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
- new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null,
- null /* underlyingNetworks */, false /* isAlwaysMetered */);
-
- try {
- assertNotNull("No proxy change was broadcast.",
- proxyBroadcastReceiver.awaitForBroadcast());
- } finally {
- proxyBroadcastReceiver.unregisterQuietly();
- }
-
- // The VPN network has no proxy set.
- assertNetworkHasExpectedProxy(null, mNetwork);
-
- proxyBroadcastReceiver = new ProxyChangeBroadcastReceiver();
- proxyBroadcastReceiver.register();
- stopVpn();
- try {
- assertNotNull("No proxy change was broadcast.",
- proxyBroadcastReceiver.awaitForBroadcast());
- } finally {
- proxyBroadcastReceiver.unregisterQuietly();
- }
- // After disconnecting from VPN, the proxy settings are the ones of the initial network.
- assertDefaultProxy(initialProxy);
- assertNetworkHasExpectedProxy(initialProxy, mCM.getActiveNetwork());
- }
-
- public void testBindToNetworkWithProxy() throws Exception {
- if (!supportedHardware()) return;
- String allowedApps = mPackageName;
- Network initialNetwork = mCM.getActiveNetwork();
- ProxyInfo initialProxy = mCM.getDefaultProxy();
- ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("10.0.0.1", 8888);
- // Receiver for the proxy change broadcast.
- BlockingBroadcastReceiver proxyBroadcastReceiver = new ProxyChangeBroadcastReceiver();
- proxyBroadcastReceiver.register();
- startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
- new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "",
- testProxyInfo, null /* underlyingNetworks */, false /* isAlwaysMetered */);
-
- assertDefaultProxy(testProxyInfo);
- mCM.bindProcessToNetwork(initialNetwork);
- try {
- assertNotNull("No proxy change was broadcast.",
- proxyBroadcastReceiver.awaitForBroadcast());
- } finally {
- proxyBroadcastReceiver.unregisterQuietly();
- }
- assertDefaultProxy(initialProxy);
- }
-
- public void testVpnMeterednessWithNoUnderlyingNetwork() throws Exception {
- if (!supportedHardware()) {
- return;
- }
- // VPN is not routing any traffic i.e. its underlying networks is an empty array.
- ArrayList<Network> underlyingNetworks = new ArrayList<>();
- String allowedApps = mPackageName;
-
- startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
- new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null,
- underlyingNetworks, false /* isAlwaysMetered */);
-
- // VPN should now be the active network.
- assertEquals(mNetwork, mCM.getActiveNetwork());
- assertVpnTransportContains(NetworkCapabilities.TRANSPORT_VPN);
- // VPN with no underlying networks should be metered by default.
- assertTrue(isNetworkMetered(mNetwork));
- assertTrue(mCM.isActiveNetworkMetered());
- }
-
- public void testVpnMeterednessWithNullUnderlyingNetwork() throws Exception {
- if (!supportedHardware()) {
- return;
- }
- Network underlyingNetwork = mCM.getActiveNetwork();
- if (underlyingNetwork == null) {
- Log.i(TAG, "testVpnMeterednessWithNullUnderlyingNetwork cannot execute"
- + " unless there is an active network");
- return;
- }
- // VPN tracks platform default.
- ArrayList<Network> underlyingNetworks = null;
- String allowedApps = mPackageName;
-
- startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
- new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null,
- underlyingNetworks, false /*isAlwaysMetered */);
-
- // Ensure VPN transports contains underlying network's transports.
- assertVpnTransportContains(underlyingNetwork);
- // Its meteredness should be same as that of underlying network.
- assertEquals(isNetworkMetered(underlyingNetwork), isNetworkMetered(mNetwork));
- // Meteredness based on VPN capabilities and CM#isActiveNetworkMetered should be in sync.
- assertEquals(isNetworkMetered(mNetwork), mCM.isActiveNetworkMetered());
- }
-
- public void testVpnMeterednessWithNonNullUnderlyingNetwork() throws Exception {
- if (!supportedHardware()) {
- return;
- }
- Network underlyingNetwork = mCM.getActiveNetwork();
- if (underlyingNetwork == null) {
- Log.i(TAG, "testVpnMeterednessWithNonNullUnderlyingNetwork cannot execute"
- + " unless there is an active network");
- return;
- }
- // VPN explicitly declares WiFi to be its underlying network.
- ArrayList<Network> underlyingNetworks = new ArrayList<>(1);
- underlyingNetworks.add(underlyingNetwork);
- String allowedApps = mPackageName;
-
- startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
- new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null,
- underlyingNetworks, false /* isAlwaysMetered */);
-
- // Ensure VPN transports contains underlying network's transports.
- assertVpnTransportContains(underlyingNetwork);
- // Its meteredness should be same as that of underlying network.
- assertEquals(isNetworkMetered(underlyingNetwork), isNetworkMetered(mNetwork));
- // Meteredness based on VPN capabilities and CM#isActiveNetworkMetered should be in sync.
- assertEquals(isNetworkMetered(mNetwork), mCM.isActiveNetworkMetered());
- }
-
- public void testAlwaysMeteredVpnWithNullUnderlyingNetwork() throws Exception {
- if (!supportedHardware()) {
- return;
- }
- Network underlyingNetwork = mCM.getActiveNetwork();
- if (underlyingNetwork == null) {
- Log.i(TAG, "testAlwaysMeteredVpnWithNullUnderlyingNetwork cannot execute"
- + " unless there is an active network");
- return;
- }
- // VPN tracks platform default.
- ArrayList<Network> underlyingNetworks = null;
- String allowedApps = mPackageName;
- boolean isAlwaysMetered = true;
-
- startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
- new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null,
- underlyingNetworks, isAlwaysMetered);
-
- // VPN's meteredness does not depend on underlying network since it is always metered.
- assertTrue(isNetworkMetered(mNetwork));
- assertTrue(mCM.isActiveNetworkMetered());
- }
-
- public void testAlwaysMeteredVpnWithNonNullUnderlyingNetwork() throws Exception {
- if (!supportedHardware()) {
- return;
- }
- Network underlyingNetwork = mCM.getActiveNetwork();
- if (underlyingNetwork == null) {
- Log.i(TAG, "testAlwaysMeteredVpnWithNonNullUnderlyingNetwork cannot execute"
- + " unless there is an active network");
- return;
- }
- // VPN explicitly declares its underlying network.
- ArrayList<Network> underlyingNetworks = new ArrayList<>(1);
- underlyingNetworks.add(underlyingNetwork);
- String allowedApps = mPackageName;
- boolean isAlwaysMetered = true;
-
- startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
- new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null,
- underlyingNetworks, isAlwaysMetered);
-
- // VPN's meteredness does not depend on underlying network since it is always metered.
- assertTrue(isNetworkMetered(mNetwork));
- assertTrue(mCM.isActiveNetworkMetered());
- }
-
- public void testB141603906() throws Exception {
- final InetSocketAddress src = new InetSocketAddress(0);
- final InetSocketAddress dst = new InetSocketAddress(0);
- final int NUM_THREADS = 8;
- final int NUM_SOCKETS = 5000;
- final Thread[] threads = new Thread[NUM_THREADS];
- startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
- new String[] {"0.0.0.0/0", "::/0"},
- "" /* allowedApplications */, "com.android.shell" /* disallowedApplications */,
- null /* proxyInfo */, null /* underlyingNetworks */, false /* isAlwaysMetered */);
-
- for (int i = 0; i < NUM_THREADS; i++) {
- threads[i] = new Thread(() -> {
- for (int j = 0; j < NUM_SOCKETS; j++) {
- mCM.getConnectionOwnerUid(IPPROTO_TCP, src, dst);
- }
- });
- }
- for (Thread thread : threads) {
- thread.start();
- }
- for (Thread thread : threads) {
- thread.join();
- }
- stopVpn();
- }
-
- private boolean isNetworkMetered(Network network) {
- NetworkCapabilities nc = mCM.getNetworkCapabilities(network);
- return !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- }
-
- private void assertVpnTransportContains(Network underlyingNetwork) {
- int[] transports = mCM.getNetworkCapabilities(underlyingNetwork).getTransportTypes();
- assertVpnTransportContains(transports);
- }
-
- private void assertVpnTransportContains(int... transports) {
- NetworkCapabilities vpnCaps = mCM.getNetworkCapabilities(mNetwork);
- for (int transport : transports) {
- assertTrue(vpnCaps.hasTransport(transport));
- }
- }
-
- private void assertDefaultProxy(ProxyInfo expected) {
- assertEquals("Incorrect proxy config.", expected, mCM.getDefaultProxy());
- String expectedHost = expected == null ? null : expected.getHost();
- String expectedPort = expected == null ? null : String.valueOf(expected.getPort());
- assertEquals("Incorrect proxy host system property.", expectedHost,
- System.getProperty("http.proxyHost"));
- assertEquals("Incorrect proxy port system property.", expectedPort,
- System.getProperty("http.proxyPort"));
- }
-
- private void assertNetworkHasExpectedProxy(ProxyInfo expected, Network network) {
- LinkProperties lp = mCM.getLinkProperties(network);
- assertNotNull("The network link properties object is null.", lp);
- assertEquals("Incorrect proxy config.", expected, lp.getHttpProxy());
-
- assertEquals(expected, mCM.getProxyForNetwork(network));
- }
-
- class ProxyChangeBroadcastReceiver extends BlockingBroadcastReceiver {
- private boolean received;
-
- public ProxyChangeBroadcastReceiver() {
- super(VpnTest.this.getInstrumentation().getContext(), Proxy.PROXY_CHANGE_ACTION);
- received = false;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!received) {
- // Do not call onReceive() more than once.
- super.onReceive(context, intent);
- }
- received = true;
- }
- }
-}
diff --git a/hostsidetests/net/app2/Android.bp b/hostsidetests/net/app2/Android.bp
deleted file mode 100644
index a6e9b11..0000000
--- a/hostsidetests/net/app2/Android.bp
+++ /dev/null
@@ -1,30 +0,0 @@
-//
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-android_test_helper_app {
- name: "CtsHostsideNetworkTestsApp2",
- defaults: ["cts_support_defaults"],
- sdk_version: "current",
- static_libs: ["CtsHostsideNetworkTestsAidl"],
- srcs: ["src/**/*.java"],
- // Tag this module as a cts test artifact
- test_suites: [
- "cts",
- "vts10",
- "general-tests",
- ],
- certificate: ":cts-net-app",
-}
diff --git a/hostsidetests/net/app2/AndroidManifest.xml b/hostsidetests/net/app2/AndroidManifest.xml
deleted file mode 100644
index ad270b3..0000000
--- a/hostsidetests/net/app2/AndroidManifest.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.net.hostside.app2" >
-
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
- <uses-permission android:name="android.permission.INTERNET" />
-
- <!--
- This application is used to listen to RESTRICT_BACKGROUND_CHANGED intents and store
- them in a shared preferences which is then read by the test app. These broadcasts are
- handled by 2 listeners, one defined the manifest and another dynamically registered by
- a service.
-
- The manifest-defined listener also handles ordered broadcasts used to share data with the
- test app.
-
- This application also provides a service, RemoteSocketFactoryService, that the test app can
- use to open sockets to remote hosts as a different user ID.
- -->
- <application android:usesCleartextTraffic="true">
- <activity android:name=".MyActivity" android:exported="true"/>
- <service android:name=".MyService" android:exported="true"/>
- <service android:name=".MyForegroundService" android:exported="true"/>
- <service android:name=".RemoteSocketFactoryService" android:exported="true"/>
-
- <receiver android:name=".MyBroadcastReceiver" >
- <intent-filter>
- <action android:name="android.net.conn.RESTRICT_BACKGROUND_CHANGED" />
- <action android:name="com.android.cts.net.hostside.app2.action.GET_COUNTERS" />
- <action android:name="com.android.cts.net.hostside.app2.action.GET_RESTRICT_BACKGROUND_STATUS" />
- <action android:name="com.android.cts.net.hostside.app2.action.CHECK_NETWORK" />
- <action android:name="com.android.cts.net.hostside.app2.action.SEND_NOTIFICATION" />
- <action android:name="com.android.cts.net.hostside.app2.action.SHOW_TOAST" />
- </intent-filter>
- </receiver>
- </application>
-
-</manifest>
diff --git a/hostsidetests/net/app2/res/drawable/ic_notification.png b/hostsidetests/net/app2/res/drawable/ic_notification.png
deleted file mode 100644
index 6ae570b..0000000
--- a/hostsidetests/net/app2/res/drawable/ic_notification.png
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/Common.java b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/Common.java
deleted file mode 100644
index 351733e..0000000
--- a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/Common.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.net.hostside.app2;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.cts.net.hostside.INetworkStateObserver;
-
-public final class Common {
-
- static final String TAG = "CtsNetApp2";
-
- // Constants below must match values defined on app's
- // AbstractRestrictBackgroundNetworkTestCase.java
- static final String MANIFEST_RECEIVER = "ManifestReceiver";
- static final String DYNAMIC_RECEIVER = "DynamicReceiver";
-
- static final String ACTION_RECEIVER_READY =
- "com.android.cts.net.hostside.app2.action.RECEIVER_READY";
- static final String ACTION_FINISH_ACTIVITY =
- "com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY";
- static final String ACTION_SHOW_TOAST =
- "com.android.cts.net.hostside.app2.action.SHOW_TOAST";
-
- static final String NOTIFICATION_TYPE_CONTENT = "CONTENT";
- static final String NOTIFICATION_TYPE_DELETE = "DELETE";
- static final String NOTIFICATION_TYPE_FULL_SCREEN = "FULL_SCREEN";
- static final String NOTIFICATION_TYPE_BUNDLE = "BUNDLE";
- static final String NOTIFICATION_TYPE_ACTION = "ACTION";
- static final String NOTIFICATION_TYPE_ACTION_BUNDLE = "ACTION_BUNDLE";
- static final String NOTIFICATION_TYPE_ACTION_REMOTE_INPUT = "ACTION_REMOTE_INPUT";
-
- static final String TEST_PKG = "com.android.cts.net.hostside";
- static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
-
- static int getUid(Context context) {
- final String packageName = context.getPackageName();
- try {
- return context.getPackageManager().getPackageUid(packageName, 0);
- } catch (NameNotFoundException e) {
- throw new IllegalStateException("Could not get UID for " + packageName, e);
- }
- }
-
- static void notifyNetworkStateObserver(Context context, Intent intent) {
- if (intent == null) {
- return;
- }
- final Bundle extras = intent.getExtras();
- if (extras == null) {
- return;
- }
- final INetworkStateObserver observer = INetworkStateObserver.Stub.asInterface(
- extras.getBinder(KEY_NETWORK_STATE_OBSERVER));
- if (observer != null) {
- try {
- if (!observer.isForeground()) {
- Log.e(TAG, "App didn't come to foreground");
- observer.onNetworkStateChecked(null);
- return;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error occurred while reading the proc state: " + e);
- }
- AsyncTask.execute(() -> {
- try {
- observer.onNetworkStateChecked(
- MyBroadcastReceiver.checkNetworkStatus(context));
- } catch (RemoteException e) {
- Log.e(TAG, "Error occurred while notifying the observer: " + e);
- }
- });
- }
- }
-}
diff --git a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
deleted file mode 100644
index 286cc2f..0000000
--- a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.net.hostside.app2;
-
-import static com.android.cts.net.hostside.app2.Common.ACTION_FINISH_ACTIVITY;
-import static com.android.cts.net.hostside.app2.Common.TAG;
-import static com.android.cts.net.hostside.app2.Common.TEST_PKG;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.cts.net.hostside.INetworkStateObserver;
-
-/**
- * Activity used to bring process to foreground.
- */
-public class MyActivity extends Activity {
-
- private BroadcastReceiver finishCommandReceiver = null;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.d(TAG, "MyActivity.onCreate()");
- Common.notifyNetworkStateObserver(this, getIntent());
- finishCommandReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "Finishing MyActivity");
- MyActivity.this.finish();
- }
- };
- registerReceiver(finishCommandReceiver, new IntentFilter(ACTION_FINISH_ACTIVITY));
- }
-
- @Override
- public void finish() {
- if (finishCommandReceiver != null) {
- unregisterReceiver(finishCommandReceiver);
- }
- super.finish();
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- Log.d(TAG, "MyActivity.onStart()");
- }
-
- @Override
- protected void onDestroy() {
- Log.d(TAG, "MyActivity.onDestroy()");
- super.onDestroy();
- }
-}
diff --git a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
deleted file mode 100644
index aa54075..0000000
--- a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside.app2;
-
-import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
-
-import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY;
-import static com.android.cts.net.hostside.app2.Common.ACTION_SHOW_TOAST;
-import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_BUNDLE;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_REMOTE_INPUT;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_BUNDLE;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_CONTENT;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_DELETE;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_FULL_SCREEN;
-import static com.android.cts.net.hostside.app2.Common.TAG;
-import static com.android.cts.net.hostside.app2.Common.getUid;
-
-import android.app.Notification;
-import android.app.Notification.Action;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.RemoteInput;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.Toast;
-
-import java.net.HttpURLConnection;
-import java.net.URL;
-
-/**
- * Receiver used to:
- * <ol>
- * <li>Count number of {@code RESTRICT_BACKGROUND_CHANGED} broadcasts received.
- * <li>Show a toast.
- * </ol>
- */
-public class MyBroadcastReceiver extends BroadcastReceiver {
-
- private static final int NETWORK_TIMEOUT_MS = 5 * 1000;
-
- private final String mName;
-
- public MyBroadcastReceiver() {
- this(MANIFEST_RECEIVER);
- }
-
- MyBroadcastReceiver(String name) {
- Log.d(TAG, "Constructing MyBroadcastReceiver named " + name);
- mName = name;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "onReceive() for " + mName + ": " + intent);
- final String action = intent.getAction();
- switch (action) {
- case ACTION_RESTRICT_BACKGROUND_CHANGED:
- increaseCounter(context, action);
- break;
- case ACTION_RECEIVER_READY:
- final String message = mName + " is ready to rumble";
- Log.d(TAG, message);
- setResultData(message);
- break;
- case ACTION_SHOW_TOAST:
- showToast(context);
- break;
- default:
- Log.e(TAG, "received unexpected action: " + action);
- }
- }
-
- @Override
- public String toString() {
- return "[MyBroadcastReceiver: mName=" + mName + "]";
- }
-
- private void increaseCounter(Context context, String action) {
- final SharedPreferences prefs = context.getApplicationContext()
- .getSharedPreferences(mName, Context.MODE_PRIVATE);
- final int value = prefs.getInt(action, 0) + 1;
- Log.d(TAG, "increaseCounter('" + action + "'): setting '" + mName + "' to " + value);
- prefs.edit().putInt(action, value).apply();
- }
-
- static int getCounter(Context context, String action, String receiverName) {
- final SharedPreferences prefs = context.getSharedPreferences(receiverName,
- Context.MODE_PRIVATE);
- final int value = prefs.getInt(action, 0);
- Log.d(TAG, "getCounter('" + action + "', '" + receiverName + "'): " + value);
- return value;
- }
-
- static String getRestrictBackgroundStatus(Context context) {
- final ConnectivityManager cm = (ConnectivityManager) context
- .getSystemService(Context.CONNECTIVITY_SERVICE);
- final int apiStatus = cm.getRestrictBackgroundStatus();
- Log.d(TAG, "getRestrictBackgroundStatus: returning " + apiStatus);
- return String.valueOf(apiStatus);
- }
-
- private static final String NETWORK_STATUS_TEMPLATE = "%s|%s|%s|%s|%s";
- /**
- * Checks whether the network is available and return a string which can then be send as a
- * result data for the ordered broadcast.
- *
- * <p>
- * The string has the following format:
- *
- * <p><pre><code>
- * NetinfoState|NetinfoDetailedState|RealConnectionCheck|RealConnectionCheckDetails|Netinfo
- * </code></pre>
- *
- * <p>Where:
- *
- * <ul>
- * <li>{@code NetinfoState}: enum value of {@link NetworkInfo.State}.
- * <li>{@code NetinfoDetailedState}: enum value of {@link NetworkInfo.DetailedState}.
- * <li>{@code RealConnectionCheck}: boolean value of a real connection check (i.e., an attempt
- * to access an external website.
- * <li>{@code RealConnectionCheckDetails}: if HTTP output core or exception string of the real
- * connection attempt
- * <li>{@code Netinfo}: string representation of the {@link NetworkInfo}.
- * </ul>
- *
- * For example, if the connection was established fine, the result would be something like:
- * <p><pre><code>
- * CONNECTED|CONNECTED|true|200|[type: WIFI[], state: CONNECTED/CONNECTED, reason: ...]
- * </code></pre>
- *
- */
- // TODO: now that it uses Binder, it counl return a Bundle with the data parts instead...
- static String checkNetworkStatus(Context context) {
- final ConnectivityManager cm =
- (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- // TODO: connect to a hostside server instead
- final String address = "http://example.com";
- final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
- Log.d(TAG, "Running checkNetworkStatus() on thread "
- + Thread.currentThread().getName() + " for UID " + getUid(context)
- + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address);
- boolean checkStatus = false;
- String checkDetails = "N/A";
- try {
- final URL url = new URL(address);
- final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setReadTimeout(NETWORK_TIMEOUT_MS);
- conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2);
- conn.setRequestMethod("GET");
- conn.setDoInput(true);
- conn.connect();
- final int response = conn.getResponseCode();
- checkStatus = true;
- checkDetails = "HTTP response for " + address + ": " + response;
- } catch (Exception e) {
- checkStatus = false;
- checkDetails = "Exception getting " + address + ": " + e;
- }
- Log.d(TAG, checkDetails);
- final String state, detailedState;
- if (networkInfo != null) {
- state = networkInfo.getState().name();
- detailedState = networkInfo.getDetailedState().name();
- } else {
- state = detailedState = "null";
- }
- final String status = String.format(NETWORK_STATUS_TEMPLATE, state, detailedState,
- Boolean.valueOf(checkStatus), checkDetails, networkInfo);
- Log.d(TAG, "Offering " + status);
- return status;
- }
-
- /**
- * Sends a system notification containing actions with pending intents to launch the app's
- * main activitiy or service.
- */
- static void sendNotification(Context context, String channelId, int notificationId,
- String notificationType ) {
- Log.d(TAG, "sendNotification: id=" + notificationId + ", type=" + notificationType);
- final Intent serviceIntent = new Intent(context, MyService.class);
- final PendingIntent pendingIntent = PendingIntent.getService(context, 0, serviceIntent,
- notificationId);
- final Bundle bundle = new Bundle();
- bundle.putCharSequence("parcelable", "I am not");
-
- final Notification.Builder builder = new Notification.Builder(context, channelId)
- .setSmallIcon(R.drawable.ic_notification);
-
- Action action = null;
- switch (notificationType) {
- case NOTIFICATION_TYPE_CONTENT:
- builder
- .setContentTitle("Light, Cameras...")
- .setContentIntent(pendingIntent);
- break;
- case NOTIFICATION_TYPE_DELETE:
- builder.setDeleteIntent(pendingIntent);
- break;
- case NOTIFICATION_TYPE_FULL_SCREEN:
- builder.setFullScreenIntent(pendingIntent, true);
- break;
- case NOTIFICATION_TYPE_BUNDLE:
- bundle.putParcelable("Magnum P.I. (Pending Intent)", pendingIntent);
- builder.setExtras(bundle);
- break;
- case NOTIFICATION_TYPE_ACTION:
- action = new Action.Builder(
- R.drawable.ic_notification, "ACTION", pendingIntent)
- .build();
- builder.addAction(action);
- break;
- case NOTIFICATION_TYPE_ACTION_BUNDLE:
- bundle.putParcelable("Magnum A.P.I. (Action Pending Intent)", pendingIntent);
- action = new Action.Builder(
- R.drawable.ic_notification, "ACTION WITH BUNDLE", null)
- .addExtras(bundle)
- .build();
- builder.addAction(action);
- break;
- case NOTIFICATION_TYPE_ACTION_REMOTE_INPUT:
- bundle.putParcelable("Magnum R.I. (Remote Input)", null);
- final RemoteInput remoteInput = new RemoteInput.Builder("RI")
- .addExtras(bundle)
- .build();
- action = new Action.Builder(
- R.drawable.ic_notification, "ACTION WITH REMOTE INPUT", pendingIntent)
- .addRemoteInput(remoteInput)
- .build();
- builder.addAction(action);
- break;
- default:
- Log.e(TAG, "Unknown notification type: " + notificationType);
- return;
- }
-
- final Notification notification = builder.build();
- ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE))
- .notify(notificationId, notification);
- }
-
- private void showToast(Context context) {
- Toast.makeText(context, "Toast from CTS test", Toast.LENGTH_SHORT).show();
- setResultData("Shown");
- }
-}
diff --git a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
deleted file mode 100644
index ff4ba65..0000000
--- a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.net.hostside.app2;
-
-import static com.android.cts.net.hostside.app2.Common.TAG;
-import static com.android.cts.net.hostside.app2.Common.TEST_PKG;
-
-import android.R;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.Service;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.cts.net.hostside.INetworkStateObserver;
-
-/**
- * Service used to change app state to FOREGROUND_SERVICE.
- */
-public class MyForegroundService extends Service {
- private static final String NOTIFICATION_CHANNEL_ID = "cts/MyForegroundService";
- private static final int FLAG_START_FOREGROUND = 1;
- private static final int FLAG_STOP_FOREGROUND = 2;
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- Log.v(TAG, "MyForegroundService.onStartCommand(): " + intent);
- NotificationManager notificationManager = getSystemService(NotificationManager.class);
- notificationManager.createNotificationChannel(new NotificationChannel(
- NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID,
- NotificationManager.IMPORTANCE_DEFAULT));
- switch (intent.getFlags()) {
- case FLAG_START_FOREGROUND:
- Log.d(TAG, "Starting foreground");
- startForeground(42, new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
- .setSmallIcon(R.drawable.ic_dialog_alert) // any icon is fine
- .build());
- Common.notifyNetworkStateObserver(this, intent);
- break;
- case FLAG_STOP_FOREGROUND:
- Log.d(TAG, "Stopping foreground");
- stopForeground(true);
- break;
- default:
- Log.wtf(TAG, "Invalid flag on intent " + intent);
- }
- return START_STICKY;
- }
-}
diff --git a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyService.java b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyService.java
deleted file mode 100644
index 590e17e..0000000
--- a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyService.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.net.hostside.app2;
-
-import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
-
-import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY;
-import static com.android.cts.net.hostside.app2.Common.DYNAMIC_RECEIVER;
-import static com.android.cts.net.hostside.app2.Common.TAG;
-
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.cts.net.hostside.IMyService;
-import com.android.cts.net.hostside.INetworkCallback;
-
-/**
- * Service used to dynamically register a broadcast receiver.
- */
-public class MyService extends Service {
- private static final String NOTIFICATION_CHANNEL_ID = "MyService";
-
- ConnectivityManager mCm;
-
- private MyBroadcastReceiver mReceiver;
- private ConnectivityManager.NetworkCallback mNetworkCallback;
-
- // TODO: move MyBroadcast static functions here - they were kept there to make git diff easier.
-
- private IMyService.Stub mBinder =
- new IMyService.Stub() {
-
- @Override
- public void registerBroadcastReceiver() {
- if (mReceiver != null) {
- Log.d(TAG, "receiver already registered: " + mReceiver);
- return;
- }
- final Context context = getApplicationContext();
- mReceiver = new MyBroadcastReceiver(DYNAMIC_RECEIVER);
- context.registerReceiver(mReceiver, new IntentFilter(ACTION_RECEIVER_READY));
- context.registerReceiver(mReceiver,
- new IntentFilter(ACTION_RESTRICT_BACKGROUND_CHANGED));
- Log.d(TAG, "receiver registered");
- }
-
- @Override
- public int getCounters(String receiverName, String action) {
- return MyBroadcastReceiver.getCounter(getApplicationContext(), action, receiverName);
- }
-
- @Override
- public String checkNetworkStatus() {
- return MyBroadcastReceiver.checkNetworkStatus(getApplicationContext());
- }
-
- @Override
- public String getRestrictBackgroundStatus() {
- return MyBroadcastReceiver.getRestrictBackgroundStatus(getApplicationContext());
- }
-
- @Override
- public void sendNotification(int notificationId, String notificationType) {
- MyBroadcastReceiver .sendNotification(getApplicationContext(), NOTIFICATION_CHANNEL_ID,
- notificationId, notificationType);
- }
-
- @Override
- public void registerNetworkCallback(INetworkCallback cb) {
- if (mNetworkCallback != null) {
- Log.d(TAG, "unregister previous network callback: " + mNetworkCallback);
- unregisterNetworkCallback();
- }
- Log.d(TAG, "registering network callback");
-
- mNetworkCallback = new ConnectivityManager.NetworkCallback() {
- @Override
- public void onBlockedStatusChanged(Network network, boolean blocked) {
- try {
- cb.onBlockedStatusChanged(network, blocked);
- } catch (RemoteException e) {
- Log.d(TAG, "Cannot send onBlockedStatusChanged: " + e);
- unregisterNetworkCallback();
- }
- }
-
- @Override
- public void onAvailable(Network network) {
- try {
- cb.onAvailable(network);
- } catch (RemoteException e) {
- Log.d(TAG, "Cannot send onAvailable: " + e);
- unregisterNetworkCallback();
- }
- }
-
- @Override
- public void onLost(Network network) {
- try {
- cb.onLost(network);
- } catch (RemoteException e) {
- Log.d(TAG, "Cannot send onLost: " + e);
- unregisterNetworkCallback();
- }
- }
-
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities cap) {
- try {
- cb.onCapabilitiesChanged(network, cap);
- } catch (RemoteException e) {
- Log.d(TAG, "Cannot send onCapabilitiesChanged: " + e);
- unregisterNetworkCallback();
- }
- }
- };
- mCm.registerNetworkCallback(makeWifiNetworkRequest(), mNetworkCallback);
- try {
- cb.asBinder().linkToDeath(() -> unregisterNetworkCallback(), 0);
- } catch (RemoteException e) {
- unregisterNetworkCallback();
- }
- }
-
- @Override
- public void unregisterNetworkCallback() {
- Log.d(TAG, "unregistering network callback");
- if (mNetworkCallback != null) {
- mCm.unregisterNetworkCallback(mNetworkCallback);
- mNetworkCallback = null;
- }
- }
- };
-
- private NetworkRequest makeWifiNetworkRequest() {
- return new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build();
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-
- @Override
- public void onCreate() {
- final Context context = getApplicationContext();
- ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE))
- .createNotificationChannel(new NotificationChannel(NOTIFICATION_CHANNEL_ID,
- NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT));
- mCm = (ConnectivityManager) getApplicationContext()
- .getSystemService(Context.CONNECTIVITY_SERVICE);
- }
-
- @Override
- public void onDestroy() {
- final Context context = getApplicationContext();
- ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE))
- .deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
- if (mReceiver != null) {
- Log.d(TAG, "onDestroy(): unregistering " + mReceiver);
- getApplicationContext().unregisterReceiver(mReceiver);
- }
-
- super.onDestroy();
- }
-}
diff --git a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/RemoteSocketFactoryService.java b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/RemoteSocketFactoryService.java
deleted file mode 100644
index b1b7d77..0000000
--- a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/RemoteSocketFactoryService.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net.hostside.app2;
-
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.util.Log;
-
-import com.android.cts.net.hostside.IRemoteSocketFactory;
-
-import java.net.Socket;
-
-
-public class RemoteSocketFactoryService extends Service {
-
- private static final String TAG = RemoteSocketFactoryService.class.getSimpleName();
-
- private IRemoteSocketFactory.Stub mBinder = new IRemoteSocketFactory.Stub() {
- @Override
- public ParcelFileDescriptor openSocketFd(String host, int port, int timeoutMs) {
- try {
- Socket s = new Socket(host, port);
- s.setSoTimeout(timeoutMs);
- return ParcelFileDescriptor.fromSocket(s);
- } catch (Exception e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- @Override
- public String getPackageName() {
- return RemoteSocketFactoryService.this.getPackageName();
- }
-
- @Override
- public int getUid() {
- return Process.myUid();
- }
- };
-
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-}
diff --git a/hostsidetests/net/certs/Android.bp b/hostsidetests/net/certs/Android.bp
deleted file mode 100644
index ab4cf34..0000000
--- a/hostsidetests/net/certs/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-android_app_certificate {
- name: "cts-net-app",
- certificate: "cts-net-app",
-}
diff --git a/hostsidetests/net/certs/README b/hostsidetests/net/certs/README
deleted file mode 100644
index b660a82..0000000
--- a/hostsidetests/net/certs/README
+++ /dev/null
@@ -1,2 +0,0 @@
-# Generated with:
-development/tools/make_key cts-net-app '/CN=cts-net-app'
diff --git a/hostsidetests/net/certs/cts-net-app.pk8 b/hostsidetests/net/certs/cts-net-app.pk8
deleted file mode 100644
index 1703e4e..0000000
--- a/hostsidetests/net/certs/cts-net-app.pk8
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/net/certs/cts-net-app.x509.pem b/hostsidetests/net/certs/cts-net-app.x509.pem
deleted file mode 100644
index a15ff48..0000000
--- a/hostsidetests/net/certs/cts-net-app.x509.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDAjCCAeqgAwIBAgIJAMhWwIIqr1r6MA0GCSqGSIb3DQEBCwUAMBYxFDASBgNV
-BAMMC2N0cy1uZXQtYXBwMB4XDTE4MDYyMDAyMjAwN1oXDTQ1MTEwNTAyMjAwN1ow
-FjEUMBIGA1UEAwwLY3RzLW5ldC1hcHAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQDefOayWQss1E+FQIONK6IhlXhe0BEyHshIrnPOOmuCPa/Svfbnmziy
-hr1KTjaQ3ET/mGShwlt6AUti7nKx9aB71IJp5mSBuwW62A8jvN3yNOo45YV8+n1o
-TrEoMWMf7hQmoOSqaSJ+VFuVms/kPSEh99okDgHCej6rsEkEcDoh6pJajQyUYDwR
-SNAF8SrqCDhqFbZW/LWedvuikCUlNtzuv7/GrcLcsiWEfHv7UOBKpMjLo9BhD1XF
-IefnxImcBQrQGMnE9TLixBiEeX5yauLgbZuxBqD/zsI2TH1FjxTeuJan83kLbqqH
-FgyvPaUjwckAdQPyom7ZUYFnBc0LQ9xzAgMBAAGjUzBRMB0GA1UdDgQWBBRZrBEw
-tAB2WNXj8dQ7ZOuJ34kY5DAfBgNVHSMEGDAWgBRZrBEwtAB2WNXj8dQ7ZOuJ34kY
-5DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDeI9AnLW6l/39y
-z96w/ldxZVFPzBRiFIsJsPHVyXlD5vUHZv/ju2jFn8TZSZR5TK0bzCEoVLp34Sho
-bbS0magP82yIvCRibyoyD+TDNnZkNJwjYnikE+/oyshTSQtpkn/rDA+0Y09BUC1E
-N2I6bV9pTXLFg7oah2FmqPRPzhgeYUKENgOQkrrjUCn6y0i/k374n7aftzdniSIz
-2kCRVEeN9gws6CnoMPx0vr32v/JVuPV6zfdJYadgj/eFRyTNE4msd9kE82Wc46eU
-YiI+LuXZ3ZMUNWGY7MK2pOUUS52JsBQ3K235dA5WaU4x8OBlY/WkNYX/eLbNs5jj
-FzLmhZZ1
------END CERTIFICATE-----
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkCallbackTests.java b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkCallbackTests.java
deleted file mode 100644
index 1312085..0000000
--- a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkCallbackTests.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.net;
-public class HostsideNetworkCallbackTests extends HostsideNetworkTestCase {
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- uninstallPackage(TEST_APP2_PKG, false);
- installPackage(TEST_APP2_APK);
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- uninstallPackage(TEST_APP2_PKG, true);
- }
-
- public void testOnBlockedStatusChanged_dataSaver() throws Exception {
- runDeviceTests(TEST_PKG,
- TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_dataSaver");
- }
-
- public void testOnBlockedStatusChanged_powerSaver() throws Exception {
- runDeviceTests(TEST_PKG,
- TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_powerSaver");
- }
-}
-
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
deleted file mode 100644
index ce20379..0000000
--- a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net;
-
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.ddmlib.Log;
-import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
-import com.android.ddmlib.testrunner.TestResult.TestStatus;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.result.CollectingTestListener;
-import com.android.tradefed.result.TestDescription;
-import com.android.tradefed.result.TestResult;
-import com.android.tradefed.result.TestRunResult;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
-
-import java.io.FileNotFoundException;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiReceiver,
- IBuildReceiver {
- protected static final boolean DEBUG = false;
- protected static final String TAG = "HostsideNetworkTests";
- protected static final String TEST_PKG = "com.android.cts.net.hostside";
- protected static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk";
- protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2";
- protected static final String TEST_APP2_APK = "CtsHostsideNetworkTestsApp2.apk";
-
- private IAbi mAbi;
- private IBuildInfo mCtsBuild;
-
- @Override
- public void setAbi(IAbi abi) {
- mAbi = abi;
- }
-
- @Override
- public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = buildInfo;
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- assertNotNull(mAbi);
- assertNotNull(mCtsBuild);
-
- uninstallPackage(TEST_PKG, false);
- installPackage(TEST_APK);
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
-
- uninstallPackage(TEST_PKG, true);
- }
-
- protected void installPackage(String apk) throws FileNotFoundException,
- DeviceNotAvailableException {
- CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
- assertNull(getDevice().installPackage(buildHelper.getTestFile(apk),
- false /* reinstall */, true /* grantPermissions */));
- }
-
- protected void uninstallPackage(String packageName, boolean shouldSucceed)
- throws DeviceNotAvailableException {
- final String result = getDevice().uninstallPackage(packageName);
- if (shouldSucceed) {
- assertNull("uninstallPackage(" + packageName + ") failed: " + result, result);
- }
- }
-
- protected void assertPackageUninstalled(String packageName) throws DeviceNotAvailableException,
- InterruptedException {
- final String command = "cmd package list packages " + packageName;
- final int max_tries = 5;
- for (int i = 1; i <= max_tries; i++) {
- final String result = runCommand(command);
- if (result.trim().isEmpty()) {
- return;
- }
- // 'list packages' filters by substring, so we need to iterate with the results
- // and check one by one, otherwise 'com.android.cts.net.hostside' could return
- // 'com.android.cts.net.hostside.app2'
- boolean found = false;
- for (String line : result.split("[\\r\\n]+")) {
- if (line.endsWith(packageName)) {
- found = true;
- break;
- }
- }
- if (!found) {
- return;
- }
- i++;
- Log.v(TAG, "Package " + packageName + " not uninstalled yet (" + result
- + "); sleeping 1s before polling again");
- Thread.sleep(1000);
- }
- fail("Package '" + packageName + "' not uinstalled after " + max_tries + " seconds");
- }
-
- protected void runDeviceTests(String packageName, String testClassName)
- throws DeviceNotAvailableException {
- runDeviceTests(packageName, testClassName, null);
- }
-
- protected void runDeviceTests(String packageName, String testClassName, String methodName)
- throws DeviceNotAvailableException {
- RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName,
- "androidx.test.runner.AndroidJUnitRunner", getDevice().getIDevice());
-
- if (testClassName != null) {
- if (methodName != null) {
- testRunner.setMethodName(testClassName, methodName);
- } else {
- testRunner.setClassName(testClassName);
- }
- }
-
- final CollectingTestListener listener = new CollectingTestListener();
- getDevice().runInstrumentationTests(testRunner, listener);
-
- final TestRunResult result = listener.getCurrentRunResults();
- if (result.isRunFailure()) {
- throw new AssertionError("Failed to successfully run device tests for "
- + result.getName() + ": " + result.getRunFailureMessage());
- }
-
- if (result.hasFailedTests()) {
- // build a meaningful error message
- StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n");
- for (Map.Entry<TestDescription, TestResult> resultEntry :
- result.getTestResults().entrySet()) {
- if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
- errorBuilder.append(resultEntry.getKey().toString());
- errorBuilder.append(":\n");
- errorBuilder.append(resultEntry.getValue().getStackTrace());
- }
- }
- throw new AssertionError(errorBuilder.toString());
- }
- }
-
- private static final Pattern UID_PATTERN =
- Pattern.compile(".*userId=([0-9]+)$", Pattern.MULTILINE);
-
- protected int getUid(String packageName) throws DeviceNotAvailableException {
- final String output = runCommand("dumpsys package " + packageName);
- final Matcher matcher = UID_PATTERN.matcher(output);
- while (matcher.find()) {
- final String match = matcher.group(1);
- return Integer.parseInt(match);
- }
- throw new RuntimeException("Did not find regexp '" + UID_PATTERN + "' on adb output\n"
- + output);
- }
-
- protected String runCommand(String command) throws DeviceNotAvailableException {
- Log.d(TAG, "Command: '" + command + "'");
- final String output = getDevice().executeShellCommand(command);
- if (DEBUG) Log.v(TAG, "Output: " + output.trim());
- return output;
- }
-}
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
deleted file mode 100644
index 4598c39..0000000
--- a/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net;
-
-import com.android.ddmlib.Log;
-import com.android.tradefed.device.DeviceNotAvailableException;
-
-public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestCase {
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- uninstallPackage(TEST_APP2_PKG, false);
- installPackage(TEST_APP2_APK);
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
-
- uninstallPackage(TEST_APP2_PKG, true);
- }
-
- /**************************
- * Data Saver Mode tests. *
- **************************/
-
- public void testDataSaverMode_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
- "testGetRestrictBackgroundStatus_disabled");
- }
-
- public void testDataSaverMode_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
- "testGetRestrictBackgroundStatus_whitelisted");
- }
-
- public void testDataSaverMode_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
- "testGetRestrictBackgroundStatus_enabled");
- }
-
- public void testDataSaverMode_blacklisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
- "testGetRestrictBackgroundStatus_blacklisted");
- }
-
- public void testDataSaverMode_reinstall() throws Exception {
- final int oldUid = getUid(TEST_APP2_PKG);
-
- // Make sure whitelist is revoked when package is removed
- addRestrictBackgroundWhitelist(oldUid);
-
- uninstallPackage(TEST_APP2_PKG, true);
- assertPackageUninstalled(TEST_APP2_PKG);
- assertRestrictBackgroundWhitelist(oldUid, false);
-
- installPackage(TEST_APP2_APK);
- final int newUid = getUid(TEST_APP2_PKG);
- assertRestrictBackgroundWhitelist(oldUid, false);
- assertRestrictBackgroundWhitelist(newUid, false);
- }
-
- public void testDataSaverMode_requiredWhitelistedPackages() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
- "testGetRestrictBackgroundStatus_requiredWhitelistedPackages");
- }
-
- public void testDataSaverMode_broadcastNotSentOnUnsupportedDevices() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
- "testBroadcastNotSentOnUnsupportedDevices");
- }
-
- /*****************************
- * Battery Saver Mode tests. *
- *****************************/
-
- public void testBatterySaverModeMetered_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest",
- "testBackgroundNetworkAccess_disabled");
- }
-
- public void testBatterySaverModeMetered_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest",
- "testBackgroundNetworkAccess_whitelisted");
- }
-
- public void testBatterySaverModeMetered_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest",
- "testBackgroundNetworkAccess_enabled");
- }
-
- public void testBatterySaverMode_reinstall() throws Exception {
- if (!isDozeModeEnabled()) {
- Log.w(TAG, "testBatterySaverMode_reinstall() skipped because device does not support "
- + "Doze Mode");
- return;
- }
-
- addPowerSaveModeWhitelist(TEST_APP2_PKG);
-
- uninstallPackage(TEST_APP2_PKG, true);
- assertPackageUninstalled(TEST_APP2_PKG);
- assertPowerSaveModeWhitelist(TEST_APP2_PKG, false);
-
- installPackage(TEST_APP2_APK);
- assertPowerSaveModeWhitelist(TEST_APP2_PKG, false);
- }
-
- public void testBatterySaverModeNonMetered_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest",
- "testBackgroundNetworkAccess_disabled");
- }
-
- public void testBatterySaverModeNonMetered_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest",
- "testBackgroundNetworkAccess_whitelisted");
- }
-
- public void testBatterySaverModeNonMetered_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest",
- "testBackgroundNetworkAccess_enabled");
- }
-
- /*******************
- * App idle tests. *
- *******************/
-
- public void testAppIdleMetered_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
- "testBackgroundNetworkAccess_disabled");
- }
-
- public void testAppIdleMetered_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
- "testBackgroundNetworkAccess_whitelisted");
- }
-
- public void testAppIdleMetered_tempWhitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
- "testBackgroundNetworkAccess_tempWhitelisted");
- }
-
- public void testAppIdleMetered_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
- "testBackgroundNetworkAccess_enabled");
- }
-
- public void testAppIdleMetered_idleWhitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
- "testAppIdleNetworkAccess_idleWhitelisted");
- }
-
- // TODO: currently power-save mode and idle uses the same whitelist, so this test would be
- // redundant (as it would be testing the same as testBatterySaverMode_reinstall())
- // public void testAppIdle_reinstall() throws Exception {
- // }
-
- public void testAppIdleNonMetered_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
- "testBackgroundNetworkAccess_disabled");
- }
-
- public void testAppIdleNonMetered_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
- "testBackgroundNetworkAccess_whitelisted");
- }
-
- public void testAppIdleNonMetered_tempWhitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
- "testBackgroundNetworkAccess_tempWhitelisted");
- }
-
- public void testAppIdleNonMetered_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
- "testBackgroundNetworkAccess_enabled");
- }
-
- public void testAppIdleNonMetered_idleWhitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
- "testAppIdleNetworkAccess_idleWhitelisted");
- }
-
- public void testAppIdleNonMetered_whenCharging() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
- "testAppIdleNetworkAccess_whenCharging");
- }
-
- public void testAppIdleMetered_whenCharging() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
- "testAppIdleNetworkAccess_whenCharging");
- }
-
- public void testAppIdle_toast() throws Exception {
- // Check that showing a toast doesn't bring an app out of standby
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
- "testAppIdle_toast");
- }
-
- /********************
- * Doze Mode tests. *
- ********************/
-
- public void testDozeModeMetered_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
- "testBackgroundNetworkAccess_disabled");
- }
-
- public void testDozeModeMetered_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
- "testBackgroundNetworkAccess_whitelisted");
- }
-
- public void testDozeModeMetered_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
- "testBackgroundNetworkAccess_enabled");
- }
-
- public void testDozeModeMetered_enabledButWhitelistedOnNotificationAction() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
- "testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction");
- }
-
- // TODO: currently power-save mode and idle uses the same whitelist, so this test would be
- // redundant (as it would be testing the same as testBatterySaverMode_reinstall())
- // public void testDozeMode_reinstall() throws Exception {
- // }
-
- public void testDozeModeNonMetered_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
- "testBackgroundNetworkAccess_disabled");
- }
-
- public void testDozeModeNonMetered_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
- "testBackgroundNetworkAccess_whitelisted");
- }
-
- public void testDozeModeNonMetered_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
- "testBackgroundNetworkAccess_enabled");
- }
-
- public void testDozeModeNonMetered_enabledButWhitelistedOnNotificationAction()
- throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
- "testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction");
- }
-
- /**********************
- * Mixed modes tests. *
- **********************/
-
- public void testDataAndBatterySaverModes_meteredNetwork() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
- "testDataAndBatterySaverModes_meteredNetwork");
- }
-
- public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
- "testDataAndBatterySaverModes_nonMeteredNetwork");
- }
-
- public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
- "testDozeAndBatterySaverMode_powerSaveWhitelists");
- }
-
- public void testDozeAndAppIdle_powerSaveWhitelists() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
- "testDozeAndAppIdle_powerSaveWhitelists");
- }
-
- public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
- "testAppIdleAndDoze_tempPowerSaveWhitelists");
- }
-
- public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
- "testAppIdleAndBatterySaver_tempPowerSaveWhitelists");
- }
-
- public void testDozeAndAppIdle_appIdleWhitelist() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
- "testDozeAndAppIdle_appIdleWhitelist");
- }
-
- public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
- "testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists");
- }
-
- public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
- "testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists");
- }
-
- /*******************
- * Helper methods. *
- *******************/
-
- private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception {
- final int max_tries = 5;
- boolean actual = false;
- for (int i = 1; i <= max_tries; i++) {
- final String output = runCommand("cmd netpolicy list restrict-background-whitelist ");
- actual = output.contains(Integer.toString(uid));
- if (expected == actual) {
- return;
- }
- Log.v(TAG, "whitelist check for uid " + uid + " doesn't match yet (expected "
- + expected + ", got " + actual + "); sleeping 1s before polling again");
- Thread.sleep(1000);
- }
- fail("whitelist check for uid " + uid + " failed: expected "
- + expected + ", got " + actual);
- }
-
- private void assertPowerSaveModeWhitelist(String packageName, boolean expected)
- throws Exception {
- // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
- // need to use netpolicy for whitelisting
- assertDelayedCommand("dumpsys deviceidle whitelist =" + packageName,
- Boolean.toString(expected));
- }
-
- /**
- * Asserts the result of a command, wait and re-running it a couple times if necessary.
- */
- private void assertDelayedCommand(String command, String expectedResult)
- throws InterruptedException, DeviceNotAvailableException {
- final int maxTries = 5;
- for (int i = 1; i <= maxTries; i++) {
- final String result = runCommand(command).trim();
- if (result.equals(expectedResult)) return;
- Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '"
- + expectedResult + "' on attempt #; sleeping 1s before polling again");
- Thread.sleep(1000);
- }
- fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries
- + " attempts");
- }
-
- protected void addRestrictBackgroundWhitelist(int uid) throws Exception {
- runCommand("cmd netpolicy add restrict-background-whitelist " + uid);
- assertRestrictBackgroundWhitelist(uid, true);
- }
-
- private void addPowerSaveModeWhitelist(String packageName) throws Exception {
- Log.i(TAG, "Adding package " + packageName + " to power-save-mode whitelist");
- // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
- // need to use netpolicy for whitelisting
- runCommand("dumpsys deviceidle whitelist +" + packageName);
- assertPowerSaveModeWhitelist(packageName, true); // Sanity check
- }
-
- protected boolean isDozeModeEnabled() throws Exception {
- final String result = runCommand("cmd deviceidle enabled deep").trim();
- return result.equals("1");
- }
-}
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideVpnTests.java b/hostsidetests/net/src/com/android/cts/net/HostsideVpnTests.java
deleted file mode 100644
index 62925ad..0000000
--- a/hostsidetests/net/src/com/android/cts/net/HostsideVpnTests.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.net;
-
-public class HostsideVpnTests extends HostsideNetworkTestCase {
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- uninstallPackage(TEST_APP2_PKG, false);
- installPackage(TEST_APP2_APK);
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
-
- uninstallPackage(TEST_APP2_PKG, true);
- }
-
- public void testDefault() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testDefault");
- }
-
- public void testAppAllowed() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testAppAllowed");
- }
-
- public void testAppDisallowed() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testAppDisallowed");
- }
-
- public void testGetConnectionOwnerUidSecurity() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testGetConnectionOwnerUidSecurity");
- }
-
- public void testSetProxy() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testSetProxy");
- }
-
- public void testSetProxyDisallowedApps() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testSetProxyDisallowedApps");
- }
-
- public void testNoProxy() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testNoProxy");
- }
-
- public void testBindToNetworkWithProxy() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testBindToNetworkWithProxy");
- }
-
- public void testVpnMeterednessWithNoUnderlyingNetwork() throws Exception {
- runDeviceTests(
- TEST_PKG, TEST_PKG + ".VpnTest", "testVpnMeterednessWithNoUnderlyingNetwork");
- }
-
- public void testVpnMeterednessWithNullUnderlyingNetwork() throws Exception {
- runDeviceTests(
- TEST_PKG, TEST_PKG + ".VpnTest", "testVpnMeterednessWithNullUnderlyingNetwork");
- }
-
- public void testVpnMeterednessWithNonNullUnderlyingNetwork() throws Exception {
- runDeviceTests(
- TEST_PKG, TEST_PKG + ".VpnTest", "testVpnMeterednessWithNonNullUnderlyingNetwork");
- }
-
- public void testAlwaysMeteredVpnWithNullUnderlyingNetwork() throws Exception {
- runDeviceTests(
- TEST_PKG, TEST_PKG + ".VpnTest", "testAlwaysMeteredVpnWithNullUnderlyingNetwork");
- }
-
- public void testAlwaysMeteredVpnWithNonNullUnderlyingNetwork() throws Exception {
- runDeviceTests(
- TEST_PKG,
- TEST_PKG + ".VpnTest",
- "testAlwaysMeteredVpnWithNonNullUnderlyingNetwork");
- }
-
- public void testB141603906() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testB141603906");
- }
-}
diff --git a/hostsidetests/net/src/com/android/cts/net/NetworkPolicyTestsPreparer.java b/hostsidetests/net/src/com/android/cts/net/NetworkPolicyTestsPreparer.java
deleted file mode 100644
index 23aca24..0000000
--- a/hostsidetests/net/src/com/android/cts/net/NetworkPolicyTestsPreparer.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.net;
-
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.invoker.TestInformation;
-import com.android.tradefed.log.LogUtil;
-import com.android.tradefed.targetprep.ITargetPreparer;
-
-public class NetworkPolicyTestsPreparer implements ITargetPreparer {
- private ITestDevice mDevice;
- private boolean mOriginalAirplaneModeEnabled;
- private String mOriginalAppStandbyEnabled;
- private String mOriginalBatteryStatsConstants;
- private final static String KEY_STABLE_CHARGING_DELAY_MS = "battery_charged_delay_ms";
- private final static int DESIRED_STABLE_CHARGING_DELAY_MS = 0;
-
- @Override
- public void setUp(TestInformation testInformation) throws DeviceNotAvailableException {
- mDevice = testInformation.getDevice();
- mOriginalAppStandbyEnabled = getAppStandbyEnabled();
- setAppStandbyEnabled("1");
- LogUtil.CLog.d("Original app_standby_enabled: " + mOriginalAppStandbyEnabled);
-
- mOriginalBatteryStatsConstants = getBatteryStatsConstants();
- setBatteryStatsConstants(
- KEY_STABLE_CHARGING_DELAY_MS + "=" + DESIRED_STABLE_CHARGING_DELAY_MS);
- LogUtil.CLog.d("Original battery_saver_constants: " + mOriginalBatteryStatsConstants);
-
- mOriginalAirplaneModeEnabled = getAirplaneModeEnabled();
- // Turn off airplane mode in case another test left the device in that state.
- setAirplaneModeEnabled(false);
- LogUtil.CLog.d("Original airplane mode state: " + mOriginalAirplaneModeEnabled);
- }
-
- @Override
- public void tearDown(TestInformation testInformation, Throwable e)
- throws DeviceNotAvailableException {
- setAirplaneModeEnabled(mOriginalAirplaneModeEnabled);
- setAppStandbyEnabled(mOriginalAppStandbyEnabled);
- setBatteryStatsConstants(mOriginalBatteryStatsConstants);
- }
-
- private void setAirplaneModeEnabled(boolean enable) throws DeviceNotAvailableException {
- executeCmd("cmd connectivity airplane-mode " + (enable ? "enable" : "disable"));
- }
-
- private boolean getAirplaneModeEnabled() throws DeviceNotAvailableException {
- return "enabled".equals(executeCmd("cmd connectivity airplane-mode").trim());
- }
-
- private void setAppStandbyEnabled(String appStandbyEnabled) throws DeviceNotAvailableException {
- if ("null".equals(appStandbyEnabled)) {
- executeCmd("settings delete global app_standby_enabled");
- } else {
- executeCmd("settings put global app_standby_enabled " + appStandbyEnabled);
- }
- }
-
- private String getAppStandbyEnabled() throws DeviceNotAvailableException {
- return executeCmd("settings get global app_standby_enabled").trim();
- }
-
- private void setBatteryStatsConstants(String batteryStatsConstants)
- throws DeviceNotAvailableException {
- executeCmd("settings put global battery_stats_constants \"" + batteryStatsConstants + "\"");
- }
-
- private String getBatteryStatsConstants() throws DeviceNotAvailableException {
- return executeCmd("settings get global battery_stats_constants");
- }
-
- private String executeCmd(String cmd) throws DeviceNotAvailableException {
- final String output = mDevice.executeShellCommand(cmd).trim();
- LogUtil.CLog.d("Output for '%s': %s", cmd, output);
- return output;
- }
-}
diff --git a/hostsidetests/net/src/com/android/cts/net/ProcNetTest.java b/hostsidetests/net/src/com/android/cts/net/ProcNetTest.java
deleted file mode 100644
index 19e61c6..0000000
--- a/hostsidetests/net/src/com/android/cts/net/ProcNetTest.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IBuildReceiver;
-import com.android.tradefed.testtype.IDeviceTest;
-
-import java.lang.Integer;
-import java.lang.String;
-import java.util.Arrays;
-import java.util.List;
-import java.util.ArrayList;
-
-/**
- * Host-side tests for values in /proc/net.
- *
- * These tests analyze /proc/net to verify that certain networking properties are correct.
- */
-public class ProcNetTest extends DeviceTestCase implements IBuildReceiver, IDeviceTest {
- private static final String SPI_TIMEOUT_SYSCTL = "/proc/sys/net/core/xfrm_acq_expires";
- private static final int MIN_ACQ_EXPIRES = 3600;
- // Global sysctls. Must be present and set to 1.
- private static final String[] GLOBAL_SYSCTLS = {
- "/proc/sys/net/ipv4/fwmark_reflect",
- "/proc/sys/net/ipv6/fwmark_reflect",
- "/proc/sys/net/ipv4/tcp_fwmark_accept",
- };
-
- // Per-interface IPv6 autoconf sysctls.
- private static final String IPV6_SYSCTL_DIR = "/proc/sys/net/ipv6/conf";
- private static final String AUTOCONF_SYSCTL = "accept_ra_rt_table";
-
- // Expected values for MIN|MAX_PLEN.
- private static final String ACCEPT_RA_RT_INFO_MIN_PLEN_STRING = "accept_ra_rt_info_min_plen";
- private static final int ACCEPT_RA_RT_INFO_MIN_PLEN_VALUE = 48;
- private static final String ACCEPT_RA_RT_INFO_MAX_PLEN_STRING = "accept_ra_rt_info_max_plen";
- private static final int ACCEPT_RA_RT_INFO_MAX_PLEN_VALUE = 64;
- // Expected values for RFC 7559 router soliciations.
- // Maximum number of router solicitations to send. -1 means no limit.
- private static final int IPV6_WIFI_ROUTER_SOLICITATIONS = -1;
- private ITestDevice mDevice;
- private IBuildInfo mBuild;
- private String[] mSysctlDirs;
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setBuild(IBuildInfo build) {
- mBuild = build;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setDevice(ITestDevice device) {
- super.setDevice(device);
- mDevice = device;
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mSysctlDirs = getSysctlDirs();
- }
-
- private String[] getSysctlDirs() throws Exception {
- String interfaceDirs[] = mDevice.executeAdbCommand("shell", "ls", "-1",
- IPV6_SYSCTL_DIR).split("\n");
- List<String> interfaceDirsList = new ArrayList<String>(Arrays.asList(interfaceDirs));
- interfaceDirsList.remove("all");
- interfaceDirsList.remove("lo");
- return interfaceDirsList.toArray(new String[interfaceDirsList.size()]);
- }
-
-
- protected void assertLess(String sysctl, int a, int b) {
- assertTrue("value of " + sysctl + ": expected < " + b + " but was: " + a, a < b);
- }
-
- protected void assertAtLeast(String sysctl, int a, int b) {
- assertTrue("value of " + sysctl + ": expected >= " + b + " but was: " + a, a >= b);
- }
-
- public int readIntFromPath(String path) throws Exception {
- String mode = mDevice.executeAdbCommand("shell", "stat", "-c", "%a", path).trim();
- String user = mDevice.executeAdbCommand("shell", "stat", "-c", "%u", path).trim();
- String group = mDevice.executeAdbCommand("shell", "stat", "-c", "%g", path).trim();
- assertEquals(mode, "644");
- assertEquals(user, "0");
- assertEquals(group, "0");
- return Integer.parseInt(mDevice.executeAdbCommand("shell", "cat", path).trim());
- }
-
- /**
- * Checks that SPI default timeouts are overridden, and set to a reasonable length of time
- */
- public void testMinAcqExpires() throws Exception {
- int value = readIntFromPath(SPI_TIMEOUT_SYSCTL);
- assertAtLeast(SPI_TIMEOUT_SYSCTL, value, MIN_ACQ_EXPIRES);
- }
-
- /**
- * Checks that the sysctls for multinetwork kernel features are present and
- * enabled.
- */
- public void testProcSysctls() throws Exception {
- for (String sysctl : GLOBAL_SYSCTLS) {
- int value = readIntFromPath(sysctl);
- assertEquals(sysctl, 1, value);
- }
-
- for (String interfaceDir : mSysctlDirs) {
- String path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + AUTOCONF_SYSCTL;
- int value = readIntFromPath(path);
- assertLess(path, value, 0);
- }
- }
-
- /**
- * Verify that accept_ra_rt_info_{min,max}_plen exists and is set to the expected value
- */
- public void testAcceptRaRtInfoMinMaxPlen() throws Exception {
- for (String interfaceDir : mSysctlDirs) {
- String path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "accept_ra_rt_info_min_plen";
- int value = readIntFromPath(path);
- assertEquals(path, value, ACCEPT_RA_RT_INFO_MIN_PLEN_VALUE);
- path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "accept_ra_rt_info_max_plen";
- value = readIntFromPath(path);
- assertEquals(path, value, ACCEPT_RA_RT_INFO_MAX_PLEN_VALUE);
- }
- }
-
- /**
- * Verify that router_solicitations exists and is set to the expected value
- * and verify that router_solicitation_max_interval exists and is in an acceptable interval.
- */
- public void testRouterSolicitations() throws Exception {
- for (String interfaceDir : mSysctlDirs) {
- String path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "router_solicitations";
- int value = readIntFromPath(path);
- assertEquals(IPV6_WIFI_ROUTER_SOLICITATIONS, value);
- path = IPV6_SYSCTL_DIR + "/" + interfaceDir + "/" + "router_solicitation_max_interval";
- int interval = readIntFromPath(path);
- final int lowerBoundSec = 15 * 60;
- final int upperBoundSec = 60 * 60;
- assertTrue(lowerBoundSec <= interval);
- assertTrue(interval <= upperBoundSec);
- }
- }
-}
diff --git a/hostsidetests/scopedstorage/Android.bp b/hostsidetests/scopedstorage/Android.bp
index 1a1a7f9..46ad4a4 100644
--- a/hostsidetests/scopedstorage/Android.bp
+++ b/hostsidetests/scopedstorage/Android.bp
@@ -72,6 +72,17 @@
}
java_test_host {
+ name: "CtsScopedStorageCoreHostTest",
+ srcs: [
+ "host/src/android/scopedstorage/cts/host/ScopedStorageCoreHostTest.java",
+ "host/src/android/scopedstorage/cts/host/BaseHostTestCase.java"
+ ],
+ libs: ["tradefed", "testng"],
+ test_suites: ["general-tests", "mts", "cts"],
+ test_config: "CoreTest.xml",
+}
+
+java_test_host {
name: "CtsScopedStorageHostTest",
srcs: ["host/src/**/*.java"],
libs: ["tradefed", "testng"],
@@ -86,3 +97,21 @@
test_suites: ["general-tests", "mts"],
test_config: "PublicVolumeTest.xml",
}
+
+android_test {
+ name: "CtsScopedStorageDeviceOnlyTest",
+ manifest: "device/AndroidManifest.xml",
+ test_config: "device/AndroidTest.xml",
+ srcs: ["device/**/*.java"],
+ static_libs: ["truth-prebuilt", "cts-scopedstorage-lib"],
+ compile_multilib: "both",
+ test_suites: ["device-tests", "mts", "cts"],
+ sdk_version: "test_current",
+ libs: ["android.test.base", "android.test.mock", "android.test.runner",],
+ java_resources: [
+ ":CtsScopedStorageTestAppA",
+ ":CtsScopedStorageTestAppB",
+ ":CtsScopedStorageTestAppC",
+ ":CtsScopedStorageTestAppCLegacy",
+ ]
+}
diff --git a/hostsidetests/scopedstorage/AndroidTest.xml b/hostsidetests/scopedstorage/AndroidTest.xml
index 43208ac..bbdf653 100644
--- a/hostsidetests/scopedstorage/AndroidTest.xml
+++ b/hostsidetests/scopedstorage/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="framework" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <!-- TODO(b/169101565): change to secondary_user when fixed -->
<option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/net/ipsec/AndroidTest.xml b/hostsidetests/scopedstorage/CoreTest.xml
similarity index 71%
rename from tests/tests/net/ipsec/AndroidTest.xml
rename to hostsidetests/scopedstorage/CoreTest.xml
index cd5c118..c251d10 100644
--- a/tests/tests/net/ipsec/AndroidTest.xml
+++ b/hostsidetests/scopedstorage/CoreTest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,22 +13,22 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Config for CTS IKE test cases">
+<configuration description="External storage host test for legacy and scoped storage">
<option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="networking" />
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <option name="not-shardable" value="true" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsIkeTestCases.apk" />
+ <option name="test-file-name" value="ScopedStorageTest.apk" />
+ <option name="test-file-name" value="LegacyStorageTest.apk" />
</target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.net.ipsec.cts" />
- <option name="hidden-api-checks" value="false" />
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="class" value="android.scopedstorage.cts.host.ScopedStorageCoreHostTest" />
</test>
+
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
- <option name="mainline-module-package-name" value="com.google.android.ipsec" />
+ <option name="mainline-module-package-name" value="com.google.android.mediaprovider" />
</object>
</configuration>
diff --git a/hostsidetests/scopedstorage/OWNERS b/hostsidetests/scopedstorage/OWNERS
index 9156e6b..5b16bdd 100644
--- a/hostsidetests/scopedstorage/OWNERS
+++ b/hostsidetests/scopedstorage/OWNERS
@@ -1,6 +1,7 @@
+corinac@google.com
jsharkey@android.com
maco@google.com
marcone@google.com
nandana@google.com
-shafik@google.com
zezeozue@google.com
+sahanas@google.com
diff --git a/hostsidetests/scopedstorage/PublicVolumeTest.xml b/hostsidetests/scopedstorage/PublicVolumeTest.xml
index 8bd3361..e70217f 100644
--- a/hostsidetests/scopedstorage/PublicVolumeTest.xml
+++ b/hostsidetests/scopedstorage/PublicVolumeTest.xml
@@ -22,6 +22,7 @@
</target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="android.scopedstorage.cts.host.PublicVolumeHostTest" />
+ <option name="class" value="android.scopedstorage.cts.host.PublicVolumeCoreHostTest" />
<option name="class" value="android.scopedstorage.cts.host.PublicVolumeLegacyHostTest" />
</test>
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppA.xml b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppA.xml
index 1747eb6..c99e95d 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppA.xml
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppA.xml
@@ -30,6 +30,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <provider
+ android:name="androidx.core.content.FileProvider"
+ android:authorities="android.scopedstorage.cts.testapp.A"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/file_paths" />
+ </provider>
</application>
</manifest>
-
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppB.xml b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppB.xml
index cf9a327..44db8fc 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppB.xml
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppB.xml
@@ -30,6 +30,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <provider
+ android:name="androidx.core.content.FileProvider"
+ android:authorities="android.scopedstorage.cts.testapp.B"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/file_paths" />
+ </provider>
</application>
</manifest>
-
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppC.xml b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppC.xml
index e6ee00a..b68e3a5 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppC.xml
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppC.xml
@@ -32,5 +32,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <provider
+ android:name="androidx.core.content.FileProvider"
+ android:authorities="android.scopedstorage.cts.testapp.C"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/file_paths" />
+ </provider>
</application>
</manifest>
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppCLegacy.xml b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppCLegacy.xml
index be1bd75..9f0d23b 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppCLegacy.xml
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppCLegacy.xml
@@ -30,5 +30,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <provider
+ android:name="androidx.core.content.FileProvider"
+ android:authorities="android.scopedstorage.cts.testapp.C"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/file_paths" />
+ </provider>
</application>
</manifest>
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java b/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
index 8dfe7b7..f71586f 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
@@ -17,11 +17,14 @@
import static android.scopedstorage.cts.lib.RedactionTestHelper.EXIF_METADATA_QUERY;
import static android.scopedstorage.cts.lib.RedactionTestHelper.getExifMetadata;
+import static android.scopedstorage.cts.lib.TestUtils.CAN_OPEN_FILE_FOR_READ_QUERY;
+import static android.scopedstorage.cts.lib.TestUtils.CAN_OPEN_FILE_FOR_WRITE_QUERY;
import static android.scopedstorage.cts.lib.TestUtils.CAN_READ_WRITE_QUERY;
-import static android.scopedstorage.cts.lib.TestUtils.CREATE_IMAGE_ENTRY_QUERY;
import static android.scopedstorage.cts.lib.TestUtils.CREATE_FILE_QUERY;
+import static android.scopedstorage.cts.lib.TestUtils.CREATE_IMAGE_ENTRY_QUERY;
import static android.scopedstorage.cts.lib.TestUtils.DELETE_FILE_QUERY;
import static android.scopedstorage.cts.lib.TestUtils.INTENT_EXCEPTION;
+import static android.scopedstorage.cts.lib.TestUtils.INTENT_EXTRA_CALLING_PKG;
import static android.scopedstorage.cts.lib.TestUtils.INTENT_EXTRA_PATH;
import static android.scopedstorage.cts.lib.TestUtils.OPEN_FILE_FOR_READ_QUERY;
import static android.scopedstorage.cts.lib.TestUtils.OPEN_FILE_FOR_WRITE_QUERY;
@@ -32,12 +35,14 @@
import static android.scopedstorage.cts.lib.TestUtils.getImageContentUri;
import android.app.Activity;
-import android.content.Intent;
import android.content.ContentValues;
+import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import androidx.annotation.Nullable;
+import androidx.core.content.FileProvider;
import java.io.File;
import java.io.IOException;
@@ -76,6 +81,8 @@
case CAN_READ_WRITE_QUERY:
case CREATE_FILE_QUERY:
case DELETE_FILE_QUERY:
+ case CAN_OPEN_FILE_FOR_READ_QUERY:
+ case CAN_OPEN_FILE_FOR_WRITE_QUERY:
case OPEN_FILE_FOR_READ_QUERY:
case OPEN_FILE_FOR_WRITE_QUERY:
case SETATTR_QUERY:
@@ -158,27 +165,47 @@
private Intent accessFile(String queryType) throws IOException {
if (getIntent().hasExtra(INTENT_EXTRA_PATH)) {
+ final String packageName = getIntent().getStringExtra(INTENT_EXTRA_CALLING_PKG);
final String filePath = getIntent().getStringExtra(INTENT_EXTRA_PATH);
final File file = new File(filePath);
- boolean returnStatus = false;
- if (queryType.equals(CAN_READ_WRITE_QUERY)) {
- returnStatus = file.exists() && file.canRead() && file.canWrite();
- } else if (queryType.equals(CREATE_FILE_QUERY)) {
- maybeCreateParentDirInAndroid(file);
- returnStatus = file.createNewFile();
- } else if (queryType.equals(DELETE_FILE_QUERY)) {
- returnStatus = file.delete();
- } else if (queryType.equals(OPEN_FILE_FOR_READ_QUERY)) {
- returnStatus = canOpen(file, false /* forWrite */);
- } else if (queryType.equals(OPEN_FILE_FOR_WRITE_QUERY)) {
- returnStatus = canOpen(file, true /* forWrite */);
- } else if (queryType.equals(SETATTR_QUERY)) {
- int newTimeMillis = 12345000;
- returnStatus = file.setLastModified(newTimeMillis);
- }
final Intent intent = new Intent(queryType);
- intent.putExtra(queryType, returnStatus);
- return intent;
+ switch (queryType) {
+ case CAN_READ_WRITE_QUERY:
+ intent.putExtra(queryType, file.exists() && file.canRead() && file.canWrite());
+ return intent;
+ case CREATE_FILE_QUERY:
+ maybeCreateParentDirInAndroid(file);
+ intent.putExtra(queryType, file.createNewFile());
+ return intent;
+ case DELETE_FILE_QUERY:
+ intent.putExtra(queryType, file.delete());
+ return intent;
+ case SETATTR_QUERY:
+ int newTimeMillis = 12345000;
+ intent.putExtra(queryType, file.setLastModified(newTimeMillis));
+ return intent;
+ case CAN_OPEN_FILE_FOR_READ_QUERY:
+ intent.putExtra(queryType, canOpen(file, false));
+ return intent;
+ case CAN_OPEN_FILE_FOR_WRITE_QUERY:
+ intent.putExtra(queryType, canOpen(file, true));
+ return intent;
+ case OPEN_FILE_FOR_READ_QUERY:
+ case OPEN_FILE_FOR_WRITE_QUERY:
+ Uri contentUri = FileProvider.getUriForFile(getApplicationContext(),
+ getApplicationContext().getPackageName(), file);
+ intent.putExtra(queryType, contentUri);
+ // Grant permission to the possible instrumenting test apps
+ if (packageName != null) {
+ getApplicationContext().grantUriPermission(packageName,
+ contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ }
+ return intent;
+ default:
+ throw new IllegalStateException(
+ "Unknown query received from launcher app: " + queryType);
+ }
} else {
throw new IllegalStateException(queryType + ": File path not set from launcher app");
}
diff --git a/hostsidetests/scopedstorage/TEST_MAPPING b/hostsidetests/scopedstorage/TEST_MAPPING
index 3f87702..fd79913 100644
--- a/hostsidetests/scopedstorage/TEST_MAPPING
+++ b/hostsidetests/scopedstorage/TEST_MAPPING
@@ -1,10 +1,16 @@
{
"presubmit": [
{
+ "name": "CtsScopedStorageCoreHostTest"
+ },
+ {
"name": "CtsScopedStorageHostTest"
},
{
"name": "CtsScopedStoragePublicVolumeHostTest"
+ },
+ {
+ "name": "CtsScopedStorageDeviceOnlyTest"
}
]
}
diff --git a/hostsidetests/scopedstorage/device/AndroidManifest.xml b/hostsidetests/scopedstorage/device/AndroidManifest.xml
new file mode 100644
index 0000000..0e91f9a
--- /dev/null
+++ b/hostsidetests/scopedstorage/device/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.scopedstorage.cts.device">
+<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+<application android:label="Scoped Storage Device Tests">
+ <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
+ android:exported="true" />
+ <uses-library android:name="android.test.runner" />
+</application>
+
+<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.scopedstorage.cts.device"
+ android:label="Device-only scoped storage tests" />
+
+</manifest>
diff --git a/tests/tests/net/api23Test/AndroidTest.xml b/hostsidetests/scopedstorage/device/AndroidTest.xml
similarity index 68%
copy from tests/tests/net/api23Test/AndroidTest.xml
copy to hostsidetests/scopedstorage/device/AndroidTest.xml
index 8042d50..e7d17cf 100644
--- a/tests/tests/net/api23Test/AndroidTest.xml
+++ b/hostsidetests/scopedstorage/device/AndroidTest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2019 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,20 +13,20 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Config for CTS Net API23 test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="networking" />
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <option name="not-shardable" value="true" />
+<configuration description="Runs device-only tests for scoped storage">
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsNetApi23TestCases.apk" />
- <option name="test-file-name" value="CtsNetTestAppForApi23.apk" />
+ <option name="test-file-name" value="CtsScopedStorageDeviceOnlyTest.apk" />
+ <option name="install-arg" value="-g" />
</target_preparer>
+
+ <option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
+ <option name="test-suite-tag" value="cts" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.net.cts.api23test" />
- <option name="hidden-api-checks" value="false" />
+ <option name="package" value="android.scopedstorage.cts.device" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
</test>
</configuration>
diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
new file mode 100644
index 0000000..1b11ea6
--- /dev/null
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
@@ -0,0 +1,2622 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.scopedstorage.cts.device;
+
+import static android.app.AppOpsManager.permissionToOp;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.SystemProperties.getBoolean;
+import static android.scopedstorage.cts.lib.RedactionTestHelper.assertExifMetadataMatch;
+import static android.scopedstorage.cts.lib.RedactionTestHelper.assertExifMetadataMismatch;
+import static android.scopedstorage.cts.lib.RedactionTestHelper.getExifMetadata;
+import static android.scopedstorage.cts.lib.RedactionTestHelper.getExifMetadataFromRawResource;
+import static android.scopedstorage.cts.lib.TestUtils.BYTES_DATA2;
+import static android.scopedstorage.cts.lib.TestUtils.STR_DATA2;
+import static android.scopedstorage.cts.lib.TestUtils.allowAppOpsToUid;
+import static android.scopedstorage.cts.lib.TestUtils.assertCanRenameDirectory;
+import static android.scopedstorage.cts.lib.TestUtils.assertCanRenameFile;
+import static android.scopedstorage.cts.lib.TestUtils.assertCantRenameDirectory;
+import static android.scopedstorage.cts.lib.TestUtils.assertCantRenameFile;
+import static android.scopedstorage.cts.lib.TestUtils.assertDirectoryContains;
+import static android.scopedstorage.cts.lib.TestUtils.assertFileContent;
+import static android.scopedstorage.cts.lib.TestUtils.assertThrows;
+import static android.scopedstorage.cts.lib.TestUtils.canOpen;
+import static android.scopedstorage.cts.lib.TestUtils.canOpenFileAs;
+import static android.scopedstorage.cts.lib.TestUtils.createFileAs;
+import static android.scopedstorage.cts.lib.TestUtils.deleteFileAs;
+import static android.scopedstorage.cts.lib.TestUtils.deleteFileAsNoThrow;
+import static android.scopedstorage.cts.lib.TestUtils.deleteRecursively;
+import static android.scopedstorage.cts.lib.TestUtils.deleteWithMediaProvider;
+import static android.scopedstorage.cts.lib.TestUtils.deleteWithMediaProviderNoThrow;
+import static android.scopedstorage.cts.lib.TestUtils.denyAppOpsToUid;
+import static android.scopedstorage.cts.lib.TestUtils.executeShellCommand;
+import static android.scopedstorage.cts.lib.TestUtils.getAlarmsDir;
+import static android.scopedstorage.cts.lib.TestUtils.getAndroidDataDir;
+import static android.scopedstorage.cts.lib.TestUtils.getAndroidMediaDir;
+import static android.scopedstorage.cts.lib.TestUtils.getAudiobooksDir;
+import static android.scopedstorage.cts.lib.TestUtils.getContentResolver;
+import static android.scopedstorage.cts.lib.TestUtils.getDcimDir;
+import static android.scopedstorage.cts.lib.TestUtils.getDocumentsDir;
+import static android.scopedstorage.cts.lib.TestUtils.getDownloadDir;
+import static android.scopedstorage.cts.lib.TestUtils.getExternalFilesDir;
+import static android.scopedstorage.cts.lib.TestUtils.getExternalMediaDir;
+import static android.scopedstorage.cts.lib.TestUtils.getExternalStorageDir;
+import static android.scopedstorage.cts.lib.TestUtils.getFileMimeTypeFromDatabase;
+import static android.scopedstorage.cts.lib.TestUtils.getFileOwnerPackageFromDatabase;
+import static android.scopedstorage.cts.lib.TestUtils.getFileRowIdFromDatabase;
+import static android.scopedstorage.cts.lib.TestUtils.getFileSizeFromDatabase;
+import static android.scopedstorage.cts.lib.TestUtils.getFileUri;
+import static android.scopedstorage.cts.lib.TestUtils.getMoviesDir;
+import static android.scopedstorage.cts.lib.TestUtils.getMusicDir;
+import static android.scopedstorage.cts.lib.TestUtils.getNotificationsDir;
+import static android.scopedstorage.cts.lib.TestUtils.getPicturesDir;
+import static android.scopedstorage.cts.lib.TestUtils.getPodcastsDir;
+import static android.scopedstorage.cts.lib.TestUtils.getRingtonesDir;
+import static android.scopedstorage.cts.lib.TestUtils.grantPermission;
+import static android.scopedstorage.cts.lib.TestUtils.installApp;
+import static android.scopedstorage.cts.lib.TestUtils.installAppWithStoragePermissions;
+import static android.scopedstorage.cts.lib.TestUtils.isAppInstalled;
+import static android.scopedstorage.cts.lib.TestUtils.listAs;
+import static android.scopedstorage.cts.lib.TestUtils.openWithMediaProvider;
+import static android.scopedstorage.cts.lib.TestUtils.pollForExternalStorageState;
+import static android.scopedstorage.cts.lib.TestUtils.queryFile;
+import static android.scopedstorage.cts.lib.TestUtils.queryFileExcludingPending;
+import static android.scopedstorage.cts.lib.TestUtils.queryImageFile;
+import static android.scopedstorage.cts.lib.TestUtils.queryVideoFile;
+import static android.scopedstorage.cts.lib.TestUtils.readExifMetadataFromTestApp;
+import static android.scopedstorage.cts.lib.TestUtils.revokePermission;
+import static android.scopedstorage.cts.lib.TestUtils.setAttrAs;
+import static android.scopedstorage.cts.lib.TestUtils.setupDefaultDirectories;
+import static android.scopedstorage.cts.lib.TestUtils.uninstallApp;
+import static android.scopedstorage.cts.lib.TestUtils.uninstallAppNoThrow;
+import static android.scopedstorage.cts.lib.TestUtils.updateDisplayNameWithMediaProvider;
+import static android.system.OsConstants.F_OK;
+import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_EXCL;
+import static android.system.OsConstants.O_RDWR;
+import static android.system.OsConstants.O_TRUNC;
+import static android.system.OsConstants.R_OK;
+import static android.system.OsConstants.S_IRWXU;
+import static android.system.OsConstants.W_OK;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.Manifest;
+import android.app.AppOpsManager;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.provider.MediaStore;
+import android.scopedstorage.cts.lib.TestUtils;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.cts.install.lib.TestApp;
+
+import com.google.common.io.Files;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Device-side test suite to verify scoped storage business logic.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ScopedStorageDeviceTest {
+ public static final String STR_DATA1 = "Just some random text";
+
+ public static final byte[] BYTES_DATA1 = STR_DATA1.getBytes();
+
+ static final String TAG = "ScopedStorageDeviceTest";
+ static final String THIS_PACKAGE_NAME = getContext().getPackageName();
+
+ /**
+ * To help avoid flaky tests, give ourselves a unique nonce to be used for
+ * all filesystem paths, so that we don't risk conflicting with previous
+ * test runs.
+ */
+ static final String NONCE = String.valueOf(System.nanoTime());
+
+ static final String TEST_DIRECTORY_NAME = "ScopedStorageDeviceTestDirectory" + NONCE;
+
+ static final String AUDIO_FILE_NAME = "ScopedStorageDeviceTest_file_" + NONCE + ".mp3";
+ static final String PLAYLIST_FILE_NAME = "ScopedStorageDeviceTest_file_" + NONCE + ".m3u";
+ static final String SUBTITLE_FILE_NAME = "ScopedStorageDeviceTest_file_" + NONCE + ".srt";
+ static final String VIDEO_FILE_NAME = "ScopedStorageDeviceTest_file_" + NONCE + ".mp4";
+ static final String IMAGE_FILE_NAME = "ScopedStorageDeviceTest_file_" + NONCE + ".jpg";
+ static final String NONMEDIA_FILE_NAME = "ScopedStorageDeviceTest_file_" + NONCE + ".pdf";
+
+ static final String FILE_CREATION_ERROR_MESSAGE = "No such file or directory";
+
+ // This app is installed with READ_EXTERNAL_STORAGE permission before tests are run
+ private static final TestApp APP_A_HAS_RES = new TestApp("TestAppA",
+ "android.scopedstorage.cts.testapp.A", 1, false, "CtsScopedStorageTestAppA.apk");
+ // This app is installed without any permissions before tests are run
+ private static final TestApp APP_B_NO_PERMS = new TestApp("TestAppB",
+ "android.scopedstorage.cts.testapp.B", 1, false, "CtsScopedStorageTestAppB.apk");
+ // This app is not installed at test startup - please install before using.
+ private static final TestApp APP_C = new TestApp("TestAppC",
+ "android.scopedstorage.cts.testapp.C", 1, false, "CtsScopedStorageTestAppC.apk");
+ // This app is not installed at test startup - please install before using.
+ private static final TestApp APP_C_LEGACY = new TestApp("TestAppCLegacy",
+ "android.scopedstorage.cts.testapp.C", 1, false, "CtsScopedStorageTestAppCLegacy.apk");
+ private static final String[] SYSTEM_GALERY_APPOPS = {
+ AppOpsManager.OPSTR_WRITE_MEDIA_IMAGES, AppOpsManager.OPSTR_WRITE_MEDIA_VIDEO};
+ private static final String OPSTR_MANAGE_EXTERNAL_STORAGE =
+ permissionToOp(Manifest.permission.MANAGE_EXTERNAL_STORAGE);
+
+ @BeforeClass
+ public static void verifyTestsWillRunOnPrimaryVolume() throws Exception {
+ TestUtils.resetDefaultExternalStorageVolume();
+ TestUtils.assertDefaultVolumeIsPrimary();
+ }
+
+ @BeforeClass
+ public static void createPublicVolume() throws Exception {
+ // Create a public volume. It's not used in this test right now, but it makes for a less
+ // flaky test to create here. ScopedStoragePublicVolumeDeviceTest will be folded into
+ // this test later, as a prametererized option, as tracked in b/159593019.
+ if (TestUtils.getCurrentPublicVolumeName() == null) {
+ TestUtils.createNewPublicVolume();
+ }
+ }
+
+ @BeforeClass
+ public static void installApps() throws Exception {
+ installAppWithStoragePermissions(APP_A_HAS_RES);
+ installApp(APP_B_NO_PERMS);
+ }
+
+ @Before
+ public void setup() throws Exception {
+ // skips all test cases if FUSE is not active.
+ assumeTrue(getBoolean("persist.sys.fuse", false));
+
+ if (!getContext().getPackageManager().isInstantApp()) {
+ pollForExternalStorageState();
+ getExternalFilesDir().mkdirs();
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ executeShellCommand("rm -r /sdcard/Android/data/com.android.shell");
+ }
+
+ @AfterClass
+ public static void uninstallApps() {
+ uninstallAppNoThrow(APP_B_NO_PERMS);
+ uninstallAppNoThrow(APP_A_HAS_RES);
+ }
+
+ @Before
+ public void setupExternalStorage() {
+ setupDefaultDirectories();
+ }
+
+ /**
+ * Test that we enforce certain media types can only be created in certain directories.
+ */
+ @Test
+ public void testTypePathConformity() throws Exception {
+ final File dcimDir = getDcimDir();
+ final File documentsDir = getDocumentsDir();
+ final File downloadDir = getDownloadDir();
+ final File moviesDir = getMoviesDir();
+ final File musicDir = getMusicDir();
+ final File picturesDir = getPicturesDir();
+ // Only audio files can be created in Music
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(musicDir, NONMEDIA_FILE_NAME).createNewFile();
+ });
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(musicDir, VIDEO_FILE_NAME).createNewFile();
+ });
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(musicDir, IMAGE_FILE_NAME).createNewFile();
+ });
+ // Only video files can be created in Movies
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(moviesDir, NONMEDIA_FILE_NAME).createNewFile();
+ });
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(moviesDir, AUDIO_FILE_NAME).createNewFile();
+ });
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(moviesDir, IMAGE_FILE_NAME).createNewFile();
+ });
+ // Only image and video files can be created in DCIM
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(dcimDir, NONMEDIA_FILE_NAME).createNewFile();
+ });
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(dcimDir, AUDIO_FILE_NAME).createNewFile();
+ });
+ // Only image and video files can be created in Pictures
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(picturesDir, NONMEDIA_FILE_NAME).createNewFile();
+ });
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(picturesDir, AUDIO_FILE_NAME).createNewFile();
+ });
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(picturesDir, PLAYLIST_FILE_NAME).createNewFile();
+ });
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(dcimDir, SUBTITLE_FILE_NAME).createNewFile();
+ });
+
+ assertCanCreateFile(new File(getAlarmsDir(), AUDIO_FILE_NAME));
+ assertCanCreateFile(new File(getAudiobooksDir(), AUDIO_FILE_NAME));
+ assertCanCreateFile(new File(dcimDir, IMAGE_FILE_NAME));
+ assertCanCreateFile(new File(dcimDir, VIDEO_FILE_NAME));
+ assertCanCreateFile(new File(documentsDir, AUDIO_FILE_NAME));
+ assertCanCreateFile(new File(documentsDir, IMAGE_FILE_NAME));
+ assertCanCreateFile(new File(documentsDir, NONMEDIA_FILE_NAME));
+ assertCanCreateFile(new File(documentsDir, PLAYLIST_FILE_NAME));
+ assertCanCreateFile(new File(documentsDir, SUBTITLE_FILE_NAME));
+ assertCanCreateFile(new File(documentsDir, VIDEO_FILE_NAME));
+ assertCanCreateFile(new File(downloadDir, AUDIO_FILE_NAME));
+ assertCanCreateFile(new File(downloadDir, IMAGE_FILE_NAME));
+ assertCanCreateFile(new File(downloadDir, NONMEDIA_FILE_NAME));
+ assertCanCreateFile(new File(downloadDir, PLAYLIST_FILE_NAME));
+ assertCanCreateFile(new File(downloadDir, SUBTITLE_FILE_NAME));
+ assertCanCreateFile(new File(downloadDir, VIDEO_FILE_NAME));
+ assertCanCreateFile(new File(moviesDir, VIDEO_FILE_NAME));
+ assertCanCreateFile(new File(moviesDir, SUBTITLE_FILE_NAME));
+ assertCanCreateFile(new File(musicDir, AUDIO_FILE_NAME));
+ assertCanCreateFile(new File(musicDir, PLAYLIST_FILE_NAME));
+ assertCanCreateFile(new File(getNotificationsDir(), AUDIO_FILE_NAME));
+ assertCanCreateFile(new File(picturesDir, IMAGE_FILE_NAME));
+ assertCanCreateFile(new File(picturesDir, VIDEO_FILE_NAME));
+ assertCanCreateFile(new File(getPodcastsDir(), AUDIO_FILE_NAME));
+ assertCanCreateFile(new File(getRingtonesDir(), AUDIO_FILE_NAME));
+
+ // No file whatsoever can be created in the top level directory
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(getExternalStorageDir(), NONMEDIA_FILE_NAME).createNewFile();
+ });
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(getExternalStorageDir(), AUDIO_FILE_NAME).createNewFile();
+ });
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(getExternalStorageDir(), IMAGE_FILE_NAME).createNewFile();
+ });
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ new File(getExternalStorageDir(), VIDEO_FILE_NAME).createNewFile();
+ });
+ }
+
+ /**
+ * Test that we can create a file in app's external files directory,
+ * and that we can write and read to/from the file.
+ */
+ @Test
+ public void testCreateFileInAppExternalDir() throws Exception {
+ final File file = new File(getExternalFilesDir(), "text.txt");
+ try {
+ assertThat(file.createNewFile()).isTrue();
+ assertThat(file.delete()).isTrue();
+ // Ensure the file is properly deleted and can be created again
+ assertThat(file.createNewFile()).isTrue();
+
+ // Write to file
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(BYTES_DATA1);
+ }
+
+ // Read the same data from file
+ assertFileContent(file, BYTES_DATA1);
+ } finally {
+ file.delete();
+ }
+ }
+
+ /**
+ * Test that we can't create a file in another app's external files directory,
+ * and that we'll get the same error regardless of whether the app exists or not.
+ */
+ @Test
+ public void testCreateFileInOtherAppExternalDir() throws Exception {
+ // Creating a file in a non existent package dir should return ENOENT, as expected
+ final File nonexistentPackageFileDir = new File(
+ getExternalFilesDir().getPath().replace(THIS_PACKAGE_NAME, "no.such.package"));
+ final File file1 = new File(nonexistentPackageFileDir, NONMEDIA_FILE_NAME);
+ assertThrows(
+ IOException.class, FILE_CREATION_ERROR_MESSAGE, () -> {
+ file1.createNewFile();
+ });
+
+ // Creating a file in an existent package dir should give the same error string to avoid
+ // leaking installed app names, and we know the following directory exists because shell
+ // mkdirs it in test setup
+ final File shellPackageFileDir = new File(
+ getExternalFilesDir().getPath().replace(THIS_PACKAGE_NAME, "com.android.shell"));
+ final File file2 = new File(shellPackageFileDir, NONMEDIA_FILE_NAME);
+ assertThrows(
+ IOException.class, FILE_CREATION_ERROR_MESSAGE, () -> {
+ file1.createNewFile();
+ });
+ }
+
+ /**
+ * Test that apps can't read/write files in another app's external files directory,
+ * and can do so in their own app's external file directory.
+ */
+ @Test
+ public void testReadWriteFilesInOtherAppExternalDir() throws Exception {
+ final File videoFile = new File(getExternalFilesDir(), VIDEO_FILE_NAME);
+
+ try {
+ // Create a file in app's external files directory
+ if (!videoFile.exists()) {
+ assertThat(videoFile.createNewFile()).isTrue();
+ }
+
+ // App A should not be able to read/write to other app's external files directory.
+ assertThat(canOpenFileAs(APP_A_HAS_RES, videoFile, false /* forWrite */)).isFalse();
+ assertThat(canOpenFileAs(APP_A_HAS_RES, videoFile, true /* forWrite */)).isFalse();
+ // App A should not be able to delete files in other app's external files
+ // directory.
+ assertThat(deleteFileAs(APP_A_HAS_RES, videoFile.getPath())).isFalse();
+
+ // Apps should have read/write access in their own app's external files directory.
+ assertThat(canOpen(videoFile, false /* forWrite */)).isTrue();
+ assertThat(canOpen(videoFile, true /* forWrite */)).isTrue();
+ // Apps should be able to delete files in their own app's external files directory.
+ assertThat(videoFile.delete()).isTrue();
+ } finally {
+ videoFile.delete();
+ }
+ }
+
+ /**
+ * Test that we can contribute media without any permissions.
+ */
+ @Test
+ public void testContributeMediaFile() throws Exception {
+ final File imageFile = new File(getDcimDir(), IMAGE_FILE_NAME);
+
+ try {
+ assertThat(imageFile.createNewFile()).isTrue();
+
+ // Ensure that the file was successfully added to the MediaProvider database
+ assertThat(getFileOwnerPackageFromDatabase(imageFile)).isEqualTo(THIS_PACKAGE_NAME);
+
+ // Try to write random data to the file
+ try (FileOutputStream fos = new FileOutputStream(imageFile)) {
+ fos.write(BYTES_DATA1);
+ fos.write(BYTES_DATA2);
+ }
+
+ final byte[] expected = (STR_DATA1 + STR_DATA2).getBytes();
+ assertFileContent(imageFile, expected);
+
+ // Closing the file after writing will not trigger a MediaScan. Call scanFile to update
+ // file's entry in MediaProvider's database.
+ assertThat(MediaStore.scanFile(getContentResolver(), imageFile)).isNotNull();
+
+ // Ensure that the scan was completed and the file's size was updated.
+ assertThat(getFileSizeFromDatabase(imageFile)).isEqualTo(
+ BYTES_DATA1.length + BYTES_DATA2.length);
+ } finally {
+ imageFile.delete();
+ }
+ // Ensure that delete makes a call to MediaProvider to remove the file from its database.
+ assertThat(getFileRowIdFromDatabase(imageFile)).isEqualTo(-1);
+ }
+
+ @Test
+ public void testCreateAndDeleteEmptyDir() throws Exception {
+ final File externalFilesDir = getExternalFilesDir();
+ // Remove directory in order to create it again
+ externalFilesDir.delete();
+
+ // Can create own external files dir
+ assertThat(externalFilesDir.mkdir()).isTrue();
+
+ final File dir1 = new File(externalFilesDir, "random_dir");
+ // Can create dirs inside it
+ assertThat(dir1.mkdir()).isTrue();
+
+ final File dir2 = new File(dir1, "random_dir_inside_random_dir");
+ // And create a dir inside the new dir
+ assertThat(dir2.mkdir()).isTrue();
+
+ // And can delete them all
+ assertThat(dir2.delete()).isTrue();
+ assertThat(dir1.delete()).isTrue();
+ assertThat(externalFilesDir.delete()).isTrue();
+
+ // Can't create external dir for other apps
+ final File nonexistentPackageFileDir = new File(
+ externalFilesDir.getPath().replace(THIS_PACKAGE_NAME, "no.such.package"));
+ final File shellPackageFileDir = new File(
+ externalFilesDir.getPath().replace(THIS_PACKAGE_NAME, "com.android.shell"));
+
+ assertThat(nonexistentPackageFileDir.mkdir()).isFalse();
+ assertThat(shellPackageFileDir.mkdir()).isFalse();
+ }
+
+ @Test
+ public void testCantAccessOtherAppsContents() throws Exception {
+ final File mediaFile = new File(getPicturesDir(), IMAGE_FILE_NAME);
+ final File nonMediaFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
+ try {
+ assertThat(createFileAs(APP_B_NO_PERMS, mediaFile.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, nonMediaFile.getPath())).isTrue();
+
+ // We can still see that the files exist
+ assertThat(mediaFile.exists()).isTrue();
+ assertThat(nonMediaFile.exists()).isTrue();
+
+ // But we can't access their content
+ assertThat(canOpen(mediaFile, /* forWrite */ false)).isFalse();
+ assertThat(canOpen(nonMediaFile, /* forWrite */ true)).isFalse();
+ assertThat(canOpen(mediaFile, /* forWrite */ false)).isFalse();
+ assertThat(canOpen(nonMediaFile, /* forWrite */ true)).isFalse();
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, nonMediaFile.getPath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, mediaFile.getPath());
+ }
+ }
+
+ @Test
+ public void testCantDeleteOtherAppsContents() throws Exception {
+ final File dirInDownload = new File(getDownloadDir(), TEST_DIRECTORY_NAME);
+ final File mediaFile = new File(dirInDownload, IMAGE_FILE_NAME);
+ final File nonMediaFile = new File(dirInDownload, NONMEDIA_FILE_NAME);
+ try {
+ assertThat(dirInDownload.mkdir()).isTrue();
+ // Have another app create a media file in the directory
+ assertThat(createFileAs(APP_B_NO_PERMS, mediaFile.getPath())).isTrue();
+
+ // Can't delete the directory since it contains another app's content
+ assertThat(dirInDownload.delete()).isFalse();
+ // Can't delete another app's content
+ assertThat(deleteRecursively(dirInDownload)).isFalse();
+
+ // Have another app create a non-media file in the directory
+ assertThat(createFileAs(APP_B_NO_PERMS, nonMediaFile.getPath())).isTrue();
+
+ // Can't delete the directory since it contains another app's content
+ assertThat(dirInDownload.delete()).isFalse();
+ // Can't delete another app's content
+ assertThat(deleteRecursively(dirInDownload)).isFalse();
+
+ // Delete only the media file and keep the non-media file
+ assertThat(deleteFileAs(APP_B_NO_PERMS, mediaFile.getPath())).isTrue();
+ // Directory now has only the non-media file contributed by another app, so we still
+ // can't delete it nor its content
+ assertThat(dirInDownload.delete()).isFalse();
+ assertThat(deleteRecursively(dirInDownload)).isFalse();
+
+ // Delete the last file belonging to another app
+ assertThat(deleteFileAs(APP_B_NO_PERMS, nonMediaFile.getPath())).isTrue();
+ // Create our own file
+ assertThat(nonMediaFile.createNewFile()).isTrue();
+
+ // Now that the directory only has content that was contributed by us, we can delete it
+ assertThat(deleteRecursively(dirInDownload)).isTrue();
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, nonMediaFile.getPath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, mediaFile.getPath());
+ // At this point, we're not sure who created this file, so we'll have both apps
+ // deleting it
+ mediaFile.delete();
+ dirInDownload.delete();
+ }
+ }
+
+ /**
+ * Test that deleting uri corresponding to a file which was already deleted via filePath
+ * doesn't result in a security exception.
+ */
+ @Test
+ public void testDeleteAlreadyUnlinkedFile() throws Exception {
+ final File nonMediaFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
+ try {
+ assertTrue(nonMediaFile.createNewFile());
+ final Uri uri = MediaStore.scanFile(getContentResolver(), nonMediaFile);
+ assertNotNull(uri);
+
+ // Delete the file via filePath
+ assertTrue(nonMediaFile.delete());
+
+ // If we delete nonMediaFile with ContentResolver#delete, it shouldn't result in a
+ // security exception.
+ assertThat(getContentResolver().delete(uri, Bundle.EMPTY)).isEqualTo(0);
+ } finally {
+ nonMediaFile.delete();
+ }
+ }
+
+ /**
+ * This test relies on the fact that {@link File#list} uses opendir internally, and that it
+ * returns {@code null} if opendir fails.
+ */
+ @Test
+ public void testOpendirRestrictions() throws Exception {
+ // Opening a non existent package directory should fail, as expected
+ final File nonexistentPackageFileDir = new File(
+ getExternalFilesDir().getPath().replace(THIS_PACKAGE_NAME, "no.such.package"));
+ assertThat(nonexistentPackageFileDir.list()).isNull();
+
+ // Opening another package's external directory should fail as well, even if it exists
+ final File shellPackageFileDir = new File(
+ getExternalFilesDir().getPath().replace(THIS_PACKAGE_NAME, "com.android.shell"));
+ assertThat(shellPackageFileDir.list()).isNull();
+
+ // We can open our own external files directory
+ final String[] filesList = getExternalFilesDir().list();
+ assertThat(filesList).isNotNull();
+
+ // We can open any public directory in external storage
+ assertThat(getDcimDir().list()).isNotNull();
+ assertThat(getDownloadDir().list()).isNotNull();
+ assertThat(getMoviesDir().list()).isNotNull();
+ assertThat(getMusicDir().list()).isNotNull();
+
+ // We can open the root directory of external storage
+ final String[] topLevelDirs = getExternalStorageDir().list();
+ assertThat(topLevelDirs).isNotNull();
+ // TODO(b/145287327): This check fails on a device with no visible files.
+ // This can be fixed if we display default directories.
+ // assertThat(topLevelDirs).isNotEmpty();
+ }
+
+ @Test
+ public void testLowLevelFileIO() throws Exception {
+ String filePath = new File(getDownloadDir(), NONMEDIA_FILE_NAME).toString();
+ try {
+ int createFlags = O_CREAT | O_RDWR;
+ int createExclFlags = createFlags | O_EXCL;
+
+ FileDescriptor fd = Os.open(filePath, createExclFlags, S_IRWXU);
+ Os.close(fd);
+ assertThrows(
+ ErrnoException.class, () -> {
+ Os.open(filePath, createExclFlags, S_IRWXU);
+ });
+
+ fd = Os.open(filePath, createFlags, S_IRWXU);
+ try {
+ assertThat(Os.write(fd,
+ ByteBuffer.wrap(BYTES_DATA1))).isEqualTo(BYTES_DATA1.length);
+ assertFileContent(fd, BYTES_DATA1);
+ } finally {
+ Os.close(fd);
+ }
+ // should just append the data
+ fd = Os.open(filePath, createFlags | O_APPEND, S_IRWXU);
+ try {
+ assertThat(Os.write(fd,
+ ByteBuffer.wrap(BYTES_DATA2))).isEqualTo(BYTES_DATA2.length);
+ final byte[] expected = (STR_DATA1 + STR_DATA2).getBytes();
+ assertFileContent(fd, expected);
+ } finally {
+ Os.close(fd);
+ }
+ // should overwrite everything
+ fd = Os.open(filePath, createFlags | O_TRUNC, S_IRWXU);
+ try {
+ final byte[] otherData = "this is different data".getBytes();
+ assertThat(Os.write(fd, ByteBuffer.wrap(otherData))).isEqualTo(otherData.length);
+ assertFileContent(fd, otherData);
+ } finally {
+ Os.close(fd);
+ }
+ } finally {
+ new File(filePath).delete();
+ }
+ }
+
+ /**
+ * Test that media files from other packages are only visible to apps with storage permission.
+ */
+ @Test
+ public void testListDirectoriesWithMediaFiles() throws Exception {
+ final File dcimDir = getDcimDir();
+ final File dir = new File(dcimDir, TEST_DIRECTORY_NAME);
+ final File videoFile = new File(dir, VIDEO_FILE_NAME);
+ final String videoFileName = videoFile.getName();
+ try {
+ if (!dir.exists()) {
+ assertThat(dir.mkdir()).isTrue();
+ }
+
+ assertThat(createFileAs(APP_B_NO_PERMS, videoFile.getPath())).isTrue();
+ // App B should see TEST_DIRECTORY in DCIM and new file in TEST_DIRECTORY.
+ assertThat(listAs(APP_B_NO_PERMS, dcimDir.getPath())).contains(TEST_DIRECTORY_NAME);
+ assertThat(listAs(APP_B_NO_PERMS, dir.getPath())).containsExactly(videoFileName);
+
+ // App A has storage permission, so should see TEST_DIRECTORY in DCIM and new file
+ // in TEST_DIRECTORY.
+ assertThat(listAs(APP_A_HAS_RES, dcimDir.getPath())).contains(TEST_DIRECTORY_NAME);
+ assertThat(listAs(APP_A_HAS_RES, dir.getPath())).containsExactly(videoFileName);
+
+ // We are an app without storage permission; should see TEST_DIRECTORY in DCIM and
+ // should not see new file in new TEST_DIRECTORY.
+ assertThat(dcimDir.list()).asList().contains(TEST_DIRECTORY_NAME);
+ assertThat(dir.list()).asList().doesNotContain(videoFileName);
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, videoFile.getPath());
+ dir.delete();
+ }
+ }
+
+ /**
+ * Test that app can't see non-media files created by other packages
+ */
+ @Test
+ public void testListDirectoriesWithNonMediaFiles() throws Exception {
+ final File downloadDir = getDownloadDir();
+ final File dir = new File(downloadDir, TEST_DIRECTORY_NAME);
+ final File pdfFile = new File(dir, NONMEDIA_FILE_NAME);
+ final String pdfFileName = pdfFile.getName();
+ try {
+ if (!dir.exists()) {
+ assertThat(dir.mkdir()).isTrue();
+ }
+
+ // Have App B create non media file in the new directory.
+ assertThat(createFileAs(APP_B_NO_PERMS, pdfFile.getPath())).isTrue();
+
+ // App B should see TEST_DIRECTORY in downloadDir and new non media file in
+ // TEST_DIRECTORY.
+ assertThat(listAs(APP_B_NO_PERMS, downloadDir.getPath())).contains(TEST_DIRECTORY_NAME);
+ assertThat(listAs(APP_B_NO_PERMS, dir.getPath())).containsExactly(pdfFileName);
+
+ // APP B with storage permission should see TEST_DIRECTORY in downloadDir
+ // and should not see non media file in TEST_DIRECTORY.
+ assertThat(listAs(APP_A_HAS_RES, downloadDir.getPath())).contains(TEST_DIRECTORY_NAME);
+ assertThat(listAs(APP_A_HAS_RES, dir.getPath())).doesNotContain(pdfFileName);
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, pdfFile.getPath());
+ dir.delete();
+ }
+ }
+
+ /**
+ * Test that app can only see its directory in Android/data.
+ */
+ @Test
+ public void testListFilesFromExternalFilesDirectory() throws Exception {
+ final String packageName = THIS_PACKAGE_NAME;
+ final File nonmediaFile = new File(getExternalFilesDir(), NONMEDIA_FILE_NAME);
+
+ try {
+ // Create a file in app's external files directory
+ if (!nonmediaFile.exists()) {
+ assertThat(nonmediaFile.createNewFile()).isTrue();
+ }
+ // App should see its directory and directories of shared packages. App should see all
+ // files and directories in its external directory.
+ assertDirectoryContains(nonmediaFile.getParentFile(), nonmediaFile);
+
+ // App A should not see other app's external files directory despite RES.
+ assertThrows(IOException.class,
+ () -> listAs(APP_A_HAS_RES, getAndroidDataDir().getPath()));
+ assertThrows(IOException.class,
+ () -> listAs(APP_A_HAS_RES, getExternalFilesDir().getPath()));
+ } finally {
+ nonmediaFile.delete();
+ }
+ }
+
+ /**
+ * Test that app can see files and directories in Android/media.
+ */
+ @Test
+ public void testListFilesFromExternalMediaDirectory() throws Exception {
+ final File videoFile = new File(getExternalMediaDir(), VIDEO_FILE_NAME);
+
+ try {
+ // Create a file in app's external media directory
+ if (!videoFile.exists()) {
+ assertThat(videoFile.createNewFile()).isTrue();
+ }
+
+ // App should see its directory and other app's external media directories with media
+ // files.
+ assertDirectoryContains(videoFile.getParentFile(), videoFile);
+
+ // App A with storage permission should see other app's external media directory.
+ // Apps with READ_EXTERNAL_STORAGE can list files in other app's external media
+ // directory.
+ assertThat(listAs(APP_A_HAS_RES, getAndroidMediaDir().getPath()))
+ .contains(THIS_PACKAGE_NAME);
+ assertThat(listAs(APP_A_HAS_RES, getExternalMediaDir().getPath()))
+ .containsExactly(videoFile.getName());
+ } finally {
+ videoFile.delete();
+ }
+ }
+
+ @Test
+ public void testMetaDataRedaction() throws Exception {
+ File jpgFile = new File(getPicturesDir(), "img_metadata.jpg");
+ try {
+ if (jpgFile.exists()) {
+ assertThat(jpgFile.delete()).isTrue();
+ }
+
+ HashMap<String, String> originalExif =
+ getExifMetadataFromRawResource(R.raw.img_with_metadata);
+
+ try (InputStream in =
+ getContext().getResources().openRawResource(R.raw.img_with_metadata);
+ OutputStream out = new FileOutputStream(jpgFile)) {
+ // Dump the image we have to external storage
+ FileUtils.copy(in, out);
+
+ HashMap<String, String> exif = getExifMetadata(jpgFile);
+ assertExifMetadataMatch(exif, originalExif);
+
+ HashMap<String, String> exifFromTestApp =
+ readExifMetadataFromTestApp(APP_A_HAS_RES, jpgFile.getPath());
+ // Other apps shouldn't have access to the same metadata without explicit permission
+ assertExifMetadataMismatch(exifFromTestApp, originalExif);
+
+ // TODO(b/146346138): Test that if we give APP_A write URI permission,
+ // it would be able to access the metadata.
+ } // Intentionally keep the original streams open during the test so bytes are more
+ // likely to be in the VFS cache from both file opens
+ } finally {
+ jpgFile.delete();
+ }
+ }
+
+ @Test
+ public void testOpenFilePathFirstWriteContentResolver() throws Exception {
+ String displayName = "open_file_path_write_content_resolver.jpg";
+ File file = new File(getDcimDir(), displayName);
+
+ try {
+ assertThat(file.createNewFile()).isTrue();
+
+ ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
+ ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
+
+ assertRWR(readPfd, writePfd);
+ assertUpperFsFd(writePfd); // With cache
+ } finally {
+ file.delete();
+ }
+ }
+
+ @Test
+ public void testOpenContentResolverFirstWriteContentResolver() throws Exception {
+ String displayName = "open_content_resolver_write_content_resolver.jpg";
+ File file = new File(getDcimDir(), displayName);
+
+ try {
+ assertThat(file.createNewFile()).isTrue();
+
+ ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
+ ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
+
+ assertRWR(readPfd, writePfd);
+ assertLowerFsFd(writePfd);
+ } finally {
+ file.delete();
+ }
+ }
+
+ @Test
+ public void testOpenFilePathFirstWriteFilePath() throws Exception {
+ String displayName = "open_file_path_write_file_path.jpg";
+ File file = new File(getDcimDir(), displayName);
+
+ try {
+ assertThat(file.createNewFile()).isTrue();
+
+ ParcelFileDescriptor writePfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
+ ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
+
+ assertRWR(readPfd, writePfd);
+ assertUpperFsFd(readPfd); // With cache
+ } finally {
+ file.delete();
+ }
+ }
+
+ @Test
+ public void testOpenContentResolverFirstWriteFilePath() throws Exception {
+ String displayName = "open_content_resolver_write_file_path.jpg";
+ File file = new File(getDcimDir(), displayName);
+
+ try {
+ assertThat(file.createNewFile()).isTrue();
+
+ ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
+ ParcelFileDescriptor writePfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
+
+ assertRWR(readPfd, writePfd);
+ assertLowerFsFd(readPfd);
+ } finally {
+ file.delete();
+ }
+ }
+
+ @Test
+ public void testOpenContentResolverWriteOnly() throws Exception {
+ String displayName = "open_content_resolver_write_only.jpg";
+ File file = new File(getDcimDir(), displayName);
+
+ try {
+ assertThat(file.createNewFile()).isTrue();
+
+ // We upgrade 'w' only to 'rw'
+ ParcelFileDescriptor writePfd = openWithMediaProvider(file, "w");
+ ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
+
+ assertRWR(readPfd, writePfd);
+ assertRWR(writePfd, readPfd); // Can read on 'w' only pfd
+ assertLowerFsFd(writePfd);
+ assertLowerFsFd(readPfd);
+ } finally {
+ file.delete();
+ }
+ }
+
+ @Test
+ public void testOpenContentResolverDup() throws Exception {
+ String displayName = "open_content_resolver_dup.jpg";
+ File file = new File(getDcimDir(), displayName);
+
+ try {
+ file.delete();
+ assertThat(file.createNewFile()).isTrue();
+
+ // Even if we close the original fd, since we have a dup open
+ // the FUSE IO should still bypass the cache
+ try (ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw")) {
+ try (ParcelFileDescriptor writePfdDup = writePfd.dup();
+ ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(
+ file, MODE_READ_WRITE)) {
+ writePfd.close();
+
+ assertRWR(readPfd, writePfdDup);
+ assertLowerFsFd(writePfdDup);
+ }
+ }
+ } finally {
+ file.delete();
+ }
+ }
+
+ @Test
+ public void testOpenContentResolverClose() throws Exception {
+ String displayName = "open_content_resolver_close.jpg";
+ File file = new File(getDcimDir(), displayName);
+
+ try {
+ byte[] readBuffer = new byte[10];
+ byte[] writeBuffer = new byte[10];
+ Arrays.fill(writeBuffer, (byte) 1);
+
+ assertThat(file.createNewFile()).isTrue();
+
+ // Lower fs open and write
+ ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
+ Os.pwrite(writePfd.getFileDescriptor(), writeBuffer, 0, 10, 0);
+
+ // Close so upper fs open will not use direct_io
+ writePfd.close();
+
+ // Upper fs open and read without direct_io
+ ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
+ Os.pread(readPfd.getFileDescriptor(), readBuffer, 0, 10, 0);
+
+ // Last write on lower fs is visible via upper fs
+ assertThat(readBuffer).isEqualTo(writeBuffer);
+ assertThat(readPfd.getStatSize()).isEqualTo(writeBuffer.length);
+ } finally {
+ file.delete();
+ }
+ }
+
+ @Test
+ public void testContentResolverDelete() throws Exception {
+ String displayName = "content_resolver_delete.jpg";
+ File file = new File(getDcimDir(), displayName);
+
+ try {
+ assertThat(file.createNewFile()).isTrue();
+
+ deleteWithMediaProvider(file);
+
+ assertThat(file.exists()).isFalse();
+ assertThat(file.createNewFile()).isTrue();
+ } finally {
+ file.delete();
+ }
+ }
+
+ @Test
+ public void testContentResolverUpdate() throws Exception {
+ String oldDisplayName = "content_resolver_update_old.jpg";
+ String newDisplayName = "content_resolver_update_new.jpg";
+ File oldFile = new File(getDcimDir(), oldDisplayName);
+ File newFile = new File(getDcimDir(), newDisplayName);
+
+ try {
+ assertThat(oldFile.createNewFile()).isTrue();
+ // Publish the pending oldFile before updating with MediaProvider. Not publishing the
+ // file will make MP consider pending from FUSE as explicit IS_PENDING
+ final Uri uri = MediaStore.scanFile(getContentResolver(), oldFile);
+ assertNotNull(uri);
+
+ updateDisplayNameWithMediaProvider(uri,
+ Environment.DIRECTORY_DCIM, oldDisplayName, newDisplayName);
+
+ assertThat(oldFile.exists()).isFalse();
+ assertThat(oldFile.createNewFile()).isTrue();
+ assertThat(newFile.exists()).isTrue();
+ assertThat(newFile.createNewFile()).isFalse();
+ } finally {
+ oldFile.delete();
+ newFile.delete();
+ }
+ }
+
+ @Test
+ public void testCreateLowerCaseDeleteUpperCase() throws Exception {
+ File upperCase = new File(getDownloadDir(), "CREATE_LOWER_DELETE_UPPER");
+ File lowerCase = new File(getDownloadDir(), "create_lower_delete_upper");
+
+ createDeleteCreate(lowerCase, upperCase);
+ }
+
+ @Test
+ public void testCreateUpperCaseDeleteLowerCase() throws Exception {
+ File upperCase = new File(getDownloadDir(), "CREATE_UPPER_DELETE_LOWER");
+ File lowerCase = new File(getDownloadDir(), "create_upper_delete_lower");
+
+ createDeleteCreate(upperCase, lowerCase);
+ }
+
+ @Test
+ public void testCreateMixedCaseDeleteDifferentMixedCase() throws Exception {
+ File mixedCase1 = new File(getDownloadDir(), "CrEaTe_MiXeD_dElEtE_mIxEd");
+ File mixedCase2 = new File(getDownloadDir(), "cReAtE_mIxEd_DeLeTe_MiXeD");
+
+ createDeleteCreate(mixedCase1, mixedCase2);
+ }
+
+ @Test
+ public void testAndroidDataObbDoesNotForgetMount() throws Exception {
+ File dataDir = getContext().getExternalFilesDir(null);
+ File upperCaseDataDir = new File(dataDir.getPath().replace("Android/data", "ANDROID/DATA"));
+
+ File obbDir = getContext().getObbDir();
+ File upperCaseObbDir = new File(obbDir.getPath().replace("Android/obb", "ANDROID/OBB"));
+
+
+ StructStat beforeDataStruct = Os.stat(dataDir.getPath());
+ StructStat beforeObbStruct = Os.stat(obbDir.getPath());
+
+ assertThat(dataDir.exists()).isTrue();
+ assertThat(upperCaseDataDir.exists()).isTrue();
+ assertThat(obbDir.exists()).isTrue();
+ assertThat(upperCaseObbDir.exists()).isTrue();
+
+ StructStat afterDataStruct = Os.stat(upperCaseDataDir.getPath());
+ StructStat afterObbStruct = Os.stat(upperCaseObbDir.getPath());
+
+ assertThat(beforeDataStruct.st_dev).isEqualTo(afterDataStruct.st_dev);
+ assertThat(beforeObbStruct.st_dev).isEqualTo(afterObbStruct.st_dev);
+ }
+
+ @Test
+ public void testCacheConsistencyForCaseInsensitivity() throws Exception {
+ File upperCaseFile = new File(getDownloadDir(), "CACHE_CONSISTENCY_FOR_CASE_INSENSITIVITY");
+ File lowerCaseFile = new File(getDownloadDir(), "cache_consistency_for_case_insensitivity");
+
+ try {
+ ParcelFileDescriptor upperCasePfd =
+ ParcelFileDescriptor.open(upperCaseFile, MODE_READ_WRITE | MODE_CREATE);
+ ParcelFileDescriptor lowerCasePfd =
+ ParcelFileDescriptor.open(lowerCaseFile, MODE_READ_WRITE | MODE_CREATE);
+
+ assertRWR(upperCasePfd, lowerCasePfd);
+ assertRWR(lowerCasePfd, upperCasePfd);
+ } finally {
+ upperCaseFile.delete();
+ lowerCaseFile.delete();
+ }
+ }
+
+ private void createDeleteCreate(File create, File delete) throws Exception {
+ try {
+ assertThat(create.createNewFile()).isTrue();
+ Thread.sleep(5);
+
+ assertThat(delete.delete()).isTrue();
+ Thread.sleep(5);
+
+ assertThat(create.createNewFile()).isTrue();
+ Thread.sleep(5);
+ } finally {
+ create.delete();
+ delete.delete();
+ }
+ }
+
+ @Test
+ public void testReadStorageInvalidation() throws Exception {
+ testAppOpInvalidation(APP_B_NO_PERMS, new File(getDcimDir(), "read_storage.jpg"),
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE, /* forWrite */ false);
+ }
+
+ @Test
+ public void testWriteStorageInvalidation() throws Exception {
+ testAppOpInvalidation(APP_C_LEGACY, new File(getDcimDir(), "write_storage.jpg"),
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ AppOpsManager.OPSTR_WRITE_EXTERNAL_STORAGE, /* forWrite */ true);
+ }
+
+ @Test
+ public void testManageStorageInvalidation() throws Exception {
+ testAppOpInvalidation(APP_C, new File(getDownloadDir(), "manage_storage.pdf"),
+ /* permission */ null, OPSTR_MANAGE_EXTERNAL_STORAGE, /* forWrite */ true);
+ }
+
+ @Test
+ public void testWriteImagesInvalidation() throws Exception {
+ testAppOpInvalidation(APP_B_NO_PERMS, new File(getDcimDir(), "write_images.jpg"),
+ /* permission */ null, AppOpsManager.OPSTR_WRITE_MEDIA_IMAGES, /* forWrite */ true);
+ }
+
+ @Test
+ public void testWriteVideoInvalidation() throws Exception {
+ testAppOpInvalidation(APP_B_NO_PERMS, new File(getDcimDir(), "write_video.mp4"),
+ /* permission */ null, AppOpsManager.OPSTR_WRITE_MEDIA_VIDEO, /* forWrite */ true);
+ }
+
+ @Test
+ public void testAccessMediaLocationInvalidation() throws Exception {
+ File imgFile = new File(getDcimDir(), "access_media_location.jpg");
+
+ try {
+ // Setup image with sensitive data on external storage
+ HashMap<String, String> originalExif =
+ getExifMetadataFromRawResource(R.raw.img_with_metadata);
+ try (InputStream in =
+ getContext().getResources().openRawResource(R.raw.img_with_metadata);
+ OutputStream out = new FileOutputStream(imgFile)) {
+ // Dump the image we have to external storage
+ FileUtils.copy(in, out);
+ }
+ HashMap<String, String> exif = getExifMetadata(imgFile);
+ assertExifMetadataMatch(exif, originalExif);
+
+ // Install test app
+ installAppWithStoragePermissions(APP_C);
+
+ // Grant A_M_L and verify access to sensitive data
+ grantPermission(APP_C.getPackageName(), Manifest.permission.ACCESS_MEDIA_LOCATION);
+ HashMap<String, String> exifFromTestApp =
+ readExifMetadataFromTestApp(APP_C, imgFile.getPath());
+ assertExifMetadataMatch(exifFromTestApp, originalExif);
+
+ // Revoke A_M_L and verify sensitive data redaction
+ revokePermission(
+ APP_C.getPackageName(), Manifest.permission.ACCESS_MEDIA_LOCATION);
+ exifFromTestApp = readExifMetadataFromTestApp(APP_C, imgFile.getPath());
+ assertExifMetadataMismatch(exifFromTestApp, originalExif);
+
+ // Re-grant A_M_L and verify access to sensitive data
+ grantPermission(APP_C.getPackageName(), Manifest.permission.ACCESS_MEDIA_LOCATION);
+ exifFromTestApp = readExifMetadataFromTestApp(APP_C, imgFile.getPath());
+ assertExifMetadataMatch(exifFromTestApp, originalExif);
+ } finally {
+ imgFile.delete();
+ uninstallAppNoThrow(APP_C);
+ }
+ }
+
+ @Test
+ public void testAppUpdateInvalidation() throws Exception {
+ File file = new File(getDcimDir(), "app_update.jpg");
+ try {
+ assertThat(file.createNewFile()).isTrue();
+
+ // Install legacy
+ installAppWithStoragePermissions(APP_C_LEGACY);
+ grantPermission(APP_C_LEGACY.getPackageName(),
+ Manifest.permission.WRITE_EXTERNAL_STORAGE); // Grants write access for legacy
+ // Legacy app can read and write media files contributed by others
+ assertThat(canOpenFileAs(APP_C_LEGACY, file, /* forWrite */ false)).isTrue();
+ assertThat(canOpenFileAs(APP_C_LEGACY, file, /* forWrite */ true)).isTrue();
+
+ // Update to non-legacy
+ installAppWithStoragePermissions(APP_C);
+ grantPermission(APP_C_LEGACY.getPackageName(),
+ Manifest.permission.WRITE_EXTERNAL_STORAGE); // No effect for non-legacy
+ // Non-legacy app can read media files contributed by others
+ assertThat(canOpenFileAs(APP_C, file, /* forWrite */ false)).isTrue();
+ // But cannot write
+ assertThat(canOpenFileAs(APP_C, file, /* forWrite */ true)).isFalse();
+ } finally {
+ file.delete();
+ uninstallAppNoThrow(APP_C);
+ }
+ }
+
+ @Test
+ public void testAppReinstallInvalidation() throws Exception {
+ File file = new File(getDcimDir(), "app_reinstall.jpg");
+
+ try {
+ assertThat(file.createNewFile()).isTrue();
+
+ // Install
+ installAppWithStoragePermissions(APP_C);
+ assertThat(canOpenFileAs(APP_C, file, /* forWrite */ false)).isTrue();
+
+ // Re-install
+ uninstallAppNoThrow(APP_C);
+ installApp(APP_C);
+ assertThat(canOpenFileAs(APP_C, file, /* forWrite */ false)).isFalse();
+ } finally {
+ file.delete();
+ uninstallAppNoThrow(APP_C);
+ }
+ }
+
+ private void testAppOpInvalidation(TestApp app, File file, @Nullable String permission,
+ String opstr, boolean forWrite) throws Exception {
+ boolean alreadyInstalled = true;
+ try {
+ if (!isAppInstalled(app)) {
+ alreadyInstalled = false;
+ installApp(app);
+ }
+ assertThat(file.createNewFile()).isTrue();
+ assertAppOpInvalidation(app, file, permission, opstr, forWrite);
+ } finally {
+ file.delete();
+ if (!alreadyInstalled) {
+ // only uninstall if we installed this app here
+ uninstallApp(app);
+ }
+ }
+ }
+
+ /** If {@code permission} is null, appops are flipped, otherwise permissions are flipped */
+ private void assertAppOpInvalidation(TestApp app, File file, @Nullable String permission,
+ String opstr, boolean forWrite) throws Exception {
+ String packageName = app.getPackageName();
+ int uid = getContext().getPackageManager().getPackageUid(packageName, 0);
+
+ // Deny
+ if (permission != null) {
+ revokePermission(packageName, permission);
+ } else {
+ denyAppOpsToUid(uid, opstr);
+ }
+ assertThat(canOpenFileAs(app, file, forWrite)).isFalse();
+
+ // Grant
+ if (permission != null) {
+ grantPermission(packageName, permission);
+ } else {
+ allowAppOpsToUid(uid, opstr);
+ }
+ assertThat(canOpenFileAs(app, file, forWrite)).isTrue();
+
+ // Deny
+ if (permission != null) {
+ revokePermission(packageName, permission);
+ } else {
+ denyAppOpsToUid(uid, opstr);
+ }
+ assertThat(canOpenFileAs(app, file, forWrite)).isFalse();
+ }
+
+ @Test
+ public void testSystemGalleryAppHasFullAccessToImages() throws Exception {
+ final File otherAppImageFile = new File(getDcimDir(), "other_" + IMAGE_FILE_NAME);
+ final File topLevelImageFile = new File(getExternalStorageDir(), IMAGE_FILE_NAME);
+ final File imageInAnObviouslyWrongPlace = new File(getMusicDir(), IMAGE_FILE_NAME);
+
+ try {
+ allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+
+ // Have another app create an image file
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppImageFile.getPath())).isTrue();
+ assertThat(otherAppImageFile.exists()).isTrue();
+
+ // Assert we can write to the file
+ try (FileOutputStream fos = new FileOutputStream(otherAppImageFile)) {
+ fos.write(BYTES_DATA1);
+ }
+
+ // Assert we can read from the file
+ assertFileContent(otherAppImageFile, BYTES_DATA1);
+
+ // Assert we can delete the file
+ assertThat(otherAppImageFile.delete()).isTrue();
+ assertThat(otherAppImageFile.exists()).isFalse();
+
+ // Can create an image anywhere
+ assertCanCreateFile(topLevelImageFile);
+ assertCanCreateFile(imageInAnObviouslyWrongPlace);
+
+ // Put the file back in its place and let APP B delete it
+ assertThat(otherAppImageFile.createNewFile()).isTrue();
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppImageFile.getAbsolutePath());
+ otherAppImageFile.delete();
+ denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+ }
+ }
+
+ @Test
+ public void testSystemGalleryAppHasNoFullAccessToAudio() throws Exception {
+ final File otherAppAudioFile = new File(getMusicDir(), "other_" + AUDIO_FILE_NAME);
+ final File topLevelAudioFile = new File(getExternalStorageDir(), AUDIO_FILE_NAME);
+ final File audioInAnObviouslyWrongPlace = new File(getPicturesDir(), AUDIO_FILE_NAME);
+
+ try {
+ allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+
+ // Have another app create an audio file
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppAudioFile.getPath())).isTrue();
+ assertThat(otherAppAudioFile.exists()).isTrue();
+
+ // Assert we can't access the file
+ assertThat(canOpen(otherAppAudioFile, /* forWrite */ false)).isFalse();
+ assertThat(canOpen(otherAppAudioFile, /* forWrite */ true)).isFalse();
+
+ // Assert we can't delete the file
+ assertThat(otherAppAudioFile.delete()).isFalse();
+
+ // Can't create an audio file where it doesn't belong
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ topLevelAudioFile.createNewFile();
+ });
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ audioInAnObviouslyWrongPlace.createNewFile();
+ });
+ } finally {
+ deleteFileAs(APP_B_NO_PERMS, otherAppAudioFile.getPath());
+ topLevelAudioFile.delete();
+ audioInAnObviouslyWrongPlace.delete();
+ denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+ }
+ }
+
+ @Test
+ public void testSystemGalleryCanRenameImagesAndVideos() throws Exception {
+ final File otherAppVideoFile = new File(getDcimDir(), "other_" + VIDEO_FILE_NAME);
+ final File imageFile = new File(getPicturesDir(), IMAGE_FILE_NAME);
+ final File videoFile = new File(getPicturesDir(), VIDEO_FILE_NAME);
+ final File topLevelVideoFile = new File(getExternalStorageDir(), VIDEO_FILE_NAME);
+ final File musicFile = new File(getMusicDir(), AUDIO_FILE_NAME);
+ try {
+ allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+
+ // Have another app create a video file
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppVideoFile.getPath())).isTrue();
+ assertThat(otherAppVideoFile.exists()).isTrue();
+
+ // Write some data to the file
+ try (FileOutputStream fos = new FileOutputStream(otherAppVideoFile)) {
+ fos.write(BYTES_DATA1);
+ }
+ assertFileContent(otherAppVideoFile, BYTES_DATA1);
+
+ // Assert we can rename the file and ensure the file has the same content
+ assertCanRenameFile(otherAppVideoFile, videoFile);
+ assertFileContent(videoFile, BYTES_DATA1);
+ // We can even move it to the top level directory
+ assertCanRenameFile(videoFile, topLevelVideoFile);
+ assertFileContent(topLevelVideoFile, BYTES_DATA1);
+ // And we can even convert it into an image file, because why not?
+ assertCanRenameFile(topLevelVideoFile, imageFile);
+ assertFileContent(imageFile, BYTES_DATA1);
+
+ // We can convert it to a music file, but we won't have access to music file after
+ // renaming.
+ assertThat(imageFile.renameTo(musicFile)).isTrue();
+ assertThat(getFileRowIdFromDatabase(musicFile)).isEqualTo(-1);
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppVideoFile.getAbsolutePath());
+ imageFile.delete();
+ videoFile.delete();
+ topLevelVideoFile.delete();
+ executeShellCommand("rm " + musicFile.getAbsolutePath());
+ MediaStore.scanFile(getContentResolver(), musicFile);
+ denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+ }
+ }
+
+ /**
+ * Test that basic file path restrictions are enforced on file rename.
+ */
+ @Test
+ public void testRenameFile() throws Exception {
+ final File downloadDir = getDownloadDir();
+ final File nonMediaDir = new File(downloadDir, TEST_DIRECTORY_NAME);
+ final File pdfFile1 = new File(downloadDir, NONMEDIA_FILE_NAME);
+ final File pdfFile2 = new File(nonMediaDir, NONMEDIA_FILE_NAME);
+ final File videoFile1 = new File(getDcimDir(), VIDEO_FILE_NAME);
+ final File videoFile2 = new File(getMoviesDir(), VIDEO_FILE_NAME);
+ final File videoFile3 = new File(downloadDir, VIDEO_FILE_NAME);
+
+ try {
+ // Renaming non media file to media directory is not allowed.
+ assertThat(pdfFile1.createNewFile()).isTrue();
+ assertCantRenameFile(pdfFile1, new File(getDcimDir(), NONMEDIA_FILE_NAME));
+ assertCantRenameFile(pdfFile1, new File(getMusicDir(), NONMEDIA_FILE_NAME));
+ assertCantRenameFile(pdfFile1, new File(getMoviesDir(), NONMEDIA_FILE_NAME));
+
+ // Renaming non media files to non media directories is allowed.
+ if (!nonMediaDir.exists()) {
+ assertThat(nonMediaDir.mkdirs()).isTrue();
+ }
+ // App can rename pdfFile to non media directory.
+ assertCanRenameFile(pdfFile1, pdfFile2);
+
+ assertThat(videoFile1.createNewFile()).isTrue();
+ // App can rename video file to Movies directory
+ assertCanRenameFile(videoFile1, videoFile2);
+ // App can rename video file to Download directory
+ assertCanRenameFile(videoFile2, videoFile3);
+ } finally {
+ pdfFile1.delete();
+ pdfFile2.delete();
+ videoFile1.delete();
+ videoFile2.delete();
+ videoFile3.delete();
+ nonMediaDir.delete();
+ }
+ }
+
+ /**
+ * Test that renaming file to different mime type is allowed.
+ */
+ @Test
+ public void testRenameFileType() throws Exception {
+ final File pdfFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
+ final File videoFile = new File(getDcimDir(), VIDEO_FILE_NAME);
+ try {
+ assertThat(pdfFile.createNewFile()).isTrue();
+ assertThat(videoFile.exists()).isFalse();
+ // Moving pdfFile to DCIM directory is not allowed.
+ assertCantRenameFile(pdfFile, new File(getDcimDir(), NONMEDIA_FILE_NAME));
+ // However, moving pdfFile to DCIM directory with changing the mime type to video is
+ // allowed.
+ assertCanRenameFile(pdfFile, videoFile);
+
+ // On rename, MediaProvider database entry for pdfFile should be updated with new
+ // videoFile path and mime type should be updated to video/mp4.
+ assertThat(getFileMimeTypeFromDatabase(videoFile)).isEqualTo("video/mp4");
+ } finally {
+ pdfFile.delete();
+ videoFile.delete();
+ }
+ }
+
+ /**
+ * Test that renaming files overwrites files in newPath.
+ */
+ @Test
+ public void testRenameAndReplaceFile() throws Exception {
+ final File videoFile1 = new File(getDcimDir(), VIDEO_FILE_NAME);
+ final File videoFile2 = new File(getMoviesDir(), VIDEO_FILE_NAME);
+ final ContentResolver cr = getContentResolver();
+ try {
+ assertThat(videoFile1.createNewFile()).isTrue();
+ assertThat(videoFile2.createNewFile()).isTrue();
+ final Uri uriVideoFile1 = MediaStore.scanFile(cr, videoFile1);
+ final Uri uriVideoFile2 = MediaStore.scanFile(cr, videoFile2);
+
+ // Renaming a file which replaces file in newPath videoFile2 is allowed.
+ assertCanRenameFile(videoFile1, videoFile2);
+
+ // Uri of videoFile2 should be accessible after rename.
+ assertThat(cr.openFileDescriptor(uriVideoFile2, "rw")).isNotNull();
+ // Uri of videoFile1 should not be accessible after rename.
+ assertThrows(FileNotFoundException.class,
+ () -> {
+ cr.openFileDescriptor(uriVideoFile1, "rw");
+ });
+ } finally {
+ videoFile1.delete();
+ videoFile2.delete();
+ }
+ }
+
+ /**
+ * Test that app without write permission for file can't update the file.
+ */
+ @Test
+ public void testRenameFileNotOwned() throws Exception {
+ final File videoFile1 = new File(getDcimDir(), VIDEO_FILE_NAME);
+ final File videoFile2 = new File(getMoviesDir(), VIDEO_FILE_NAME);
+ try {
+ assertThat(createFileAs(APP_B_NO_PERMS, videoFile1.getAbsolutePath())).isTrue();
+ // App can't rename a file owned by APP B.
+ assertCantRenameFile(videoFile1, videoFile2);
+
+ assertThat(videoFile2.createNewFile()).isTrue();
+ // App can't rename a file to videoFile1 which is owned by APP B.
+ assertCantRenameFile(videoFile2, videoFile1);
+ // TODO(b/146346138): Test that app with right URI permission should be able to rename
+ // the corresponding file
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, videoFile1.getAbsolutePath());
+ videoFile2.delete();
+ }
+ }
+
+ /**
+ * Test that renaming directories is allowed and aligns to default directory restrictions.
+ */
+ @Test
+ public void testRenameDirectory() throws Exception {
+ final File dcimDir = getDcimDir();
+ final File downloadDir = getDownloadDir();
+ final String nonMediaDirectoryName = TEST_DIRECTORY_NAME + "NonMedia";
+ final File nonMediaDirectory = new File(downloadDir, nonMediaDirectoryName);
+ final File pdfFile = new File(nonMediaDirectory, NONMEDIA_FILE_NAME);
+
+ final String mediaDirectoryName = TEST_DIRECTORY_NAME + "Media";
+ final File mediaDirectory1 = new File(dcimDir, mediaDirectoryName);
+ final File videoFile1 = new File(mediaDirectory1, VIDEO_FILE_NAME);
+ final File mediaDirectory2 = new File(downloadDir, mediaDirectoryName);
+ final File videoFile2 = new File(mediaDirectory2, VIDEO_FILE_NAME);
+ final File mediaDirectory3 = new File(getMoviesDir(), TEST_DIRECTORY_NAME);
+ final File videoFile3 = new File(mediaDirectory3, VIDEO_FILE_NAME);
+ final File mediaDirectory4 = new File(mediaDirectory3, mediaDirectoryName);
+
+ try {
+ if (!nonMediaDirectory.exists()) {
+ assertThat(nonMediaDirectory.mkdirs()).isTrue();
+ }
+ assertThat(pdfFile.createNewFile()).isTrue();
+ // Move directory with pdf file to DCIM directory is not allowed.
+ assertThat(nonMediaDirectory.renameTo(new File(dcimDir, nonMediaDirectoryName)))
+ .isFalse();
+
+ if (!mediaDirectory1.exists()) {
+ assertThat(mediaDirectory1.mkdirs()).isTrue();
+ }
+ assertThat(videoFile1.createNewFile()).isTrue();
+ // Renaming to and from default directories is not allowed.
+ assertThat(mediaDirectory1.renameTo(dcimDir)).isFalse();
+ // Moving top level default directories is not allowed.
+ assertCantRenameDirectory(downloadDir, new File(dcimDir, TEST_DIRECTORY_NAME), null);
+
+ // Moving media directory to Download directory is allowed.
+ assertCanRenameDirectory(mediaDirectory1, mediaDirectory2, new File[] {videoFile1},
+ new File[] {videoFile2});
+
+ // Moving media directory to Movies directory and renaming directory in new path is
+ // allowed.
+ assertCanRenameDirectory(mediaDirectory2, mediaDirectory3, new File[] {videoFile2},
+ new File[] {videoFile3});
+
+ // Can't rename a mediaDirectory to non empty non Media directory.
+ assertCantRenameDirectory(mediaDirectory3, nonMediaDirectory, new File[] {videoFile3});
+ // Can't rename a file to a directory.
+ assertCantRenameFile(videoFile3, mediaDirectory3);
+ // Can't rename a directory to file.
+ assertCantRenameDirectory(mediaDirectory3, pdfFile, null);
+ if (!mediaDirectory4.exists()) {
+ assertThat(mediaDirectory4.mkdir()).isTrue();
+ }
+ // Can't rename a directory to subdirectory of itself.
+ assertCantRenameDirectory(mediaDirectory3, mediaDirectory4, new File[] {videoFile3});
+
+ } finally {
+ pdfFile.delete();
+ nonMediaDirectory.delete();
+
+ videoFile1.delete();
+ videoFile2.delete();
+ videoFile3.delete();
+ mediaDirectory1.delete();
+ mediaDirectory2.delete();
+ mediaDirectory3.delete();
+ mediaDirectory4.delete();
+ }
+ }
+
+ /**
+ * Test that renaming directory checks file ownership permissions.
+ */
+ @Test
+ public void testRenameDirectoryNotOwned() throws Exception {
+ final String mediaDirectoryName = TEST_DIRECTORY_NAME + "Media";
+ File mediaDirectory1 = new File(getDcimDir(), mediaDirectoryName);
+ File mediaDirectory2 = new File(getMoviesDir(), mediaDirectoryName);
+ File videoFile = new File(mediaDirectory1, VIDEO_FILE_NAME);
+
+ try {
+ if (!mediaDirectory1.exists()) {
+ assertThat(mediaDirectory1.mkdirs()).isTrue();
+ }
+ assertThat(createFileAs(APP_B_NO_PERMS, videoFile.getAbsolutePath())).isTrue();
+ // App doesn't have access to videoFile1, can't rename mediaDirectory1.
+ assertThat(mediaDirectory1.renameTo(mediaDirectory2)).isFalse();
+ assertThat(videoFile.exists()).isTrue();
+ // Test app can delete the file since the file is not moved to new directory.
+ assertThat(deleteFileAs(APP_B_NO_PERMS, videoFile.getAbsolutePath())).isTrue();
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, videoFile.getAbsolutePath());
+ mediaDirectory1.delete();
+ }
+ }
+
+ /**
+ * Test renaming empty directory is allowed
+ */
+ @Test
+ public void testRenameEmptyDirectory() throws Exception {
+ final String emptyDirectoryName = TEST_DIRECTORY_NAME + "Media";
+ File emptyDirectoryOldPath = new File(getDcimDir(), emptyDirectoryName);
+ File emptyDirectoryNewPath = new File(getMoviesDir(), TEST_DIRECTORY_NAME + "23456");
+ try {
+ if (emptyDirectoryOldPath.exists()) {
+ executeShellCommand("rm -r " + emptyDirectoryOldPath.getPath());
+ }
+ assertThat(emptyDirectoryOldPath.mkdirs()).isTrue();
+ assertCanRenameDirectory(emptyDirectoryOldPath, emptyDirectoryNewPath, null, null);
+ } finally {
+ emptyDirectoryOldPath.delete();
+ emptyDirectoryNewPath.delete();
+ }
+ }
+
+ /**
+ * Test that apps can create and delete hidden file.
+ */
+ @Test
+ public void testCanCreateHiddenFile() throws Exception {
+ final File hiddenImageFile = new File(getDownloadDir(), ".hiddenFile" + IMAGE_FILE_NAME);
+ try {
+ assertThat(hiddenImageFile.createNewFile()).isTrue();
+ // Write to hidden file is allowed.
+ try (FileOutputStream fos = new FileOutputStream(hiddenImageFile)) {
+ fos.write(BYTES_DATA1);
+ }
+ assertFileContent(hiddenImageFile, BYTES_DATA1);
+
+ assertNotMediaTypeImage(hiddenImageFile);
+
+ assertDirectoryContains(getDownloadDir(), hiddenImageFile);
+ assertThat(getFileRowIdFromDatabase(hiddenImageFile)).isNotEqualTo(-1);
+
+ // We can delete hidden file
+ assertThat(hiddenImageFile.delete()).isTrue();
+ assertThat(hiddenImageFile.exists()).isFalse();
+ } finally {
+ hiddenImageFile.delete();
+ }
+ }
+
+ /**
+ * Test that apps can rename a hidden file.
+ */
+ @Test
+ public void testCanRenameHiddenFile() throws Exception {
+ final String hiddenFileName = ".hidden" + IMAGE_FILE_NAME;
+ final File hiddenImageFile1 = new File(getDcimDir(), hiddenFileName);
+ final File hiddenImageFile2 = new File(getDownloadDir(), hiddenFileName);
+ final File imageFile = new File(getDownloadDir(), IMAGE_FILE_NAME);
+ try {
+ assertThat(hiddenImageFile1.createNewFile()).isTrue();
+ assertCanRenameFile(hiddenImageFile1, hiddenImageFile2);
+ assertNotMediaTypeImage(hiddenImageFile2);
+
+ // We can also rename hidden file to non-hidden
+ assertCanRenameFile(hiddenImageFile2, imageFile);
+ assertIsMediaTypeImage(imageFile);
+
+ // We can rename non-hidden file to hidden
+ assertCanRenameFile(imageFile, hiddenImageFile1);
+ assertNotMediaTypeImage(hiddenImageFile1);
+ } finally {
+ hiddenImageFile1.delete();
+ hiddenImageFile2.delete();
+ imageFile.delete();
+ }
+ }
+
+ /**
+ * Test that files in hidden directory have MEDIA_TYPE=MEDIA_TYPE_NONE
+ */
+ @Test
+ public void testHiddenDirectory() throws Exception {
+ final File hiddenDir = new File(getDownloadDir(), ".hidden" + TEST_DIRECTORY_NAME);
+ final File hiddenImageFile = new File(hiddenDir, IMAGE_FILE_NAME);
+ final File nonHiddenDir = new File(getDownloadDir(), TEST_DIRECTORY_NAME);
+ final File imageFile = new File(nonHiddenDir, IMAGE_FILE_NAME);
+ try {
+ if (!hiddenDir.exists()) {
+ assertThat(hiddenDir.mkdir()).isTrue();
+ }
+ assertThat(hiddenImageFile.createNewFile()).isTrue();
+
+ assertNotMediaTypeImage(hiddenImageFile);
+
+ // Renaming hiddenDir to nonHiddenDir makes the imageFile non-hidden and vice versa
+ assertCanRenameDirectory(
+ hiddenDir, nonHiddenDir, new File[] {hiddenImageFile}, new File[] {imageFile});
+ assertIsMediaTypeImage(imageFile);
+
+ assertCanRenameDirectory(
+ nonHiddenDir, hiddenDir, new File[] {imageFile}, new File[] {hiddenImageFile});
+ assertNotMediaTypeImage(hiddenImageFile);
+ } finally {
+ hiddenImageFile.delete();
+ imageFile.delete();
+ hiddenDir.delete();
+ nonHiddenDir.delete();
+ }
+ }
+
+ /**
+ * Test that files in directory with nomedia have MEDIA_TYPE=MEDIA_TYPE_NONE
+ */
+ @Test
+ public void testHiddenDirectory_nomedia() throws Exception {
+ final File directoryNoMedia = new File(getDownloadDir(), "nomedia" + TEST_DIRECTORY_NAME);
+ final File noMediaFile = new File(directoryNoMedia, ".nomedia");
+ final File imageFile = new File(directoryNoMedia, IMAGE_FILE_NAME);
+ final File videoFile = new File(directoryNoMedia, VIDEO_FILE_NAME);
+ try {
+ if (!directoryNoMedia.exists()) {
+ assertThat(directoryNoMedia.mkdir()).isTrue();
+ }
+ assertThat(noMediaFile.createNewFile()).isTrue();
+ assertThat(imageFile.createNewFile()).isTrue();
+
+ assertNotMediaTypeImage(imageFile);
+
+ // Deleting the .nomedia file makes the parent directory non hidden.
+ noMediaFile.delete();
+ MediaStore.scanFile(getContentResolver(), directoryNoMedia);
+ assertIsMediaTypeImage(imageFile);
+
+ // Creating the .nomedia file makes the parent directory hidden again
+ assertThat(noMediaFile.createNewFile()).isTrue();
+ MediaStore.scanFile(getContentResolver(), directoryNoMedia);
+ assertNotMediaTypeImage(imageFile);
+
+ // Renaming the .nomedia file to non hidden file makes the parent directory non hidden.
+ assertCanRenameFile(noMediaFile, videoFile);
+ assertIsMediaTypeImage(imageFile);
+ } finally {
+ noMediaFile.delete();
+ imageFile.delete();
+ videoFile.delete();
+ directoryNoMedia.delete();
+ }
+ }
+
+ /**
+ * Test that only file manager and app that created the hidden file can list it.
+ */
+ @Test
+ public void testListHiddenFile() throws Exception {
+ final File dcimDir = getDcimDir();
+ final String hiddenImageFileName = ".hidden" + IMAGE_FILE_NAME;
+ final File hiddenImageFile = new File(dcimDir, hiddenImageFileName);
+ try {
+ assertThat(hiddenImageFile.createNewFile()).isTrue();
+ assertNotMediaTypeImage(hiddenImageFile);
+
+ assertDirectoryContains(dcimDir, hiddenImageFile);
+
+ // TestApp with read permissions can't see the hidden image file created by other app
+ assertThat(listAs(APP_B_NO_PERMS, dcimDir.getAbsolutePath()))
+ .doesNotContain(hiddenImageFileName);
+
+ final int testAppUid =
+ getContext().getPackageManager().getPackageUid(APP_B_NO_PERMS.getPackageName(),
+ 0);
+ // FileManager can see the hidden image file created by other app
+ try {
+ allowAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
+ assertThat(listAs(APP_B_NO_PERMS, dcimDir.getAbsolutePath()))
+ .contains(hiddenImageFileName);
+ } finally {
+ denyAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
+ }
+
+ // Gallery can not see the hidden image file created by other app
+ try {
+ allowAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
+ assertThat(listAs(APP_B_NO_PERMS, dcimDir.getAbsolutePath()))
+ .doesNotContain(hiddenImageFileName);
+ } finally {
+ denyAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
+ }
+ } finally {
+ hiddenImageFile.delete();
+ }
+ }
+
+ @Test
+ public void testOpenPendingAndTrashed() throws Exception {
+ final File pendingImageFile = new File(getDcimDir(), IMAGE_FILE_NAME);
+ final File trashedVideoFile = new File(getPicturesDir(), VIDEO_FILE_NAME);
+ final File pendingPdfFile = new File(getDocumentsDir(), NONMEDIA_FILE_NAME);
+ final File trashedPdfFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
+ Uri pendingImgaeFileUri = null;
+ Uri trashedVideoFileUri = null;
+ Uri pendingPdfFileUri = null;
+ Uri trashedPdfFileUri = null;
+ try {
+ pendingImgaeFileUri = createPendingFile(pendingImageFile);
+ assertOpenPendingOrTrashed(pendingImgaeFileUri, APP_A_HAS_RES, /*isImageOrVideo*/ true);
+
+ pendingPdfFileUri = createPendingFile(pendingPdfFile);
+ assertOpenPendingOrTrashed(pendingPdfFileUri, APP_A_HAS_RES,
+ /*isImageOrVideo*/ false);
+
+ trashedVideoFileUri = createTrashedFile(trashedVideoFile);
+ assertOpenPendingOrTrashed(trashedVideoFileUri, APP_A_HAS_RES, /*isImageOrVideo*/ true);
+
+ trashedPdfFileUri = createTrashedFile(trashedPdfFile);
+ assertOpenPendingOrTrashed(trashedPdfFileUri, APP_A_HAS_RES,
+ /*isImageOrVideo*/ false);
+
+ } finally {
+ deleteFiles(pendingImageFile, pendingImageFile, trashedVideoFile,
+ trashedPdfFile);
+ deleteWithMediaProviderNoThrow(pendingImgaeFileUri, trashedVideoFileUri,
+ pendingPdfFileUri, trashedPdfFileUri);
+ }
+ }
+
+ @Test
+ public void testListPendingAndTrashed() throws Exception {
+ final File imageFile = new File(getDcimDir(), IMAGE_FILE_NAME);
+ final File pdfFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
+ Uri imageFileUri = null;
+ Uri pdfFileUri = null;
+ try {
+ imageFileUri = createPendingFile(imageFile);
+ // Check that only owner package, file manager and system gallery can list pending image
+ // file.
+ assertListPendingOrTrashed(imageFileUri, imageFile, APP_A_HAS_RES,
+ /*isImageOrVideo*/ true);
+
+ trashFile(imageFileUri);
+ // Check that only owner package, file manager and system gallery can list trashed image
+ // file.
+ assertListPendingOrTrashed(imageFileUri, imageFile, APP_A_HAS_RES,
+ /*isImageOrVideo*/ true);
+
+ pdfFileUri = createPendingFile(pdfFile);
+ // Check that only owner package, file manager can list pending non media file.
+ assertListPendingOrTrashed(pdfFileUri, pdfFile, APP_A_HAS_RES,
+ /*isImageOrVideo*/ false);
+
+ trashFile(pdfFileUri);
+ // Check that only owner package, file manager can list trashed non media file.
+ assertListPendingOrTrashed(pdfFileUri, pdfFile, APP_A_HAS_RES,
+ /*isImageOrVideo*/ false);
+ } finally {
+ deleteWithMediaProviderNoThrow(imageFileUri, pdfFileUri);
+ deleteFiles(imageFile, pdfFile);
+ }
+ }
+
+ @Test
+ public void testDeletePendingAndTrashed() throws Exception {
+ final File pendingVideoFile = new File(getDcimDir(), VIDEO_FILE_NAME);
+ final File trashedImageFile = new File(getPicturesDir(), IMAGE_FILE_NAME);
+ final File pendingPdfFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
+ final File trashedPdfFile = new File(getDocumentsDir(), NONMEDIA_FILE_NAME);
+ // Actual path of the file gets rewritten for pending and trashed files.
+ String pendingVideoFilePath = null;
+ String trashedImageFilePath = null;
+ String pendingPdfFilePath = null;
+ String trashedPdfFilePath = null;
+ try {
+ pendingVideoFilePath = getFilePathFromUri(createPendingFile(pendingVideoFile));
+ trashedImageFilePath = getFilePathFromUri(createTrashedFile(trashedImageFile));
+ pendingPdfFilePath = getFilePathFromUri(createPendingFile(pendingPdfFile));
+ trashedPdfFilePath = getFilePathFromUri(createTrashedFile(trashedPdfFile));
+
+ // App can delete its own pending and trashed file.
+ assertCanDeletePaths(pendingVideoFilePath, trashedImageFilePath, pendingPdfFilePath,
+ trashedPdfFilePath);
+
+ pendingVideoFilePath = getFilePathFromUri(createPendingFile(pendingVideoFile));
+ trashedImageFilePath = getFilePathFromUri(createTrashedFile(trashedImageFile));
+ pendingPdfFilePath = getFilePathFromUri(createPendingFile(pendingPdfFile));
+ trashedPdfFilePath = getFilePathFromUri(createTrashedFile(trashedPdfFile));
+
+ // App can't delete other app's pending and trashed file.
+ assertCantDeletePathsAs(APP_A_HAS_RES, pendingVideoFilePath, trashedImageFilePath,
+ pendingPdfFilePath, trashedPdfFilePath);
+
+ final int testAppUid =
+ getContext().getPackageManager().getPackageUid(APP_A_HAS_RES.getPackageName(),
+ 0);
+ try {
+ allowAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
+ // File Manager can delete any pending and trashed file
+ assertCanDeletePathsAs(APP_A_HAS_RES, pendingVideoFilePath, trashedImageFilePath,
+ pendingPdfFilePath, trashedPdfFilePath);
+ } finally {
+ denyAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
+ }
+
+ pendingVideoFilePath = getFilePathFromUri(createPendingFile(pendingVideoFile));
+ trashedImageFilePath = getFilePathFromUri(createTrashedFile(trashedImageFile));
+ pendingPdfFilePath = getFilePathFromUri(createPendingFile(pendingPdfFile));
+ trashedPdfFilePath = getFilePathFromUri(createTrashedFile(trashedPdfFile));
+
+ try {
+ allowAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
+ // System Gallery can delete any pending and trashed image or video file.
+ assertTrue(isMediaTypeImageOrVideo(new File(pendingVideoFilePath)));
+ assertTrue(isMediaTypeImageOrVideo(new File(trashedImageFilePath)));
+ assertCanDeletePathsAs(APP_A_HAS_RES, pendingVideoFilePath, trashedImageFilePath);
+
+ // System Gallery can't delete other app's pending and trashed pdf file.
+ assertFalse(isMediaTypeImageOrVideo(new File(pendingPdfFilePath)));
+ assertFalse(isMediaTypeImageOrVideo(new File(trashedPdfFilePath)));
+ assertCantDeletePathsAs(APP_A_HAS_RES, pendingPdfFilePath, trashedPdfFilePath);
+ } finally {
+ denyAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
+ }
+ } finally {
+ deletePaths(pendingVideoFilePath, trashedImageFilePath, pendingPdfFilePath,
+ trashedPdfFilePath);
+ deleteFiles(pendingVideoFile, trashedImageFile, pendingPdfFile, trashedPdfFile);
+ }
+ }
+
+ @Test
+ public void testQueryOtherAppsFiles() throws Exception {
+ final File otherAppPdf = new File(getDownloadDir(), "other" + NONMEDIA_FILE_NAME);
+ final File otherAppImg = new File(getDcimDir(), "other" + IMAGE_FILE_NAME);
+ final File otherAppMusic = new File(getMusicDir(), "other" + AUDIO_FILE_NAME);
+ final File otherHiddenFile = new File(getPicturesDir(), ".otherHiddenFile.jpg");
+ try {
+ // Apps can't query other app's pending file, hence create file and publish it.
+ assertCreatePublishedFilesAs(
+ APP_B_NO_PERMS, otherAppImg, otherAppMusic, otherAppPdf, otherHiddenFile);
+
+ // Since the test doesn't have READ_EXTERNAL_STORAGE nor any other special permissions,
+ // it can't query for another app's contents.
+ assertCantQueryFile(otherAppImg);
+ assertCantQueryFile(otherAppMusic);
+ assertCantQueryFile(otherAppPdf);
+ assertCantQueryFile(otherHiddenFile);
+ } finally {
+ deleteFilesAs(APP_B_NO_PERMS, otherAppImg, otherAppMusic, otherAppPdf, otherHiddenFile);
+ }
+ }
+
+ @Test
+ public void testSystemGalleryQueryOtherAppsFiles() throws Exception {
+ final File otherAppPdf = new File(getDownloadDir(), "other" + NONMEDIA_FILE_NAME);
+ final File otherAppImg = new File(getDcimDir(), "other" + IMAGE_FILE_NAME);
+ final File otherAppMusic = new File(getMusicDir(), "other" + AUDIO_FILE_NAME);
+ final File otherHiddenFile = new File(getPicturesDir(), ".otherHiddenFile.jpg");
+ try {
+ // Apps can't query other app's pending file, hence create file and publish it.
+ assertCreatePublishedFilesAs(
+ APP_B_NO_PERMS, otherAppImg, otherAppMusic, otherAppPdf, otherHiddenFile);
+
+ // System gallery apps have access to video and image files
+ allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+
+ assertCanQueryAndOpenFile(otherAppImg, "rw");
+ // System gallery doesn't have access to hidden image files of other app
+ assertCantQueryFile(otherHiddenFile);
+ // But no access to PDFs or music files
+ assertCantQueryFile(otherAppMusic);
+ assertCantQueryFile(otherAppPdf);
+ } finally {
+ denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+ deleteFilesAs(APP_B_NO_PERMS, otherAppImg, otherAppMusic, otherAppPdf, otherHiddenFile);
+ }
+ }
+
+ /**
+ * Test that System Gallery app can rename any directory under the default directories
+ * designated for images and videos, even if they contain other apps' contents that
+ * System Gallery doesn't have read access to.
+ */
+ @Test
+ public void testSystemGalleryCanRenameImageAndVideoDirs() throws Exception {
+ final File dirInDcim = new File(getDcimDir(), TEST_DIRECTORY_NAME);
+ final File dirInPictures = new File(getPicturesDir(), TEST_DIRECTORY_NAME);
+ final File dirInPodcasts = new File(getPodcastsDir(), TEST_DIRECTORY_NAME);
+ final File otherAppImageFile1 = new File(dirInDcim, "other_" + IMAGE_FILE_NAME);
+ final File otherAppVideoFile1 = new File(dirInDcim, "other_" + VIDEO_FILE_NAME);
+ final File otherAppPdfFile1 = new File(dirInDcim, "other_" + NONMEDIA_FILE_NAME);
+ final File otherAppImageFile2 = new File(dirInPictures, "other_" + IMAGE_FILE_NAME);
+ final File otherAppVideoFile2 = new File(dirInPictures, "other_" + VIDEO_FILE_NAME);
+ final File otherAppPdfFile2 = new File(dirInPictures, "other_" + NONMEDIA_FILE_NAME);
+ try {
+ assertThat(dirInDcim.exists() || dirInDcim.mkdir()).isTrue();
+
+ executeShellCommand("touch " + otherAppPdfFile1);
+ MediaStore.scanFile(getContentResolver(), otherAppPdfFile1);
+
+ allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+
+ assertCreateFilesAs(APP_A_HAS_RES, otherAppImageFile1, otherAppVideoFile1);
+
+ // System gallery privileges don't go beyond DCIM, Movies and Pictures boundaries.
+ assertCantRenameDirectory(dirInDcim, dirInPodcasts, /*oldFilesList*/ null);
+
+ // Rename should succeed, but System Gallery still can't access that PDF file!
+ assertCanRenameDirectory(dirInDcim, dirInPictures,
+ new File[] {otherAppImageFile1, otherAppVideoFile1},
+ new File[] {otherAppImageFile2, otherAppVideoFile2});
+ assertThat(getFileRowIdFromDatabase(otherAppPdfFile1)).isEqualTo(-1);
+ assertThat(getFileRowIdFromDatabase(otherAppPdfFile2)).isEqualTo(-1);
+ } finally {
+ executeShellCommand("rm " + otherAppPdfFile1);
+ executeShellCommand("rm " + otherAppPdfFile2);
+ MediaStore.scanFile(getContentResolver(), otherAppPdfFile1);
+ MediaStore.scanFile(getContentResolver(), otherAppPdfFile2);
+ otherAppImageFile1.delete();
+ otherAppImageFile2.delete();
+ otherAppVideoFile1.delete();
+ otherAppVideoFile2.delete();
+ otherAppPdfFile1.delete();
+ otherAppPdfFile2.delete();
+ dirInDcim.delete();
+ dirInPictures.delete();
+ denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+ }
+ }
+
+ /**
+ * Test that row ID corresponding to deleted path is restored on subsequent create.
+ */
+ @Test
+ public void testCreateCanRestoreDeletedRowId() throws Exception {
+ final File imageFile = new File(getDcimDir(), IMAGE_FILE_NAME);
+ final ContentResolver cr = getContentResolver();
+
+ try {
+ assertThat(imageFile.createNewFile()).isTrue();
+ final long oldRowId = getFileRowIdFromDatabase(imageFile);
+ assertThat(oldRowId).isNotEqualTo(-1);
+ final Uri uriOfOldFile = MediaStore.scanFile(cr, imageFile);
+ assertThat(uriOfOldFile).isNotNull();
+
+ assertThat(imageFile.delete()).isTrue();
+ // We should restore old row Id corresponding to deleted imageFile.
+ assertThat(imageFile.createNewFile()).isTrue();
+ assertThat(getFileRowIdFromDatabase(imageFile)).isEqualTo(oldRowId);
+ assertThat(cr.openFileDescriptor(uriOfOldFile, "rw")).isNotNull();
+
+ assertThat(imageFile.delete()).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, imageFile.getAbsolutePath())).isTrue();
+
+ final Uri uriOfNewFile = MediaStore.scanFile(getContentResolver(), imageFile);
+ assertThat(uriOfNewFile).isNotNull();
+ // We shouldn't restore deleted row Id if delete & create are called from different apps
+ assertThat(Integer.getInteger(uriOfNewFile.getLastPathSegment()))
+ .isNotEqualTo(oldRowId);
+ } finally {
+ imageFile.delete();
+ deleteFileAsNoThrow(APP_B_NO_PERMS, imageFile.getAbsolutePath());
+ }
+ }
+
+ /**
+ * Test that row ID corresponding to deleted path is restored on subsequent rename.
+ */
+ @Test
+ public void testRenameCanRestoreDeletedRowId() throws Exception {
+ final File imageFile = new File(getDcimDir(), IMAGE_FILE_NAME);
+ final File temporaryFile = new File(getDownloadDir(), IMAGE_FILE_NAME + "_.tmp");
+ final ContentResolver cr = getContentResolver();
+
+ try {
+ assertThat(imageFile.createNewFile()).isTrue();
+ final Uri oldUri = MediaStore.scanFile(cr, imageFile);
+ assertThat(oldUri).isNotNull();
+
+ Files.copy(imageFile, temporaryFile);
+ assertThat(imageFile.delete()).isTrue();
+ assertCanRenameFile(temporaryFile, imageFile);
+
+ final Uri newUri = MediaStore.scanFile(cr, imageFile);
+ assertThat(newUri).isNotNull();
+ assertThat(newUri.getLastPathSegment()).isEqualTo(oldUri.getLastPathSegment());
+ // oldUri of imageFile is still accessible after delete and rename.
+ assertThat(cr.openFileDescriptor(oldUri, "rw")).isNotNull();
+ } finally {
+ imageFile.delete();
+ temporaryFile.delete();
+ }
+ }
+
+ @Test
+ public void testCantCreateOrRenameFileWithInvalidName() throws Exception {
+ File invalidFile = new File(getDownloadDir(), "<>");
+ File validFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
+ try {
+ assertThrows(IOException.class, "Operation not permitted",
+ () -> {
+ invalidFile.createNewFile();
+ });
+
+ assertThat(validFile.createNewFile()).isTrue();
+ // We can't rename a file to a file name with invalid FAT characters.
+ assertCantRenameFile(validFile, invalidFile);
+ } finally {
+ invalidFile.delete();
+ validFile.delete();
+ }
+ }
+
+ @Test
+ public void testRenameWithSpecialChars() throws Exception {
+ final String specialCharsSuffix = "'`~!@#$%^& ()_+-={}[];'.)";
+
+ final File fileSpecialChars =
+ new File(getDownloadDir(), NONMEDIA_FILE_NAME + specialCharsSuffix);
+
+ final File dirSpecialChars =
+ new File(getDownloadDir(), TEST_DIRECTORY_NAME + specialCharsSuffix);
+ final File file1 = new File(dirSpecialChars, NONMEDIA_FILE_NAME);
+ final File fileSpecialChars1 =
+ new File(dirSpecialChars, NONMEDIA_FILE_NAME + specialCharsSuffix);
+
+ final File renamedDir = new File(getDocumentsDir(), TEST_DIRECTORY_NAME);
+ final File file2 = new File(renamedDir, NONMEDIA_FILE_NAME);
+ final File fileSpecialChars2 =
+ new File(renamedDir, NONMEDIA_FILE_NAME + specialCharsSuffix);
+ try {
+ assertTrue(fileSpecialChars.createNewFile());
+ if (!dirSpecialChars.exists()) {
+ assertTrue(dirSpecialChars.mkdir());
+ }
+ assertTrue(file1.createNewFile());
+
+ // We can rename file name with special characters
+ assertCanRenameFile(fileSpecialChars, fileSpecialChars1);
+
+ // We can rename directory name with special characters
+ assertCanRenameDirectory(dirSpecialChars, renamedDir,
+ new File[] {file1, fileSpecialChars1}, new File[] {file2, fileSpecialChars2});
+ } finally {
+ file1.delete();
+ file2.delete();
+ fileSpecialChars.delete();
+ fileSpecialChars1.delete();
+ fileSpecialChars2.delete();
+ dirSpecialChars.delete();
+ renamedDir.delete();
+ }
+ }
+
+ /**
+ * Test that IS_PENDING is set for files created via filepath
+ */
+ @Test
+ public void testPendingFromFuse() throws Exception {
+ final File pendingFile = new File(getDcimDir(), IMAGE_FILE_NAME);
+ final File otherPendingFile = new File(getDcimDir(), VIDEO_FILE_NAME);
+ try {
+ assertTrue(pendingFile.createNewFile());
+ // Newly created file should have IS_PENDING set
+ try (Cursor c = queryFile(pendingFile, MediaStore.MediaColumns.IS_PENDING)) {
+ assertTrue(c.moveToFirst());
+ assertThat(c.getInt(0)).isEqualTo(1);
+ }
+
+ // If we query with MATCH_EXCLUDE, we should still see this pendingFile
+ try (Cursor c = queryFileExcludingPending(pendingFile,
+ MediaStore.MediaColumns.IS_PENDING)) {
+ assertThat(c.getCount()).isEqualTo(1);
+ assertTrue(c.moveToFirst());
+ assertThat(c.getInt(0)).isEqualTo(1);
+ }
+
+ assertNotNull(MediaStore.scanFile(getContentResolver(), pendingFile));
+
+ // IS_PENDING should be unset after the scan
+ try (Cursor c = queryFile(pendingFile, MediaStore.MediaColumns.IS_PENDING)) {
+ assertTrue(c.moveToFirst());
+ assertThat(c.getInt(0)).isEqualTo(0);
+ }
+
+ assertCreateFilesAs(APP_A_HAS_RES, otherPendingFile);
+ // We can't query other apps pending file from FUSE with MATCH_EXCLUDE
+ try (Cursor c = queryFileExcludingPending(otherPendingFile,
+ MediaStore.MediaColumns.IS_PENDING)) {
+ assertThat(c.getCount()).isEqualTo(0);
+ }
+ } finally {
+ pendingFile.delete();
+ deleteFileAsNoThrow(APP_A_HAS_RES, otherPendingFile.getAbsolutePath());
+ }
+ }
+
+ /**
+ * Test that apps can't set attributes on another app's files.
+ */
+ @Test
+ public void testCantSetAttrOtherAppsFile() throws Exception {
+ // This path's permission is checked in MediaProvider (directory/external media dir)
+ final File externalMediaPath = new File(getExternalMediaDir(), VIDEO_FILE_NAME);
+
+ try {
+ // Create the files
+ if (!externalMediaPath.exists()) {
+ assertThat(externalMediaPath.createNewFile()).isTrue();
+ }
+
+ // APP A should not be able to setattr to other app's files.
+ assertWithMessage(
+ "setattr on directory/external media path [%s]", externalMediaPath.getPath())
+ .that(setAttrAs(APP_A_HAS_RES, externalMediaPath.getPath()))
+ .isFalse();
+ } finally {
+ externalMediaPath.delete();
+ }
+ }
+
+ /**
+ * b/171768780: Test that scan doesn't skip scanning renamed hidden file.
+ */
+ @Test
+ public void testScanUpdatesMetadataForRenamedHiddenFile() throws Exception {
+ final File hiddenFile = new File(getPicturesDir(), ".hidden_" + IMAGE_FILE_NAME);
+ final File jpgFile = new File(getPicturesDir(), IMAGE_FILE_NAME);
+ try {
+ // Copy the image content to hidden file
+ try (InputStream in =
+ getContext().getResources().openRawResource(R.raw.img_with_metadata);
+ FileOutputStream out = new FileOutputStream(hiddenFile)) {
+ FileUtils.copy(in, out);
+ out.getFD().sync();
+ }
+ Uri scanUri = MediaStore.scanFile(getContentResolver(), hiddenFile);
+ assertNotNull(scanUri);
+
+ // Rename hidden file to non-hidden
+ assertCanRenameFile(hiddenFile, jpgFile);
+
+ try (Cursor c = queryFile(jpgFile, MediaStore.MediaColumns.DATE_TAKEN)) {
+ assertTrue(c.moveToFirst());
+ // The file is not scanned yet, hence the metadata is not updated yet.
+ assertThat(c.getString(0)).isNull();
+ }
+
+ // Scan the file to update the metadata for renamed hidden file.
+ scanUri = MediaStore.scanFile(getContentResolver(), jpgFile);
+ assertNotNull(scanUri);
+
+ // Scan should be able to update metadata even if File.lastModifiedTime hasn't changed.
+ try (Cursor c = queryFile(jpgFile, MediaStore.MediaColumns.DATE_TAKEN)) {
+ assertTrue(c.moveToFirst());
+ assertThat(c.getString(0)).isNotNull();
+ }
+ } finally {
+ hiddenFile.delete();
+ jpgFile.delete();
+ }
+ }
+
+ /**
+ * Checks restrictions for opening pending and trashed files by different apps. Assumes that
+ * given {@code testApp} is already installed and has READ_EXTERNAL_STORAGE permission. This
+ * method doesn't uninstall given {@code testApp} at the end.
+ */
+ private void assertOpenPendingOrTrashed(Uri uri, TestApp testApp, boolean isImageOrVideo)
+ throws Exception {
+ final File pendingOrTrashedFile = new File(getFilePathFromUri(uri));
+
+ // App can open its pending or trashed file for read or write
+ assertTrue(canOpen(pendingOrTrashedFile, /*forWrite*/ false));
+ assertTrue(canOpen(pendingOrTrashedFile, /*forWrite*/ true));
+
+ // App with READ_EXTERNAL_STORAGE can't open other app's pending or trashed file for read or
+ // write
+ assertFalse(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ false));
+ assertFalse(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ true));
+
+ final int testAppUid =
+ getContext().getPackageManager().getPackageUid(testApp.getPackageName(), 0);
+ try {
+ allowAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
+ // File Manager can open any pending or trashed file for read or write
+ assertTrue(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ false));
+ assertTrue(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ true));
+ } finally {
+ denyAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
+ }
+
+ try {
+ allowAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
+ if (isImageOrVideo) {
+ // System Gallery can open any pending or trashed image/video file for read or write
+ assertTrue(isMediaTypeImageOrVideo(pendingOrTrashedFile));
+ assertTrue(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ false));
+ assertTrue(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ true));
+ } else {
+ // System Gallery can't open other app's pending or trashed non-media file for read
+ // or write
+ assertFalse(isMediaTypeImageOrVideo(pendingOrTrashedFile));
+ assertFalse(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ false));
+ assertFalse(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ true));
+ }
+ } finally {
+ denyAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
+ }
+ }
+
+ /**
+ * Checks restrictions for listing pending and trashed files by different apps. Assumes that
+ * given {@code testApp} is already installed and has READ_EXTERNAL_STORAGE permission. This
+ * method doesn't uninstall given {@code testApp} at the end.
+ */
+ private void assertListPendingOrTrashed(Uri uri, File file, TestApp testApp,
+ boolean isImageOrVideo) throws Exception {
+ final String parentDirPath = file.getParent();
+ assertTrue(new File(parentDirPath).isDirectory());
+
+ final List<String> listedFileNames = Arrays.asList(new File(parentDirPath).list());
+ assertThat(listedFileNames).doesNotContain(file);
+
+ final File pendingOrTrashedFile = new File(getFilePathFromUri(uri));
+
+ assertThat(listedFileNames).contains(pendingOrTrashedFile.getName());
+
+ // App with READ_EXTERNAL_STORAGE can't see other app's pending or trashed file.
+ assertThat(listAs(testApp, parentDirPath)).doesNotContain(pendingOrTrashedFile.getName());
+
+ final int testAppUid =
+ getContext().getPackageManager().getPackageUid(testApp.getPackageName(), 0);
+ try {
+ allowAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
+ // File Manager can see any pending or trashed file.
+ assertThat(listAs(testApp, parentDirPath)).contains(pendingOrTrashedFile.getName());
+ } finally {
+ denyAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
+ }
+
+ try {
+ allowAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
+ if (isImageOrVideo) {
+ // System Gallery can see any pending or trashed image/video file.
+ assertTrue(isMediaTypeImageOrVideo(pendingOrTrashedFile));
+ assertThat(listAs(testApp, parentDirPath)).contains(pendingOrTrashedFile.getName());
+ } else {
+ // System Gallery can't see other app's pending or trashed non media file.
+ assertFalse(isMediaTypeImageOrVideo(pendingOrTrashedFile));
+ assertThat(listAs(testApp, parentDirPath))
+ .doesNotContain(pendingOrTrashedFile.getName());
+ }
+ } finally {
+ denyAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
+ }
+ }
+
+ private Uri createPendingFile(File pendingFile) throws Exception {
+ assertTrue(pendingFile.createNewFile());
+
+ final ContentResolver cr = getContentResolver();
+ final Uri trashedFileUri = MediaStore.scanFile(cr, pendingFile);
+ assertNotNull(trashedFileUri);
+
+ final ContentValues values = new ContentValues();
+ values.put(MediaStore.MediaColumns.IS_PENDING, 1);
+ assertEquals(1, cr.update(trashedFileUri, values, Bundle.EMPTY));
+
+ return trashedFileUri;
+ }
+
+ private Uri createTrashedFile(File trashedFile) throws Exception {
+ assertTrue(trashedFile.createNewFile());
+
+ final ContentResolver cr = getContentResolver();
+ final Uri trashedFileUri = MediaStore.scanFile(cr, trashedFile);
+ assertNotNull(trashedFileUri);
+
+ trashFile(trashedFileUri);
+ return trashedFileUri;
+ }
+
+ private void trashFile(Uri uri) throws Exception {
+ final ContentValues values = new ContentValues();
+ values.put(MediaStore.MediaColumns.IS_TRASHED, 1);
+ assertEquals(1, getContentResolver().update(uri, values, Bundle.EMPTY));
+ }
+
+ /**
+ * Gets file path corresponding to the db row pointed by {@code uri}. If {@code uri} points to
+ * multiple db rows, file path is extracted from the first db row of the database query result.
+ */
+ private String getFilePathFromUri(Uri uri) {
+ final String[] projection = new String[] {MediaStore.MediaColumns.DATA};
+ try (Cursor c = getContentResolver().query(uri, projection, null, null)) {
+ assertTrue(c.moveToFirst());
+ return c.getString(0);
+ }
+ }
+
+ private boolean isMediaTypeImageOrVideo(File file) {
+ return queryImageFile(file).getCount() == 1 || queryVideoFile(file).getCount() == 1;
+ }
+
+ private static void assertIsMediaTypeImage(File file) {
+ final Cursor c = queryImageFile(file);
+ assertEquals(1, c.getCount());
+ }
+
+ private static void assertNotMediaTypeImage(File file) {
+ final Cursor c = queryImageFile(file);
+ assertEquals(0, c.getCount());
+ }
+
+ private static void assertCantQueryFile(File file) {
+ assertThat(getFileUri(file)).isNull();
+ // Confirm that file exists in the database.
+ assertNotNull(MediaStore.scanFile(getContentResolver(), file));
+ }
+
+ private static void assertCreateFilesAs(TestApp testApp, File... files) throws Exception {
+ for (File file : files) {
+ assertFalse("File already exists: " + file, file.exists());
+ assertTrue("Failed to create file " + file + " on behalf of "
+ + testApp.getPackageName(), createFileAs(testApp, file.getPath()));
+ }
+ }
+
+ /**
+ * Makes {@code testApp} create {@code files}. Publishes {@code files} by scanning the file.
+ * Pending files from FUSE are not visible to other apps via MediaStore APIs. We have to publish
+ * the file or make the file non-pending to make the file visible to other apps.
+ * <p>
+ * Note that this method can only be used for scannable files.
+ */
+ private static void assertCreatePublishedFilesAs(TestApp testApp, File... files)
+ throws Exception {
+ for (File file : files) {
+ assertTrue("Failed to create published file " + file + " on behalf of "
+ + testApp.getPackageName(), createFileAs(testApp, file.getPath()));
+ assertNotNull("Failed to scan " + file,
+ MediaStore.scanFile(getContentResolver(), file));
+ }
+ }
+
+
+ private static void deleteFilesAs(TestApp testApp, File... files) throws Exception {
+ for (File file : files) {
+ deleteFileAs(testApp, file.getPath());
+ }
+ }
+ private static void assertCanDeletePathsAs(TestApp testApp, String... filePaths)
+ throws Exception {
+ for (String path: filePaths) {
+ assertTrue("Failed to delete file " + path + " on behalf of "
+ + testApp.getPackageName(), deleteFileAs(testApp, path));
+ }
+ }
+
+ private static void assertCantDeletePathsAs(TestApp testApp, String... filePaths)
+ throws Exception {
+ for (String path: filePaths) {
+ assertFalse("Deleting " + path + " on behalf of " + testApp.getPackageName()
+ + " was expected to fail", deleteFileAs(testApp, path));
+ }
+ }
+
+ private void deleteFiles(File... files) {
+ for (File file: files) {
+ if (file == null) continue;
+ file.delete();
+ }
+ }
+
+ private void deletePaths(String... paths) {
+ for (String path: paths) {
+ if (path == null) continue;
+ new File(path).delete();
+ }
+ }
+
+ private static void assertCanDeletePaths(String... filePaths) {
+ for (String filePath : filePaths) {
+ assertTrue("Failed to delete " + filePath,
+ new File(filePath).delete());
+ }
+ }
+
+ /**
+ * For possible values of {@code mode}, look at {@link android.content.ContentProvider#openFile}
+ */
+ private static void assertCanQueryAndOpenFile(File file, String mode) throws IOException {
+ // This call performs the query
+ final Uri fileUri = getFileUri(file);
+ // The query succeeds iff it didn't return null
+ assertThat(fileUri).isNotNull();
+ // Now we assert that we can open the file through ContentResolver
+ try (ParcelFileDescriptor pfd =
+ getContentResolver().openFileDescriptor(fileUri, mode)) {
+ assertThat(pfd).isNotNull();
+ }
+ }
+
+ /**
+ * Assert that the last read in: read - write - read using {@code readFd} and {@code writeFd}
+ * see the last write. {@code readFd} and {@code writeFd} are fds pointing to the same
+ * underlying file on disk but may be derived from different mount points and in that case
+ * have separate VFS caches.
+ */
+ private void assertRWR(ParcelFileDescriptor readPfd, ParcelFileDescriptor writePfd)
+ throws Exception {
+ FileDescriptor readFd = readPfd.getFileDescriptor();
+ FileDescriptor writeFd = writePfd.getFileDescriptor();
+
+ byte[] readBuffer = new byte[10];
+ byte[] writeBuffer = new byte[10];
+ Arrays.fill(writeBuffer, (byte) 1);
+
+ // Write so readFd has content to read from next
+ Os.pwrite(readFd, readBuffer, 0, 10, 0);
+ // Read so readBuffer is in readFd's mount VFS cache
+ Os.pread(readFd, readBuffer, 0, 10, 0);
+
+ // Assert that readBuffer is zeroes
+ assertThat(readBuffer).isEqualTo(new byte[10]);
+
+ // Write so writeFd and readFd should now see writeBuffer
+ Os.pwrite(writeFd, writeBuffer, 0, 10, 0);
+
+ // Read so the last write can be verified on readFd
+ Os.pread(readFd, readBuffer, 0, 10, 0);
+
+ // Assert that the last write is indeed visible via readFd
+ assertThat(readBuffer).isEqualTo(writeBuffer);
+ assertThat(readPfd.getStatSize()).isEqualTo(writePfd.getStatSize());
+ }
+
+ private void assertLowerFsFd(ParcelFileDescriptor pfd) throws Exception {
+ assertThat(Os.readlink("/proc/self/fd/" + pfd.getFd()).startsWith("/storage")).isTrue();
+ }
+
+ private void assertUpperFsFd(ParcelFileDescriptor pfd) throws Exception {
+ assertThat(Os.readlink("/proc/self/fd/" + pfd.getFd()).startsWith("/mnt/user")).isTrue();
+ }
+
+ private static void assertCanCreateFile(File file) throws IOException {
+ // If the file somehow managed to survive a previous run, then the test app was uninstalled
+ // and MediaProvider will remove our its ownership of the file, so it's not guaranteed that
+ // we can create nor delete it.
+ if (!file.exists()) {
+ assertThat(file.createNewFile()).isTrue();
+ assertThat(file.delete()).isTrue();
+ } else {
+ Log.w(TAG,
+ "Couldn't assertCanCreateFile(" + file + ") because file existed prior to "
+ + "running the test!");
+ }
+ }
+
+ private static void assertAccess(File file, boolean exists, boolean canRead, boolean canWrite)
+ throws Exception {
+ assertAccess(file, exists, canRead, canWrite, true /* checkExists */);
+ }
+
+ private static void assertAccess(File file, boolean exists, boolean canRead, boolean canWrite,
+ boolean checkExists) throws Exception {
+ if (checkExists) {
+ assertThat(file.exists()).isEqualTo(exists);
+ }
+ assertThat(file.canRead()).isEqualTo(canRead);
+ assertThat(file.canWrite()).isEqualTo(canWrite);
+ if (file.isDirectory()) {
+ if (checkExists) {
+ assertThat(file.canExecute()).isEqualTo(exists);
+ }
+ } else {
+ assertThat(file.canExecute()).isFalse(); // Filesytem is mounted with MS_NOEXEC
+ }
+
+ // Test some combinations of mask.
+ assertAccess(file, R_OK, canRead);
+ assertAccess(file, W_OK, canWrite);
+ assertAccess(file, R_OK | W_OK, canRead && canWrite);
+ assertAccess(file, W_OK | F_OK, canWrite);
+
+ if (checkExists) {
+ assertAccess(file, F_OK, exists);
+ }
+ }
+
+ private static void assertAccess(File file, int mask, boolean expected) throws Exception {
+ if (expected) {
+ assertThat(Os.access(file.getAbsolutePath(), mask)).isTrue();
+ } else {
+ assertThrows(ErrnoException.class, () -> {
+ Os.access(file.getAbsolutePath(), mask);
+ });
+ }
+ }
+}
diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStoragePublicVolumeDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStoragePublicVolumeDeviceTest.java
new file mode 100644
index 0000000..8856887
--- /dev/null
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStoragePublicVolumeDeviceTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.scopedstorage.cts.device;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.scopedstorage.cts.lib.TestUtils;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+
+/**
+ * Test suite to run ScopedStorageDeviceTest on a public volume.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ScopedStoragePublicVolumeDeviceTest extends ScopedStorageDeviceTest {
+
+ @BeforeClass
+ public static void createPublicVolume() throws Exception {
+ ScopedStorageDeviceTest.createPublicVolume();
+ }
+
+ @AfterClass
+ public static void resetDefaultVolume() throws Exception {
+ TestUtils.resetDefaultExternalStorageVolume();
+ }
+
+ @Before
+ public void setup() throws Exception {
+ String volumeName = TestUtils.getPublicVolumeName();
+ assertThat(volumeName).isNotNull();
+ TestUtils.setExternalStorageVolume(volumeName);
+ TestUtils.assertDefaultVolumeIsPublic();
+ super.setup();
+ }
+}
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/BaseHostTestCase.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/BaseHostTestCase.java
new file mode 100644
index 0000000..983cc66
--- /dev/null
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/BaseHostTestCase.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.scopedstorage.cts.host;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.device.NativeDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+abstract class BaseHostTestCase extends BaseHostJUnit4Test {
+ private int mCurrentUserId = NativeDevice.INVALID_USER_ID;
+
+ protected String executeShellCommand(String cmd, Object... args) throws Exception {
+ return getDevice().executeShellCommand(String.format(cmd, args));
+ }
+
+ protected int getCurrentUserId() throws Exception {
+ setCurrentUserId();
+
+ return mCurrentUserId;
+ }
+
+ private void setCurrentUserId() throws Exception {
+ if (mCurrentUserId != NativeDevice.INVALID_USER_ID) return;
+
+ ITestDevice device = getDevice();
+ mCurrentUserId = device.getCurrentUser();
+ CLog.i("Current user: %d");
+ }
+}
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
index 8729f9b..c44060f 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
@@ -18,12 +18,9 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertTrue;
-
import android.platform.test.annotations.AppModeFull;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import org.junit.After;
import org.junit.Before;
@@ -35,20 +32,17 @@
*/
@RunWith(DeviceJUnit4ClassRunner.class)
@AppModeFull
-public class LegacyStorageHostTest extends BaseHostJUnit4Test {
- private boolean isExternalStorageSetup = false;
+public class LegacyStorageHostTest extends BaseHostTestCase {
- private String executeShellCommand(String cmd) throws Exception {
- return getDevice().executeShellCommand(cmd);
- }
+ private boolean mIsExternalStorageSetup;
/**
* Runs the given phase of LegacyFileAccessTest by calling into the device.
* Throws an exception if the test phase fails.
*/
void runDeviceTest(String phase) throws Exception {
- assertTrue(runDeviceTests("android.scopedstorage.cts.legacy",
- "android.scopedstorage.cts.legacy.LegacyStorageTest", phase));
+ assertThat(runDeviceTests("android.scopedstorage.cts.legacy",
+ "android.scopedstorage.cts.legacy.LegacyStorageTest", phase)).isTrue();
}
/**
@@ -56,14 +50,18 @@
* so in order to test a case where the reader has only WRITE, we must explicitly revoke READ.
*/
private void grantPermissions(String... perms) throws Exception {
+ int currentUserId = getCurrentUserId();
for (String perm : perms) {
- executeShellCommand("pm grant android.scopedstorage.cts.legacy " + perm);
+ executeShellCommand("pm grant --user %d android.scopedstorage.cts.legacy %s",
+ currentUserId, perm);
}
}
private void revokePermissions(String... perms) throws Exception {
+ int currentUserId = getCurrentUserId();
for (String perm : perms) {
- executeShellCommand("pm revoke android.scopedstorage.cts.legacy " + perm);
+ executeShellCommand("pm revoke --user %d android.scopedstorage.cts.legacy %s",
+ currentUserId, perm);
}
}
@@ -72,14 +70,14 @@
* creating file.
*/
private void createFileAsShell(String filePath) throws Exception {
- executeShellCommand("touch " + filePath);
+ executeShellCommand("touch %s", filePath);
assertThat(getDevice().doesFileExist(filePath)).isTrue();
}
private void setupExternalStorage() throws Exception {
- if (!isExternalStorageSetup) {
+ if (!mIsExternalStorageSetup) {
runDeviceTest("setupExternalStorage");
- isExternalStorageSetup = true;
+ mIsExternalStorageSetup = true;
}
}
@@ -199,4 +197,25 @@
public void testInsertWithUnsupportedMimeType() throws Exception {
runDeviceTest("testInsertWithUnsupportedMimeType");
}
+
+ @Test
+ public void testLegacySystemGalleryCanRenameImagesAndVideosWithoutDbUpdates() throws Exception {
+ runDeviceTest("testLegacySystemGalleryCanRenameImagesAndVideosWithoutDbUpdates");
+ }
+
+ @Test
+ public void testLegacySystemGalleryWithoutWESCannotRename() throws Exception {
+ revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+ runDeviceTest("testLegacySystemGalleryWithoutWESCannotRename");
+ }
+
+ @Test
+ public void testLegacyWESCanRenameImagesAndVideosWithDbUpdates_hasW() throws Exception {
+ runDeviceTest("testLegacyWESCanRenameImagesAndVideosWithDbUpdates_hasW");
+ }
+
+ @Test
+ public void testScanUpdatesMetadataForNewlyAddedFile_hasRW() throws Exception {
+ runDeviceTest("testScanUpdatesMetadataForNewlyAddedFile_hasRW");
+ }
}
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeCoreHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeCoreHostTest.java
new file mode 100644
index 0000000..e92217d
--- /dev/null
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeCoreHostTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.scopedstorage.cts.host;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tradefed.device.ITestDevice;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+
+public class PublicVolumeCoreHostTest extends ScopedStorageCoreHostTest {
+ /* Used to clean up the virtual volume after the test */
+ private static ITestDevice sDevice = null;
+ private boolean mIsPublicVolumeSetup = false;
+ String executeShellCommand(String cmd) throws Exception {
+ return getDevice().executeShellCommand(cmd);
+ }
+
+ private void setupNewPublicVolume() throws Exception {
+ if (!mIsPublicVolumeSetup) {
+ assertTrue(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.PublicVolumeTestHelper", "setupNewPublicVolume"));
+ mIsPublicVolumeSetup = true;
+ }
+ }
+
+ private void setupDevice() {
+ if (sDevice == null) {
+ sDevice = getDevice();
+ }
+ }
+
+ /**
+ * Runs the given phase of PublicVolumeTest by calling into the device.
+ * Throws an exception if the test phase fails.
+ */
+ @Override
+ void runDeviceTest(String phase) throws Exception {
+ assertTrue(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.PublicVolumeTest", phase));
+ }
+
+ @Before
+ public void setup() throws Exception {
+ setupDevice();
+ setupNewPublicVolume();
+ super.setup();
+ }
+
+ @AfterClass
+ public static void deletePublicVolumes() throws Exception {
+ if (sDevice != null) {
+ sDevice.executeShellCommand("sm set-virtual-disk false");
+ }
+ }
+}
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeHostTest.java
index dbfa9fb..256540a 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeHostTest.java
@@ -16,7 +16,7 @@
package android.scopedstorage.cts.host;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import com.android.tradefed.device.ITestDevice;
@@ -25,16 +25,14 @@
public class PublicVolumeHostTest extends ScopedStorageHostTest {
/** Used to clean up the virtual volume after the test */
- private static ITestDevice sDevice = null;
- private boolean mIsPublicVolumeSetup = false;
- String executeShellCommand(String cmd) throws Exception {
- return getDevice().executeShellCommand(cmd);
- }
+ private static ITestDevice sDevice;
+ private boolean mIsPublicVolumeSetup;
private void setupNewPublicVolume() throws Exception {
if (!mIsPublicVolumeSetup) {
- assertTrue(runDeviceTests("android.scopedstorage.cts",
- "android.scopedstorage.cts.PublicVolumeTestHelper", "setupNewPublicVolume"));
+ assertThat(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.PublicVolumeTestHelper", "setupNewPublicVolume"))
+ .isTrue();
mIsPublicVolumeSetup = true;
}
}
@@ -51,8 +49,8 @@
*/
@Override
void runDeviceTest(String phase) throws Exception {
- assertTrue(runDeviceTests("android.scopedstorage.cts",
- "android.scopedstorage.cts.PublicVolumeTest", phase));
+ assertThat(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.PublicVolumeTest", phase)).isTrue();
}
@Before
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeLegacyHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeLegacyHostTest.java
index c9bd65f..4b38df1 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeLegacyHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeLegacyHostTest.java
@@ -16,7 +16,7 @@
package android.scopedstorage.cts.host;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -33,8 +33,9 @@
private void setupNewPublicVolume() throws Exception {
if (!mIsPublicVolumeSetup) {
- assertTrue(runDeviceTests("android.scopedstorage.cts",
- "android.scopedstorage.cts.PublicVolumeTestHelper", "setupNewPublicVolume"));
+ assertThat(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.PublicVolumeTestHelper", "setupNewPublicVolume"))
+ .isTrue();
mIsPublicVolumeSetup = true;
}
}
@@ -51,8 +52,8 @@
*/
@Override
void runDeviceTest(String phase) throws Exception {
- assertTrue(runDeviceTests("android.scopedstorage.cts.legacy",
- "android.scopedstorage.cts.legacy.PublicVolumeLegacyTest", phase));
+ assertThat(runDeviceTests("android.scopedstorage.cts.legacy",
+ "android.scopedstorage.cts.legacy.PublicVolumeLegacyTest", phase)).isTrue();
}
@Before
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageCoreHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageCoreHostTest.java
new file mode 100644
index 0000000..b38c193
--- /dev/null
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageCoreHostTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.scopedstorage.cts.host;
+
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.AppModeFull;
+
+import com.android.tradefed.device.contentprovider.ContentProviderHandler;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Runs the core ScopedStorageTest tests.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+@AppModeFull
+public class ScopedStorageCoreHostTest extends BaseHostTestCase {
+ private boolean mIsExternalStorageSetup = false;
+
+ private ContentProviderHandler mContentProviderHandler;
+
+ /**
+ * Runs the given phase of ScopedStorageTest by calling into the device.
+ * Throws an exception if the test phase fails.
+ */
+ void runDeviceTest(String phase) throws Exception {
+ assertTrue(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.ScopedStorageTest", phase));
+
+ }
+
+ private void setupExternalStorage() throws Exception {
+ if (!mIsExternalStorageSetup) {
+ runDeviceTest("setupExternalStorage");
+ mIsExternalStorageSetup = true;
+ }
+ }
+
+ @Before
+ public void setup() throws Exception {
+ // Set up content provider. This would install android.tradefed.contentprovider
+ // which is used to create and delete files/Dir on device side test.
+ mContentProviderHandler = new ContentProviderHandler(getDevice());
+ mContentProviderHandler.setUp();
+
+ setupExternalStorage();
+ executeShellCommand("mkdir /sdcard/Android/data/com.android.shell -m 2770");
+ executeShellCommand("mkdir /sdcard/Android/data/com.android.shell/files -m 2770");
+ }
+
+ @Before
+ public void revokeStoragePermissions() throws Exception {
+ revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE",
+ "android.permission.READ_EXTERNAL_STORAGE");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mContentProviderHandler.tearDown();
+ executeShellCommand("rm -r /sdcard/Android/data/com.android.shell");
+ }
+
+ @Test
+ public void testManageExternalStorageCanCreateFilesAnywhere() throws Exception {
+ allowAppOps("android:manage_external_storage");
+ try {
+ runDeviceTest("testManageExternalStorageCanCreateFilesAnywhere");
+ } finally {
+ denyAppOps("android:manage_external_storage");
+ }
+ }
+
+ @Test
+ public void testManageExternalStorageReaddir() throws Exception {
+ allowAppOps("android:manage_external_storage");
+ try {
+ runDeviceTest("testManageExternalStorageReaddir");
+ } finally {
+ denyAppOps("android:manage_external_storage");
+ }
+ }
+
+ @Test
+ public void testAccess_file() throws Exception {
+ grantPermissions("android.permission.READ_EXTERNAL_STORAGE");
+ try {
+ runDeviceTest("testAccess_file");
+ } finally {
+ revokePermissions("android.permission.READ_EXTERNAL_STORAGE");
+ }
+ }
+
+ @Test
+ public void testAccess_directory() throws Exception {
+ grantPermissions("android.permission.READ_EXTERNAL_STORAGE",
+ "android.permission.WRITE_EXTERNAL_STORAGE");
+ try {
+ runDeviceTest("testAccess_directory");
+ } finally {
+ revokePermissions("android.permission.READ_EXTERNAL_STORAGE",
+ "android.permission.WRITE_EXTERNAL_STORAGE");
+ }
+ }
+
+ private void grantPermissions(String... perms) throws Exception {
+ int currentUserId = getCurrentUserId();
+ for (String perm : perms) {
+ executeShellCommand("pm grant --user %d android.scopedstorage.cts %s",
+ currentUserId, perm);
+ }
+ }
+
+ private void revokePermissions(String... perms) throws Exception {
+ int currentUserId = getCurrentUserId();
+ for (String perm : perms) {
+ executeShellCommand("pm revoke --user %d android.scopedstorage.cts %s",
+ currentUserId, perm);
+ }
+ }
+
+ private void allowAppOps(String... ops) throws Exception {
+ for (String op : ops) {
+ executeShellCommand("cmd appops set --uid android.scopedstorage.cts %s allow", op);
+ }
+ }
+
+ private void denyAppOps(String... ops) throws Exception {
+ for (String op : ops) {
+ executeShellCommand("cmd appops set --uid android.scopedstorage.cts %s deny", op);
+ }
+ }
+}
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
index b20342c..41ffe8e 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
@@ -16,13 +16,13 @@
package android.scopedstorage.cts.host;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import android.platform.test.annotations.AppModeFull;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.device.contentprovider.ContentProviderHandler;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
import org.junit.After;
@@ -35,17 +35,18 @@
*/
@RunWith(DeviceJUnit4ClassRunner.class)
@AppModeFull
-public class ScopedStorageHostTest extends BaseHostJUnit4Test {
- private boolean mIsExternalStorageSetup = false;
+public class ScopedStorageHostTest extends BaseHostTestCase {
+ private boolean mIsExternalStorageSetup;
+
+ private ContentProviderHandler mContentProviderHandler;
/**
* Runs the given phase of ScopedStorageTest by calling into the device.
* Throws an exception if the test phase fails.
*/
void runDeviceTest(String phase) throws Exception {
- assertTrue(runDeviceTests("android.scopedstorage.cts",
- "android.scopedstorage.cts.ScopedStorageTest", phase));
-
+ assertThat(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.ScopedStorageTest", phase)).isTrue();
}
/**
@@ -61,10 +62,6 @@
.setDisableIsolatedStorage(true));
}
- String executeShellCommand(String cmd) throws Exception {
- return getDevice().executeShellCommand(cmd);
- }
-
private void setupExternalStorage() throws Exception {
if (!mIsExternalStorageSetup) {
runDeviceTest("setupExternalStorage");
@@ -74,6 +71,11 @@
@Before
public void setup() throws Exception {
+ // Set up content provider. This would install android.tradefed.contentprovider
+ // which is used to create and delete files/Dir on device side test.
+ mContentProviderHandler = new ContentProviderHandler(getDevice());
+ mContentProviderHandler.setUp();
+
setupExternalStorage();
executeShellCommand("mkdir /sdcard/Android/data/com.android.shell -m 2770");
executeShellCommand("mkdir /sdcard/Android/data/com.android.shell/files -m 2770");
@@ -87,78 +89,10 @@
@After
public void tearDown() throws Exception {
+ mContentProviderHandler.tearDown();
executeShellCommand("rm -r /sdcard/Android/data/com.android.shell");
}
- @Test
- public void testTypePathConformity() throws Exception {
- runDeviceTest("testTypePathConformity");
- }
-
- @Test
- public void testCreateFileInAppExternalDir() throws Exception {
- runDeviceTest("testCreateFileInAppExternalDir");
- }
-
- @Test
- public void testCreateFileInOtherAppExternalDir() throws Exception {
- runDeviceTest("testCreateFileInOtherAppExternalDir");
- }
-
- @Test
- public void testReadWriteFilesInOtherAppExternalDir() throws Exception {
- runDeviceTest("testReadWriteFilesInOtherAppExternalDir");
- }
-
- @Test
- public void testContributeMediaFile() throws Exception {
- runDeviceTest("testContributeMediaFile");
- }
-
- @Test
- public void testCreateAndDeleteEmptyDir() throws Exception {
- runDeviceTest("testCreateAndDeleteEmptyDir");
- }
-
- @Test
- public void testCantDeleteOtherAppsContents() throws Exception {
- runDeviceTest("testCantDeleteOtherAppsContents");
- }
-
- @Test
- public void testDeleteAlreadyUnlinkedFile() throws Exception {
- runDeviceTest("testDeleteAlreadyUnlinkedFile");
-
- }
- @Test
- public void testOpendirRestrictions() throws Exception {
- runDeviceTest("testOpendirRestrictions");
- }
-
- @Test
- public void testLowLevelFileIO() throws Exception {
- runDeviceTest("testLowLevelFileIO");
- }
-
- @Test
- public void testListDirectoriesWithMediaFiles() throws Exception {
- runDeviceTest("testListDirectoriesWithMediaFiles");
- }
-
- @Test
- public void testListDirectoriesWithNonMediaFiles() throws Exception {
- runDeviceTest("testListDirectoriesWithNonMediaFiles");
- }
-
- @Test
- public void testListFilesFromExternalFilesDirectory() throws Exception {
- runDeviceTest("testListFilesFromExternalFilesDirectory");
- }
-
- @Test
- public void testListFilesFromExternalMediaDirectory() throws Exception {
- runDeviceTest("testListFilesFromExternalMediaDirectory");
- }
@Test
public void testListUnsupportedFileType() throws Exception {
@@ -166,107 +100,8 @@
}
@Test
- public void testMetaDataRedaction() throws Exception {
- runDeviceTest("testMetaDataRedaction");
- }
-
- @Test
- public void testVfsCacheConsistency() throws Exception {
- runDeviceTest("testOpenFilePathFirstWriteContentResolver");
- runDeviceTest("testOpenContentResolverFirstWriteContentResolver");
- runDeviceTest("testOpenFilePathFirstWriteFilePath");
- runDeviceTest("testOpenContentResolverFirstWriteFilePath");
- runDeviceTest("testOpenContentResolverWriteOnly");
- runDeviceTest("testOpenContentResolverDup");
- runDeviceTest("testContentResolverDelete");
- runDeviceTest("testContentResolverUpdate");
- runDeviceTest("testOpenContentResolverClose");
- }
-
- @Test
- public void testCaseInsensitivity() throws Exception {
- runDeviceTest("testCreateLowerCaseDeleteUpperCase");
- runDeviceTest("testCreateUpperCaseDeleteLowerCase");
- runDeviceTest("testCreateMixedCaseDeleteDifferentMixedCase");
- runDeviceTest("testAndroidDataObbDoesNotForgetMount");
- runDeviceTest("testCacheConsistencyForCaseInsensitivity");
- }
-
- @Test
- public void testCallingIdentityCacheInvalidation() throws Exception {
- // General IO access
- runDeviceTest("testReadStorageInvalidation");
- runDeviceTest("testWriteStorageInvalidation");
- // File manager access
- runDeviceTest("testManageStorageInvalidation");
- // Default gallery
- runDeviceTest("testWriteImagesInvalidation");
- runDeviceTest("testWriteVideoInvalidation");
- // EXIF access
- runDeviceTest("testAccessMediaLocationInvalidation");
-
- runDeviceTest("testAppUpdateInvalidation");
- runDeviceTest("testAppReinstallInvalidation");
- }
-
- @Test
- public void testRenameFile() throws Exception {
- runDeviceTest("testRenameFile");
- }
-
- @Test
- public void testRenameFileType() throws Exception {
- runDeviceTest("testRenameFileType");
- }
-
- @Test
- public void testRenameAndReplaceFile() throws Exception {
- runDeviceTest("testRenameAndReplaceFile");
- }
-
- @Test
- public void testRenameFileNotOwned() throws Exception {
- runDeviceTest("testRenameFileNotOwned");
- }
-
- @Test
- public void testRenameDirectory() throws Exception {
- runDeviceTest("testRenameDirectory");
- }
-
- @Test
- public void testRenameDirectoryNotOwned() throws Exception {
- runDeviceTest("testRenameDirectoryNotOwned");
- }
-
- @Test
- public void testRenameEmptyDirectory() throws Exception {
- runDeviceTest("testRenameEmptyDirectory");
- }
-
- @Test
- public void testSystemGalleryAppHasFullAccessToImages() throws Exception {
- runDeviceTest("testSystemGalleryAppHasFullAccessToImages");
- }
-
- @Test
- public void testSystemGalleryAppHasNoFullAccessToAudio() throws Exception {
- runDeviceTest("testSystemGalleryAppHasNoFullAccessToAudio");
- }
-
- @Test
- public void testSystemGalleryCanRenameImagesAndVideos() throws Exception {
- runDeviceTest("testSystemGalleryCanRenameImagesAndVideos");
- }
-
- @Test
- public void testManageExternalStorageCanCreateFilesAnywhere() throws Exception {
- allowAppOps("android:manage_external_storage");
- try {
- runDeviceTest("testManageExternalStorageCanCreateFilesAnywhere");
- } finally {
- denyAppOps("android:manage_external_storage");
- }
+ public void testCantRenameToTopLevelDirectory() throws Exception {
+ runDeviceTest("testCantRenameToTopLevelDirectory");
}
@Test
@@ -280,16 +115,6 @@
}
@Test
- public void testManageExternalStorageReaddir() throws Exception {
- allowAppOps("android:manage_external_storage");
- try {
- runDeviceTest("testManageExternalStorageReaddir");
- } finally {
- denyAppOps("android:manage_external_storage");
- }
- }
-
- @Test
public void testManageExternalStorageCanRenameOtherAppsContents() throws Exception {
allowAppOps("android:manage_external_storage");
try {
@@ -310,51 +135,6 @@
}
@Test
- public void testCantAccessOtherAppsContents() throws Exception {
- runDeviceTest("testCantAccessOtherAppsContents");
- }
-
- @Test
- public void testCanCreateHiddenFile() throws Exception {
- runDeviceTest("testCanCreateHiddenFile");
- }
-
- @Test
- public void testCanRenameHiddenFile() throws Exception {
- runDeviceTest("testCanRenameHiddenFile");
- }
-
- @Test
- public void testHiddenDirectory() throws Exception {
- runDeviceTest("testHiddenDirectory");
- }
-
- @Test
- public void testHiddenDirectory_nomedia() throws Exception {
- runDeviceTest("testHiddenDirectory_nomedia");
- }
-
- @Test
- public void testListHiddenFile() throws Exception {
- runDeviceTest("testListHiddenFile");
- }
-
- @Test
- public void testOpenPendingAndTrashed() throws Exception {
- runDeviceTest("testOpenPendingAndTrashed");
- }
-
- @Test
- public void testDeletePendingAndTrashed() throws Exception {
- runDeviceTest("testDeletePendingAndTrashed");
- }
-
- @Test
- public void testListPendingAndTrashed() throws Exception {
- runDeviceTest("testListPendingAndTrashed");
- }
-
- @Test
public void testCanCreateDefaultDirectory() throws Exception {
runDeviceTest("testCanCreateDefaultDirectory");
}
@@ -370,38 +150,13 @@
}
@Test
- public void testSystemGalleryQueryOtherAppsFiles() throws Exception {
- runDeviceTest("testSystemGalleryQueryOtherAppsFiles");
- }
-
- @Test
- public void testQueryOtherAppsFiles() throws Exception {
- runDeviceTest("testQueryOtherAppsFiles");
- }
-
- @Test
- public void testSystemGalleryCanRenameImageAndVideoDirs() throws Exception {
- runDeviceTest("testSystemGalleryCanRenameImageAndVideoDirs");
- }
-
- @Test
- public void testCreateCanRestoreDeletedRowId() throws Exception {
- runDeviceTest("testCreateCanRestoreDeletedRowId");
- }
-
- @Test
- public void testRenameCanRestoreDeletedRowId() throws Exception {
- runDeviceTest("testRenameCanRestoreDeletedRowId");
- }
-
- @Test
- public void testCantCreateOrRenameFileWithInvalidName() throws Exception {
- runDeviceTest("testCantCreateOrRenameFileWithInvalidName");
- }
-
- @Test
- public void testPendingFromFuse() throws Exception {
- runDeviceTest("testPendingFromFuse");
+ public void testManageExternalStorageDoesntSkipScanningDirtyNomediaDir() throws Exception {
+ allowAppOps("android:manage_external_storage");
+ try {
+ runDeviceTest("testManageExternalStorageDoesntSkipScanningDirtyNomediaDir");
+ } finally {
+ denyAppOps("android:manage_external_storage");
+ }
}
@Test
@@ -415,33 +170,6 @@
}
@Test
- public void testCantSetAttrOtherAppsFile() throws Exception {
- runDeviceTest("testCantSetAttrOtherAppsFile");
- }
-
- @Test
- public void testAccess_file() throws Exception {
- grantPermissions("android.permission.READ_EXTERNAL_STORAGE");
- try {
- runDeviceTest("testAccess_file");
- } finally {
- revokePermissions("android.permission.READ_EXTERNAL_STORAGE");
- }
- }
-
- @Test
- public void testAccess_directory() throws Exception {
- grantPermissions("android.permission.READ_EXTERNAL_STORAGE",
- "android.permission.WRITE_EXTERNAL_STORAGE");
- try {
- runDeviceTest("testAccess_directory");
- } finally {
- revokePermissions("android.permission.READ_EXTERNAL_STORAGE",
- "android.permission.WRITE_EXTERNAL_STORAGE");
- }
- }
-
- @Test
public void testAndroidMedia() throws Exception {
grantPermissions("android.permission.READ_EXTERNAL_STORAGE");
try {
@@ -488,11 +216,6 @@
"testNoIsolatedStorageCantReadWriteOtherAppExternalDir");
runDeviceTestWithDisabledIsolatedStorage("testNoIsolatedStorageStorageReaddir");
runDeviceTestWithDisabledIsolatedStorage("testNoIsolatedStorageQueryOtherAppsFile");
-
- // Check that appop is revoked after instrumentation is over.
- runDeviceTest("testCreateFileInAppExternalDir");
- runDeviceTest("testCreateFileInOtherAppExternalDir");
- runDeviceTest("testReadWriteFilesInOtherAppExternalDir");
}
@Test
@@ -511,15 +234,29 @@
}
}
+ @Test
+ public void testClearPackageData() throws Exception {
+ grantPermissions("android.permission.READ_EXTERNAL_STORAGE");
+ try {
+ runDeviceTest("testClearPackageData");
+ } finally {
+ revokePermissions("android.permission.READ_EXTERNAL_STORAGE");
+ }
+ }
+
private void grantPermissions(String... perms) throws Exception {
+ int currentUserId = getCurrentUserId();
for (String perm : perms) {
- executeShellCommand("pm grant android.scopedstorage.cts " + perm);
+ executeShellCommand("pm grant --user %d android.scopedstorage.cts %s",
+ currentUserId, perm);
}
}
private void revokePermissions(String... perms) throws Exception {
+ int currentUserId = getCurrentUserId();
for (String perm : perms) {
- executeShellCommand("pm revoke android.scopedstorage.cts " + perm);
+ executeShellCommand("pm revoke --user %d android.scopedstorage.cts %s",
+ currentUserId, perm);
}
}
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageInstantAppHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageInstantAppHostTest.java
index c97b41f..50fd029 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageInstantAppHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageInstantAppHostTest.java
@@ -16,12 +16,11 @@
package android.scopedstorage.cts.host;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import android.platform.test.annotations.AppModeInstant;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -30,14 +29,14 @@
* Runs the ScopedStorageTest tests for an instant app.
*/
@RunWith(DeviceJUnit4ClassRunner.class)
-public class ScopedStorageInstantAppHostTest extends BaseHostJUnit4Test {
+public class ScopedStorageInstantAppHostTest extends BaseHostTestCase {
/**
* Runs the given phase of Test by calling into the device.
* Throws an exception if the test phase fails.
*/
protected void runDeviceTest(String phase) throws Exception {
- assertTrue(runDeviceTests("android.scopedstorage.cts",
- "android.scopedstorage.cts.ScopedStorageTest", phase));
+ assertThat(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.ScopedStorageTest", phase)).isTrue();
}
@Test
diff --git a/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java b/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
index 4596cab..214ba01 100644
--- a/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
+++ b/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
@@ -20,30 +20,35 @@
import static android.scopedstorage.cts.lib.TestUtils.BYTES_DATA2;
import static android.scopedstorage.cts.lib.TestUtils.STR_DATA1;
import static android.scopedstorage.cts.lib.TestUtils.STR_DATA2;
+import static android.scopedstorage.cts.lib.TestUtils.allowAppOpsToUid;
import static android.scopedstorage.cts.lib.TestUtils.assertCanRenameDirectory;
import static android.scopedstorage.cts.lib.TestUtils.assertCanRenameFile;
import static android.scopedstorage.cts.lib.TestUtils.assertCantRenameFile;
import static android.scopedstorage.cts.lib.TestUtils.assertDirectoryContains;
import static android.scopedstorage.cts.lib.TestUtils.assertFileContent;
+import static android.scopedstorage.cts.lib.TestUtils.canOpenFileAs;
import static android.scopedstorage.cts.lib.TestUtils.createFileAs;
import static android.scopedstorage.cts.lib.TestUtils.createImageEntryAs;
import static android.scopedstorage.cts.lib.TestUtils.deleteFileAsNoThrow;
import static android.scopedstorage.cts.lib.TestUtils.deleteWithMediaProviderNoThrow;
+import static android.scopedstorage.cts.lib.TestUtils.denyAppOpsToUid;
import static android.scopedstorage.cts.lib.TestUtils.executeShellCommand;
import static android.scopedstorage.cts.lib.TestUtils.getContentResolver;
+import static android.scopedstorage.cts.lib.TestUtils.getDcimDir;
import static android.scopedstorage.cts.lib.TestUtils.getFileOwnerPackageFromDatabase;
import static android.scopedstorage.cts.lib.TestUtils.getFileRowIdFromDatabase;
import static android.scopedstorage.cts.lib.TestUtils.getImageContentUri;
+import static android.scopedstorage.cts.lib.TestUtils.getPicturesDir;
import static android.scopedstorage.cts.lib.TestUtils.installApp;
import static android.scopedstorage.cts.lib.TestUtils.listAs;
-import static android.scopedstorage.cts.lib.TestUtils.openFileAs;
-import static android.scopedstorage.cts.lib.TestUtils.openWithMediaProvider;
import static android.scopedstorage.cts.lib.TestUtils.pollForExternalStorageState;
import static android.scopedstorage.cts.lib.TestUtils.pollForPermission;
import static android.scopedstorage.cts.lib.TestUtils.setupDefaultDirectories;
import static android.scopedstorage.cts.lib.TestUtils.uninstallApp;
import static android.scopedstorage.cts.lib.TestUtils.uninstallAppNoThrow;
+import static androidx.test.InstrumentationRegistry.getContext;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -53,13 +58,15 @@
import static org.junit.Assert.fail;
import android.Manifest;
+import android.app.AppOpsManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
-import android.os.ParcelFileDescriptor;
+import android.os.FileUtils;
+import android.os.Process;
import android.provider.MediaStore;
import android.scopedstorage.cts.lib.TestUtils;
import android.system.ErrnoException;
@@ -84,6 +91,7 @@
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
@@ -117,6 +125,9 @@
private static final TestApp TEST_APP_A = new TestApp("TestAppA",
"android.scopedstorage.cts.testapp.A", 1, false, "CtsScopedStorageTestAppA.apk");
+ private static final String[] SYSTEM_GALERY_APPOPS = {
+ AppOpsManager.OPSTR_WRITE_MEDIA_IMAGES, AppOpsManager.OPSTR_WRITE_MEDIA_VIDEO};
+
/**
* This method needs to be called once before running the whole test.
*/
@@ -274,7 +285,7 @@
// can open file for read
FileDescriptor fd = null;
try {
- executeShellCommand("touch " + existingFile);
+ executeShellCommand("touch %s", existingFile);
MediaStore.scanFile(getContentResolver(), existingFile);
fd = Os.open(existingFile.getPath(), OsConstants.O_RDONLY, /*mode*/ 0);
} finally {
@@ -704,8 +715,8 @@
// We have transferred ownership away from TEST_APP_A so reads / writes
// should no longer work.
- assertThat(openFileAs(TEST_APP_A, fullPath, false /* for write */)).isFalse();
- assertThat(openFileAs(TEST_APP_A, fullPath, false /* for read */)).isFalse();
+ assertThat(canOpenFileAs(TEST_APP_A, fullPath, false /* for write */)).isFalse();
+ assertThat(canOpenFileAs(TEST_APP_A, fullPath, false /* for read */)).isFalse();
} finally {
deleteFileAsNoThrow(TEST_APP_A, fullPath.getAbsolutePath());
uninstallAppNoThrow(TEST_APP_A);
@@ -764,6 +775,137 @@
}
}
+ @Test
+ public void testLegacySystemGalleryCanRenameImagesAndVideosWithoutDbUpdates() throws Exception {
+ pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ true);
+
+ final File otherAppVideoFile = new File(getDcimDir(), "other_" + VIDEO_FILE_NAME);
+ final File videoFile = new File(getPicturesDir(), VIDEO_FILE_NAME);
+
+ try {
+ installApp(TEST_APP_A);
+
+ try {
+ allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+
+ // Create and write some data to the file
+ assertThat(createFileAs(TEST_APP_A, otherAppVideoFile.getPath())).isTrue();
+ try (final FileOutputStream fos = new FileOutputStream(otherAppVideoFile)) {
+ fos.write(BYTES_DATA1);
+ }
+
+ // Assert legacy system gallery can rename the file.
+ assertCanRenameFile(otherAppVideoFile, videoFile, false /* checkDatabase */);
+ assertFileContent(videoFile, BYTES_DATA1);
+ // Database was not updated.
+ assertThat(getFileRowIdFromDatabase(otherAppVideoFile)).isNotEqualTo(-1);
+ assertThat(getFileRowIdFromDatabase(videoFile)).isEqualTo(-1);
+ }
+ finally {
+ otherAppVideoFile.delete();
+ videoFile.delete();
+ denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+ }
+ } finally {
+ uninstallAppNoThrow(TEST_APP_A);
+ }
+ }
+
+ @Test
+ public void testLegacySystemGalleryWithoutWESCannotRename() throws Exception {
+ pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ false);
+
+ final File otherAppVideoFile = new File(getDcimDir(), "other_" + VIDEO_FILE_NAME);
+ final File videoFile = new File(getPicturesDir(), VIDEO_FILE_NAME);
+
+ try {
+ installApp(TEST_APP_A);
+
+ try {
+ allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+
+ // Create file of other app.
+ assertThat(createFileAs(TEST_APP_A, otherAppVideoFile.getPath())).isTrue();
+
+ // Check we cannot rename it.
+ assertThat(otherAppVideoFile.renameTo(videoFile)).isFalse();
+ }
+ finally {
+ otherAppVideoFile.delete();
+ videoFile.delete();
+ denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+ }
+ } finally {
+ uninstallAppNoThrow(TEST_APP_A);
+ }
+ }
+
+ @Test
+ public void testLegacyWESCanRenameImagesAndVideosWithDbUpdates_hasW() throws Exception {
+ pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ true);
+
+ final File otherAppVideoFile = new File(getDcimDir(), "other_" + VIDEO_FILE_NAME);
+ final File videoFile = new File(getPicturesDir(), VIDEO_FILE_NAME);
+
+ try {
+ installApp(TEST_APP_A);
+ // Create and write some data to the file
+ assertThat(createFileAs(TEST_APP_A, otherAppVideoFile.getPath())).isTrue();
+ try (final FileOutputStream fos = new FileOutputStream(otherAppVideoFile)) {
+ fos.write(BYTES_DATA1);
+ }
+
+ // Assert legacy WES can rename the file (including database updated).
+ assertCanRenameFile(otherAppVideoFile, videoFile);
+ assertFileContent(videoFile, BYTES_DATA1);
+ } finally {
+ otherAppVideoFile.delete();
+ videoFile.delete();
+ uninstallAppNoThrow(TEST_APP_A);
+ }
+ }
+
+ @Test
+ public void testScanUpdatesMetadataForNewlyAddedFile_hasRW() throws Exception {
+ pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /*granted*/ true);
+ pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ true);
+
+ final File jpgFile = new File(getPicturesDir(), IMAGE_FILE_NAME);
+ try {
+ // Copy the image content to jpgFile
+ try (InputStream in =
+ getContext().getResources().openRawResource(R.raw.img_with_metadata);
+ FileOutputStream out = new FileOutputStream(jpgFile)) {
+ FileUtils.copy(in, out);
+ out.getFD().sync();
+ }
+ // Insert a new row for jpgFile.
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.MediaColumns.DATA, jpgFile.getAbsolutePath());
+ final Uri targetUri =
+ getContentResolver().insert(getImageContentUri(), values, Bundle.EMPTY);
+ assertNotNull(targetUri);
+
+ try (Cursor c = TestUtils.queryFile(jpgFile, MediaStore.MediaColumns.DATE_TAKEN)) {
+ // Since the file is not yet scanned, no metadata is available
+ assertThat(c.moveToFirst()).isTrue();
+ assertThat(c.getString(0)).isNull();
+ }
+
+ // Scan the file to update the metadata. This scan shouldn't no-op
+ final Uri scanUri = MediaStore.scanFile(getContentResolver(), jpgFile);
+ assertNotNull(scanUri);
+
+ // ScanFile was able to update the metadata hence we should see DATE_TAKEN value.
+ try (Cursor c = TestUtils.queryFile(jpgFile, MediaStore.MediaColumns.DATE_TAKEN)) {
+ assertThat(c.moveToFirst()).isTrue();
+ assertThat(c.getString(0)).isNotNull();
+ }
+ } finally {
+ jpgFile.delete();
+ }
+ }
+
private static void assertCanCreateFile(File file) throws IOException {
if (file.exists()) {
file.delete();
diff --git a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/Android.bp b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/Android.bp
index be2ae44..5e59439 100644
--- a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/Android.bp
+++ b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/Android.bp
@@ -15,6 +15,11 @@
java_library {
name: "cts-scopedstorage-lib",
srcs: ["src/**/*.java"],
- static_libs: ["androidx.test.rules", "cts-install-lib", "platform-test-annotations",],
+ static_libs: [
+ "androidx.test.rules",
+ "cts-install-lib",
+ "platform-test-annotations",
+ "androidx.legacy_legacy-support-v4"
+ ],
sdk_version: "test_current"
}
diff --git a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
index 9237046..54084d3 100644
--- a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
+++ b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
@@ -62,7 +62,6 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
@@ -83,11 +82,16 @@
public static final String QUERY_TYPE = "android.scopedstorage.cts.queryType";
public static final String INTENT_EXTRA_PATH = "android.scopedstorage.cts.path";
+ public static final String INTENT_EXTRA_CALLING_PKG = "android.scopedstorage.cts.calling_pkg";
public static final String INTENT_EXCEPTION = "android.scopedstorage.cts.exception";
public static final String CREATE_FILE_QUERY = "android.scopedstorage.cts.createfile";
public static final String CREATE_IMAGE_ENTRY_QUERY =
"android.scopedstorage.cts.createimageentry";
public static final String DELETE_FILE_QUERY = "android.scopedstorage.cts.deletefile";
+ public static final String CAN_OPEN_FILE_FOR_READ_QUERY =
+ "android.scopedstorage.cts.can_openfile_read";
+ public static final String CAN_OPEN_FILE_FOR_WRITE_QUERY =
+ "android.scopedstorage.cts.can_openfile_write";
public static final String OPEN_FILE_FOR_READ_QUERY =
"android.scopedstorage.cts.openfile_read";
public static final String OPEN_FILE_FOR_WRITE_QUERY =
@@ -120,6 +124,7 @@
public static void setupDefaultDirectories() {
for (File dir : getDefaultTopLevelDirs()) {
dir.mkdir();
+ assertThat(dir.exists()).isTrue();
}
}
@@ -170,7 +175,8 @@
/**
* Executes a shell command.
*/
- public static String executeShellCommand(String command) throws IOException {
+ public static String executeShellCommand(String pattern, Object...args) throws IOException {
+ String command = String.format(pattern, args);
int attempt = 0;
while (attempt++ < 5) {
try {
@@ -267,9 +273,10 @@
*
* <p>This method drops shell permission identity.
*/
- public static boolean openFileAs(TestApp testApp, File file, boolean forWrite)
+ public static boolean canOpenFileAs(TestApp testApp, File file, boolean forWrite)
throws Exception {
- return openFileAs(testApp, file.getAbsolutePath(), forWrite);
+ String actionName = forWrite ? CAN_OPEN_FILE_FOR_WRITE_QUERY : CAN_OPEN_FILE_FOR_READ_QUERY;
+ return getResultFromTestApp(testApp, file.getPath(), actionName);
}
/**
@@ -277,10 +284,11 @@
*
* <p>This method drops shell permission identity.
*/
- public static boolean openFileAs(TestApp testApp, String path, boolean forWrite)
+ public static ParcelFileDescriptor openFileAs(TestApp testApp, File file, boolean forWrite)
throws Exception {
- return getResultFromTestApp(
- testApp, path, forWrite ? OPEN_FILE_FOR_WRITE_QUERY : OPEN_FILE_FOR_READ_QUERY);
+ String actionName = forWrite ? OPEN_FILE_FOR_WRITE_QUERY : OPEN_FILE_FOR_READ_QUERY;
+ String mode = forWrite ? "rw" : "r";
+ return getPfdFromTestApp(testApp, file, actionName, mode);
}
/**
@@ -317,7 +325,7 @@
final String packageName = testApp.getPackageName();
uiAutomation.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES);
- if (InstallUtils.getInstalledVersion(packageName) != -1) {
+ if (isAppInstalled(testApp)) {
Uninstall.packages(packageName);
}
Install.single(testApp).commit();
@@ -330,6 +338,10 @@
}
}
+ public static boolean isAppInstalled(TestApp testApp) {
+ return InstallUtils.getInstalledVersion(testApp.getPackageName()) != -1;
+ }
+
/**
* Uninstalls a {@link TestApp}.
*/
@@ -566,6 +578,29 @@
}
/**
+ * Opens the given file via file path
+ */
+ @NonNull
+ public static ParcelFileDescriptor openWithFilePath(File file, boolean forWrite)
+ throws IOException {
+ return ParcelFileDescriptor.open(file,
+ forWrite
+ ? ParcelFileDescriptor.MODE_READ_WRITE : ParcelFileDescriptor.MODE_READ_ONLY);
+ }
+
+ /**
+ * Returns whether we can open the file.
+ */
+ public static boolean canOpen(File file, boolean forWrite) {
+ try {
+ openWithFilePath(file, forWrite);
+ return true;
+ } catch (IOException expected) {
+ return false;
+ }
+ }
+
+ /**
* Asserts the given operation throws an exception of type {@code T}.
*/
public static <T extends Exception> void assertThrows(Class<T> clazz, Operation<Exception> r)
@@ -680,25 +715,6 @@
}
/**
- * Returns whether we can open the file.
- */
- public static boolean canOpen(File file, boolean forWrite) {
- if (forWrite) {
- try (FileOutputStream fis = new FileOutputStream(file)) {
- return true;
- } catch (IOException expected) {
- return false;
- }
- } else {
- try (FileInputStream fis = new FileInputStream(file)) {
- return true;
- } catch (IOException expected) {
- return false;
- }
- }
- }
-
- /**
* Polls for external storage to be mounted.
*/
public static void pollForExternalStorageState() throws Exception {
@@ -775,6 +791,20 @@
}
/**
+ * Asserts the default volume used in helper methods is the primary volume.
+ */
+ public static void assertDefaultVolumeIsPrimary() {
+ assertVolumeType(true /* isPrimary */);
+ }
+
+ /**
+ * Asserts the default volume used in helper methods is a public volume.
+ */
+ public static void assertDefaultVolumeIsPublic() {
+ assertVolumeType(false /* isPrimary */);
+ }
+
+ /**
* Creates and returns the Android data sub-directory belonging to the calling package.
*/
public static File getExternalFilesDir() {
@@ -913,7 +943,9 @@
uiAutomation.adoptShellPermissionIdentity(Manifest.permission.FORCE_STOP_PACKAGES);
getContext().getSystemService(ActivityManager.class).forceStopPackage(packageName);
- Thread.sleep(1000);
+ pollForCondition(() -> {
+ return !isProcessRunning(packageName);
+ }, "Timed out while waiting for " + packageName + " to be stopped");
} finally {
uiAutomation.dropShellPermissionIdentity();
}
@@ -938,6 +970,7 @@
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(QUERY_TYPE, actionName);
intent.putExtra(INTENT_EXTRA_PATH, dirPath);
+ intent.putExtra(INTENT_EXTRA_CALLING_PKG, getContext().getPackageName());
intent.addCategory(Intent.CATEGORY_LAUNCHER);
getContext().startActivity(intent);
if (!latch.await(POLLING_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
@@ -955,28 +988,8 @@
*/
private static HashMap<String, String> getMetadataFromTestApp(
TestApp testApp, String dirPath, String actionName) throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
- final HashMap<String, String> appOutputList = new HashMap<>();
- final Exception[] exception = new Exception[1];
- exception[0] = null;
- final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.hasExtra(INTENT_EXCEPTION)) {
- exception[0] = (Exception) (intent.getExtras().get(INTENT_EXCEPTION));
- } else if (intent.hasExtra(actionName)) {
- HashMap<String, String> res =
- (HashMap<String, String>) intent.getExtras().get(actionName);
- appOutputList.putAll(res);
- }
- latch.countDown();
- }
- };
- sendIntentToTestApp(testApp, dirPath, actionName, broadcastReceiver, latch);
- if (exception[0] != null) {
- throw exception[0];
- }
- return appOutputList;
+ Bundle bundle = getFromTestApp(testApp, dirPath, actionName);
+ return (HashMap<String, String>) bundle.get(actionName);
}
/**
@@ -984,27 +997,8 @@
*/
private static ArrayList<String> getContentsFromTestApp(
TestApp testApp, String dirPath, String actionName) throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
- final ArrayList<String> appOutputList = new ArrayList<String>();
- final Exception[] exception = new Exception[1];
- exception[0] = null;
- final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.hasExtra(INTENT_EXCEPTION)) {
- exception[0] = (Exception) (intent.getSerializableExtra(INTENT_EXCEPTION));
- } else if (intent.hasExtra(actionName)) {
- appOutputList.addAll(intent.getStringArrayListExtra(actionName));
- }
- latch.countDown();
- }
- };
-
- sendIntentToTestApp(testApp, dirPath, actionName, broadcastReceiver, latch);
- if (exception[0] != null) {
- throw exception[0];
- }
- return appOutputList;
+ Bundle bundle = getFromTestApp(testApp, dirPath, actionName);
+ return bundle.getStringArrayList(actionName);
}
/**
@@ -1012,8 +1006,23 @@
*/
private static boolean getResultFromTestApp(TestApp testApp, String dirPath, String actionName)
throws Exception {
+ Bundle bundle = getFromTestApp(testApp, dirPath, actionName);
+ return bundle.getBoolean(actionName, false);
+ }
+
+ private static ParcelFileDescriptor getPfdFromTestApp(TestApp testApp, File dirPath,
+ String actionName, String mode) throws Exception {
+ Bundle bundle = getFromTestApp(testApp, dirPath.getPath(), actionName);
+ return getContentResolver().openFileDescriptor(bundle.getParcelable(actionName), mode);
+ }
+
+ /**
+ * <p>This method drops shell permission identity.
+ */
+ private static Bundle getFromTestApp(TestApp testApp, String dirPath, String actionName)
+ throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
- final boolean[] appOutput = new boolean[1];
+ final Bundle[] bundle = new Bundle[1];
final Exception[] exception = new Exception[1];
exception[0] = null;
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@@ -1021,8 +1030,8 @@
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra(INTENT_EXCEPTION)) {
exception[0] = (Exception) (intent.getSerializableExtra(INTENT_EXCEPTION));
- } else if (intent.hasExtra(actionName)) {
- appOutput[0] = intent.getBooleanExtra(actionName, false);
+ } else {
+ bundle[0] = intent.getExtras();
}
latch.countDown();
}
@@ -1032,7 +1041,7 @@
if (exception[0] != null) {
throw exception[0];
}
- return appOutput[0];
+ return bundle[0];
}
/**
@@ -1109,19 +1118,22 @@
}
/**
- * Gets the name of the public volume.
+ * Gets the name of the public volume, waiting for a bit for it to be available.
*/
public static String getPublicVolumeName() throws Exception {
final String[] volName = new String[1];
pollForCondition(() -> {
- volName[0] = getPublicVolumeNameInternal();
+ volName[0] = getCurrentPublicVolumeName();
return volName[0] != null;
}, "Timed out while waiting for public volume to be ready");
return volName[0];
}
- private static String getPublicVolumeNameInternal() {
+ /**
+ * @return the currently mounted public volume, if any.
+ */
+ public static String getCurrentPublicVolumeName() {
final String[] allVolumeDetails;
try {
allVolumeDetails = executeShellCommand("sm list-volumes")
@@ -1169,4 +1181,25 @@
() -> Environment.isExternalStorageManager(),
"Timed out while waiting for MANAGE_EXTERNAL_STORAGE");
}
+
+ private static void assertVolumeType(boolean isPrimary) {
+ String[] parts = getExternalFilesDir().getAbsolutePath().split("/");
+ assertThat(parts.length).isAtLeast(3);
+ assertThat(parts[1]).isEqualTo("storage");
+ if (isPrimary) {
+ assertThat(parts[2]).isEqualTo("emulated");
+ } else {
+ assertThat(parts[2]).isNotEqualTo("emulated");
+ }
+ }
+
+ private static boolean isProcessRunning(String packageName) {
+ try {
+ return getContext().getSystemService(
+ ActivityManager.class).getRunningAppProcesses().stream().anyMatch(
+ p -> packageName.equals(p.processName));
+ } catch (Exception e) {
+ return false;
+ }
+ }
}
diff --git a/hostsidetests/scopedstorage/res/xml/file_paths.xml b/hostsidetests/scopedstorage/res/xml/file_paths.xml
new file mode 100644
index 0000000..2d5ccaf
--- /dev/null
+++ b/hostsidetests/scopedstorage/res/xml/file_paths.xml
@@ -0,0 +1,3 @@
+<external-paths xmlns:android="http://schemas.android.com/apk/res/android">
+ <external-path name="external_files" path="."/>
+</external-paths>
diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
index abf72f0..b8bdb75 100644
--- a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
+++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
@@ -19,92 +19,61 @@
import static android.app.AppOpsManager.permissionToOp;
import static android.os.SystemProperties.getBoolean;
import static android.provider.MediaStore.MediaColumns;
-import static android.scopedstorage.cts.lib.RedactionTestHelper.assertExifMetadataMatch;
-import static android.scopedstorage.cts.lib.RedactionTestHelper.assertExifMetadataMismatch;
-import static android.scopedstorage.cts.lib.RedactionTestHelper.getExifMetadata;
-import static android.scopedstorage.cts.lib.RedactionTestHelper.getExifMetadataFromRawResource;
import static android.scopedstorage.cts.lib.TestUtils.BYTES_DATA1;
-import static android.scopedstorage.cts.lib.TestUtils.BYTES_DATA2;
-import static android.scopedstorage.cts.lib.TestUtils.STR_DATA1;
-import static android.scopedstorage.cts.lib.TestUtils.STR_DATA2;
import static android.scopedstorage.cts.lib.TestUtils.adoptShellPermissionIdentity;
import static android.scopedstorage.cts.lib.TestUtils.allowAppOpsToUid;
import static android.scopedstorage.cts.lib.TestUtils.assertCanRenameDirectory;
import static android.scopedstorage.cts.lib.TestUtils.assertCanRenameFile;
import static android.scopedstorage.cts.lib.TestUtils.assertCantRenameDirectory;
-import static android.scopedstorage.cts.lib.TestUtils.assertCantRenameFile;
import static android.scopedstorage.cts.lib.TestUtils.assertDirectoryContains;
import static android.scopedstorage.cts.lib.TestUtils.assertFileContent;
import static android.scopedstorage.cts.lib.TestUtils.assertThrows;
import static android.scopedstorage.cts.lib.TestUtils.canOpen;
+import static android.scopedstorage.cts.lib.TestUtils.canOpenFileAs;
import static android.scopedstorage.cts.lib.TestUtils.canReadAndWriteAs;
import static android.scopedstorage.cts.lib.TestUtils.createFileAs;
import static android.scopedstorage.cts.lib.TestUtils.deleteFileAs;
import static android.scopedstorage.cts.lib.TestUtils.deleteFileAsNoThrow;
-import static android.scopedstorage.cts.lib.TestUtils.deleteRecursively;
-import static android.scopedstorage.cts.lib.TestUtils.deleteWithMediaProvider;
import static android.scopedstorage.cts.lib.TestUtils.deleteWithMediaProviderNoThrow;
import static android.scopedstorage.cts.lib.TestUtils.denyAppOpsToUid;
import static android.scopedstorage.cts.lib.TestUtils.dropShellPermissionIdentity;
import static android.scopedstorage.cts.lib.TestUtils.executeShellCommand;
-import static android.scopedstorage.cts.lib.TestUtils.getAlarmsDir;
-import static android.scopedstorage.cts.lib.TestUtils.getAndroidDataDir;
import static android.scopedstorage.cts.lib.TestUtils.getAndroidDir;
import static android.scopedstorage.cts.lib.TestUtils.getAndroidMediaDir;
-import static android.scopedstorage.cts.lib.TestUtils.getAudiobooksDir;
import static android.scopedstorage.cts.lib.TestUtils.getContentResolver;
import static android.scopedstorage.cts.lib.TestUtils.getDcimDir;
import static android.scopedstorage.cts.lib.TestUtils.getDefaultTopLevelDirs;
-import static android.scopedstorage.cts.lib.TestUtils.getDocumentsDir;
import static android.scopedstorage.cts.lib.TestUtils.getDownloadDir;
import static android.scopedstorage.cts.lib.TestUtils.getExternalFilesDir;
import static android.scopedstorage.cts.lib.TestUtils.getExternalMediaDir;
import static android.scopedstorage.cts.lib.TestUtils.getExternalStorageDir;
-import static android.scopedstorage.cts.lib.TestUtils.getFileMimeTypeFromDatabase;
import static android.scopedstorage.cts.lib.TestUtils.getFileOwnerPackageFromDatabase;
import static android.scopedstorage.cts.lib.TestUtils.getFileRowIdFromDatabase;
-import static android.scopedstorage.cts.lib.TestUtils.getFileSizeFromDatabase;
import static android.scopedstorage.cts.lib.TestUtils.getFileUri;
+import static android.scopedstorage.cts.lib.TestUtils.getImageContentUri;
import static android.scopedstorage.cts.lib.TestUtils.getMoviesDir;
import static android.scopedstorage.cts.lib.TestUtils.getMusicDir;
-import static android.scopedstorage.cts.lib.TestUtils.getNotificationsDir;
import static android.scopedstorage.cts.lib.TestUtils.getPicturesDir;
import static android.scopedstorage.cts.lib.TestUtils.getPodcastsDir;
-import static android.scopedstorage.cts.lib.TestUtils.getRingtonesDir;
-import static android.scopedstorage.cts.lib.TestUtils.grantPermission;
import static android.scopedstorage.cts.lib.TestUtils.installApp;
import static android.scopedstorage.cts.lib.TestUtils.installAppWithStoragePermissions;
import static android.scopedstorage.cts.lib.TestUtils.listAs;
-import static android.scopedstorage.cts.lib.TestUtils.openFileAs;
import static android.scopedstorage.cts.lib.TestUtils.openWithMediaProvider;
import static android.scopedstorage.cts.lib.TestUtils.pollForExternalStorageState;
import static android.scopedstorage.cts.lib.TestUtils.pollForManageExternalStorageAllowed;
import static android.scopedstorage.cts.lib.TestUtils.pollForPermission;
-import static android.scopedstorage.cts.lib.TestUtils.queryFile;
-import static android.scopedstorage.cts.lib.TestUtils.queryFileExcludingPending;
import static android.scopedstorage.cts.lib.TestUtils.queryImageFile;
import static android.scopedstorage.cts.lib.TestUtils.queryVideoFile;
-import static android.scopedstorage.cts.lib.TestUtils.readExifMetadataFromTestApp;
-import static android.scopedstorage.cts.lib.TestUtils.revokePermission;
-import static android.scopedstorage.cts.lib.TestUtils.setAttrAs;
import static android.scopedstorage.cts.lib.TestUtils.setupDefaultDirectories;
import static android.scopedstorage.cts.lib.TestUtils.uninstallApp;
import static android.scopedstorage.cts.lib.TestUtils.uninstallAppNoThrow;
-import static android.scopedstorage.cts.lib.TestUtils.updateDisplayNameWithMediaProvider;
import static android.system.OsConstants.F_OK;
-import static android.system.OsConstants.O_APPEND;
-import static android.system.OsConstants.O_CREAT;
-import static android.system.OsConstants.O_EXCL;
-import static android.system.OsConstants.O_RDWR;
-import static android.system.OsConstants.O_TRUNC;
import static android.system.OsConstants.R_OK;
-import static android.system.OsConstants.S_IRWXU;
import static android.system.OsConstants.W_OK;
import static androidx.test.InstrumentationRegistry.getContext;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -122,24 +91,17 @@
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Environment;
-import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
-import android.os.Process;
import android.platform.test.annotations.AppModeInstant;
import android.provider.MediaStore;
import android.system.ErrnoException;
import android.system.Os;
-import android.system.StructStat;
import android.util.Log;
-import androidx.annotation.Nullable;
import androidx.test.runner.AndroidJUnit4;
import com.android.cts.install.lib.TestApp;
-import com.google.common.io.Files;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -149,11 +111,8 @@
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
/**
@@ -164,7 +123,9 @@
@RunWith(AndroidJUnit4.class)
public class ScopedStorageTest {
static final String TAG = "ScopedStorageTest";
+ static final String CONTENT_PROVIDER_URL = "content://android.tradefed.contentprovider";
static final String THIS_PACKAGE_NAME = getContext().getPackageName();
+ static final int USER_SYSTEM = 0;
/**
* To help avoid flaky tests, give ourselves a unique nonce to be used for
@@ -217,547 +178,6 @@
}
/**
- * Test that we enforce certain media types can only be created in certain directories.
- */
- @Test
- public void testTypePathConformity() throws Exception {
- final File dcimDir = getDcimDir();
- final File documentsDir = getDocumentsDir();
- final File downloadDir = getDownloadDir();
- final File moviesDir = getMoviesDir();
- final File musicDir = getMusicDir();
- final File picturesDir = getPicturesDir();
- // Only audio files can be created in Music
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(musicDir, NONMEDIA_FILE_NAME).createNewFile(); });
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(musicDir, VIDEO_FILE_NAME).createNewFile(); });
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(musicDir, IMAGE_FILE_NAME).createNewFile(); });
- // Only video files can be created in Movies
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(moviesDir, NONMEDIA_FILE_NAME).createNewFile(); });
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(moviesDir, AUDIO_FILE_NAME).createNewFile(); });
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(moviesDir, IMAGE_FILE_NAME).createNewFile(); });
- // Only image and video files can be created in DCIM
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(dcimDir, NONMEDIA_FILE_NAME).createNewFile(); });
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(dcimDir, AUDIO_FILE_NAME).createNewFile(); });
- // Only image and video files can be created in Pictures
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(picturesDir, NONMEDIA_FILE_NAME).createNewFile(); });
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(picturesDir, AUDIO_FILE_NAME).createNewFile(); });
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(picturesDir, PLAYLIST_FILE_NAME).createNewFile(); });
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(dcimDir, SUBTITLE_FILE_NAME).createNewFile(); });
-
- assertCanCreateFile(new File(getAlarmsDir(), AUDIO_FILE_NAME));
- assertCanCreateFile(new File(getAudiobooksDir(), AUDIO_FILE_NAME));
- assertCanCreateFile(new File(dcimDir, IMAGE_FILE_NAME));
- assertCanCreateFile(new File(dcimDir, VIDEO_FILE_NAME));
- assertCanCreateFile(new File(documentsDir, AUDIO_FILE_NAME));
- assertCanCreateFile(new File(documentsDir, IMAGE_FILE_NAME));
- assertCanCreateFile(new File(documentsDir, NONMEDIA_FILE_NAME));
- assertCanCreateFile(new File(documentsDir, VIDEO_FILE_NAME));
- assertCanCreateFile(new File(downloadDir, AUDIO_FILE_NAME));
- assertCanCreateFile(new File(downloadDir, IMAGE_FILE_NAME));
- assertCanCreateFile(new File(downloadDir, NONMEDIA_FILE_NAME));
- assertCanCreateFile(new File(downloadDir, VIDEO_FILE_NAME));
- assertCanCreateFile(new File(moviesDir, VIDEO_FILE_NAME));
- assertCanCreateFile(new File(moviesDir, SUBTITLE_FILE_NAME));
- assertCanCreateFile(new File(musicDir, AUDIO_FILE_NAME));
- assertCanCreateFile(new File(musicDir, PLAYLIST_FILE_NAME));
- assertCanCreateFile(new File(getNotificationsDir(), AUDIO_FILE_NAME));
- assertCanCreateFile(new File(picturesDir, IMAGE_FILE_NAME));
- assertCanCreateFile(new File(picturesDir, VIDEO_FILE_NAME));
- assertCanCreateFile(new File(getPodcastsDir(), AUDIO_FILE_NAME));
- assertCanCreateFile(new File(getRingtonesDir(), AUDIO_FILE_NAME));
-
- // No file whatsoever can be created in the top level directory
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(getExternalStorageDir(), NONMEDIA_FILE_NAME).createNewFile(); });
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(getExternalStorageDir(), AUDIO_FILE_NAME).createNewFile(); });
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(getExternalStorageDir(), IMAGE_FILE_NAME).createNewFile(); });
- assertThrows(IOException.class, "Operation not permitted",
- () -> { new File(getExternalStorageDir(), VIDEO_FILE_NAME).createNewFile(); });
- }
-
- /**
- * Test that we can create a file in app's external files directory,
- * and that we can write and read to/from the file.
- */
- @Test
- public void testCreateFileInAppExternalDir() throws Exception {
- final File file = new File(getExternalFilesDir(), "text.txt");
- try {
- assertThat(file.createNewFile()).isTrue();
- assertThat(file.delete()).isTrue();
- // Ensure the file is properly deleted and can be created again
- assertThat(file.createNewFile()).isTrue();
-
- // Write to file
- try (final FileOutputStream fos = new FileOutputStream(file)) {
- fos.write(BYTES_DATA1);
- }
-
- // Read the same data from file
- assertFileContent(file, BYTES_DATA1);
- } finally {
- file.delete();
- }
- }
-
- /**
- * Test that we can't create a file in another app's external files directory,
- * and that we'll get the same error regardless of whether the app exists or not.
- */
- @Test
- public void testCreateFileInOtherAppExternalDir() throws Exception {
- // Creating a file in a non existent package dir should return ENOENT, as expected
- final File nonexistentPackageFileDir = new File(
- getExternalFilesDir().getPath().replace(THIS_PACKAGE_NAME, "no.such.package"));
- final File file1 = new File(nonexistentPackageFileDir, NONMEDIA_FILE_NAME);
- assertThrows(
- IOException.class, FILE_CREATION_ERROR_MESSAGE, () -> { file1.createNewFile(); });
-
- // Creating a file in an existent package dir should give the same error string to avoid
- // leaking installed app names, and we know the following directory exists because shell
- // mkdirs it in test setup
- final File shellPackageFileDir = new File(
- getExternalFilesDir().getPath().replace(THIS_PACKAGE_NAME, "com.android.shell"));
- final File file2 = new File(shellPackageFileDir, NONMEDIA_FILE_NAME);
- assertThrows(
- IOException.class, FILE_CREATION_ERROR_MESSAGE, () -> { file1.createNewFile(); });
- }
-
- /**
- * Test that apps can't read/write files in another app's external files directory,
- * and can do so in their own app's external file directory.
- */
- @Test
- public void testReadWriteFilesInOtherAppExternalDir() throws Exception {
- final File videoFile = new File(getExternalFilesDir(), VIDEO_FILE_NAME);
-
- try {
- // Create a file in app's external files directory
- if (!videoFile.exists()) {
- assertThat(videoFile.createNewFile()).isTrue();
- }
-
- // Install TEST_APP_A with READ_EXTERNAL_STORAGE permission.
- installAppWithStoragePermissions(TEST_APP_A);
-
- // TEST_APP_A should not be able to read/write to other app's external files directory.
- assertThat(openFileAs(TEST_APP_A, videoFile.getPath(), false /* forWrite */)).isFalse();
- assertThat(openFileAs(TEST_APP_A, videoFile.getPath(), true /* forWrite */)).isFalse();
- // TEST_APP_A should not be able to delete files in other app's external files
- // directory.
- assertThat(deleteFileAs(TEST_APP_A, videoFile.getPath())).isFalse();
-
- // Apps should have read/write access in their own app's external files directory.
- assertThat(canOpen(videoFile, false /* forWrite */)).isTrue();
- assertThat(canOpen(videoFile, true /* forWrite */)).isTrue();
- // Apps should be able to delete files in their own app's external files directory.
- assertThat(videoFile.delete()).isTrue();
- } finally {
- videoFile.delete();
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
-
- /**
- * Test that we can contribute media without any permissions.
- */
- @Test
- public void testContributeMediaFile() throws Exception {
- final File imageFile = new File(getDcimDir(), IMAGE_FILE_NAME);
-
- try {
- assertThat(imageFile.createNewFile()).isTrue();
-
- // Ensure that the file was successfully added to the MediaProvider database
- assertThat(getFileOwnerPackageFromDatabase(imageFile)).isEqualTo(THIS_PACKAGE_NAME);
-
- // Try to write random data to the file
- try (final FileOutputStream fos = new FileOutputStream(imageFile)) {
- fos.write(BYTES_DATA1);
- fos.write(BYTES_DATA2);
- }
-
- final byte[] expected = (STR_DATA1 + STR_DATA2).getBytes();
- assertFileContent(imageFile, expected);
-
- // Closing the file after writing will not trigger a MediaScan. Call scanFile to update
- // file's entry in MediaProvider's database.
- assertThat(MediaStore.scanFile(getContentResolver(), imageFile)).isNotNull();
-
- // Ensure that the scan was completed and the file's size was updated.
- assertThat(getFileSizeFromDatabase(imageFile)).isEqualTo(
- BYTES_DATA1.length + BYTES_DATA2.length);
- } finally {
- imageFile.delete();
- }
- // Ensure that delete makes a call to MediaProvider to remove the file from its database.
- assertThat(getFileRowIdFromDatabase(imageFile)).isEqualTo(-1);
- }
-
- @Test
- public void testCreateAndDeleteEmptyDir() throws Exception {
- final File externalFilesDir = getExternalFilesDir();
- // Remove directory in order to create it again
- externalFilesDir.delete();
-
- // Can create own external files dir
- assertThat(externalFilesDir.mkdir()).isTrue();
-
- final File dir1 = new File(externalFilesDir, "random_dir");
- // Can create dirs inside it
- assertThat(dir1.mkdir()).isTrue();
-
- final File dir2 = new File(dir1, "random_dir_inside_random_dir");
- // And create a dir inside the new dir
- assertThat(dir2.mkdir()).isTrue();
-
- // And can delete them all
- assertThat(dir2.delete()).isTrue();
- assertThat(dir1.delete()).isTrue();
- assertThat(externalFilesDir.delete()).isTrue();
-
- // Can't create external dir for other apps
- final File nonexistentPackageFileDir = new File(
- externalFilesDir.getPath().replace(THIS_PACKAGE_NAME, "no.such.package"));
- final File shellPackageFileDir = new File(
- externalFilesDir.getPath().replace(THIS_PACKAGE_NAME, "com.android.shell"));
-
- assertThat(nonexistentPackageFileDir.mkdir()).isFalse();
- assertThat(shellPackageFileDir.mkdir()).isFalse();
- }
-
- @Test
- public void testCantAccessOtherAppsContents() throws Exception {
- final File mediaFile = new File(getPicturesDir(), IMAGE_FILE_NAME);
- final File nonMediaFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
- try {
- installApp(TEST_APP_A);
-
- assertThat(createFileAs(TEST_APP_A, mediaFile.getPath())).isTrue();
- assertThat(createFileAs(TEST_APP_A, nonMediaFile.getPath())).isTrue();
-
- // We can still see that the files exist
- assertThat(mediaFile.exists()).isTrue();
- assertThat(nonMediaFile.exists()).isTrue();
-
- // But we can't access their content
- assertThat(canOpen(mediaFile, /* forWrite */ false)).isFalse();
- assertThat(canOpen(nonMediaFile, /* forWrite */ true)).isFalse();
- assertThat(canOpen(mediaFile, /* forWrite */ false)).isFalse();
- assertThat(canOpen(nonMediaFile, /* forWrite */ true)).isFalse();
- } finally {
- deleteFileAsNoThrow(TEST_APP_A, nonMediaFile.getPath());
- deleteFileAsNoThrow(TEST_APP_A, mediaFile.getPath());
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
-
- @Test
- public void testCantDeleteOtherAppsContents() throws Exception {
- final File dirInDownload = new File(getDownloadDir(), TEST_DIRECTORY_NAME);
- final File mediaFile = new File(dirInDownload, IMAGE_FILE_NAME);
- final File nonMediaFile = new File(dirInDownload, NONMEDIA_FILE_NAME);
- try {
- installApp(TEST_APP_A);
- assertThat(dirInDownload.mkdir()).isTrue();
- // Have another app create a media file in the directory
- assertThat(createFileAs(TEST_APP_A, mediaFile.getPath())).isTrue();
-
- // Can't delete the directory since it contains another app's content
- assertThat(dirInDownload.delete()).isFalse();
- // Can't delete another app's content
- assertThat(deleteRecursively(dirInDownload)).isFalse();
-
- // Have another app create a non-media file in the directory
- assertThat(createFileAs(TEST_APP_A, nonMediaFile.getPath())).isTrue();
-
- // Can't delete the directory since it contains another app's content
- assertThat(dirInDownload.delete()).isFalse();
- // Can't delete another app's content
- assertThat(deleteRecursively(dirInDownload)).isFalse();
-
- // Delete only the media file and keep the non-media file
- assertThat(deleteFileAs(TEST_APP_A, mediaFile.getPath())).isTrue();
- // Directory now has only the non-media file contributed by another app, so we still
- // can't delete it nor its content
- assertThat(dirInDownload.delete()).isFalse();
- assertThat(deleteRecursively(dirInDownload)).isFalse();
-
- // Delete the last file belonging to another app
- assertThat(deleteFileAs(TEST_APP_A, nonMediaFile.getPath())).isTrue();
- // Create our own file
- assertThat(nonMediaFile.createNewFile()).isTrue();
-
- // Now that the directory only has content that was contributed by us, we can delete it
- assertThat(deleteRecursively(dirInDownload)).isTrue();
- } finally {
- deleteFileAsNoThrow(TEST_APP_A, nonMediaFile.getPath());
- deleteFileAsNoThrow(TEST_APP_A, mediaFile.getPath());
- // At this point, we're not sure who created this file, so we'll have both apps
- // deleting it
- mediaFile.delete();
- uninstallAppNoThrow(TEST_APP_A);
- dirInDownload.delete();
- }
- }
-
- /**
- * Test that deleting uri corresponding to a file which was already deleted via filePath
- * doesn't result in a security exception.
- */
- @Test
- public void testDeleteAlreadyUnlinkedFile() throws Exception {
- final File nonMediaFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
- try {
- assertTrue(nonMediaFile.createNewFile());
- final Uri uri = MediaStore.scanFile(getContentResolver(), nonMediaFile);
- assertNotNull(uri);
-
- // Delete the file via filePath
- assertTrue(nonMediaFile.delete());
-
- // If we delete nonMediaFile with ContentResolver#delete, it shouldn't result in a
- // security exception.
- assertThat(getContentResolver().delete(uri, Bundle.EMPTY)).isEqualTo(0);
- } finally {
- nonMediaFile.delete();
- }
- }
-
- /**
- * This test relies on the fact that {@link File#list} uses opendir internally, and that it
- * returns {@code null} if opendir fails.
- */
- @Test
- public void testOpendirRestrictions() throws Exception {
- // Opening a non existent package directory should fail, as expected
- final File nonexistentPackageFileDir = new File(
- getExternalFilesDir().getPath().replace(THIS_PACKAGE_NAME, "no.such.package"));
- assertThat(nonexistentPackageFileDir.list()).isNull();
-
- // Opening another package's external directory should fail as well, even if it exists
- final File shellPackageFileDir = new File(
- getExternalFilesDir().getPath().replace(THIS_PACKAGE_NAME, "com.android.shell"));
- assertThat(shellPackageFileDir.list()).isNull();
-
- // We can open our own external files directory
- final String[] filesList = getExternalFilesDir().list();
- assertThat(filesList).isNotNull();
-
- // We can open any public directory in external storage
- assertThat(getDcimDir().list()).isNotNull();
- assertThat(getDownloadDir().list()).isNotNull();
- assertThat(getMoviesDir().list()).isNotNull();
- assertThat(getMusicDir().list()).isNotNull();
-
- // We can open the root directory of external storage
- final String[] topLevelDirs = getExternalStorageDir().list();
- assertThat(topLevelDirs).isNotNull();
- // TODO(b/145287327): This check fails on a device with no visible files.
- // This can be fixed if we display default directories.
- // assertThat(topLevelDirs).isNotEmpty();
- }
-
- @Test
- public void testLowLevelFileIO() throws Exception {
- String filePath = new File(getDownloadDir(), NONMEDIA_FILE_NAME).toString();
- try {
- int createFlags = O_CREAT | O_RDWR;
- int createExclFlags = createFlags | O_EXCL;
-
- FileDescriptor fd = Os.open(filePath, createExclFlags, S_IRWXU);
- Os.close(fd);
- assertThrows(
- ErrnoException.class, () -> { Os.open(filePath, createExclFlags, S_IRWXU); });
-
- fd = Os.open(filePath, createFlags, S_IRWXU);
- try {
- assertThat(Os.write(fd, ByteBuffer.wrap(BYTES_DATA1))).isEqualTo(BYTES_DATA1.length);
- assertFileContent(fd, BYTES_DATA1);
- } finally {
- Os.close(fd);
- }
- // should just append the data
- fd = Os.open(filePath, createFlags | O_APPEND, S_IRWXU);
- try {
- assertThat(Os.write(fd, ByteBuffer.wrap(BYTES_DATA2))).isEqualTo(BYTES_DATA2.length);
- final byte[] expected = (STR_DATA1 + STR_DATA2).getBytes();
- assertFileContent(fd, expected);
- } finally {
- Os.close(fd);
- }
- // should overwrite everything
- fd = Os.open(filePath, createFlags | O_TRUNC, S_IRWXU);
- try {
- final byte[] otherData = "this is different data".getBytes();
- assertThat(Os.write(fd, ByteBuffer.wrap(otherData))).isEqualTo(otherData.length);
- assertFileContent(fd, otherData);
- } finally {
- Os.close(fd);
- }
- } finally {
- new File(filePath).delete();
- }
- }
-
- /**
- * Test that media files from other packages are only visible to apps with storage permission.
- */
- @Test
- public void testListDirectoriesWithMediaFiles() throws Exception {
- final File dcimDir = getDcimDir();
- final File dir = new File(dcimDir, TEST_DIRECTORY_NAME);
- final File videoFile = new File(dir, VIDEO_FILE_NAME);
- final String videoFileName = videoFile.getName();
- try {
- if (!dir.exists()) {
- assertThat(dir.mkdir()).isTrue();
- }
-
- // Install TEST_APP_A and create media file in the new directory.
- installApp(TEST_APP_A);
- assertThat(createFileAs(TEST_APP_A, videoFile.getPath())).isTrue();
- // TEST_APP_A should see TEST_DIRECTORY in DCIM and new file in TEST_DIRECTORY.
- assertThat(listAs(TEST_APP_A, dcimDir.getPath())).contains(TEST_DIRECTORY_NAME);
- assertThat(listAs(TEST_APP_A, dir.getPath())).containsExactly(videoFileName);
-
- // Install TEST_APP_B with storage permission.
- installAppWithStoragePermissions(TEST_APP_B);
- // TEST_APP_B with storage permission should see TEST_DIRECTORY in DCIM and new file
- // in TEST_DIRECTORY.
- assertThat(listAs(TEST_APP_B, dcimDir.getPath())).contains(TEST_DIRECTORY_NAME);
- assertThat(listAs(TEST_APP_B, dir.getPath())).containsExactly(videoFileName);
-
- // Revoke storage permission for TEST_APP_B
- revokePermission(
- TEST_APP_B.getPackageName(), Manifest.permission.READ_EXTERNAL_STORAGE);
- // TEST_APP_B without storage permission should see TEST_DIRECTORY in DCIM and should
- // not see new file in new TEST_DIRECTORY.
- assertThat(listAs(TEST_APP_B, dcimDir.getPath())).contains(TEST_DIRECTORY_NAME);
- assertThat(listAs(TEST_APP_B, dir.getPath())).doesNotContain(videoFileName);
- } finally {
- uninstallAppNoThrow(TEST_APP_B);
- deleteFileAsNoThrow(TEST_APP_A, videoFile.getPath());
- dir.delete();
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
-
- /**
- * Test that app can't see non-media files created by other packages
- */
- @Test
- public void testListDirectoriesWithNonMediaFiles() throws Exception {
- final File downloadDir = getDownloadDir();
- final File dir = new File(downloadDir, TEST_DIRECTORY_NAME);
- final File pdfFile = new File(dir, NONMEDIA_FILE_NAME);
- final String pdfFileName = pdfFile.getName();
- try {
- if (!dir.exists()) {
- assertThat(dir.mkdir()).isTrue();
- }
-
- // Install TEST_APP_A and create non media file in the new directory.
- installApp(TEST_APP_A);
- assertThat(createFileAs(TEST_APP_A, pdfFile.getPath())).isTrue();
-
- // TEST_APP_A should see TEST_DIRECTORY in downloadDir and new non media file in
- // TEST_DIRECTORY.
- assertThat(listAs(TEST_APP_A, downloadDir.getPath())).contains(TEST_DIRECTORY_NAME);
- assertThat(listAs(TEST_APP_A, dir.getPath())).containsExactly(pdfFileName);
-
- // Install TEST_APP_B with storage permission.
- installAppWithStoragePermissions(TEST_APP_B);
- // TEST_APP_B with storage permission should see TEST_DIRECTORY in downloadDir
- // and should not see new non media file in TEST_DIRECTORY.
- assertThat(listAs(TEST_APP_B, downloadDir.getPath())).contains(TEST_DIRECTORY_NAME);
- assertThat(listAs(TEST_APP_B, dir.getPath())).doesNotContain(pdfFileName);
- } finally {
- uninstallAppNoThrow(TEST_APP_B);
- deleteFileAsNoThrow(TEST_APP_A, pdfFile.getPath());
- dir.delete();
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
-
- /**
- * Test that app can only see its directory in Android/data.
- */
- @Test
- public void testListFilesFromExternalFilesDirectory() throws Exception {
- final String packageName = THIS_PACKAGE_NAME;
- final File nonmediaFile = new File(getExternalFilesDir(), NONMEDIA_FILE_NAME);
-
- try {
- // Create a file in app's external files directory
- if (!nonmediaFile.exists()) {
- assertThat(nonmediaFile.createNewFile()).isTrue();
- }
- // App should see its directory and directories of shared packages. App should see all
- // files and directories in its external directory.
- assertDirectoryContains(nonmediaFile.getParentFile(), nonmediaFile);
-
- // Install TEST_APP_A with READ_EXTERNAL_STORAGE permission.
- // TEST_APP_A should not see other app's external files directory.
- installAppWithStoragePermissions(TEST_APP_A);
-
- assertThrows(IOException.class,
- () -> listAs(TEST_APP_A, getAndroidDataDir().getPath()));
- assertThrows(IOException.class,
- () -> listAs(TEST_APP_A, getExternalFilesDir().getPath()));
- } finally {
- nonmediaFile.delete();
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
-
- /**
- * Test that app can see files and directories in Android/media.
- */
- @Test
- public void testListFilesFromExternalMediaDirectory() throws Exception {
- final File videoFile = new File(getExternalMediaDir(), VIDEO_FILE_NAME);
-
- try {
- // Create a file in app's external media directory
- if (!videoFile.exists()) {
- assertThat(videoFile.createNewFile()).isTrue();
- }
-
- // App should see its directory and other app's external media directories with media
- // files.
- assertDirectoryContains(videoFile.getParentFile(), videoFile);
-
- // Install TEST_APP_A with READ_EXTERNAL_STORAGE permission.
- // TEST_APP_A with storage permission should see other app's external media directory.
- installAppWithStoragePermissions(TEST_APP_A);
- // Apps with READ_EXTERNAL_STORAGE can list files in other app's external media
- // directory.
- assertThat(listAs(TEST_APP_A, getAndroidMediaDir().getPath()))
- .contains(THIS_PACKAGE_NAME);
- assertThat(listAs(TEST_APP_A, getExternalMediaDir().getPath()))
- .containsExactly(videoFile.getName());
- } finally {
- videoFile.delete();
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
-
- /**
* Test that readdir lists unsupported file types in default directories.
*/
@Test
@@ -766,7 +186,7 @@
final File videoFile = new File(getMusicDir(), VIDEO_FILE_NAME);
try {
// TEST_APP_A with storage permission should not see pdf file in DCIM
- executeShellCommand("touch " + pdfFile.getAbsolutePath());
+ createFileUsingTradefedContentProvider(pdfFile);
assertThat(pdfFile.exists()).isTrue();
assertThat(MediaStore.scanFile(getContentResolver(), pdfFile)).isNotNull();
@@ -774,866 +194,44 @@
assertThat(listAs(TEST_APP_A, getDcimDir().getPath()))
.doesNotContain(NONMEDIA_FILE_NAME);
- executeShellCommand("touch " + videoFile.getAbsolutePath());
+ createFileUsingTradefedContentProvider(videoFile);
// We don't insert files to db for files created by shell.
assertThat(MediaStore.scanFile(getContentResolver(), videoFile)).isNotNull();
// TEST_APP_A with storage permission should see video file in Music directory.
assertThat(listAs(TEST_APP_A, getMusicDir().getPath())).contains(VIDEO_FILE_NAME);
} finally {
- executeShellCommand("rm " + pdfFile.getAbsolutePath());
- executeShellCommand("rm " + videoFile.getAbsolutePath());
+ deleteFileUsingTradefedContentProvider(pdfFile);
+ deleteFileUsingTradefedContentProvider(videoFile);
MediaStore.scanFile(getContentResolver(), pdfFile);
MediaStore.scanFile(getContentResolver(), videoFile);
uninstallAppNoThrow(TEST_APP_A);
}
}
- @Test
- public void testMetaDataRedaction() throws Exception {
- File jpgFile = new File(getPicturesDir(), "img_metadata.jpg");
- try {
- if (jpgFile.exists()) {
- assertThat(jpgFile.delete()).isTrue();
- }
-
- HashMap<String, String> originalExif =
- getExifMetadataFromRawResource(R.raw.img_with_metadata);
-
- try (InputStream in =
- getContext().getResources().openRawResource(R.raw.img_with_metadata);
- OutputStream out = new FileOutputStream(jpgFile)) {
- // Dump the image we have to external storage
- FileUtils.copy(in, out);
- }
-
- HashMap<String, String> exif = getExifMetadata(jpgFile);
- assertExifMetadataMatch(exif, originalExif);
-
- installAppWithStoragePermissions(TEST_APP_A);
- HashMap<String, String> exifFromTestApp =
- readExifMetadataFromTestApp(TEST_APP_A, jpgFile.getPath());
- // Other apps shouldn't have access to the same metadata without explicit permission
- assertExifMetadataMismatch(exifFromTestApp, originalExif);
-
- // TODO(b/146346138): Test that if we give TEST_APP_A write URI permission,
- // it would be able to access the metadata.
- } finally {
- jpgFile.delete();
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
-
- @Test
- public void testOpenFilePathFirstWriteContentResolver() throws Exception {
- String displayName = "open_file_path_write_content_resolver.jpg";
- File file = new File(getDcimDir(), displayName);
-
- try {
- assertThat(file.createNewFile()).isTrue();
-
- ParcelFileDescriptor readPfd =
- ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
- ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
-
- assertRWR(readPfd, writePfd);
- assertUpperFsFd(writePfd); // With cache
- } finally {
- file.delete();
- }
- }
-
- @Test
- public void testOpenContentResolverFirstWriteContentResolver() throws Exception {
- String displayName = "open_content_resolver_write_content_resolver.jpg";
- File file = new File(getDcimDir(), displayName);
-
- try {
- assertThat(file.createNewFile()).isTrue();
-
- ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
- ParcelFileDescriptor readPfd =
- ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
-
- assertRWR(readPfd, writePfd);
- assertLowerFsFd(writePfd);
- } finally {
- file.delete();
- }
- }
-
- @Test
- public void testOpenFilePathFirstWriteFilePath() throws Exception {
- String displayName = "open_file_path_write_file_path.jpg";
- File file = new File(getDcimDir(), displayName);
-
- try {
- assertThat(file.createNewFile()).isTrue();
-
- ParcelFileDescriptor writePfd =
- ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
- ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
-
- assertRWR(readPfd, writePfd);
- assertUpperFsFd(readPfd); // With cache
- } finally {
- file.delete();
- }
- }
-
- @Test
- public void testOpenContentResolverFirstWriteFilePath() throws Exception {
- String displayName = "open_content_resolver_write_file_path.jpg";
- File file = new File(getDcimDir(), displayName);
-
- try {
- assertThat(file.createNewFile()).isTrue();
-
- ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
- ParcelFileDescriptor writePfd =
- ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
-
- assertRWR(readPfd, writePfd);
- assertLowerFsFd(readPfd);
- } finally {
- file.delete();
- }
- }
-
- @Test
- public void testOpenContentResolverWriteOnly() throws Exception {
- String displayName = "open_content_resolver_write_only.jpg";
- File file = new File(getDcimDir(), displayName);
-
- try {
- assertThat(file.createNewFile()).isTrue();
-
- // We upgrade 'w' only to 'rw'
- ParcelFileDescriptor writePfd = openWithMediaProvider(file, "w");
- ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
-
- assertRWR(readPfd, writePfd);
- assertRWR(writePfd, readPfd); // Can read on 'w' only pfd
- assertLowerFsFd(writePfd);
- assertLowerFsFd(readPfd);
- } finally {
- file.delete();
- }
- }
-
- @Test
- public void testOpenContentResolverDup() throws Exception {
- String displayName = "open_content_resolver_dup.jpg";
- File file = new File(getDcimDir(), displayName);
-
- try {
- file.delete();
- assertThat(file.createNewFile()).isTrue();
-
- // Even if we close the original fd, since we have a dup open
- // the FUSE IO should still bypass the cache
- try (ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw")) {
- try (ParcelFileDescriptor writePfdDup = writePfd.dup();
- ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(
- file, ParcelFileDescriptor.MODE_READ_WRITE)) {
- writePfd.close();
-
- assertRWR(readPfd, writePfdDup);
- assertLowerFsFd(writePfdDup);
- }
- }
- } finally {
- file.delete();
- }
- }
-
- @Test
- public void testOpenContentResolverClose() throws Exception {
- String displayName = "open_content_resolver_close.jpg";
- File file = new File(getDcimDir(), displayName);
-
- try {
- byte[] readBuffer = new byte[10];
- byte[] writeBuffer = new byte[10];
- Arrays.fill(writeBuffer, (byte) 1);
-
- assertThat(file.createNewFile()).isTrue();
-
- // Lower fs open and write
- ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
- Os.pwrite(writePfd.getFileDescriptor(), writeBuffer, 0, 10, 0);
-
- // Close so upper fs open will not use direct_io
- writePfd.close();
-
- // Upper fs open and read without direct_io
- ParcelFileDescriptor readPfd =
- ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
- Os.pread(readPfd.getFileDescriptor(), readBuffer, 0, 10, 0);
-
- // Last write on lower fs is visible via upper fs
- assertThat(readBuffer).isEqualTo(writeBuffer);
- assertThat(readPfd.getStatSize()).isEqualTo(writeBuffer.length);
- } finally {
- file.delete();
- }
- }
-
- @Test
- public void testContentResolverDelete() throws Exception {
- String displayName = "content_resolver_delete.jpg";
- File file = new File(getDcimDir(), displayName);
-
- try {
- assertThat(file.createNewFile()).isTrue();
-
- deleteWithMediaProvider(file);
-
- assertThat(file.exists()).isFalse();
- assertThat(file.createNewFile()).isTrue();
- } finally {
- file.delete();
- }
- }
-
- @Test
- public void testContentResolverUpdate() throws Exception {
- String oldDisplayName = "content_resolver_update_old.jpg";
- String newDisplayName = "content_resolver_update_new.jpg";
- File oldFile = new File(getDcimDir(), oldDisplayName);
- File newFile = new File(getDcimDir(), newDisplayName);
-
- try {
- assertThat(oldFile.createNewFile()).isTrue();
- // Publish the pending oldFile before updating with MediaProvider. Not publishing the
- // file will make MP consider pending from FUSE as explicit IS_PENDING
- final Uri uri = MediaStore.scanFile(getContentResolver(), oldFile);
- assertNotNull(uri);
-
- updateDisplayNameWithMediaProvider(uri,
- Environment.DIRECTORY_DCIM, oldDisplayName, newDisplayName);
-
- assertThat(oldFile.exists()).isFalse();
- assertThat(oldFile.createNewFile()).isTrue();
- assertThat(newFile.exists()).isTrue();
- assertThat(newFile.createNewFile()).isFalse();
- } finally {
- oldFile.delete();
- newFile.delete();
- }
- }
-
- @Test
- public void testCreateLowerCaseDeleteUpperCase() throws Exception {
- File upperCase = new File(getDownloadDir(), "CREATE_LOWER_DELETE_UPPER");
- File lowerCase = new File(getDownloadDir(), "create_lower_delete_upper");
-
- createDeleteCreate(lowerCase, upperCase);
- }
-
- @Test
- public void testCreateUpperCaseDeleteLowerCase() throws Exception {
- File upperCase = new File(getDownloadDir(), "CREATE_UPPER_DELETE_LOWER");
- File lowerCase = new File(getDownloadDir(), "create_upper_delete_lower");
-
- createDeleteCreate(upperCase, lowerCase);
- }
-
- @Test
- public void testCreateMixedCaseDeleteDifferentMixedCase() throws Exception {
- File mixedCase1 = new File(getDownloadDir(), "CrEaTe_MiXeD_dElEtE_mIxEd");
- File mixedCase2 = new File(getDownloadDir(), "cReAtE_mIxEd_DeLeTe_MiXeD");
-
- createDeleteCreate(mixedCase1, mixedCase2);
- }
-
- @Test
- public void testAndroidDataObbDoesNotForgetMount() throws Exception {
- File dataDir = getContext().getExternalFilesDir(null);
- File upperCaseDataDir = new File(dataDir.getPath().replace("Android/data", "ANDROID/DATA"));
-
- File obbDir = getContext().getObbDir();
- File upperCaseObbDir = new File(obbDir.getPath().replace("Android/obb", "ANDROID/OBB"));
-
-
- StructStat beforeDataStruct = Os.stat(dataDir.getPath());
- StructStat beforeObbStruct = Os.stat(obbDir.getPath());
-
- assertThat(dataDir.exists()).isTrue();
- assertThat(upperCaseDataDir.exists()).isTrue();
- assertThat(obbDir.exists()).isTrue();
- assertThat(upperCaseObbDir.exists()).isTrue();
-
- StructStat afterDataStruct = Os.stat(upperCaseDataDir.getPath());
- StructStat afterObbStruct = Os.stat(upperCaseObbDir.getPath());
-
- assertThat(beforeDataStruct.st_dev).isEqualTo(afterDataStruct.st_dev);
- assertThat(beforeObbStruct.st_dev).isEqualTo(afterObbStruct.st_dev);
- }
-
- @Test
- public void testCacheConsistencyForCaseInsensitivity() throws Exception {
- File upperCaseFile = new File(getDownloadDir(), "CACHE_CONSISTENCY_FOR_CASE_INSENSITIVITY");
- File lowerCaseFile = new File(getDownloadDir(), "cache_consistency_for_case_insensitivity");
-
- try {
- ParcelFileDescriptor upperCasePfd =
- ParcelFileDescriptor.open(upperCaseFile,
- ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE);
- ParcelFileDescriptor lowerCasePfd =
- ParcelFileDescriptor.open(lowerCaseFile,
- ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE);
-
- assertRWR(upperCasePfd, lowerCasePfd);
- assertRWR(lowerCasePfd, upperCasePfd);
- } finally {
- upperCaseFile.delete();
- lowerCaseFile.delete();
- }
- }
-
- private void createDeleteCreate(File create, File delete) throws Exception {
- try {
- assertThat(create.createNewFile()).isTrue();
- Thread.sleep(5);
-
- assertThat(delete.delete()).isTrue();
- Thread.sleep(5);
-
- assertThat(create.createNewFile()).isTrue();
- Thread.sleep(5);
- } finally {
- create.delete();
- delete.delete();
- }
- }
-
- @Test
- public void testReadStorageInvalidation() throws Exception {
- testAppOpInvalidation(TEST_APP_C, new File(getDcimDir(), "read_storage.jpg"),
- Manifest.permission.READ_EXTERNAL_STORAGE,
- AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE, /* forWrite */ false);
- }
-
- @Test
- public void testWriteStorageInvalidation() throws Exception {
- testAppOpInvalidation(TEST_APP_C_LEGACY, new File(getDcimDir(), "write_storage.jpg"),
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- AppOpsManager.OPSTR_WRITE_EXTERNAL_STORAGE, /* forWrite */ true);
- }
-
- @Test
- public void testManageStorageInvalidation() throws Exception {
- testAppOpInvalidation(TEST_APP_C, new File(getDownloadDir(), "manage_storage.pdf"),
- /* permission */ null, OPSTR_MANAGE_EXTERNAL_STORAGE, /* forWrite */ true);
- }
-
- @Test
- public void testWriteImagesInvalidation() throws Exception {
- testAppOpInvalidation(TEST_APP_C, new File(getDcimDir(), "write_images.jpg"),
- /* permission */ null, AppOpsManager.OPSTR_WRITE_MEDIA_IMAGES, /* forWrite */ true);
- }
-
- @Test
- public void testWriteVideoInvalidation() throws Exception {
- testAppOpInvalidation(TEST_APP_C, new File(getDcimDir(), "write_video.mp4"),
- /* permission */ null, AppOpsManager.OPSTR_WRITE_MEDIA_VIDEO, /* forWrite */ true);
- }
-
- @Test
- public void testAccessMediaLocationInvalidation() throws Exception {
- File imgFile = new File(getDcimDir(), "access_media_location.jpg");
-
- try {
- // Setup image with sensitive data on external storage
- HashMap<String, String> originalExif =
- getExifMetadataFromRawResource(R.raw.img_with_metadata);
- try (InputStream in =
- getContext().getResources().openRawResource(R.raw.img_with_metadata);
- OutputStream out = new FileOutputStream(imgFile)) {
- // Dump the image we have to external storage
- FileUtils.copy(in, out);
- }
- HashMap<String, String> exif = getExifMetadata(imgFile);
- assertExifMetadataMatch(exif, originalExif);
-
- // Install test app
- installAppWithStoragePermissions(TEST_APP_C);
-
- // Grant A_M_L and verify access to sensitive data
- grantPermission(TEST_APP_C.getPackageName(), Manifest.permission.ACCESS_MEDIA_LOCATION);
- HashMap<String, String> exifFromTestApp =
- readExifMetadataFromTestApp(TEST_APP_C, imgFile.getPath());
- assertExifMetadataMatch(exifFromTestApp, originalExif);
-
- // Revoke A_M_L and verify sensitive data redaction
- revokePermission(
- TEST_APP_C.getPackageName(), Manifest.permission.ACCESS_MEDIA_LOCATION);
- exifFromTestApp = readExifMetadataFromTestApp(TEST_APP_C, imgFile.getPath());
- assertExifMetadataMismatch(exifFromTestApp, originalExif);
-
- // Re-grant A_M_L and verify access to sensitive data
- grantPermission(TEST_APP_C.getPackageName(), Manifest.permission.ACCESS_MEDIA_LOCATION);
- exifFromTestApp = readExifMetadataFromTestApp(TEST_APP_C, imgFile.getPath());
- assertExifMetadataMatch(exifFromTestApp, originalExif);
- } finally {
- imgFile.delete();
- uninstallAppNoThrow(TEST_APP_C);
- }
- }
-
- @Test
- public void testAppUpdateInvalidation() throws Exception {
- File file = new File(getDcimDir(), "app_update.jpg");
- try {
- assertThat(file.createNewFile()).isTrue();
-
- // Install legacy
- installAppWithStoragePermissions(TEST_APP_C_LEGACY);
- grantPermission(TEST_APP_C_LEGACY.getPackageName(),
- Manifest.permission.WRITE_EXTERNAL_STORAGE); // Grants write access for legacy
- // Legacy app can read and write media files contributed by others
- assertThat(openFileAs(TEST_APP_C_LEGACY, file.getPath(), /* forWrite */ false)).isTrue();
- assertThat(openFileAs(TEST_APP_C_LEGACY, file.getPath(), /* forWrite */ true)).isTrue();
-
- // Update to non-legacy
- installAppWithStoragePermissions(TEST_APP_C);
- grantPermission(TEST_APP_C_LEGACY.getPackageName(),
- Manifest.permission.WRITE_EXTERNAL_STORAGE); // No effect for non-legacy
- // Non-legacy app can read media files contributed by others
- assertThat(openFileAs(TEST_APP_C, file.getPath(), /* forWrite */ false)).isTrue();
- // But cannot write
- assertThat(openFileAs(TEST_APP_C, file.getPath(), /* forWrite */ true)).isFalse();
- } finally {
- file.delete();
- uninstallAppNoThrow(TEST_APP_C);
- }
- }
-
- @Test
- public void testAppReinstallInvalidation() throws Exception {
- File file = new File(getDcimDir(), "app_reinstall.jpg");
-
- try {
- assertThat(file.createNewFile()).isTrue();
-
- // Install
- installAppWithStoragePermissions(TEST_APP_C);
- assertThat(openFileAs(TEST_APP_C, file.getPath(), /* forWrite */ false)).isTrue();
-
- // Re-install
- uninstallAppNoThrow(TEST_APP_C);
- installApp(TEST_APP_C);
- assertThat(openFileAs(TEST_APP_C, file.getPath(), /* forWrite */ false)).isFalse();
- } finally {
- file.delete();
- uninstallAppNoThrow(TEST_APP_C);
- }
- }
-
- private void testAppOpInvalidation(TestApp app, File file, @Nullable String permission,
- String opstr, boolean forWrite) throws Exception {
- try {
- installApp(app);
- assertThat(file.createNewFile()).isTrue();
- assertAppOpInvalidation(app, file, permission, opstr, forWrite);
- } finally {
- file.delete();
- uninstallApp(app);
- }
- }
-
- /** If {@code permission} is null, appops are flipped, otherwise permissions are flipped */
- private void assertAppOpInvalidation(TestApp app, File file, @Nullable String permission,
- String opstr, boolean forWrite) throws Exception {
- String packageName = app.getPackageName();
- int uid = getContext().getPackageManager().getPackageUid(packageName, 0);
-
- // Deny
- if (permission != null) {
- revokePermission(packageName, permission);
- } else {
- denyAppOpsToUid(uid, opstr);
- }
- assertThat(openFileAs(app, file.getPath(), forWrite)).isFalse();
-
- // Grant
- if (permission != null) {
- grantPermission(packageName, permission);
- } else {
- allowAppOpsToUid(uid, opstr);
- }
- assertThat(openFileAs(app, file.getPath(), forWrite)).isTrue();
-
- // Deny
- if (permission != null) {
- revokePermission(packageName, permission);
- } else {
- denyAppOpsToUid(uid, opstr);
- }
- assertThat(openFileAs(app, file.getPath(), forWrite)).isFalse();
- }
-
- @Test
- public void testSystemGalleryAppHasFullAccessToImages() throws Exception {
- final File otherAppImageFile = new File(getDcimDir(), "other_" + IMAGE_FILE_NAME);
- final File topLevelImageFile = new File(getExternalStorageDir(), IMAGE_FILE_NAME);
- final File imageInAnObviouslyWrongPlace = new File(getMusicDir(), IMAGE_FILE_NAME);
-
- try {
- installApp(TEST_APP_A);
- allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
-
- // Have another app create an image file
- assertThat(createFileAs(TEST_APP_A, otherAppImageFile.getPath())).isTrue();
- assertThat(otherAppImageFile.exists()).isTrue();
-
- // Assert we can write to the file
- try (final FileOutputStream fos = new FileOutputStream(otherAppImageFile)) {
- fos.write(BYTES_DATA1);
- }
-
- // Assert we can read from the file
- assertFileContent(otherAppImageFile, BYTES_DATA1);
-
- // Assert we can delete the file
- assertThat(otherAppImageFile.delete()).isTrue();
- assertThat(otherAppImageFile.exists()).isFalse();
-
- // Can create an image anywhere
- assertCanCreateFile(topLevelImageFile);
- assertCanCreateFile(imageInAnObviouslyWrongPlace);
-
- // Put the file back in its place and let TEST_APP_A delete it
- assertThat(otherAppImageFile.createNewFile()).isTrue();
- } finally {
- deleteFileAsNoThrow(TEST_APP_A, otherAppImageFile.getAbsolutePath());
- otherAppImageFile.delete();
- uninstallApp(TEST_APP_A);
- denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
- }
- }
-
- @Test
- public void testSystemGalleryAppHasNoFullAccessToAudio() throws Exception {
- final File otherAppAudioFile = new File(getMusicDir(), "other_" + AUDIO_FILE_NAME);
- final File topLevelAudioFile = new File(getExternalStorageDir(), AUDIO_FILE_NAME);
- final File audioInAnObviouslyWrongPlace = new File(getPicturesDir(), AUDIO_FILE_NAME);
-
- try {
- installApp(TEST_APP_A);
- allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
-
- // Have another app create an audio file
- assertThat(createFileAs(TEST_APP_A, otherAppAudioFile.getPath())).isTrue();
- assertThat(otherAppAudioFile.exists()).isTrue();
-
- // Assert we can't access the file
- assertThat(canOpen(otherAppAudioFile, /* forWrite */ false)).isFalse();
- assertThat(canOpen(otherAppAudioFile, /* forWrite */ true)).isFalse();
-
- // Assert we can't delete the file
- assertThat(otherAppAudioFile.delete()).isFalse();
-
- // Can't create an audio file where it doesn't belong
- assertThrows(IOException.class, "Operation not permitted",
- () -> { topLevelAudioFile.createNewFile(); });
- assertThrows(IOException.class, "Operation not permitted",
- () -> { audioInAnObviouslyWrongPlace.createNewFile(); });
- } finally {
- deleteFileAs(TEST_APP_A, otherAppAudioFile.getPath());
- uninstallApp(TEST_APP_A);
- topLevelAudioFile.delete();
- audioInAnObviouslyWrongPlace.delete();
- denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
- }
- }
-
- @Test
- public void testSystemGalleryCanRenameImagesAndVideos() throws Exception {
- final File otherAppVideoFile = new File(getDcimDir(), "other_" + VIDEO_FILE_NAME);
- final File imageFile = new File(getPicturesDir(), IMAGE_FILE_NAME);
- final File videoFile = new File(getPicturesDir(), VIDEO_FILE_NAME);
- final File topLevelVideoFile = new File(getExternalStorageDir(), VIDEO_FILE_NAME);
- final File musicFile = new File(getMusicDir(), AUDIO_FILE_NAME);
- try {
- installApp(TEST_APP_A);
- allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
-
- // Have another app create a video file
- assertThat(createFileAs(TEST_APP_A, otherAppVideoFile.getPath())).isTrue();
- assertThat(otherAppVideoFile.exists()).isTrue();
-
- // Write some data to the file
- try (final FileOutputStream fos = new FileOutputStream(otherAppVideoFile)) {
- fos.write(BYTES_DATA1);
- }
- assertFileContent(otherAppVideoFile, BYTES_DATA1);
-
- // Assert we can rename the file and ensure the file has the same content
- assertCanRenameFile(otherAppVideoFile, videoFile);
- assertFileContent(videoFile, BYTES_DATA1);
- // We can even move it to the top level directory
- assertCanRenameFile(videoFile, topLevelVideoFile);
- assertFileContent(topLevelVideoFile, BYTES_DATA1);
- // And we can even convert it into an image file, because why not?
- assertCanRenameFile(topLevelVideoFile, imageFile);
- assertFileContent(imageFile, BYTES_DATA1);
-
- // We can convert it to a music file, but we won't have access to music file after
- // renaming.
- assertThat(imageFile.renameTo(musicFile)).isTrue();
- assertThat(getFileRowIdFromDatabase(musicFile)).isEqualTo(-1);
- } finally {
- deleteFileAsNoThrow(TEST_APP_A, otherAppVideoFile.getAbsolutePath());
- uninstallApp(TEST_APP_A);
- imageFile.delete();
- videoFile.delete();
- topLevelVideoFile.delete();
- executeShellCommand("rm " + musicFile.getAbsolutePath());
- MediaStore.scanFile(getContentResolver(), musicFile);
- denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
- }
- }
-
- /**
- * Test that basic file path restrictions are enforced on file rename.
+ /**
+ * Test that we don't allow renaming to top level directory
*/
@Test
- public void testRenameFile() throws Exception {
- final File downloadDir = getDownloadDir();
- final File nonMediaDir = new File(downloadDir, TEST_DIRECTORY_NAME);
- final File pdfFile1 = new File(downloadDir, NONMEDIA_FILE_NAME);
- final File pdfFile2 = new File(nonMediaDir, NONMEDIA_FILE_NAME);
- final File videoFile1 = new File(getDcimDir(), VIDEO_FILE_NAME);
- final File videoFile2 = new File(getMoviesDir(), VIDEO_FILE_NAME);
- final File videoFile3 = new File(downloadDir, VIDEO_FILE_NAME);
-
+ public void testCantRenameToTopLevelDirectory() throws Exception {
+ final File topLevelDir1 = new File(getExternalStorageDir(), TEST_DIRECTORY_NAME + "_1");
+ final File topLevelDir2 = new File(getExternalStorageDir(), TEST_DIRECTORY_NAME + "_2");
+ final File nonTopLevelDir = new File(getDcimDir(), TEST_DIRECTORY_NAME);
try {
- // Renaming non media file to media directory is not allowed.
- assertThat(pdfFile1.createNewFile()).isTrue();
- assertCantRenameFile(pdfFile1, new File(getDcimDir(), NONMEDIA_FILE_NAME));
- assertCantRenameFile(pdfFile1, new File(getMusicDir(), NONMEDIA_FILE_NAME));
- assertCantRenameFile(pdfFile1, new File(getMoviesDir(), NONMEDIA_FILE_NAME));
+ createDirUsingTradefedContentProvider(topLevelDir1);
+ assertTrue(topLevelDir1.exists());
- // Renaming non media files to non media directories is allowed.
- if (!nonMediaDir.exists()) {
- assertThat(nonMediaDir.mkdirs()).isTrue();
- }
- // App can rename pdfFile to non media directory.
- assertCanRenameFile(pdfFile1, pdfFile2);
+ // We can't rename a top level directory to a top level directory
+ assertCantRenameDirectory(topLevelDir1, topLevelDir2, null);
- assertThat(videoFile1.createNewFile()).isTrue();
- // App can rename video file to Movies directory
- assertCanRenameFile(videoFile1, videoFile2);
- // App can rename video file to Download directory
- assertCanRenameFile(videoFile2, videoFile3);
+ // However, we can rename a top level directory to non-top level directory.
+ assertCanRenameDirectory(topLevelDir1, nonTopLevelDir, null, null);
+
+ // We can't rename a non-top level directory to a top level directory.
+ assertCantRenameDirectory(nonTopLevelDir, topLevelDir2, null);
} finally {
- pdfFile1.delete();
- pdfFile2.delete();
- videoFile1.delete();
- videoFile2.delete();
- videoFile3.delete();
- nonMediaDir.delete();
- }
- }
-
- /**
- * Test that renaming file to different mime type is allowed.
- */
- @Test
- public void testRenameFileType() throws Exception {
- final File pdfFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
- final File videoFile = new File(getDcimDir(), VIDEO_FILE_NAME);
- try {
- assertThat(pdfFile.createNewFile()).isTrue();
- assertThat(videoFile.exists()).isFalse();
- // Moving pdfFile to DCIM directory is not allowed.
- assertCantRenameFile(pdfFile, new File(getDcimDir(), NONMEDIA_FILE_NAME));
- // However, moving pdfFile to DCIM directory with changing the mime type to video is
- // allowed.
- assertCanRenameFile(pdfFile, videoFile);
-
- // On rename, MediaProvider database entry for pdfFile should be updated with new
- // videoFile path and mime type should be updated to video/mp4.
- assertThat(getFileMimeTypeFromDatabase(videoFile)).isEqualTo("video/mp4");
- } finally {
- pdfFile.delete();
- videoFile.delete();
- }
- }
-
- /**
- * Test that renaming files overwrites files in newPath.
- */
- @Test
- public void testRenameAndReplaceFile() throws Exception {
- final File videoFile1 = new File(getDcimDir(), VIDEO_FILE_NAME);
- final File videoFile2 = new File(getMoviesDir(), VIDEO_FILE_NAME);
- final ContentResolver cr = getContentResolver();
- try {
- assertThat(videoFile1.createNewFile()).isTrue();
- assertThat(videoFile2.createNewFile()).isTrue();
- final Uri uriVideoFile1 = MediaStore.scanFile(cr, videoFile1);
- final Uri uriVideoFile2 = MediaStore.scanFile(cr, videoFile2);
-
- // Renaming a file which replaces file in newPath videoFile2 is allowed.
- assertCanRenameFile(videoFile1, videoFile2);
-
- // Uri of videoFile2 should be accessible after rename.
- assertThat(cr.openFileDescriptor(uriVideoFile2, "rw")).isNotNull();
- // Uri of videoFile1 should not be accessible after rename.
- assertThrows(FileNotFoundException.class,
- () -> { cr.openFileDescriptor(uriVideoFile1, "rw"); });
- } finally {
- videoFile1.delete();
- videoFile2.delete();
- }
- }
-
- /**
- * Test that app without write permission for file can't update the file.
- */
- @Test
- public void testRenameFileNotOwned() throws Exception {
- final File videoFile1 = new File(getDcimDir(), VIDEO_FILE_NAME);
- final File videoFile2 = new File(getMoviesDir(), VIDEO_FILE_NAME);
- try {
- installApp(TEST_APP_A);
- assertThat(createFileAs(TEST_APP_A, videoFile1.getAbsolutePath())).isTrue();
- // App can't rename a file owned by TEST_APP_A.
- assertCantRenameFile(videoFile1, videoFile2);
-
- assertThat(videoFile2.createNewFile()).isTrue();
- // App can't rename a file to videoFile1 which is owned by TEST_APP_A
- assertCantRenameFile(videoFile2, videoFile1);
- // TODO(b/146346138): Test that app with right URI permission should be able to rename
- // the corresponding file
- } finally {
- deleteFileAsNoThrow(TEST_APP_A, videoFile1.getAbsolutePath());
- videoFile2.delete();
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
-
- /**
- * Test that renaming directories is allowed and aligns to default directory restrictions.
- */
- @Test
- public void testRenameDirectory() throws Exception {
- final File dcimDir = getDcimDir();
- final File downloadDir = getDownloadDir();
- final String nonMediaDirectoryName = TEST_DIRECTORY_NAME + "NonMedia";
- final File nonMediaDirectory = new File(downloadDir, nonMediaDirectoryName);
- final File pdfFile = new File(nonMediaDirectory, NONMEDIA_FILE_NAME);
-
- final String mediaDirectoryName = TEST_DIRECTORY_NAME + "Media";
- final File mediaDirectory1 = new File(dcimDir, mediaDirectoryName);
- final File videoFile1 = new File(mediaDirectory1, VIDEO_FILE_NAME);
- final File mediaDirectory2 = new File(downloadDir, mediaDirectoryName);
- final File videoFile2 = new File(mediaDirectory2, VIDEO_FILE_NAME);
- final File mediaDirectory3 = new File(getMoviesDir(), TEST_DIRECTORY_NAME);
- final File videoFile3 = new File(mediaDirectory3, VIDEO_FILE_NAME);
- final File mediaDirectory4 = new File(mediaDirectory3, mediaDirectoryName);
-
- try {
- if (!nonMediaDirectory.exists()) {
- assertThat(nonMediaDirectory.mkdirs()).isTrue();
- }
- assertThat(pdfFile.createNewFile()).isTrue();
- // Move directory with pdf file to DCIM directory is not allowed.
- assertThat(nonMediaDirectory.renameTo(new File(dcimDir, nonMediaDirectoryName)))
- .isFalse();
-
- if (!mediaDirectory1.exists()) {
- assertThat(mediaDirectory1.mkdirs()).isTrue();
- }
- assertThat(videoFile1.createNewFile()).isTrue();
- // Renaming to and from default directories is not allowed.
- assertThat(mediaDirectory1.renameTo(dcimDir)).isFalse();
- // Moving top level default directories is not allowed.
- assertCantRenameDirectory(downloadDir, new File(dcimDir, TEST_DIRECTORY_NAME), null);
-
- // Moving media directory to Download directory is allowed.
- assertCanRenameDirectory(mediaDirectory1, mediaDirectory2, new File[] {videoFile1},
- new File[] {videoFile2});
-
- // Moving media directory to Movies directory and renaming directory in new path is
- // allowed.
- assertCanRenameDirectory(mediaDirectory2, mediaDirectory3, new File[] {videoFile2},
- new File[] {videoFile3});
-
- // Can't rename a mediaDirectory to non empty non Media directory.
- assertCantRenameDirectory(mediaDirectory3, nonMediaDirectory, new File[] {videoFile3});
- // Can't rename a file to a directory.
- assertCantRenameFile(videoFile3, mediaDirectory3);
- // Can't rename a directory to file.
- assertCantRenameDirectory(mediaDirectory3, pdfFile, null);
- if (!mediaDirectory4.exists()) {
- assertThat(mediaDirectory4.mkdir()).isTrue();
- }
- // Can't rename a directory to subdirectory of itself.
- assertCantRenameDirectory(mediaDirectory3, mediaDirectory4, new File[] {videoFile3});
-
- } finally {
- pdfFile.delete();
- nonMediaDirectory.delete();
-
- videoFile1.delete();
- videoFile2.delete();
- videoFile3.delete();
- mediaDirectory1.delete();
- mediaDirectory2.delete();
- mediaDirectory3.delete();
- mediaDirectory4.delete();
- }
- }
-
- /**
- * Test that renaming directory checks file ownership permissions.
- */
- @Test
- public void testRenameDirectoryNotOwned() throws Exception {
- final String mediaDirectoryName = TEST_DIRECTORY_NAME + "Media";
- File mediaDirectory1 = new File(getDcimDir(), mediaDirectoryName);
- File mediaDirectory2 = new File(getMoviesDir(), mediaDirectoryName);
- File videoFile = new File(mediaDirectory1, VIDEO_FILE_NAME);
-
- try {
- installApp(TEST_APP_A);
-
- if (!mediaDirectory1.exists()) {
- assertThat(mediaDirectory1.mkdirs()).isTrue();
- }
- assertThat(createFileAs(TEST_APP_A, videoFile.getAbsolutePath())).isTrue();
- // App doesn't have access to videoFile1, can't rename mediaDirectory1.
- assertThat(mediaDirectory1.renameTo(mediaDirectory2)).isFalse();
- assertThat(videoFile.exists()).isTrue();
- // Test app can delete the file since the file is not moved to new directory.
- assertThat(deleteFileAs(TEST_APP_A, videoFile.getAbsolutePath())).isTrue();
- } finally {
- deleteFileAsNoThrow(TEST_APP_A, videoFile.getAbsolutePath());
- uninstallAppNoThrow(TEST_APP_A);
- mediaDirectory1.delete();
- }
- }
-
- /**
- * Test renaming empty directory is allowed
- */
- @Test
- public void testRenameEmptyDirectory() throws Exception {
- final String emptyDirectoryName = TEST_DIRECTORY_NAME + "Media";
- File emptyDirectoryOldPath = new File(getDcimDir(), emptyDirectoryName);
- File emptyDirectoryNewPath = new File(getMoviesDir(), TEST_DIRECTORY_NAME);
- try {
- if (emptyDirectoryOldPath.exists()) {
- executeShellCommand("rm -r " + emptyDirectoryOldPath.getPath());
- }
- assertThat(emptyDirectoryOldPath.mkdirs()).isTrue();
- assertCanRenameDirectory(emptyDirectoryOldPath, emptyDirectoryNewPath, null, null);
- } finally {
- emptyDirectoryOldPath.delete();
- emptyDirectoryNewPath.delete();
+ deleteDirUsingTradefedContentProvider(topLevelDir1);
+ deleteDirUsingTradefedContentProvider(topLevelDir2);
+ nonTopLevelDir.delete();
}
}
@@ -1686,351 +284,44 @@
}
/**
- * Tests that an instant app can't access external storage.
+ * b/168830497: Test that app can write to file in DCIM/Camera even with .nomedia presence
*/
@Test
- @AppModeInstant
- public void testInstantAppsCantAccessExternalStorage() throws Exception {
- assumeTrue("This test requires that the test runs as an Instant app",
- getContext().getPackageManager().isInstantApp());
- assertThat(getContext().getPackageManager().isInstantApp()).isTrue();
+ public void testCanWriteToDCIMCameraWithNomedia() throws Exception {
+ final File cameraDir = new File(getDcimDir(), "Camera");
+ final File nomediaFile = new File(cameraDir, ".nomedia");
+ Uri targetUri = null;
- // Can't read ExternalStorageDir
- assertThat(getExternalStorageDir().list()).isNull();
-
- // Can't create a top-level direcotry
- final File topLevelDir = new File(getExternalStorageDir(), TEST_DIRECTORY_NAME);
- assertThat(topLevelDir.mkdir()).isFalse();
-
- // Can't create file under root dir
- final File newTxtFile = new File(getExternalStorageDir(), NONMEDIA_FILE_NAME);
- assertThrows(IOException.class,
- () -> { newTxtFile.createNewFile(); });
-
- // Can't create music file under /MUSIC
- final File newMusicFile = new File(getMusicDir(), AUDIO_FILE_NAME);
- assertThrows(IOException.class,
- () -> { newMusicFile.createNewFile(); });
-
- // getExternalFilesDir() is not null
- assertThat(getExternalFilesDir()).isNotNull();
-
- // Can't read/write app specific dir
- assertThat(getExternalFilesDir().list()).isNull();
- assertThat(getExternalFilesDir().exists()).isFalse();
- }
-
- /**
- * Test that apps can create and delete hidden file.
- */
- @Test
- public void testCanCreateHiddenFile() throws Exception {
- final File hiddenImageFile = new File(getDownloadDir(), ".hiddenFile" + IMAGE_FILE_NAME);
try {
- assertThat(hiddenImageFile.createNewFile()).isTrue();
- // Write to hidden file is allowed.
- try (final FileOutputStream fos = new FileOutputStream(hiddenImageFile)) {
- fos.write(BYTES_DATA1);
- }
- assertFileContent(hiddenImageFile, BYTES_DATA1);
-
- assertNotMediaTypeImage(hiddenImageFile);
-
- assertDirectoryContains(getDownloadDir(), hiddenImageFile);
- assertThat(getFileRowIdFromDatabase(hiddenImageFile)).isNotEqualTo(-1);
-
- // We can delete hidden file
- assertThat(hiddenImageFile.delete()).isTrue();
- assertThat(hiddenImageFile.exists()).isFalse();
- } finally {
- hiddenImageFile.delete();
- }
- }
-
- /**
- * Test that apps can rename a hidden file.
- */
- @Test
- public void testCanRenameHiddenFile() throws Exception {
- final String hiddenFileName = ".hidden" + IMAGE_FILE_NAME;
- final File hiddenImageFile1 = new File(getDcimDir(), hiddenFileName);
- final File hiddenImageFile2 = new File(getDownloadDir(), hiddenFileName);
- final File imageFile = new File(getDownloadDir(), IMAGE_FILE_NAME);
- try {
- assertThat(hiddenImageFile1.createNewFile()).isTrue();
- assertCanRenameFile(hiddenImageFile1, hiddenImageFile2);
- assertNotMediaTypeImage(hiddenImageFile2);
-
- // We can also rename hidden file to non-hidden
- assertCanRenameFile(hiddenImageFile2, imageFile);
- assertIsMediaTypeImage(imageFile);
-
- // We can rename non-hidden file to hidden
- assertCanRenameFile(imageFile, hiddenImageFile1);
- assertNotMediaTypeImage(hiddenImageFile1);
- } finally {
- hiddenImageFile1.delete();
- hiddenImageFile2.delete();
- imageFile.delete();
- }
- }
-
- /**
- * Test that files in hidden directory have MEDIA_TYPE=MEDIA_TYPE_NONE
- */
- @Test
- public void testHiddenDirectory() throws Exception {
- final File hiddenDir = new File(getDownloadDir(), ".hidden" + TEST_DIRECTORY_NAME);
- final File hiddenImageFile = new File(hiddenDir, IMAGE_FILE_NAME);
- final File nonHiddenDir = new File(getDownloadDir(), TEST_DIRECTORY_NAME);
- final File imageFile = new File(nonHiddenDir, IMAGE_FILE_NAME);
- try {
- if (!hiddenDir.exists()) {
- assertThat(hiddenDir.mkdir()).isTrue();
- }
- assertThat(hiddenImageFile.createNewFile()).isTrue();
-
- assertNotMediaTypeImage(hiddenImageFile);
-
- // Renaming hiddenDir to nonHiddenDir makes the imageFile non-hidden and vice versa
- assertCanRenameDirectory(
- hiddenDir, nonHiddenDir, new File[] {hiddenImageFile}, new File[] {imageFile});
- assertIsMediaTypeImage(imageFile);
-
- assertCanRenameDirectory(
- nonHiddenDir, hiddenDir, new File[] {imageFile}, new File[] {hiddenImageFile});
- assertNotMediaTypeImage(hiddenImageFile);
- } finally {
- hiddenImageFile.delete();
- imageFile.delete();
- hiddenDir.delete();
- nonHiddenDir.delete();
- }
- }
-
- /**
- * Test that files in directory with nomedia have MEDIA_TYPE=MEDIA_TYPE_NONE
- */
- @Test
- public void testHiddenDirectory_nomedia() throws Exception {
- final File directoryNoMedia = new File(getDownloadDir(), "nomedia" + TEST_DIRECTORY_NAME);
- final File noMediaFile = new File(directoryNoMedia, ".nomedia");
- final File imageFile = new File(directoryNoMedia, IMAGE_FILE_NAME);
- final File videoFile = new File(directoryNoMedia, VIDEO_FILE_NAME);
- try {
- if (!directoryNoMedia.exists()) {
- assertThat(directoryNoMedia.mkdir()).isTrue();
- }
- assertThat(noMediaFile.createNewFile()).isTrue();
- assertThat(imageFile.createNewFile()).isTrue();
-
- assertNotMediaTypeImage(imageFile);
-
- // Deleting the .nomedia file makes the parent directory non hidden.
- noMediaFile.delete();
- MediaStore.scanFile(getContentResolver(), directoryNoMedia);
- assertIsMediaTypeImage(imageFile);
-
- // Creating the .nomedia file makes the parent directory hidden again
- assertThat(noMediaFile.createNewFile()).isTrue();
- MediaStore.scanFile(getContentResolver(), directoryNoMedia);
- assertNotMediaTypeImage(imageFile);
-
- // Renaming the .nomedia file to non hidden file makes the parent directory non hidden.
- assertCanRenameFile(noMediaFile, videoFile);
- assertIsMediaTypeImage(imageFile);
- } finally {
- noMediaFile.delete();
- imageFile.delete();
- videoFile.delete();
- directoryNoMedia.delete();
- }
- }
-
- /**
- * Test that only file manager and app that created the hidden file can list it.
- */
- @Test
- public void testListHiddenFile() throws Exception {
- final File dcimDir = getDcimDir();
- final String hiddenImageFileName = ".hidden" + IMAGE_FILE_NAME;
- final File hiddenImageFile = new File(dcimDir, hiddenImageFileName);
- try {
- assertThat(hiddenImageFile.createNewFile()).isTrue();
- assertNotMediaTypeImage(hiddenImageFile);
-
- assertDirectoryContains(dcimDir, hiddenImageFile);
-
- installApp(TEST_APP_A, true);
- // TestApp with read permissions can't see the hidden image file created by other app
- assertThat(listAs(TEST_APP_A, dcimDir.getAbsolutePath()))
- .doesNotContain(hiddenImageFileName);
-
- final int testAppUid =
- getContext().getPackageManager().getPackageUid(TEST_APP_A.getPackageName(), 0);
- // FileManager can see the hidden image file created by other app
- try {
- allowAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
- assertThat(listAs(TEST_APP_A, dcimDir.getAbsolutePath()))
- .contains(hiddenImageFileName);
- } finally {
- denyAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
+ // Recreate required file and directory
+ if (cameraDir.exists()) {
+ // This is a work around to address a known inode cache inconsistency issue
+ // that occurs when test runs for the second time.
+ deleteDirUsingTradefedContentProvider(cameraDir);
}
- // Gallery can not see the hidden image file created by other app
- try {
- allowAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
- assertThat(listAs(TEST_APP_A, dcimDir.getAbsolutePath()))
- .doesNotContain(hiddenImageFileName);
- } finally {
- denyAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
- }
- } finally {
- hiddenImageFile.delete();
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
+ createDirUsingTradefedContentProvider(cameraDir);
+ assertTrue(cameraDir.exists());
- @Test
- public void testOpenPendingAndTrashed() throws Exception {
- final File pendingImageFile = new File(getDcimDir(), IMAGE_FILE_NAME);
- final File trashedVideoFile = new File(getPicturesDir(), VIDEO_FILE_NAME);
- final File pendingPdfFile = new File(getDocumentsDir(), NONMEDIA_FILE_NAME);
- final File trashedPdfFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
- Uri pendingImgaeFileUri = null;
- Uri trashedVideoFileUri = null;
- Uri pendingPdfFileUri = null;
- Uri trashedPdfFileUri = null;
- try {
- installAppWithStoragePermissions(TEST_APP_A);
+ createFileUsingTradefedContentProvider(nomediaFile);
+ assertTrue(nomediaFile.exists());
- pendingImgaeFileUri = createPendingFile(pendingImageFile);
- assertOpenPendingOrTrashed(pendingImgaeFileUri, TEST_APP_A, /*isImageOrVideo*/ true);
+ ContentValues values = new ContentValues();
+ values.put(MediaColumns.RELATIVE_PATH, "DCIM/Camera");
+ targetUri = getContentResolver().insert(getImageContentUri(), values, Bundle.EMPTY);
+ assertNotNull(targetUri);
- pendingPdfFileUri = createPendingFile(pendingPdfFile);
- assertOpenPendingOrTrashed(pendingPdfFileUri, TEST_APP_A,
- /*isImageOrVideo*/ false);
-
- trashedVideoFileUri = createTrashedFile(trashedVideoFile);
- assertOpenPendingOrTrashed(trashedVideoFileUri, TEST_APP_A, /*isImageOrVideo*/ true);
-
- trashedPdfFileUri = createTrashedFile(trashedPdfFile);
- assertOpenPendingOrTrashed(trashedPdfFileUri, TEST_APP_A,
- /*isImageOrVideo*/ false);
-
- } finally {
- deleteFiles(pendingImageFile, pendingImageFile, trashedVideoFile,
- trashedPdfFile);
- deleteWithMediaProviderNoThrow(pendingImgaeFileUri, trashedVideoFileUri,
- pendingPdfFileUri, trashedPdfFileUri);
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
-
- @Test
- public void testListPendingAndTrashed() throws Exception {
- final File imageFile = new File(getDcimDir(), IMAGE_FILE_NAME);
- final File pdfFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
- Uri imageFileUri = null;
- Uri pdfFileUri = null;
- try {
- installAppWithStoragePermissions(TEST_APP_A);
-
- imageFileUri = createPendingFile(imageFile);
- // Check that only owner package, file manager and system gallery can list pending image
- // file.
- assertListPendingOrTrashed(imageFileUri, imageFile, TEST_APP_A,
- /*isImageOrVideo*/ true);
-
- trashFile(imageFileUri);
- // Check that only owner package, file manager and system gallery can list trashed image
- // file.
- assertListPendingOrTrashed(imageFileUri, imageFile, TEST_APP_A,
- /*isImageOrVideo*/ true);
-
- pdfFileUri = createPendingFile(pdfFile);
- // Check that only owner package, file manager can list pending non media file.
- assertListPendingOrTrashed(pdfFileUri, pdfFile, TEST_APP_A,
- /*isImageOrVideo*/ false);
-
- trashFile(pdfFileUri);
- // Check that only owner package, file manager can list trashed non media file.
- assertListPendingOrTrashed(pdfFileUri, pdfFile, TEST_APP_A,
- /*isImageOrVideo*/ false);
- } finally {
- deleteWithMediaProviderNoThrow(imageFileUri, pdfFileUri);
- deleteFiles(imageFile, pdfFile);
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
-
- @Test
- public void testDeletePendingAndTrashed() throws Exception {
- final File pendingVideoFile = new File(getDcimDir(), VIDEO_FILE_NAME);
- final File trashedImageFile = new File(getPicturesDir(), IMAGE_FILE_NAME);
- final File pendingPdfFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
- final File trashedPdfFile = new File(getDocumentsDir(), NONMEDIA_FILE_NAME);
- // Actual path of the file gets rewritten for pending and trashed files.
- String pendingVideoFilePath = null;
- String trashedImageFilePath = null;
- String pendingPdfFilePath = null;
- String trashedPdfFilePath = null;
- try {
- pendingVideoFilePath = getFilePathFromUri(createPendingFile(pendingVideoFile));
- trashedImageFilePath = getFilePathFromUri(createTrashedFile(trashedImageFile));
- pendingPdfFilePath = getFilePathFromUri(createPendingFile(pendingPdfFile));
- trashedPdfFilePath = getFilePathFromUri(createTrashedFile(trashedPdfFile));
-
- // App can delete its own pending and trashed file.
- assertCanDeletePaths(pendingVideoFilePath, trashedImageFilePath, pendingPdfFilePath,
- trashedPdfFilePath);
-
- pendingVideoFilePath = getFilePathFromUri(createPendingFile(pendingVideoFile));
- trashedImageFilePath = getFilePathFromUri(createTrashedFile(trashedImageFile));
- pendingPdfFilePath = getFilePathFromUri(createPendingFile(pendingPdfFile));
- trashedPdfFilePath = getFilePathFromUri(createTrashedFile(trashedPdfFile));
-
- installAppWithStoragePermissions(TEST_APP_A);
-
- // App can't delete other app's pending and trashed file.
- assertCantDeletePathsAs(TEST_APP_A, pendingVideoFilePath, trashedImageFilePath,
- pendingPdfFilePath, trashedPdfFilePath);
-
- final int testAppUid =
- getContext().getPackageManager().getPackageUid(TEST_APP_A.getPackageName(), 0);
- try {
- allowAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
- // File Manager can delete any pending and trashed file
- assertCanDeletePathsAs(TEST_APP_A, pendingVideoFilePath, trashedImageFilePath,
- pendingPdfFilePath, trashedPdfFilePath);
- } finally {
- denyAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
+ try (ParcelFileDescriptor pfd =
+ getContentResolver().openFileDescriptor(targetUri, "w")) {
+ assertThat(pfd).isNotNull();
+ Os.write(pfd.getFileDescriptor(), ByteBuffer.wrap(BYTES_DATA1));
}
- pendingVideoFilePath = getFilePathFromUri(createPendingFile(pendingVideoFile));
- trashedImageFilePath = getFilePathFromUri(createTrashedFile(trashedImageFile));
- pendingPdfFilePath = getFilePathFromUri(createPendingFile(pendingPdfFile));
- trashedPdfFilePath = getFilePathFromUri(createTrashedFile(trashedPdfFile));
-
- try {
- allowAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
- // System Gallery can delete any pending and trashed image or video file.
- assertTrue(isMediaTypeImageOrVideo(new File(pendingVideoFilePath)));
- assertTrue(isMediaTypeImageOrVideo(new File(trashedImageFilePath)));
- assertCanDeletePathsAs(TEST_APP_A, pendingVideoFilePath, trashedImageFilePath);
-
- // System Gallery can't delete other app's pending and trashed pdf file.
- assertFalse(isMediaTypeImageOrVideo(new File(pendingPdfFilePath)));
- assertFalse(isMediaTypeImageOrVideo(new File(trashedPdfFilePath)));
- assertCantDeletePathsAs(TEST_APP_A, pendingPdfFilePath, trashedPdfFilePath);
- } finally {
- denyAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
- }
+ assertFileContent(new File(getFilePathFromUri(targetUri)), BYTES_DATA1);
} finally {
- deletePaths(pendingVideoFilePath, trashedImageFilePath, pendingPdfFilePath,
- trashedPdfFilePath);
- deleteFiles(pendingVideoFile, trashedImageFile, pendingPdfFile, trashedPdfFile);
- uninstallAppNoThrow(TEST_APP_A);
+ deleteWithMediaProviderNoThrow(targetUri);
+ deleteFileUsingTradefedContentProvider(nomediaFile);
+ deleteDirUsingTradefedContentProvider(cameraDir);
}
}
@@ -2094,15 +385,15 @@
assertAccess(doesntExistPdf, false, false, false);
// We can check only exists for another app's files on root.
- // Use shell to create root file because TEST_APP_A is in
+ // Use content provider to create root file because TEST_APP_A is in
// scoped storage.
- executeShellCommand("touch " + shellPdfAtRoot.getAbsolutePath());
+ createFileUsingTradefedContentProvider(shellPdfAtRoot);
MediaStore.scanFile(getContentResolver(), shellPdfAtRoot);
assertFileAccess_existsOnly(shellPdfAtRoot);
} finally {
deleteFileAsNoThrow(TEST_APP_A, otherAppPdf.getAbsolutePath());
deleteFileAsNoThrow(TEST_APP_A, otherAppImage.getAbsolutePath());
- executeShellCommand("rm " + shellPdfAtRoot.getAbsolutePath());
+ deleteFileUsingTradefedContentProvider(shellPdfAtRoot);
MediaStore.scanFile(getContentResolver(), shellPdfAtRoot);
myAppPdf.delete();
uninstallApp(TEST_APP_A);
@@ -2150,13 +441,13 @@
assertDirectoryAccess(new File(getExternalStorageDir(), "Android"), true, false);
assertDirectoryAccess(new File(getExternalStorageDir(), "doesnt/exist"), false, false);
- executeShellCommand("mkdir " + topLevelDir.getAbsolutePath());
+ createDirUsingTradefedContentProvider(topLevelDir);
assertDirectoryAccess(topLevelDir, true, false);
assertCannotReadOrWrite(new File("/storage/emulated"));
} finally {
uninstallApp(TEST_APP_A); // Uninstalling deletes external app dirs
- executeShellCommand("rmdir " + topLevelDir.getAbsolutePath());
+ deleteDirUsingTradefedContentProvider(topLevelDir);
}
}
@@ -2212,13 +503,11 @@
final File podcastsDir = getPodcastsDir();
try {
if (podcastsDir.exists()) {
- // Apps can't delete top level directories, not even default directories, so we let
- // shell do the deed for us.
- executeShellCommand("rm -r " + podcastsDir);
+ deleteDirUsingTradefedContentProvider(podcastsDir);
}
assertThat(podcastsDir.mkdir()).isTrue();
} finally {
- executeShellCommand("mkdir " + podcastsDir);
+ createDirUsingTradefedContentProvider(podcastsDir);
}
}
@@ -2234,7 +523,7 @@
try {
installApp(TEST_APP_A);
assertCreateFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf);
- executeShellCommand("touch " + otherTopLevelFile);
+ createFileUsingTradefedContentProvider(otherTopLevelFile);
MediaStore.scanFile(getContentResolver(), otherTopLevelFile);
// We can list other apps' files
@@ -2247,7 +536,7 @@
// We can also list all top level directories
assertDirectoryContains(getExternalStorageDir(), getDefaultTopLevelDirs());
} finally {
- executeShellCommand("rm " + otherTopLevelFile);
+ deleteFileUsingTradefedContentProvider(otherTopLevelFile);
MediaStore.scanFile(getContentResolver(), otherTopLevelFile);
deleteFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf);
uninstallApp(TEST_APP_A);
@@ -2278,191 +567,41 @@
}
}
- @Test
- public void testQueryOtherAppsFiles() throws Exception {
- final File otherAppPdf = new File(getDownloadDir(), "other" + NONMEDIA_FILE_NAME);
- final File otherAppImg = new File(getDcimDir(), "other" + IMAGE_FILE_NAME);
- final File otherAppMusic = new File(getMusicDir(), "other" + AUDIO_FILE_NAME);
- final File otherHiddenFile = new File(getPicturesDir(), ".otherHiddenFile.jpg");
- try {
- installApp(TEST_APP_A);
- // Apps can't query other app's pending file, hence create file and publish it.
- assertCreatePublishedFilesAs(
- TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf, otherHiddenFile);
-
- // Since the test doesn't have READ_EXTERNAL_STORAGE nor any other special permissions,
- // it can't query for another app's contents.
- assertCantQueryFile(otherAppImg);
- assertCantQueryFile(otherAppMusic);
- assertCantQueryFile(otherAppPdf);
- assertCantQueryFile(otherHiddenFile);
- } finally {
- deleteFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf, otherHiddenFile);
- uninstallApp(TEST_APP_A);
- }
- }
-
- @Test
- public void testSystemGalleryQueryOtherAppsFiles() throws Exception {
- final File otherAppPdf = new File(getDownloadDir(), "other" + NONMEDIA_FILE_NAME);
- final File otherAppImg = new File(getDcimDir(), "other" + IMAGE_FILE_NAME);
- final File otherAppMusic = new File(getMusicDir(), "other" + AUDIO_FILE_NAME);
- final File otherHiddenFile = new File(getPicturesDir(), ".otherHiddenFile.jpg");
- try {
- installApp(TEST_APP_A);
- // Apps can't query other app's pending file, hence create file and publish it.
- assertCreatePublishedFilesAs(
- TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf, otherHiddenFile);
-
- // System gallery apps have access to video and image files
- allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
-
- assertCanQueryAndOpenFile(otherAppImg, "rw");
- // System gallery doesn't have access to hidden image files of other app
- assertCantQueryFile(otherHiddenFile);
- // But no access to PDFs or music files
- assertCantQueryFile(otherAppMusic);
- assertCantQueryFile(otherAppPdf);
- } finally {
- denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
- deleteFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf, otherHiddenFile);
- uninstallApp(TEST_APP_A);
- }
- }
-
- /**
- * Test that System Gallery app can rename any directory under the default directories
- * designated for images and videos, even if they contain other apps' contents that
- * System Gallery doesn't have read access to.
+ /*
+ * b/174211425: Test that for apps bypassing database operations we mark the nomedia directory
+ * as dirty for create/rename/delete.
*/
@Test
- public void testSystemGalleryCanRenameImageAndVideoDirs() throws Exception {
- final File dirInDcim = new File(getDcimDir(), TEST_DIRECTORY_NAME);
- final File dirInPictures = new File(getPicturesDir(), TEST_DIRECTORY_NAME);
- final File dirInPodcasts = new File(getPodcastsDir(), TEST_DIRECTORY_NAME);
- final File otherAppImageFile1 = new File(dirInDcim, "other_" + IMAGE_FILE_NAME);
- final File otherAppVideoFile1 = new File(dirInDcim, "other_" + VIDEO_FILE_NAME);
- final File otherAppPdfFile1 = new File(dirInDcim, "other_" + NONMEDIA_FILE_NAME);
- final File otherAppImageFile2 = new File(dirInPictures, "other_" + IMAGE_FILE_NAME);
- final File otherAppVideoFile2 = new File(dirInPictures, "other_" + VIDEO_FILE_NAME);
- final File otherAppPdfFile2 = new File(dirInPictures, "other_" + NONMEDIA_FILE_NAME);
+ public void testManageExternalStorageDoesntSkipScanningDirtyNomediaDir() throws Exception {
+ pollForManageExternalStorageAllowed();
+
+ final File nomediaDir = new File(getDownloadDir(), TEST_DIRECTORY_NAME);
+ final File nomediaFile = new File(nomediaDir, ".nomedia");
+ final File mediaFile = new File(nomediaDir, IMAGE_FILE_NAME);
+ final File renamedMediaFile = new File(nomediaDir, "Renamed_" + IMAGE_FILE_NAME);
try {
- assertThat(dirInDcim.exists() || dirInDcim.mkdir()).isTrue();
+ if (!nomediaDir.exists()) {
+ assertTrue(nomediaDir.mkdirs());
+ }
+ assertThat(nomediaFile.createNewFile()).isTrue();
+ MediaStore.scanFile(getContentResolver(), nomediaDir);
- executeShellCommand("touch " + otherAppPdfFile1);
- MediaStore.scanFile(getContentResolver(), otherAppPdfFile1);
+ assertThat(mediaFile.createNewFile()).isTrue();
+ MediaStore.scanFile(getContentResolver(), nomediaDir);
+ assertThat(getFileRowIdFromDatabase(mediaFile)).isNotEqualTo(-1);
- installAppWithStoragePermissions(TEST_APP_A);
- allowAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
+ assertThat(mediaFile.renameTo(renamedMediaFile)).isTrue();
+ MediaStore.scanFile(getContentResolver(), nomediaDir);
+ assertThat(getFileRowIdFromDatabase(renamedMediaFile)).isNotEqualTo(-1);
- assertCreateFilesAs(TEST_APP_A, otherAppImageFile1, otherAppVideoFile1);
-
- // System gallery privileges don't go beyond DCIM, Movies and Pictures boundaries.
- assertCantRenameDirectory(dirInDcim, dirInPodcasts, /*oldFilesList*/ null);
-
- // Rename should succeed, but System Gallery still can't access that PDF file!
- assertCanRenameDirectory(dirInDcim, dirInPictures,
- new File[] {otherAppImageFile1, otherAppVideoFile1},
- new File[] {otherAppImageFile2, otherAppVideoFile2});
- assertThat(getFileRowIdFromDatabase(otherAppPdfFile1)).isEqualTo(-1);
- assertThat(getFileRowIdFromDatabase(otherAppPdfFile2)).isEqualTo(-1);
+ assertThat(renamedMediaFile.delete()).isTrue();
+ MediaStore.scanFile(getContentResolver(), nomediaDir);
+ assertThat(getFileRowIdFromDatabase(renamedMediaFile)).isEqualTo(-1);
} finally {
- executeShellCommand("rm " + otherAppPdfFile1);
- executeShellCommand("rm " + otherAppPdfFile2);
- MediaStore.scanFile(getContentResolver(), otherAppPdfFile1);
- MediaStore.scanFile(getContentResolver(), otherAppPdfFile2);
- otherAppImageFile1.delete();
- otherAppImageFile2.delete();
- otherAppVideoFile1.delete();
- otherAppVideoFile2.delete();
- otherAppPdfFile1.delete();
- otherAppPdfFile2.delete();
- dirInDcim.delete();
- dirInPictures.delete();
- uninstallAppNoThrow(TEST_APP_A);
- denyAppOpsToUid(Process.myUid(), SYSTEM_GALERY_APPOPS);
- }
- }
-
- /**
- * Test that row ID corresponding to deleted path is restored on subsequent create.
- */
- @Test
- public void testCreateCanRestoreDeletedRowId() throws Exception {
- final File imageFile = new File(getDcimDir(), IMAGE_FILE_NAME);
- final ContentResolver cr = getContentResolver();
-
- try {
- assertThat(imageFile.createNewFile()).isTrue();
- final long oldRowId = getFileRowIdFromDatabase(imageFile);
- assertThat(oldRowId).isNotEqualTo(-1);
- final Uri uriOfOldFile = MediaStore.scanFile(cr, imageFile);
- assertThat(uriOfOldFile).isNotNull();
-
- assertThat(imageFile.delete()).isTrue();
- // We should restore old row Id corresponding to deleted imageFile.
- assertThat(imageFile.createNewFile()).isTrue();
- assertThat(getFileRowIdFromDatabase(imageFile)).isEqualTo(oldRowId);
- assertThat(cr.openFileDescriptor(uriOfOldFile, "rw")).isNotNull();
-
- assertThat(imageFile.delete()).isTrue();
- installApp(TEST_APP_A);
- assertThat(createFileAs(TEST_APP_A, imageFile.getAbsolutePath())).isTrue();
-
- final Uri uriOfNewFile = MediaStore.scanFile(getContentResolver(), imageFile);
- assertThat(uriOfNewFile).isNotNull();
- // We shouldn't restore deleted row Id if delete & create are called from different apps
- assertThat(Integer.getInteger(uriOfNewFile.getLastPathSegment())).isNotEqualTo(oldRowId);
- } finally {
- imageFile.delete();
- deleteFileAsNoThrow(TEST_APP_A, imageFile.getAbsolutePath());
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
-
- /**
- * Test that row ID corresponding to deleted path is restored on subsequent rename.
- */
- @Test
- public void testRenameCanRestoreDeletedRowId() throws Exception {
- final File imageFile = new File(getDcimDir(), IMAGE_FILE_NAME);
- final File temporaryFile = new File(getDownloadDir(), IMAGE_FILE_NAME + "_.tmp");
- final ContentResolver cr = getContentResolver();
-
- try {
- assertThat(imageFile.createNewFile()).isTrue();
- final Uri oldUri = MediaStore.scanFile(cr, imageFile);
- assertThat(oldUri).isNotNull();
-
- Files.copy(imageFile, temporaryFile);
- assertThat(imageFile.delete()).isTrue();
- assertCanRenameFile(temporaryFile, imageFile);
-
- final Uri newUri = MediaStore.scanFile(cr, imageFile);
- assertThat(newUri).isNotNull();
- assertThat(newUri.getLastPathSegment()).isEqualTo(oldUri.getLastPathSegment());
- // oldUri of imageFile is still accessible after delete and rename.
- assertThat(cr.openFileDescriptor(oldUri, "rw")).isNotNull();
- } finally {
- imageFile.delete();
- temporaryFile.delete();
- }
- }
-
- @Test
- public void testCantCreateOrRenameFileWithInvalidName() throws Exception {
- File invalidFile = new File(getDownloadDir(), "<>");
- File validFile = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
- try {
- assertThrows(IOException.class, "Operation not permitted",
- () -> { invalidFile.createNewFile(); });
-
- assertThat(validFile.createNewFile()).isTrue();
- // We can't rename a file to a file name with invalid FAT characters.
- assertCantRenameFile(validFile, invalidFile);
- } finally {
- invalidFile.delete();
- validFile.delete();
+ nomediaFile.delete();
+ mediaFile.delete();
+ renamedMediaFile.delete();
+ nomediaDir.delete();
}
}
@@ -2490,6 +629,8 @@
@Test
public void testWallpaperApisNoPermission() throws Exception {
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getContext());
+ assumeTrue("Test skipped as wallpaper is not supported.",
+ wallpaperManager.isWallpaperSupported());
assertThrows(SecurityException.class, () -> wallpaperManager.getFastDrawable());
assertThrows(SecurityException.class, () -> wallpaperManager.peekFastDrawable());
assertThrows(SecurityException.class,
@@ -2554,51 +695,10 @@
}
}
- /**
- * Test that IS_PENDING is set for files created via filepath
- */
- @Test
- public void testPendingFromFuse() throws Exception {
- final File pendingFile = new File(getDcimDir(), IMAGE_FILE_NAME);
- final File otherPendingFile = new File(getDcimDir(), VIDEO_FILE_NAME);
- try {
- assertTrue(pendingFile.createNewFile());
- // Newly created file should have IS_PENDING set
- try (Cursor c = queryFile(pendingFile, MediaStore.MediaColumns.IS_PENDING)) {
- assertTrue(c.moveToFirst());
- assertThat(c.getInt(0)).isEqualTo(1);
- }
-
- // If we query with MATCH_EXCLUDE, we should still see this pendingFile
- try (Cursor c = queryFileExcludingPending(pendingFile, MediaColumns.IS_PENDING)) {
- assertThat(c.getCount()).isEqualTo(1);
- assertTrue(c.moveToFirst());
- assertThat(c.getInt(0)).isEqualTo(1);
- }
-
- assertNotNull(MediaStore.scanFile(getContentResolver(), pendingFile));
-
- // IS_PENDING should be unset after the scan
- try (Cursor c = queryFile(pendingFile, MediaStore.MediaColumns.IS_PENDING)) {
- assertTrue(c.moveToFirst());
- assertThat(c.getInt(0)).isEqualTo(0);
- }
-
- installAppWithStoragePermissions(TEST_APP_A);
- assertCreateFilesAs(TEST_APP_A, otherPendingFile);
- // We can't query other apps pending file from FUSE with MATCH_EXCLUDE
- try (Cursor c = queryFileExcludingPending(otherPendingFile, MediaColumns.IS_PENDING)) {
- assertThat(c.getCount()).isEqualTo(0);
- }
- } finally {
- pendingFile.delete();
- deleteFileAsNoThrow(TEST_APP_A, otherPendingFile.getAbsolutePath());
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
@Test
public void testOpenOtherPendingFilesFromFuse() throws Exception {
+ pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /*granted*/ true);
final File otherPendingFile = new File(getDcimDir(), IMAGE_FILE_NAME);
try {
installApp(TEST_APP_A);
@@ -2615,34 +715,6 @@
}
}
- /**
- * Test that apps can't set attributes on another app's files.
- */
- @Test
- public void testCantSetAttrOtherAppsFile() throws Exception {
- // This path's permission is checked in MediaProvider (directory/external media dir)
- final File externalMediaPath = new File(getExternalMediaDir(), VIDEO_FILE_NAME);
-
- try {
- // Create the files
- if (!externalMediaPath.exists()) {
- assertThat(externalMediaPath.createNewFile()).isTrue();
- }
-
- // Install TEST_APP_A with READ_EXTERNAL_STORAGE permission.
- installAppWithStoragePermissions(TEST_APP_A);
-
- // TEST_APP_A should not be able to setattr to other app's files.
- assertWithMessage(
- "setattr on directory/external media path [%s]", externalMediaPath.getPath())
- .that(setAttrAs(TEST_APP_A, externalMediaPath.getPath()))
- .isFalse();
- } finally {
- externalMediaPath.delete();
- uninstallAppNoThrow(TEST_APP_A);
- }
- }
-
@Test
public void testNoIsolatedStorageCanCreateFilesAnywhere() throws Exception {
final File topLevelPdf = new File(getExternalStorageDir(), NONMEDIA_FILE_NAME);
@@ -2696,7 +768,7 @@
try {
installApp(TEST_APP_A);
assertCreateFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf);
- executeShellCommand("touch " + otherTopLevelFile);
+ createFileUsingTradefedContentProvider(otherTopLevelFile);
// We can list other apps' files
assertDirectoryContains(otherAppPdf.getParentFile(), otherAppPdf);
@@ -2708,7 +780,7 @@
// We can also list all top level directories
assertDirectoryContains(getExternalStorageDir(), getDefaultTopLevelDirs());
} finally {
- executeShellCommand("rm " + otherTopLevelFile);
+ deleteFileUsingTradefedContentProvider(otherTopLevelFile);
deleteFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf);
uninstallApp(TEST_APP_A);
}
@@ -2738,6 +810,8 @@
@Test
public void testRenameFromShell() throws Exception {
+ // This test is for shell and shell always runs as USER_SYSTEM
+ assumeTrue("Test is applicable only for System User.", getCurrentUser() == USER_SYSTEM);
final File imageFile = new File(getPicturesDir(), IMAGE_FILE_NAME);
final File dir = new File(getMoviesDir(), TEST_DIRECTORY_NAME);
final File renamedDir = new File(getMusicDir(), TEST_DIRECTORY_NAME);
@@ -2776,6 +850,100 @@
}
}
+ @Test
+ public void testClearPackageData() throws Exception {
+ pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /*granted*/ true);
+
+ File fileToRemain = new File(getPicturesDir(), IMAGE_FILE_NAME);
+ String testAppPackageName = TEST_APP_A.getPackageName();
+ File fileToBeDeleted =
+ new File(
+ getAndroidMediaDir(),
+ String.format("%s/%s", testAppPackageName, IMAGE_FILE_NAME));
+ File nestedFileToBeDeleted =
+ new File(
+ getAndroidMediaDir(),
+ String.format("%s/nesteddir/%s", testAppPackageName, IMAGE_FILE_NAME));
+
+ try {
+ installApp(TEST_APP_A);
+
+ createAndCheckFileAsApp(TEST_APP_A, fileToRemain);
+ createAndCheckFileAsApp(TEST_APP_A, fileToBeDeleted);
+ createAndCheckFileAsApp(TEST_APP_A, nestedFileToBeDeleted);
+
+ executeShellCommand("pm clear " + testAppPackageName);
+
+ // Wait a max of 5 seconds for the cleaning after "pm clear" command to complete.
+ int i = 0;
+ while(i < 10 && getFileRowIdFromDatabase(fileToBeDeleted) != -1
+ && getFileRowIdFromDatabase(nestedFileToBeDeleted) != -1) {
+ Thread.sleep(500);
+ i++;
+ }
+
+ assertThat(getFileOwnerPackageFromDatabase(fileToRemain)).isNull();
+ assertThat(getFileRowIdFromDatabase(fileToRemain)).isNotEqualTo(-1);
+
+ assertThat(getFileOwnerPackageFromDatabase(fileToBeDeleted)).isNull();
+ assertThat(getFileRowIdFromDatabase(fileToBeDeleted)).isEqualTo(-1);
+
+ assertThat(getFileOwnerPackageFromDatabase(nestedFileToBeDeleted)).isNull();
+ assertThat(getFileRowIdFromDatabase(nestedFileToBeDeleted)).isEqualTo(-1);
+ } finally {
+ deleteFilesAs(TEST_APP_A, fileToRemain);
+ deleteFilesAs(TEST_APP_A, fileToBeDeleted);
+ deleteFilesAs(TEST_APP_A, nestedFileToBeDeleted);
+ uninstallAppNoThrow(TEST_APP_A);
+ }
+ }
+
+ /**
+ * Tests that an instant app can't access external storage.
+ */
+ @Test
+ @AppModeInstant
+ public void testInstantAppsCantAccessExternalStorage() throws Exception {
+ assumeTrue("This test requires that the test runs as an Instant app",
+ getContext().getPackageManager().isInstantApp());
+ assertThat(getContext().getPackageManager().isInstantApp()).isTrue();
+
+ // Can't read ExternalStorageDir
+ assertThat(getExternalStorageDir().list()).isNull();
+
+ // Can't create a top-level direcotry
+ final File topLevelDir = new File(getExternalStorageDir(), TEST_DIRECTORY_NAME);
+ assertThat(topLevelDir.mkdir()).isFalse();
+
+ // Can't create file under root dir
+ final File newTxtFile = new File(getExternalStorageDir(), NONMEDIA_FILE_NAME);
+ assertThrows(IOException.class,
+ () -> {
+ newTxtFile.createNewFile();
+ });
+
+ // Can't create music file under /MUSIC
+ final File newMusicFile = new File(getMusicDir(), AUDIO_FILE_NAME);
+ assertThrows(IOException.class,
+ () -> {
+ newMusicFile.createNewFile();
+ });
+
+ // getExternalFilesDir() is not null
+ assertThat(getExternalFilesDir()).isNotNull();
+
+ // Can't read/write app specific dir
+ assertThat(getExternalFilesDir().list()).isNull();
+ assertThat(getExternalFilesDir().exists()).isFalse();
+ }
+
+ private void createAndCheckFileAsApp(TestApp testApp, File newFile) throws Exception {
+ assertThat(createFileAs(testApp, newFile.getPath())).isTrue();
+ assertThat(getFileOwnerPackageFromDatabase(newFile))
+ .isEqualTo(testApp.getPackageName());
+ assertThat(getFileRowIdFromDatabase(newFile)).isNotEqualTo(-1);
+ }
+
/**
* Checks restrictions for opening pending and trashed files by different apps. Assumes that
* given {@code testApp} is already installed and has READ_EXTERNAL_STORAGE permission. This
@@ -2791,16 +959,16 @@
// App with READ_EXTERNAL_STORAGE can't open other app's pending or trashed file for read or
// write
- assertFalse(openFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ false));
- assertFalse(openFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ true));
+ assertFalse(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ false));
+ assertFalse(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ true));
final int testAppUid =
getContext().getPackageManager().getPackageUid(testApp.getPackageName(), 0);
try {
allowAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
// File Manager can open any pending or trashed file for read or write
- assertTrue(openFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ false));
- assertTrue(openFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ true));
+ assertTrue(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ false));
+ assertTrue(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ true));
} finally {
denyAppOpsToUid(testAppUid, OPSTR_MANAGE_EXTERNAL_STORAGE);
}
@@ -2810,14 +978,14 @@
if (isImageOrVideo) {
// System Gallery can open any pending or trashed image/video file for read or write
assertTrue(isMediaTypeImageOrVideo(pendingOrTrashedFile));
- assertTrue(openFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ false));
- assertTrue(openFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ true));
+ assertTrue(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ false));
+ assertTrue(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ true));
} else {
// System Gallery can't open other app's pending or trashed non-media file for read
// or write
assertFalse(isMediaTypeImageOrVideo(pendingOrTrashedFile));
- assertFalse(openFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ false));
- assertFalse(openFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ true));
+ assertFalse(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ false));
+ assertFalse(canOpenFileAs(testApp, pendingOrTrashedFile, /*forWrite*/ true));
}
} finally {
denyAppOpsToUid(testAppUid, SYSTEM_GALERY_APPOPS);
@@ -2936,7 +1104,9 @@
private static void assertCreateFilesAs(TestApp testApp, File... files) throws Exception {
for (File file : files) {
- assertThat(createFileAs(testApp, file.getPath())).isTrue();
+ assertFalse("File already exists: " + file, file.exists());
+ assertTrue("Failed to create file " + file + " on behalf of "
+ + testApp.getPackageName(), createFileAs(testApp, file.getPath()));
}
}
@@ -2950,8 +1120,10 @@
private static void assertCreatePublishedFilesAs(TestApp testApp, File... files)
throws Exception {
for (File file : files) {
- assertThat(createFileAs(testApp, file.getPath())).isTrue();
- assertNotNull(MediaStore.scanFile(getContentResolver(), file));
+ assertTrue("Failed to create published file " + file + " on behalf of "
+ + testApp.getPackageName(), createFileAs(testApp, file.getPath()));
+ assertNotNull("Failed to scan " + file,
+ MediaStore.scanFile(getContentResolver(), file));
}
}
@@ -2964,14 +1136,16 @@
private static void assertCanDeletePathsAs(TestApp testApp, String... filePaths)
throws Exception {
for (String path: filePaths) {
- assertTrue(deleteFileAs(testApp, path));
+ assertTrue("Failed to delete file " + path + " on behalf of "
+ + testApp.getPackageName(), deleteFileAs(testApp, path));
}
}
private static void assertCantDeletePathsAs(TestApp testApp, String... filePaths)
throws Exception {
for (String path: filePaths) {
- assertFalse(deleteFileAs(testApp, path));
+ assertFalse("Deleting " + path + " on behalf of " + testApp.getPackageName()
+ + " was expected to fail", deleteFileAs(testApp, path));
}
}
@@ -2991,7 +1165,8 @@
private static void assertCanDeletePaths(String... filePaths) {
for (String filePath : filePaths) {
- assertTrue(new File(filePath).delete());
+ assertTrue("Failed to delete " + filePath,
+ new File(filePath).delete());
}
}
@@ -3144,4 +1319,38 @@
assertThrows(ErrnoException.class, () -> { Os.access(file.getAbsolutePath(), mask); });
}
}
+
+ private void createFileUsingTradefedContentProvider(File file) throws Exception {
+ // Files/Dirs are created using content provider. Owner of the Filse/Dirs is
+ // android.tradefed.contentprovider.
+ Log.d(TAG, "Creating file " + file);
+ getContentResolver().openFile(Uri.parse(CONTENT_PROVIDER_URL + file.getPath()), "w", null);
+ }
+
+ private void createDirUsingTradefedContentProvider(File file) throws Exception {
+ // Files/Dirs are created using content provider. Owner of the Files/Dirs is
+ // android.tradefed.contentprovider.
+ Log.d(TAG, "Creating Dir " + file);
+ // Create a tmp file in the target directory, this would also create the required
+ // directory, then delete the tmp file. It would leave only new directory.
+ getContentResolver()
+ .openFile(Uri.parse(CONTENT_PROVIDER_URL + file.getPath() + "/tmp.txt"), "w", null);
+ getContentResolver()
+ .delete(Uri.parse(CONTENT_PROVIDER_URL + file.getPath() + "/tmp.txt"), null, null);
+ }
+
+ private void deleteFileUsingTradefedContentProvider(File file) throws Exception {
+ Log.d(TAG, "Deleting file " + file);
+ getContentResolver().delete(Uri.parse(CONTENT_PROVIDER_URL + file.getPath()), null, null);
+ }
+
+ private void deleteDirUsingTradefedContentProvider(File file) throws Exception {
+ Log.d(TAG, "Deleting Dir " + file);
+ getContentResolver().delete(Uri.parse(CONTENT_PROVIDER_URL + file.getPath()), null, null);
+ }
+
+ private int getCurrentUser() throws Exception {
+ String userId = executeShellCommand("am get-current-user");
+ return Integer.parseInt(userId.trim());
+ }
}
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index a02c6a3..72f8415 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -1128,9 +1128,8 @@
// Start test app.
try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action",
"action.show_notification")) {
- // Trigger a pull and wait for new pull before killing the process.
Thread.sleep(WAIT_TIME_LONG);
- // Trigger new pull.
+ // Trigger a pull and wait for new pull before killing the process.
setAppBreadcrumbPredicate();
Thread.sleep(WAIT_TIME_LONG);
}
diff --git a/hostsidetests/statsd/src/android/cts/statsd/metric/CountMetricsTests.java b/hostsidetests/statsd/src/android/cts/statsd/metric/CountMetricsTests.java
index 9eccad6..a63e01e 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/metric/CountMetricsTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/CountMetricsTests.java
@@ -303,117 +303,6 @@
assertThat(totalCount).isEqualTo(2);
}
- public void testSlicedStateCountMetric() throws Exception {
- if (!hasFeature(FEATURE_BLUETOOTH_LE, true)) return;
-
- int whatMatcherId = 3;
- int stateId = 4;
-
- // Atom 9999 {
- // repeated AttributionNode attribution_node = 1;
- // optional bool is_filtered = 2;
- // optional bool is_first_match = 3;
- // optional bool is_opportunistic = 4;
- // }
- int whatAtomId = 9_999;
-
- StatsdConfigProto.AtomMatcher whatMatcher =
- MetricsUtils.getAtomMatcher(whatAtomId)
- .setId(whatMatcherId)
- .build();
-
- StatsdConfigProto.State state = StatsdConfigProto.State.newBuilder()
- .setId(stateId)
- .setAtomId(Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER)
- .build();
-
- StatsdConfigProto.MetricStateLink stateLink = StatsdConfigProto.MetricStateLink.newBuilder()
- .setStateAtomId(Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER)
- .setFieldsInWhat(FieldMatcher.newBuilder()
- .setField(whatAtomId)
- .addChild(FieldMatcher.newBuilder()
- .setField(1)
- .setPosition(Position.FIRST)
- .addChild(FieldMatcher.newBuilder()
- .setField(AttributionNode.UID_FIELD_NUMBER)
- )
- )
- .addChild(FieldMatcher.newBuilder()
- .setField(2)
- )
- .addChild(FieldMatcher.newBuilder()
- .setField(3)
- )
- .addChild(FieldMatcher.newBuilder()
- .setField(4)
- )
- )
- .setFieldsInState(FieldMatcher.newBuilder()
- .setField(Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER)
- .addChild(FieldMatcher.newBuilder()
- .setField(BleScanStateChanged.ATTRIBUTION_NODE_FIELD_NUMBER)
- .setPosition(Position.FIRST)
- .addChild(FieldMatcher.newBuilder()
- .setField(AttributionNode.UID_FIELD_NUMBER)
- )
- )
- .addChild(FieldMatcher.newBuilder()
- .setField(BleScanStateChanged.IS_FILTERED_FIELD_NUMBER)
- )
- .addChild(FieldMatcher.newBuilder()
- .setField(BleScanStateChanged.IS_FIRST_MATCH_FIELD_NUMBER)
- )
- .addChild(FieldMatcher.newBuilder()
- .setField(BleScanStateChanged.IS_OPPORTUNISTIC_FIELD_NUMBER)
- )
- )
- .build();
-
- StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder()
- .addCountMetric(StatsdConfigProto.CountMetric.newBuilder()
- .setId(MetricsUtils.COUNT_METRIC_ID)
- .setBucket(StatsdConfigProto.TimeUnit.CTS)
- .setWhat(whatMatcherId)
- .addSliceByState(stateId)
- .addStateLink(stateLink)
- )
- .addAtomMatcher(whatMatcher)
- .addState(state);
- uploadConfig(builder);
-
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testBleScanInterrupted");
-
- StatsLogReport metricReport = getStatsLogReport();
- LogUtil.CLog.d("Got the following stats log report: \n" + metricReport.toString());
- assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.COUNT_METRIC_ID);
- assertThat(metricReport.hasCountMetrics()).isTrue();
-
- StatsLogReport.CountMetricDataWrapper dataWrapper = metricReport.getCountMetrics();
- assertThat(dataWrapper.getDataCount()).isEqualTo(2);
-
- CountMetricData data = dataWrapper.getData(0);
- assertThat(data.getSliceByStateCount()).isEqualTo(1);
- assertThat(data.getSliceByState(0).getAtomId())
- .isEqualTo(Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER);
- assertThat(data.getSliceByState(0).getValue())
- .isEqualTo(BleScanStateChanged.State.OFF.ordinal());
- long totalCount = data.getBucketInfoList().stream()
- .mapToLong(CountBucketInfo::getCount)
- .sum();
- assertThat(totalCount).isEqualTo(3);
-
- data = dataWrapper.getData(1);
- assertThat(data.getSliceByStateCount()).isEqualTo(1);
- assertThat(data.getSliceByState(0).getAtomId())
- .isEqualTo(Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER);
- assertThat(data.getSliceByState(0).getValue())
- .isEqualTo(BleScanStateChanged.State.ON.ordinal());
- totalCount = data.getBucketInfoList().stream()
- .mapToLong(CountBucketInfo::getCount)
- .sum();
- assertThat(totalCount).isEqualTo(2);
- }
-
public void testSlicedStateCountMetricNoReset() throws Exception {
int whatMatcherId = 3;
int stateId = 4;
diff --git a/hostsidetests/statsd/src/android/cts/statsd/metric/DurationMetricsTests.java b/hostsidetests/statsd/src/android/cts/statsd/metric/DurationMetricsTests.java
index 1a553b2..65cef95 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/metric/DurationMetricsTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/DurationMetricsTests.java
@@ -500,12 +500,10 @@
builder.addPredicate(predicateA);
FieldMatcher.Builder dimensionsBuilder = FieldMatcher.newBuilder()
- .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER);
- dimensionsBuilder.addChild(FieldMatcher.newBuilder()
- .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)
- .setPosition(Position.FIRST)
+ .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER);
+ dimensionsBuilder
.addChild(FieldMatcher.newBuilder().setField(
- AppBreadcrumbReported.LABEL_FIELD_NUMBER)));
+ AppBreadcrumbReported.LABEL_FIELD_NUMBER));
Predicate predicateB =
Predicate.newBuilder()
.setId(MetricsUtils.StringToId("Predicate_B"))
@@ -527,12 +525,9 @@
.setBucket(StatsdConfigProto.TimeUnit.CTS)
.setDimensionsInWhat(
FieldMatcher.newBuilder()
- .setField(Atom.BATTERY_SAVER_MODE_STATE_CHANGED_FIELD_NUMBER)
- .addChild(FieldMatcher.newBuilder()
- .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
- .setPosition(Position.FIRST)
- .addChild(FieldMatcher.newBuilder().setField(
- AppBreadcrumbReported.LABEL_FIELD_NUMBER)))));
+ .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
+ .addChild(FieldMatcher.newBuilder().setField(
+ AppBreadcrumbReported.LABEL_FIELD_NUMBER))));
// Upload config.
uploadConfig(builder);
@@ -554,10 +549,21 @@
assertThat(metricReport.hasDurationMetrics()).isTrue();
StatsLogReport.DurationMetricDataWrapper durationData
= metricReport.getDurationMetrics();
- assertThat(durationData.getDataCount()).isEqualTo(1);
- assertThat(durationData.getData(0).getBucketInfoCount()).isGreaterThan(1);
+ assertThat(durationData.getDataCount()).isEqualTo(2);
+ assertThat(durationData.getData(0).getBucketInfoCount()).isGreaterThan(3);
+ assertThat(durationData.getData(1).getBucketInfoCount()).isGreaterThan(3);
+ long totalDuration = 0;
for (DurationBucketInfo bucketInfo : durationData.getData(0).getBucketInfoList()) {
- assertThat(bucketInfo.getDurationNanos()).isIn(Range.openClosed(0L, (long)1e9));
+ assertThat(bucketInfo.getDurationNanos()).isIn(Range.openClosed(0L, (long) 1e9));
+ totalDuration += bucketInfo.getDurationNanos();
}
+ // Duration for both labels is expected to be 4s.
+ assertThat(totalDuration).isIn(Range.open((long) 3e9, (long) 8e9));
+ totalDuration = 0;
+ for (DurationBucketInfo bucketInfo : durationData.getData(1).getBucketInfoList()) {
+ assertThat(bucketInfo.getDurationNanos()).isIn(Range.openClosed(0L, (long) 1e9));
+ totalDuration += bucketInfo.getDurationNanos();
+ }
+ assertThat(totalDuration).isIn(Range.open((long) 3e9, (long) 8e9));
}
}
diff --git a/libs/install/Android.bp b/libs/install/Android.bp
index 0e1ebb0..6babab7 100644
--- a/libs/install/Android.bp
+++ b/libs/install/Android.bp
@@ -92,7 +92,7 @@
java_library {
name: "cts-install-lib",
- srcs: ["src/**/*.java"],
+ srcs: ["src/**/lib/*.java"],
static_libs: ["androidx.test.rules", "compatibility-device-util-axt", "truth-prebuilt"],
sdk_version: "test_current",
java_resources: [
@@ -110,3 +110,9 @@
":StagedInstallTestApexV3",
],
}
+
+java_library_host {
+ name: "cts-install-lib-host",
+ srcs: ["src/**/host/InstallUtilsHost.java"],
+ libs: ["tradefed", "cts-shim-host-lib",],
+}
diff --git a/libs/install/src/android/cts/install/lib/host/InstallUtilsHost.java b/libs/install/src/android/cts/install/lib/host/InstallUtilsHost.java
new file mode 100644
index 0000000..f6de85b
--- /dev/null
+++ b/libs/install/src/android/cts/install/lib/host/InstallUtilsHost.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.cts.install.lib.host;
+
+import static com.android.cts.shim.lib.ShimPackage.SHIM_APEX_PACKAGE_NAME;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.android.ddmlib.Log;
+import com.android.tradefed.build.BuildInfoKey;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.IRunUtil;
+import com.android.tradefed.util.RunUtil;
+import com.android.tradefed.util.SystemUtil;
+
+import com.google.common.base.Stopwatch;
+
+import java.io.File;
+import java.io.IOException;
+import java.time.Duration;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Utilities to facilitate installation in tests on host side.
+ */
+public class InstallUtilsHost {
+ private static final String TAG = InstallUtilsHost.class.getSimpleName();
+ private static final String APEX_INFO_EXTRACT_REGEX =
+ ".*package:\\sname='(\\S+)\\'\\sversionCode='(\\d+)'\\s.*";
+
+ private final IRunUtil mRunUtil = new RunUtil();
+ private final BaseHostJUnit4Test mTest;
+
+ public InstallUtilsHost(BaseHostJUnit4Test test) {
+ mTest = test;
+ }
+
+ /**
+ * Return {@code true} if and only if device supports updating apex.
+ */
+ public boolean isApexUpdateSupported() throws Exception {
+ return mTest.getDevice().getBooleanProperty("ro.apex.updatable", false);
+ }
+
+ /**
+ * Return {@code true} if and only if device supports file system checkpoint.
+ */
+ public boolean isCheckpointSupported() throws Exception {
+ CommandResult result = mTest.getDevice().executeShellV2Command("sm supports-checkpoint");
+ assertWithMessage("Failed to check if file system checkpoint is supported : %s",
+ result.getStderr()).that(result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
+ return "true".equals(result.getStdout().trim());
+ }
+
+ /**
+ * Uninstalls a shim apex only if it's latest version is installed on /data partition (i.e.
+ * it has a version higher than {@code 1}).
+ *
+ * <p>This is purely to optimize tests run time. Since uninstalling an apex requires a reboot,
+ * and only a small subset of tests successfully install an apex, this code avoids ~10
+ * unnecessary reboots.
+ */
+ public void uninstallShimApexIfNecessary() throws Exception {
+ if (!isApexUpdateSupported()) {
+ // Device doesn't support updating apex. Nothing to uninstall.
+ return;
+ }
+ final ITestDevice.ApexInfo shimApex = getShimApex().orElseThrow(
+ () -> new AssertionError("Can't find " + SHIM_APEX_PACKAGE_NAME));
+ if (shimApex.sourceDir.startsWith("/system")) {
+ // System version is active, nothing to uninstall.
+ return;
+ }
+ // Non system version is active, need to uninstall it and reboot the device.
+ Log.i(TAG, "Uninstalling shim apex");
+ final String errorMessage = mTest.getDevice().uninstallPackage(SHIM_APEX_PACKAGE_NAME);
+ if (errorMessage != null) {
+ Log.e(TAG, "Failed to uninstall " + SHIM_APEX_PACKAGE_NAME + " : " + errorMessage);
+ } else {
+ mTest.getDevice().reboot();
+ final ITestDevice.ApexInfo shim = getShimApex().orElseThrow(
+ () -> new AssertionError("Can't find " + SHIM_APEX_PACKAGE_NAME));
+ assertThat(shim.versionCode).isEqualTo(1L);
+ assertThat(shim.sourceDir).startsWith("/system");
+ }
+ }
+
+ /**
+ * Returns the active shim apex as optional.
+ */
+ public Optional<ITestDevice.ApexInfo> getShimApex() throws DeviceNotAvailableException {
+ return mTest.getDevice().getActiveApexes().stream().filter(
+ apex -> apex.name.equals(SHIM_APEX_PACKAGE_NAME)).findAny();
+ }
+
+ /**
+ * Retrieve package name and version code from test apex file.
+ *
+ * @param apex input apex file to retrieve the info from
+ */
+ public ITestDevice.ApexInfo getApexInfo(File apex) {
+ String aaptOutput = runCmd(String.format("aapt dump badging %s", apex.getAbsolutePath()));
+ String[] lines = aaptOutput.split("\n");
+ Pattern p = Pattern.compile(APEX_INFO_EXTRACT_REGEX);
+ for (String l : lines) {
+ Matcher m = p.matcher(l);
+ if (m.matches()) {
+ return new ITestDevice.ApexInfo(m.group(1), Long.parseLong(m.group(2)));
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Installs packages using staged install flow and waits for pre-reboot verification to complete
+ */
+ public String installStagedPackage(File pkg) throws Exception {
+ return mTest.getDevice().installPackage(pkg, false, "--staged");
+ }
+
+ /**
+ * Install multiple package at the same time
+ */
+ public void installApexes(String... filenames) throws Exception {
+ String[] args = new String[filenames.length + 1];
+ args[0] = "install-multi-package";
+ for (int i = 0; i < filenames.length; i++) {
+ args[i + 1] = getTestFile(filenames[i]).getAbsolutePath();
+ }
+ String stdout = mTest.getDevice().executeAdbCommand(args);
+ assertThat(stdout).isNotNull();
+ }
+
+ /**
+ * Waits for given {@code timeout} for {@code filePath} to be deleted.
+ */
+ public void waitForFileDeleted(String filePath, Duration timeout) throws Exception {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ while (true) {
+ if (!mTest.getDevice().doesFileExist(filePath)) {
+ return;
+ }
+ if (stopwatch.elapsed().compareTo(timeout) > 0) {
+ break;
+ }
+ Thread.sleep(500);
+ }
+ throw new AssertionError("Timed out waiting for " + filePath + " to be deleted");
+ }
+
+ /**
+ * Get the test file.
+ *
+ * @param testFileName name of the file
+ */
+ public File getTestFile(String testFileName) throws IOException {
+ File testFile = null;
+
+ String testcasesPath = System.getenv(
+ SystemUtil.EnvVariable.ANDROID_HOST_OUT_TESTCASES.toString());
+ if (testcasesPath != null) {
+ testFile = searchTestFile(new File(testcasesPath), testFileName);
+ }
+ if (testFile != null) {
+ return testFile;
+ }
+
+ File hostLinkedDir = mTest.getBuild().getFile(
+ BuildInfoKey.BuildInfoFileKey.HOST_LINKED_DIR);
+ if (hostLinkedDir != null) {
+ testFile = searchTestFile(hostLinkedDir, testFileName);
+ }
+ if (testFile != null) {
+ return testFile;
+ }
+
+ // Find the file in the buildinfo.
+ File buildInfoFile = mTest.getBuild().getFile(testFileName);
+ if (buildInfoFile != null) {
+ return buildInfoFile;
+ }
+
+ throw new IOException("Cannot find " + testFileName);
+ }
+
+ /**
+ * Searches the file with the given name under the given directory, returns null if not found.
+ */
+ private File searchTestFile(File baseSearchFile, String testFileName) {
+ if (baseSearchFile != null && baseSearchFile.isDirectory()) {
+ File testFile = FileUtil.findFile(baseSearchFile, testFileName);
+ if (testFile != null && testFile.isFile()) {
+ return testFile;
+ }
+ }
+ return null;
+ }
+
+ private String runCmd(String cmd) {
+ Log.d("About to run command: %s", cmd);
+ CommandResult result = mRunUtil.runTimedCmd(1000 * 60 * 5, cmd.split("\\s+"));
+ assertThat(result).isNotNull();
+ assertWithMessage(String.format("Command %s failed", cmd)).that(result.getStatus())
+ .isEqualTo(CommandStatus.SUCCESS);
+ Log.d("output:\n%s", result.getStdout());
+ return result.getStdout();
+ }
+
+
+}
diff --git a/tests/tests/net/util/Android.bp b/libs/shim/Android.bp
similarity index 66%
rename from tests/tests/net/util/Android.bp
rename to libs/shim/Android.bp
index 1f94613..908cd8e 100644
--- a/tests/tests/net/util/Android.bp
+++ b/libs/shim/Android.bp
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,12 +14,15 @@
// limitations under the License.
//
-// Common utilities for cts net tests.
java_library {
- name: "cts-net-utils",
- srcs: ["java/**/*.java", "java/**/*.kt"],
- static_libs: [
- "compatibility-device-util-axt",
- "junit",
- ],
-}
\ No newline at end of file
+ name: "cts-shim-lib",
+ host_supported: true,
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
+
+// Compatibility version of host library
+java_library_host {
+ name: "cts-shim-host-lib",
+ static_libs: ["cts-shim-lib"],
+}
diff --git a/libs/shim/src/com/android/cts/shim/lib/ShimPackage.java b/libs/shim/src/com/android/cts/shim/lib/ShimPackage.java
new file mode 100644
index 0000000..a357941
--- /dev/null
+++ b/libs/shim/src/com/android/cts/shim/lib/ShimPackage.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.shim.lib;
+
+/**
+ * The constants about shim package.
+ */
+public class ShimPackage {
+
+ /**
+ * Package name of the privileged CTS shim apk
+ */
+ public static final String PRIVILEGED_SHIM_PACKAGE_NAME = "com.android.cts.priv.ctsshim";
+
+ /**
+ * Package name of the system CTS shim apk
+ */
+ public static final String SHIM_PACKAGE_NAME = "com.android.cts.ctsshim";
+
+ /**
+ * Package name of the system CTS shim apex
+ */
+ public static final String SHIM_APEX_PACKAGE_NAME = "com.android.apex.cts.shim";
+
+ /**
+ * Package name of the non pre-installed CTS shim apex
+ */
+ public static final String NOT_PRE_INSTALL_APEX_PACKAGE_NAME =
+ "com.android.apex.cts.shim_not_pre_installed";
+
+ /**
+ * Package name of the CTS shim apex that has the different package name
+ */
+ public static final String DIFFERENT_APEX_PACKAGE_NAME = "com.android.apex.cts.shim.different";
+}
diff --git a/tests/app/src/android/app/cts/NotificationTest.java b/tests/app/src/android/app/cts/NotificationTest.java
index b9f8784..56c369f 100644
--- a/tests/app/src/android/app/cts/NotificationTest.java
+++ b/tests/app/src/android/app/cts/NotificationTest.java
@@ -854,6 +854,40 @@
assertTrue((n.flags & FLAG_BUBBLE) != 0);
}
+ public void testGetMessagesFromBundleArray() {
+ Person sender = new Person.Builder().setName("Sender").build();
+ Notification.MessagingStyle.Message firstExpectedMessage =
+ new Notification.MessagingStyle.Message("hello", /* timestamp= */ 123, sender);
+ Notification.MessagingStyle.Message secondExpectedMessage =
+ new Notification.MessagingStyle.Message("hello2", /* timestamp= */ 456, sender);
+
+ Notification.MessagingStyle messagingStyle =
+ new Notification.MessagingStyle("self name")
+ .addMessage(firstExpectedMessage)
+ .addMessage(secondExpectedMessage);
+ Notification notification = new Notification.Builder(mContext, "test id")
+ .setSmallIcon(1)
+ .setContentTitle("test title")
+ .setStyle(messagingStyle)
+ .build();
+
+ List<Notification.MessagingStyle.Message> actualMessages =
+ Notification.MessagingStyle.Message.getMessagesFromBundleArray(
+ notification.extras.getParcelableArray(Notification.EXTRA_MESSAGES));
+
+ assertEquals(2, actualMessages.size());
+ assertMessageEquals(firstExpectedMessage, actualMessages.get(0));
+ assertMessageEquals(secondExpectedMessage, actualMessages.get(1));
+ }
+
+ private static void assertMessageEquals(
+ Notification.MessagingStyle.Message expected,
+ Notification.MessagingStyle.Message actual) {
+ assertEquals(expected.getText(), actual.getText());
+ assertEquals(expected.getTimestamp(), actual.getTimestamp());
+ assertEquals(expected.getSenderPerson(), actual.getSenderPerson());
+ }
+
private static RemoteInput newDataOnlyRemoteInput() {
return new RemoteInput.Builder(DATA_RESULT_KEY)
.setAllowFreeFormInput(false)
diff --git a/tests/backup/Android.bp b/tests/backup/Android.bp
index 38f1044..e1fcf7f 100644
--- a/tests/backup/Android.bp
+++ b/tests/backup/Android.bp
@@ -35,6 +35,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
sdk_version: "test_current",
}
diff --git a/tests/backup/app/Android.bp b/tests/backup/app/Android.bp
index ccbe771..352ed6d 100644
--- a/tests/backup/app/Android.bp
+++ b/tests/backup/app/Android.bp
@@ -26,6 +26,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
platform_apis: true,
manifest: "fullbackup/AndroidManifest.xml"
@@ -46,6 +47,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
platform_apis: true,
manifest: "keyvalue/AndroidManifest.xml"
@@ -66,6 +68,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
platform_apis: true,
manifest: "permission/AndroidManifest.xml"
@@ -86,6 +89,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
platform_apis: true,
manifest: "permission22/AndroidManifest.xml"
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
index be945d6..5cbe40e 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
@@ -183,7 +183,7 @@
@Override
public void close() {
- SystemUtil.runWithShellPermissionIdentity(mWallpaperManager::clearWallpaper);
+ SystemUtil.runWithShellPermissionIdentity(() -> mWallpaperManager.clearWallpaper());
if (mTestBitmap != null) {
mTestBitmap.recycle();
}
diff --git a/tests/inputmethod/mockime/Android.bp b/tests/inputmethod/mockime/Android.bp
index c73f870..2283541 100644
--- a/tests/inputmethod/mockime/Android.bp
+++ b/tests/inputmethod/mockime/Android.bp
@@ -42,6 +42,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
static_libs: [
"androidx.annotation_annotation",
diff --git a/tests/tests/net/ipsec/Android.bp b/tests/tests/apache-http/Android.bp
similarity index 69%
rename from tests/tests/net/ipsec/Android.bp
rename to tests/tests/apache-http/Android.bp
index 124e93c..9167002 100644
--- a/tests/tests/net/ipsec/Android.bp
+++ b/tests/tests/apache-http/Android.bp
@@ -13,36 +13,28 @@
// limitations under the License.
android_test {
- name: "CtsIkeTestCases",
+ name: "CtsApacheHttpTestCases",
defaults: ["cts_defaults"],
-
- // Include both the 32 and 64 bit versions
- compile_multilib: "both",
-
- libs: [
- "android.net.ipsec.ike.stubs.system",
- "android.test.base.stubs",
- ],
-
+ sdk_version: "test_current",
srcs: [
"src/**/*.java",
- ":ike-test-utils",
+ "src/**/*.kt",
],
-
+ libs: [
+ "android.test.base",
+ "org.apache.http.legacy",
+ ],
static_libs: [
- "androidx.test.ext.junit",
"compatibility-device-util-axt",
- "ctstestrunner-axt",
- "net-tests-utils",
+ "mockwebserver",
+ "ctstestserver",
],
-
- platform_apis: true,
-
- // Tag this module as a cts test artifact
+ jni_libs: [
+ "libcts_jni",
+ ],
test_suites: [
"cts",
- "mts",
- "vts",
"general-tests",
],
+ compile_multilib: "both",
}
diff --git a/tests/tests/apache-http/AndroidManifest.xml b/tests/tests/apache-http/AndroidManifest.xml
new file mode 100644
index 0000000..8fa478b
--- /dev/null
+++ b/tests/tests/apache-http/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.apachehttp.cts">
+
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application android:usesCleartextTraffic="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!-- self-instrumenting test package. -->
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.apachehttp.cts" >
+ </instrumentation>
+</manifest>
diff --git a/tests/tests/net/api23Test/AndroidTest.xml b/tests/tests/apache-http/AndroidTest.xml
similarity index 71%
rename from tests/tests/net/api23Test/AndroidTest.xml
rename to tests/tests/apache-http/AndroidTest.xml
index 8042d50..0bd9d28 100644
--- a/tests/tests/net/api23Test/AndroidTest.xml
+++ b/tests/tests/apache-http/AndroidTest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2019 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,20 +13,18 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Config for CTS Net API23 test cases">
+
+<configuration description="Config for CtsApacheHttpDeviceTestCases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="networking" />
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsNetApi23TestCases.apk" />
- <option name="test-file-name" value="CtsNetTestAppForApi23.apk" />
+ <option name="test-file-name" value="CtsApacheHttpTestCases.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.net.cts.api23test" />
- <option name="hidden-api-checks" value="false" />
+ <option name="package" value="android.apachehttp.cts" />
</test>
</configuration>
diff --git a/tests/tests/apache-http/OWNERS b/tests/tests/apache-http/OWNERS
new file mode 100644
index 0000000..b9032af
--- /dev/null
+++ b/tests/tests/apache-http/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 24949
+include platform/frameworks/base:/core/java/android/net/http/OWNERS
diff --git a/tests/tests/net/src/android/net/http/cts/ApacheHttpClientTest.java b/tests/tests/apache-http/src/android/net/http/cts/ApacheHttpClientTest.java
similarity index 100%
rename from tests/tests/net/src/android/net/http/cts/ApacheHttpClientTest.java
rename to tests/tests/apache-http/src/android/net/http/cts/ApacheHttpClientTest.java
diff --git a/tests/tests/net/src/android/net/http/cts/HttpResponseCacheTest.java b/tests/tests/apache-http/src/android/net/http/cts/HttpResponseCacheTest.java
similarity index 100%
rename from tests/tests/net/src/android/net/http/cts/HttpResponseCacheTest.java
rename to tests/tests/apache-http/src/android/net/http/cts/HttpResponseCacheTest.java
diff --git a/tests/tests/net/src/android/net/http/cts/SslCertificateTest.java b/tests/tests/apache-http/src/android/net/http/cts/SslCertificateTest.java
similarity index 100%
rename from tests/tests/net/src/android/net/http/cts/SslCertificateTest.java
rename to tests/tests/apache-http/src/android/net/http/cts/SslCertificateTest.java
diff --git a/tests/tests/net/src/android/net/http/cts/SslCertificate_DNameTest.java b/tests/tests/apache-http/src/android/net/http/cts/SslCertificate_DNameTest.java
similarity index 100%
rename from tests/tests/net/src/android/net/http/cts/SslCertificate_DNameTest.java
rename to tests/tests/apache-http/src/android/net/http/cts/SslCertificate_DNameTest.java
diff --git a/tests/tests/net/src/android/net/http/cts/SslErrorTest.java b/tests/tests/apache-http/src/android/net/http/cts/SslErrorTest.java
similarity index 100%
rename from tests/tests/net/src/android/net/http/cts/SslErrorTest.java
rename to tests/tests/apache-http/src/android/net/http/cts/SslErrorTest.java
diff --git a/tests/tests/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java b/tests/tests/apache-http/src/android/net/http/cts/X509TrustManagerExtensionsTest.java
similarity index 100%
rename from tests/tests/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java
rename to tests/tests/apache-http/src/android/net/http/cts/X509TrustManagerExtensionsTest.java
diff --git a/tests/tests/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java b/tests/tests/apache-http/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java
similarity index 100%
rename from tests/tests/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java
rename to tests/tests/apache-http/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java
diff --git a/tests/tests/appop/Android.bp b/tests/tests/appop/Android.bp
index 20ab4bf..adf36f1 100644
--- a/tests/tests/appop/Android.bp
+++ b/tests/tests/appop/Android.bp
@@ -92,5 +92,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/appop/AndroidTest.xml b/tests/tests/appop/AndroidTest.xml
index 29f01e0..fc5c0bf 100644
--- a/tests/tests/appop/AndroidTest.xml
+++ b/tests/tests/appop/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/appop/AppInBackground/Android.bp b/tests/tests/appop/AppInBackground/Android.bp
index b46e877..032043e 100644
--- a/tests/tests/appop/AppInBackground/Android.bp
+++ b/tests/tests/appop/AppInBackground/Android.bp
@@ -19,5 +19,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
]
}
diff --git a/tests/tests/appop/AppThatCanBeForcedIntoForegroundStates/Android.bp b/tests/tests/appop/AppThatCanBeForcedIntoForegroundStates/Android.bp
index cc1f836..7a088c6 100644
--- a/tests/tests/appop/AppThatCanBeForcedIntoForegroundStates/Android.bp
+++ b/tests/tests/appop/AppThatCanBeForcedIntoForegroundStates/Android.bp
@@ -25,5 +25,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
]
}
\ No newline at end of file
diff --git a/tests/tests/appop/AppThatUsesAppOps/Android.bp b/tests/tests/appop/AppThatUsesAppOps/Android.bp
index 0ba18c3..82982e6 100644
--- a/tests/tests/appop/AppThatUsesAppOps/Android.bp
+++ b/tests/tests/appop/AppThatUsesAppOps/Android.bp
@@ -59,5 +59,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
]
}
\ No newline at end of file
diff --git a/tests/tests/appop/AppToBlame1/Android.bp b/tests/tests/appop/AppToBlame1/Android.bp
index 70d1c6e..ce92d4a 100644
--- a/tests/tests/appop/AppToBlame1/Android.bp
+++ b/tests/tests/appop/AppToBlame1/Android.bp
@@ -19,5 +19,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
]
}
\ No newline at end of file
diff --git a/tests/tests/appop/AppToBlame2/Android.bp b/tests/tests/appop/AppToBlame2/Android.bp
index 85f97c9..75df191 100644
--- a/tests/tests/appop/AppToBlame2/Android.bp
+++ b/tests/tests/appop/AppToBlame2/Android.bp
@@ -19,5 +19,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
]
}
\ No newline at end of file
diff --git a/tests/tests/appop/AppToCollect/Android.bp b/tests/tests/appop/AppToCollect/Android.bp
index 8a1b5a8..e9eb489 100644
--- a/tests/tests/appop/AppToCollect/Android.bp
+++ b/tests/tests/appop/AppToCollect/Android.bp
@@ -19,5 +19,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
]
}
\ No newline at end of file
diff --git a/tests/tests/appop/AppWithAttributionInheritingFromExisting/Android.bp b/tests/tests/appop/AppWithAttributionInheritingFromExisting/Android.bp
index 8fd4431..33b04d2 100644
--- a/tests/tests/appop/AppWithAttributionInheritingFromExisting/Android.bp
+++ b/tests/tests/appop/AppWithAttributionInheritingFromExisting/Android.bp
@@ -19,5 +19,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
]
}
\ No newline at end of file
diff --git a/tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/Android.bp b/tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/Android.bp
index 8d519dc..1d450b8 100644
--- a/tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/Android.bp
+++ b/tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/Android.bp
@@ -19,5 +19,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
]
}
\ No newline at end of file
diff --git a/tests/tests/appop/AppWithAttributionInheritingFromSelf/Android.bp b/tests/tests/appop/AppWithAttributionInheritingFromSelf/Android.bp
index eab4652..fcb3613 100644
--- a/tests/tests/appop/AppWithAttributionInheritingFromSelf/Android.bp
+++ b/tests/tests/appop/AppWithAttributionInheritingFromSelf/Android.bp
@@ -19,5 +19,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
]
}
\ No newline at end of file
diff --git a/tests/tests/appop/AppWithDuplicateAttribution/Android.bp b/tests/tests/appop/AppWithDuplicateAttribution/Android.bp
index cab076c..ec545e3 100644
--- a/tests/tests/appop/AppWithDuplicateAttribution/Android.bp
+++ b/tests/tests/appop/AppWithDuplicateAttribution/Android.bp
@@ -19,5 +19,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
]
}
\ No newline at end of file
diff --git a/tests/tests/appop/AppWithLongAttributionTag/Android.bp b/tests/tests/appop/AppWithLongAttributionTag/Android.bp
index e82d3e5..0ff9efd 100644
--- a/tests/tests/appop/AppWithLongAttributionTag/Android.bp
+++ b/tests/tests/appop/AppWithLongAttributionTag/Android.bp
@@ -19,5 +19,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
]
}
\ No newline at end of file
diff --git a/tests/tests/appop/AppWithTooManyAttributions/Android.bp b/tests/tests/appop/AppWithTooManyAttributions/Android.bp
index 8676715..9467086 100644
--- a/tests/tests/appop/AppWithTooManyAttributions/Android.bp
+++ b/tests/tests/appop/AppWithTooManyAttributions/Android.bp
@@ -19,5 +19,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
]
}
\ No newline at end of file
diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
index 133973a..efb863b 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
@@ -69,6 +69,13 @@
}
@Test
+ fun ensureCorrectOpStr() {
+ appOpsManager.noteOp(OPSTR_WIFI_SCAN, myUid, myPackage, null, null)
+ val opEntry = getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!
+ assertThat(opEntry.opStr).isEqualTo(OPSTR_WIFI_SCAN)
+ }
+
+ @Test
fun switchUidStateWhileOpsAreRunning() {
val before = System.currentTimeMillis()
diff --git a/tests/tests/carrierapi/AndroidTest.xml b/tests/tests/carrierapi/AndroidTest.xml
index adafe53..e5e885d 100644
--- a/tests/tests/carrierapi/AndroidTest.xml
+++ b/tests/tests/carrierapi/AndroidTest.xml
@@ -20,9 +20,6 @@
<option name="config-descriptor:metadata" key="component" value="telecom" />
<option name="config-descriptor:metadata" key="token" value="UICC_SIM_CARD" />
<option name="not-shardable" value="true" />
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.TokenRequirement">
- <option name="token" value="sim-card-with-certs" />
- </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsCarrierApiTestCases.apk" />
diff --git a/tests/tests/content/Android.bp b/tests/tests/content/Android.bp
index eba49d3..a1dd914 100644
--- a/tests/tests/content/Android.bp
+++ b/tests/tests/content/Android.bp
@@ -71,6 +71,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
min_sdk_version: "29",
}
diff --git a/tests/tests/content/BinderPermissionTestService/Android.bp b/tests/tests/content/BinderPermissionTestService/Android.bp
index 8408547..7d4577c 100644
--- a/tests/tests/content/BinderPermissionTestService/Android.bp
+++ b/tests/tests/content/BinderPermissionTestService/Android.bp
@@ -26,6 +26,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
optimize: {
enabled: false,
diff --git a/tests/tests/content/DirectBootUnawareTestApp/Android.bp b/tests/tests/content/DirectBootUnawareTestApp/Android.bp
index 1206cb3..49d08cf 100644
--- a/tests/tests/content/DirectBootUnawareTestApp/Android.bp
+++ b/tests/tests/content/DirectBootUnawareTestApp/Android.bp
@@ -21,6 +21,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
min_sdk_version: "29",
diff --git a/tests/tests/content/PartiallyDirectBootAwareTestApp/Android.bp b/tests/tests/content/PartiallyDirectBootAwareTestApp/Android.bp
index c08aa30..6c10355 100644
--- a/tests/tests/content/PartiallyDirectBootAwareTestApp/Android.bp
+++ b/tests/tests/content/PartiallyDirectBootAwareTestApp/Android.bp
@@ -21,6 +21,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
min_sdk_version : "29"
}
diff --git a/tests/tests/content/SyncAccountAccessStubs/Android.bp b/tests/tests/content/SyncAccountAccessStubs/Android.bp
index 6358d12..03a19fe 100644
--- a/tests/tests/content/SyncAccountAccessStubs/Android.bp
+++ b/tests/tests/content/SyncAccountAccessStubs/Android.bp
@@ -24,6 +24,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
optimize: {
enabled: false,
diff --git a/tests/tests/content/emptytestapp/Android.bp b/tests/tests/content/emptytestapp/Android.bp
index 71baac9..c3aef50 100644
--- a/tests/tests/content/emptytestapp/Android.bp
+++ b/tests/tests/content/emptytestapp/Android.bp
@@ -21,6 +21,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
min_sdk_version : "29"
}
diff --git a/tests/tests/content/src/android/content/cts/ApexEnvironmentTest.java b/tests/tests/content/src/android/content/cts/ApexEnvironmentTest.java
new file mode 100644
index 0000000..eb97850
--- /dev/null
+++ b/tests/tests/content/src/android/content/cts/ApexEnvironmentTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.ApexEnvironment;
+import android.os.UserHandle;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Copied from frameworks/base/core/tests/coretests/src/android/content/ApexEnvironmentTest.java
+ */
+@AppModeFull(reason = "Doesn't interact with system server")
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ApexEnvironmentTest {
+
+ @Test
+ public void dataDirectoryPathsAreAsExpected() {
+ ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment("my.apex");
+
+ assertEquals("/data/misc/apexdata/my.apex",
+ apexEnvironment.getDeviceProtectedDataDir().getAbsolutePath());
+
+ assertEquals("/data/misc_de/5/apexdata/my.apex",
+ apexEnvironment
+ .getDeviceProtectedDataDirForUser(UserHandle.of(5)).getAbsolutePath());
+
+ assertEquals("/data/misc_ce/16/apexdata/my.apex",
+ apexEnvironment.getCredentialProtectedDataDirForUser(
+ UserHandle.of(16)).getAbsolutePath());
+ }
+}
diff --git a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
index 11b0c62..f0fb434 100644
--- a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
@@ -26,6 +26,7 @@
#include <assert.h>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
+#include <sys/stat.h>
#include <android/native_window_jni.h>
@@ -59,8 +60,10 @@
static bool gListenerGotValidExpiryTime = false;
static bool gOnKeyChangeListenerOK = false;
-static const size_t kPlayTimeSeconds = 30;
-static const size_t kUuidSize = 16;
+static const char kFileScheme[] = "file://";
+static constexpr size_t kFileSchemeStrLen = sizeof(kFileScheme) - 1;
+static constexpr size_t kPlayTimeSeconds = 30;
+static constexpr size_t kUuidSize = 16;
static const uint8_t kClearKeyUuid[kUuidSize] = {
0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
@@ -131,6 +134,40 @@
return juuid;
}
+static media_status_t setDataSourceFdFromUrl(
+ AMediaExtractor* extractor, const char* url) {
+
+ const char *path = url + kFileSchemeStrLen;
+ FILE* fp = fopen(path, "r");
+ struct stat buf {};
+ media_status_t status = AMEDIA_ERROR_BASE;
+ if (fp && !fstat(fileno(fp), &buf)) {
+ status = AMediaExtractor_setDataSourceFd(
+ extractor,
+ fileno(fp), 0, buf.st_size);
+ } else {
+ status = AMEDIA_ERROR_IO;
+ ALOGE("Failed to convert URL to Fd");
+ }
+ if (fp && fclose(fp) == EOF) {
+ // 0 indicate success, EOF for error
+ ALOGE("Failed to close file pointer");
+ }
+ return status;
+}
+
+static media_status_t setDataSourceFdOrUrl(
+ AMediaExtractor* extractor, const char* url) {
+
+ media_status_t status = AMEDIA_ERROR_BASE;
+ if (strlen(url) > kFileSchemeStrLen && strncmp(url, kFileScheme, kFileSchemeStrLen) == 0) {
+ status = setDataSourceFdFromUrl(extractor, url);
+ } else {
+ status = AMediaExtractor_setDataSource(extractor, url);
+ }
+ return status;
+}
+
extern "C" jboolean Java_android_media_cts_NativeMediaDrmClearkeyTest_isCryptoSchemeSupportedNative(
JNIEnv* env, jclass /*clazz*/, jbyteArray uuid) {
@@ -279,7 +316,7 @@
aMediaObjects.setVideoExtractor(AMediaExtractor_new());
const char* url = env->GetStringUTFChars(videoUrl, 0);
if (url) {
- media_status_t status = AMediaExtractor_setDataSource(
+ media_status_t status = setDataSourceFdOrUrl(
aMediaObjects.getVideoExtractor(), url);
env->ReleaseStringUTFChars(videoUrl, url);
@@ -696,7 +733,7 @@
aMediaObjects.setAudioExtractor(AMediaExtractor_new());
const char* url = env->GetStringUTFChars(params.audioUrl, 0);
if (url) {
- status = AMediaExtractor_setDataSource(
+ status = setDataSourceFdOrUrl(
aMediaObjects.getAudioExtractor(), url);
env->ReleaseStringUTFChars(params.audioUrl, url);
@@ -710,7 +747,7 @@
aMediaObjects.setVideoExtractor(AMediaExtractor_new());
url = env->GetStringUTFChars(params.videoUrl, 0);
if (url) {
- status = AMediaExtractor_setDataSource(
+ status = setDataSourceFdOrUrl(
aMediaObjects.getVideoExtractor(), url);
env->ReleaseStringUTFChars(params.videoUrl, url);
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java b/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
index f06687c..de9859f 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
@@ -15,6 +15,7 @@
*/
package android.media.cts;
+import android.content.Context;
import android.content.res.Resources;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
@@ -93,6 +94,7 @@
private Thread mThread;
private Uri mAudioUri;
private Uri mVideoUri;
+ private Context mContext;
private Resources mResources;
private Error mErrorFromThread;
@@ -143,11 +145,12 @@
* Media player class to stream CENC content using MediaCodec class.
*/
public MediaCodecClearKeyPlayer(
- List<Surface> surfaces, byte[] sessionId, boolean scrambled, Resources resources) {
+ List<Surface> surfaces, byte[] sessionId, boolean scrambled, Context context) {
mSessionId = sessionId;
mScrambled = scrambled;
mSurfaces = new ArrayDeque<>(surfaces);
- mResources = resources;
+ mContext = context;
+ mResources = context.getResources();
mState = STATE_IDLE;
mThread = new Thread(new Runnable() {
@Override
@@ -300,22 +303,6 @@
}
}
- private void setDataSource(MediaExtractor extractor, Uri uri, Map<String, String> headers)
- throws IOException, MediaCasException {
- String scheme = uri.getScheme();
- if (scheme.startsWith("http")) {
- extractor.setDataSource(uri.toString(), headers);
- } else if (scheme.startsWith(FILE_SCHEME)) {
- extractor.setDataSource(uri.toString().substring(FILE_SCHEME.length()), headers);
- } else if (scheme.equals("android.resource")) {
- int res = Integer.parseInt(uri.getLastPathSegment());
- AssetFileDescriptor fd = mResources.openRawResourceFd(res);
- extractor.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
- } else {
- throw new IllegalArgumentException(uri.toString());
- }
- }
-
private void initCasAndDescrambler(MediaExtractor extractor) throws MediaCasException {
int trackCount = extractor.getTrackCount();
for (int trackId = 0; trackId < trackCount; trackId++) {
@@ -370,7 +357,7 @@
return;
}
}
- setDataSource(mAudioExtractor, mAudioUri, mAudioHeaders);
+ mAudioExtractor.setDataSource(mContext, mAudioUri, mAudioHeaders);
if (mScrambled) {
initCasAndDescrambler(mAudioExtractor);
@@ -383,7 +370,7 @@
return;
}
}
- setDataSource(mVideoExtractor, mVideoUri, mVideoHeaders);
+ mVideoExtractor.setDataSource(mContext, mVideoUri, mVideoHeaders);
}
if (null == mVideoCodecStates) {
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecPlayerTestBase.java b/tests/tests/media/src/android/media/cts/MediaCodecPlayerTestBase.java
index 288b173..c0aff22 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecPlayerTestBase.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecPlayerTestBase.java
@@ -93,7 +93,7 @@
mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
surfaces,
sessionId, scrambled,
- mContext.getResources());
+ mContext);
mMediaCodecPlayer.setAudioDataSource(audioUrl, null, audioEncrypted);
mMediaCodecPlayer.setVideoDataSource(videoUrl, null, videoEncrypted);
diff --git a/tests/tests/media/src/android/media/cts/MediaDrmClearkeyTest.java b/tests/tests/media/src/android/media/cts/MediaDrmClearkeyTest.java
index 91c3ec4..e3c7f6b 100644
--- a/tests/tests/media/src/android/media/cts/MediaDrmClearkeyTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaDrmClearkeyTest.java
@@ -456,7 +456,7 @@
mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
getSurfaces(),
mSessionId, false /*scrambled */,
- mContext.getResources());
+ mContext);
Uri audioUrl = Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH);
mMediaCodecPlayer.setAudioDataSource(audioUrl, null, false);
@@ -541,7 +541,7 @@
mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
getSurfaces(),
mSessionId, false,
- mContext.getResources());
+ mContext);
mMediaCodecPlayer.setAudioDataSource(
Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH), null, false);
mMediaCodecPlayer.setVideoDataSource(
@@ -587,7 +587,7 @@
mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
getSurfaces(),
mSessionId, false,
- mContext.getResources());
+ mContext);
mMediaCodecPlayer.setAudioDataSource(
Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH), null, false);
mMediaCodecPlayer.setVideoDataSource(
@@ -1051,7 +1051,7 @@
mSessionId = openSession(drm);
mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
- getSurfaces(), mSessionId, false, mContext.getResources());
+ getSurfaces(), mSessionId, false, mContext);
mMediaCodecPlayer.setAudioDataSource(
Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH), null, false);
mMediaCodecPlayer.setVideoDataSource(
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerDrmTestBase.java b/tests/tests/media/src/android/media/cts/MediaPlayerDrmTestBase.java
index b65c690..23ad13a 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerDrmTestBase.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerDrmTestBase.java
@@ -175,19 +175,28 @@
// the asset such that each asset is downloaded once and played back with multiple tests.
protected void playModularDrmVideoDownload(Uri uri, Uri path, int width, int height,
ModularDrmTestType testType) throws Exception {
- final long DOWNLOAD_TIMEOUT_SECONDS = 600;
- Log.i(TAG, "Downloading file:" + path);
+ Uri file = uri;
+ long id = -1;
MediaDownloadManager mediaDownloadManager = new MediaDownloadManager(mContext);
- final long id = mediaDownloadManager.downloadFileWithRetries(
- uri, path, DOWNLOAD_TIMEOUT_SECONDS, STREAM_RETRIES);
- assertFalse("Download " + uri + " failed.", id == -1);
- Uri file = mediaDownloadManager.getUriForDownloadedFile(id);
- Log.i(TAG, "Downloaded file:" + path + " id:" + id + " uri:" + file);
+ if (uri.getScheme().startsWith("file")) {
+ Log.i(TAG, "Playing existing file:" + uri);
+ // file = uri;
+ } else {
+ final long DOWNLOAD_TIMEOUT_SECONDS = 600;
+ Log.i(TAG, "Downloading file:" + path);
+ id = mediaDownloadManager.downloadFileWithRetries(
+ uri, path, DOWNLOAD_TIMEOUT_SECONDS, STREAM_RETRIES);
+ assertFalse("Download " + uri + " failed.", id == -1);
+ file = mediaDownloadManager.getUriForDownloadedFile(id);
+ Log.i(TAG, "Downloaded file:" + path + " id:" + id + " uri:" + file);
+ }
try {
playModularDrmVideo(file, width, height, testType);
} finally {
- mediaDownloadManager.removeFile(id);
+ if (id != -1) {
+ mediaDownloadManager.removeFile(id);
+ }
}
}
diff --git a/tests/tests/mediaparser/Android.bp b/tests/tests/mediaparser/Android.bp
index 6a13d24..13859a77 100644
--- a/tests/tests/mediaparser/Android.bp
+++ b/tests/tests/mediaparser/Android.bp
@@ -14,25 +14,33 @@
android_test {
name: "CtsMediaParserTestCases",
- defaults: ["cts_defaults"],
+ defaults: ["CtsMediaParserTestCasesDefaults", "cts_defaults"],
+ min_sdk_version: "29",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts",
+ ],
+}
+
+// App for host-side testing of the MediaParser integration with MediaMetrics.
+android_test_helper_app {
+ name: "CtsMediaParserTestCasesApp",
+ defaults: ["CtsMediaParserTestCasesDefaults"],
+}
+
+java_defaults {
+ name: "CtsMediaParserTestCasesDefaults",
+ srcs: ["src/**/*.java"],
static_libs: [
"ctstestrunner-axt",
"androidx.test.ext.junit",
"exoplayer2-extractor-test-utils",
"exoplayer2-extractor-tests-assets",
],
- srcs: ["src/**/*.java"],
- sdk_version: "test_current",
- min_sdk_version: "29",
libs: [
"android.test.base.stubs",
"android.test.runner.stubs",
],
-
- test_suites: [
- "cts",
- "vts10",
- "general-tests",
- "mts",
- ],
+ sdk_version: "test_current",
}
diff --git a/tests/tests/mediaparser/TEST_MAPPING b/tests/tests/mediaparser/TEST_MAPPING
index ec2d2e2..3d21914 100644
--- a/tests/tests/mediaparser/TEST_MAPPING
+++ b/tests/tests/mediaparser/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "CtsMediaParserTestCases"
+ },
+ {
+ "name": "CtsMediaParserHostTestCases"
}
]
}
diff --git a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
index 40ddad9..145ac99 100644
--- a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
+++ b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
@@ -673,42 +673,44 @@
mediaParser.setParameter(entry.getKey(), entry.getValue());
}
- mediaParser.advance(inputReader);
- if (expectedParserName != null) {
- assertThat(expectedParserName).isEqualTo(mediaParser.getParserName());
- // We are only checking that the extractor is the right one.
- mediaParser.release();
- return;
- }
+ try {
+ mediaParser.advance(inputReader);
+ if (expectedParserName != null) {
+ assertThat(expectedParserName).isEqualTo(mediaParser.getParserName());
+ // We are only checking that the extractor is the right one.
+ return;
+ }
- while (mediaParser.advance(inputReader)) {
- // Do nothing.
- }
+ while (mediaParser.advance(inputReader)) {
+ // Do nothing.
+ }
- // If the SeekMap is seekable, test seeking in the stream.
- MediaParser.SeekMap seekMap = outputConsumer.getSeekMap();
- assertThat(seekMap).isNotNull();
- if (seekMap.isSeekable()) {
- long durationUs = seekMap.getDurationMicros();
- for (int j = 0; j < 4; j++) {
- outputConsumer.clearTrackOutputs();
- long timeUs =
- durationUs == MediaParser.SeekMap.UNKNOWN_DURATION
- ? 0
- : (durationUs * j) / 3;
- MediaParser.SeekPoint seekPoint = seekMap.getSeekPoints(timeUs).first;
- inputReader.reset();
- inputReader.setPosition((int) seekPoint.position);
- mediaParser.seek(seekPoint);
- while (mediaParser.advance(inputReader)) {
- // Do nothing.
- }
- if (durationUs == MediaParser.SeekMap.UNKNOWN_DURATION) {
- break;
+ // If the SeekMap is seekable, test seeking in the stream.
+ MediaParser.SeekMap seekMap = outputConsumer.getSeekMap();
+ assertThat(seekMap).isNotNull();
+ if (seekMap.isSeekable()) {
+ long durationUs = seekMap.getDurationMicros();
+ for (int j = 0; j < 4; j++) {
+ outputConsumer.clearTrackOutputs();
+ long timeUs =
+ durationUs == MediaParser.SeekMap.UNKNOWN_DURATION
+ ? 0
+ : (durationUs * j) / 3;
+ MediaParser.SeekPoint seekPoint = seekMap.getSeekPoints(timeUs).first;
+ inputReader.reset();
+ inputReader.setPosition((int) seekPoint.position);
+ mediaParser.seek(seekPoint);
+ while (mediaParser.advance(inputReader)) {
+ // Do nothing.
+ }
+ if (durationUs == MediaParser.SeekMap.UNKNOWN_DURATION) {
+ break;
+ }
}
}
+ } finally {
+ mediaParser.release();
}
- mediaParser.release();
}
private static MockMediaParserInputReader getInputReader(String assetPath) throws IOException {
diff --git a/tests/tests/net/Android.bp b/tests/tests/net/Android.bp
deleted file mode 100644
index 7eaf133..0000000
--- a/tests/tests/net/Android.bp
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-java_defaults {
- name: "CtsNetTestCasesDefaults",
- defaults: ["cts_defaults"],
-
- // Include both the 32 and 64 bit versions
- compile_multilib: "both",
-
- libs: [
- "voip-common",
- "org.apache.http.legacy",
- "android.test.base.stubs",
- ],
-
- jni_libs: [
- "libcts_jni",
- "libnativedns_jni",
- "libnativemultinetwork_jni",
- "libnativehelper_compat_libc++",
- ],
-
- srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- ],
- jarjar_rules: "jarjar-rules-shared.txt",
- static_libs: [
- "FrameworksNetCommonTests",
- "TestNetworkStackLib",
- "compatibility-device-util-axt",
- "core-tests-support",
- "cts-net-utils",
- "ctstestrunner-axt",
- "ctstestserver",
- "junit",
- "junit-params",
- "libnanohttpd",
- "mockwebserver",
- "net-utils-framework-common",
- "truth-prebuilt",
- ],
-
- // uncomment when b/13249961 is fixed
- // sdk_version: "current",
- platform_apis: true,
-}
-
-// Networking CTS tests for development and release. These tests always target the platform SDK
-// version, and are subject to all the restrictions appropriate to that version. Before SDK
-// finalization, these tests have a min_sdk_version of 10000, and cannot be installed on release
-// devices.
-android_test {
- name: "CtsNetTestCases",
- defaults: ["CtsNetTestCasesDefaults"],
- test_suites: [
- "cts",
- "vts10",
- "general-tests",
- ],
- test_config_template: "AndroidTestTemplate.xml",
-}
-
-// Networking CTS tests that target the latest released SDK. These tests can be installed on release
-// devices at any point in the Android release cycle and are useful for qualifying mainline modules
-// on release devices.
-android_test {
- name: "CtsNetTestCasesLatestSdk",
- defaults: ["CtsNetTestCasesDefaults"],
- jni_uses_sdk_apis: true,
- min_sdk_version: "29",
- target_sdk_version: "30",
- test_suites: [
- "general-tests",
- "mts",
- ],
- test_config_template: "AndroidTestTemplate.xml",
-}
diff --git a/tests/tests/net/AndroidManifest.xml b/tests/tests/net/AndroidManifest.xml
deleted file mode 100644
index a7e2bd7..0000000
--- a/tests/tests/net/AndroidManifest.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.net.cts"
- android:targetSandboxVersion="2">
-
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <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" />
- <uses-permission android:name="android.permission.RECORD_AUDIO" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
-
- <!-- This test also uses signature permissions through adopting the shell identity.
- The permissions acquired that way include (probably not exhaustive) :
- android.permission.MANAGE_TEST_NETWORKS
- -->
-
- <application android:usesCleartextTraffic="true">
- <uses-library android:name="android.test.runner" />
- <uses-library android:name="org.apache.http.legacy" android:required="false" />
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.net.cts"
- android:label="CTS tests of android.net">
- <meta-data android:name="listener"
- android:value="com.android.cts.runner.CtsTestRunListener" />
- </instrumentation>
-
-</manifest>
-
diff --git a/tests/tests/net/AndroidTestTemplate.xml b/tests/tests/net/AndroidTestTemplate.xml
deleted file mode 100644
index 4e93751..0000000
--- a/tests/tests/net/AndroidTestTemplate.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Test config for {MODULE}">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="networking" />
- <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
- <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
-
- <option name="config-descriptor:metadata" key="mainline-param" value="CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk" />
- <option name="not-shardable" value="true" />
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="{MODULE}.apk" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.net.cts" />
- <option name="runtime-hint" value="9m4s" />
- <option name="hidden-api-checks" value="false" />
- <option name="isolated-storage" value="false" />
- </test>
-</configuration>
diff --git a/tests/tests/net/OWNERS b/tests/tests/net/OWNERS
deleted file mode 100644
index d558556..0000000
--- a/tests/tests/net/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 31808
-lorenzo@google.com
-satk@google.com
diff --git a/tests/tests/net/TEST_MAPPING b/tests/tests/net/TEST_MAPPING
deleted file mode 100644
index 3162e22..0000000
--- a/tests/tests/net/TEST_MAPPING
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- // TODO: move to mainline-presubmit once supported
- "postsubmit": [
- {
- "name": "CtsNetTestCasesLatestSdk",
- "options": [
- {
- "exclude-annotation": "com.android.testutils.SkipPresubmit"
- }
- ]
- }
- ],
- "mainline-presubmit": [
- {
- "name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk]",
- "options": [
- {
- "exclude-annotation": "com.android.testutils.SkipPresubmit"
- }
- ]
- }
- ]
-}
diff --git a/tests/tests/net/api23Test/Android.bp b/tests/tests/net/api23Test/Android.bp
deleted file mode 100644
index ffeef48..0000000
--- a/tests/tests/net/api23Test/Android.bp
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-android_test {
- name: "CtsNetApi23TestCases",
- defaults: ["cts_defaults"],
-
- // Include both the 32 and 64 bit versions
- compile_multilib: "both",
-
- libs: [
- "android.test.base.stubs",
- ],
-
- srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- ],
-
- static_libs: [
- "core-tests-support",
- "compatibility-device-util-axt",
- "cts-net-utils",
- "ctstestrunner-axt",
- "ctstestserver",
- "mockwebserver",
- "junit",
- "junit-params",
- "truth-prebuilt",
- ],
-
- platform_apis: true,
-
- // Tag this module as a cts test artifact
- test_suites: [
- "cts",
- "vts10",
- "general-tests",
- ],
-
-}
diff --git a/tests/tests/net/api23Test/AndroidManifest.xml b/tests/tests/net/api23Test/AndroidManifest.xml
deleted file mode 100644
index 4889660..0000000
--- a/tests/tests/net/api23Test/AndroidManifest.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.net.cts.api23test">
-
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
- <uses-permission android:name="android.permission.INTERNET" />
-
- <application android:usesCleartextTraffic="true">
- <uses-library android:name="android.test.runner" />
-
- <receiver android:name=".ConnectivityReceiver">
- <intent-filter>
- <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
- </intent-filter>
- </receiver>
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.net.cts.api23test"
- android:label="CTS tests of android.net">
- <meta-data android:name="listener"
- android:value="com.android.cts.runner.CtsTestRunListener" />
- </instrumentation>
-</manifest>
-
diff --git a/tests/tests/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java b/tests/tests/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java
deleted file mode 100644
index cdb66e3..0000000
--- a/tests/tests/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts.api23test;
-
-import static android.content.pm.PackageManager.FEATURE_WIFI;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.cts.util.CtsNetUtils;
-import android.os.Looper;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-public class ConnectivityManagerApi23Test extends AndroidTestCase {
- private static final String TAG = ConnectivityManagerApi23Test.class.getSimpleName();
- private static final int SEND_BROADCAST_TIMEOUT = 30000;
- // Intent string to get the number of wifi CONNECTIVITY_ACTION callbacks the test app has seen
- public static final String GET_WIFI_CONNECTIVITY_ACTION_COUNT =
- "android.net.cts.appForApi23.getWifiConnectivityActionCount";
- // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
-
- private Context mContext;
- private PackageManager mPackageManager;
- private CtsNetUtils mCtsNetUtils;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- Looper.prepare();
- mContext = getContext();
- mPackageManager = mContext.getPackageManager();
- mCtsNetUtils = new CtsNetUtils(mContext);
- }
-
- /**
- * Tests reporting of connectivity changed.
- */
- public void testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent() {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent cannot execute unless device supports WiFi");
- return;
- }
- ConnectivityReceiver.prepare();
-
- mCtsNetUtils.toggleWifi();
-
- // The connectivity broadcast has been sent; push through a terminal broadcast
- // to wait for in the receive to confirm it didn't see the connectivity change.
- Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION);
- finalIntent.setClass(mContext, ConnectivityReceiver.class);
- mContext.sendBroadcast(finalIntent);
- assertFalse(ConnectivityReceiver.waitForBroadcast());
- }
-
- public void testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent()
- throws InterruptedException {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent cannot"
- + "execute unless device supports WiFi");
- return;
- }
- mContext.startActivity(new Intent()
- .setComponent(new ComponentName("android.net.cts.appForApi23",
- "android.net.cts.appForApi23.ConnectivityListeningActivity"))
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
- Thread.sleep(200);
-
- mCtsNetUtils.toggleWifi();
-
- Intent getConnectivityCount = new Intent(GET_WIFI_CONNECTIVITY_ACTION_COUNT);
- assertEquals(2, sendOrderedBroadcastAndReturnResultCode(
- getConnectivityCount, SEND_BROADCAST_TIMEOUT));
- }
-
- public void testConnectivityChanged_whenRegistered_shouldReceiveIntent() {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testConnectivityChanged_whenRegistered_shouldReceiveIntent cannot execute unless device supports WiFi");
- return;
- }
- ConnectivityReceiver.prepare();
- ConnectivityReceiver receiver = new ConnectivityReceiver();
- IntentFilter filter = new IntentFilter();
- filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- mContext.registerReceiver(receiver, filter);
-
- mCtsNetUtils.toggleWifi();
- Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION);
- finalIntent.setClass(mContext, ConnectivityReceiver.class);
- mContext.sendBroadcast(finalIntent);
-
- assertTrue(ConnectivityReceiver.waitForBroadcast());
- }
-
- private int sendOrderedBroadcastAndReturnResultCode(
- Intent intent, int timeoutMs) throws InterruptedException {
- final LinkedBlockingQueue<Integer> result = new LinkedBlockingQueue<>(1);
- mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- result.offer(getResultCode());
- }
- }, null, 0, null, null);
-
- Integer resultCode = result.poll(timeoutMs, TimeUnit.MILLISECONDS);
- assertNotNull("Timed out (more than " + timeoutMs +
- " milliseconds) waiting for result code for broadcast", resultCode);
- return resultCode;
- }
-
-}
\ No newline at end of file
diff --git a/tests/tests/net/api23Test/src/android/net/cts/api23test/ConnectivityReceiver.java b/tests/tests/net/api23Test/src/android/net/cts/api23test/ConnectivityReceiver.java
deleted file mode 100644
index 9d2b8ad..0000000
--- a/tests/tests/net/api23Test/src/android/net/cts/api23test/ConnectivityReceiver.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts.api23test;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.util.Log;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public class ConnectivityReceiver extends BroadcastReceiver {
- static boolean sReceivedConnectivity;
- static boolean sReceivedFinal;
- static CountDownLatch sLatch;
-
- static void prepare() {
- synchronized (ConnectivityReceiver.class) {
- sReceivedConnectivity = sReceivedFinal = false;
- sLatch = new CountDownLatch(1);
- }
- }
-
- static boolean waitForBroadcast() {
- try {
- sLatch.await(30, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- throw new IllegalStateException(e);
- }
- synchronized (ConnectivityReceiver.class) {
- sLatch = null;
- if (!sReceivedFinal) {
- throw new IllegalStateException("Never received final broadcast");
- }
- return sReceivedConnectivity;
- }
- }
-
- static final String FINAL_ACTION = "android.net.cts.action.FINAL";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.i("ConnectivityReceiver", "Received: " + intent.getAction());
- if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
- sReceivedConnectivity = true;
- } else if (FINAL_ACTION.equals(intent.getAction())) {
- sReceivedFinal = true;
- if (sLatch != null) {
- sLatch.countDown();
- }
- }
- }
-}
diff --git a/tests/tests/net/appForApi23/Android.bp b/tests/tests/net/appForApi23/Android.bp
deleted file mode 100644
index 399c199..0000000
--- a/tests/tests/net/appForApi23/Android.bp
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-android_test {
- name: "CtsNetTestAppForApi23",
- defaults: ["cts_defaults"],
-
- // Include both the 32 and 64 bit versions
- compile_multilib: "both",
-
- srcs: ["src/**/*.java"],
-
- sdk_version: "23",
-
- // Tag this module as a cts test artifact
- test_suites: [
- "cts",
- "vts10",
- "general-tests",
- ],
-
-}
diff --git a/tests/tests/net/appForApi23/AndroidManifest.xml b/tests/tests/net/appForApi23/AndroidManifest.xml
deleted file mode 100644
index ed4cedb..0000000
--- a/tests/tests/net/appForApi23/AndroidManifest.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.net.cts.appForApi23">
-
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.INTERNET" />
-
- <application>
- <receiver android:name=".ConnectivityReceiver">
- <intent-filter>
- <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
- </intent-filter>
- <intent-filter>
- <action android:name="android.net.cts.appForApi23.getWifiConnectivityActionCount" />
- </intent-filter>
- </receiver>
-
- <activity android:name=".ConnectivityListeningActivity"
- android:label="ConnectivityListeningActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
- </application>
-
-</manifest>
-
diff --git a/tests/tests/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityListeningActivity.java b/tests/tests/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityListeningActivity.java
deleted file mode 100644
index 24fb68e..0000000
--- a/tests/tests/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityListeningActivity.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.cts.appForApi23;
-
-import android.app.Activity;
-
-// Stub activity used to start the app
-public class ConnectivityListeningActivity extends Activity {
-}
\ No newline at end of file
diff --git a/tests/tests/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityReceiver.java b/tests/tests/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityReceiver.java
deleted file mode 100644
index 8039a4f..0000000
--- a/tests/tests/net/appForApi23/src/android/net/cts/appForApi23/ConnectivityReceiver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.cts.appForApi23;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-
-public class ConnectivityReceiver extends BroadcastReceiver {
- public static String GET_WIFI_CONNECTIVITY_ACTION_COUNT =
- "android.net.cts.appForApi23.getWifiConnectivityActionCount";
-
- private static int sWifiConnectivityActionCount = 0;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
- int networkType = intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 0);
- if (networkType == ConnectivityManager.TYPE_WIFI) {
- sWifiConnectivityActionCount++;
- }
- }
- if (GET_WIFI_CONNECTIVITY_ACTION_COUNT.equals(intent.getAction())) {
- setResultCode(sWifiConnectivityActionCount);
- }
- }
-}
diff --git a/tests/tests/net/assets/network_watchlist_config_empty_for_test.xml b/tests/tests/net/assets/network_watchlist_config_empty_for_test.xml
deleted file mode 100644
index 19628d1..0000000
--- a/tests/tests/net/assets/network_watchlist_config_empty_for_test.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright (C) 2018 The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<!-- This test config file is for NetworkWatchlistTest tests -->
-<watchlist-config>
- <sha256-domain>
- </sha256-domain>
- <sha256-ip>
- </sha256-ip>
- <crc32-domain>
- </crc32-domain>
- <crc32-ip>
- </crc32-ip>
-</watchlist-config>
diff --git a/tests/tests/net/assets/network_watchlist_config_for_test.xml b/tests/tests/net/assets/network_watchlist_config_for_test.xml
deleted file mode 100644
index 835ae0f..0000000
--- a/tests/tests/net/assets/network_watchlist_config_for_test.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright (C) 2018 The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<!-- This test config file just contains some random hashes for testing
-ConnectivityManager.getWatchlistConfigHash() -->
-<watchlist-config>
- <sha256-domain>
- <hash>F0905DA7549614957B449034C281EF7BDEFDBC2B6E050AD1E78D6DE18FBD0D5F</hash>
- </sha256-domain>
- <sha256-ip>
- <hash>18DD41C9F2E8E4879A1575FB780514EF33CF6E1F66578C4AE7CCA31F49B9F2EC</hash>
- </sha256-ip>
- <crc32-domain>
- <hash>AAAAAAAA</hash>
- </crc32-domain>
- <crc32-ip>
- <hash>BBBBBBBB</hash>
- </crc32-ip>
-</watchlist-config>
diff --git a/tests/tests/net/ipsec/AndroidManifest.xml b/tests/tests/net/ipsec/AndroidManifest.xml
deleted file mode 100644
index de7d23c..0000000
--- a/tests/tests/net/ipsec/AndroidManifest.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.net.ipsec.cts"
- android:targetSandboxVersion="2">
-
- <!--Allow tests to call ConnectivityManager#getActiveNetwork()-->
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
- <!--Allow tests to create socket -->
- <uses-permission android:name="android.permission.INTERNET"/>
-
- <application android:label="CtsIkeTestCases">
- <uses-library android:name="android.test.runner" />
- <uses-library android:name="android.net.ipsec.ike" />
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.net.ipsec.cts"
- android:label="CTS tests of android.net.ipsec">
- <meta-data android:name="listener"
- android:value="com.android.cts.runner.CtsTestRunListener" />
- </instrumentation>
-
-</manifest>
diff --git a/tests/tests/net/ipsec/OWNERS b/tests/tests/net/ipsec/OWNERS
deleted file mode 100644
index 26407ff..0000000
--- a/tests/tests/net/ipsec/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-lorenzo@google.com
-nharold@google.com
-satk@google.com
diff --git a/tests/tests/net/ipsec/assets/key/client-a-private-key.key b/tests/tests/net/ipsec/assets/key/client-a-private-key.key
deleted file mode 100644
index 22736e9..0000000
--- a/tests/tests/net/ipsec/assets/key/client-a-private-key.key
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCv3CvrCGokJSWL
-8ufg6u9LCW4EezztbktqpC0T+1m98+Ujb8/eJ0L2UaxZ9QBSBAqXxEoeZFBeoCXu
-7ezUd5qUPfIhKLAkQTAyU/KgfhHh4i+MJK5ghPbGDE8r2gKUXOkM6M5//ZCpmu0K
-Y/9uQL6D5bkxEaoWegEO+wSXm+hTTgKDtQKHvRibgdcZkcY0cA9JsLrC/nIkP+7i
-pbBT+VTuV6gAnKIV0nq8zvI3A/Z3nAb5Gt0g3qaqs59StDT0QtuXzJkuZEo3XSrS
-jon+8NjSNzqVbJj95B7+uiH+91VEbMtJYFz2MipKvJQDK7Zlxke7LxRj2xJfksJK
-a92/ncxfAgMBAAECggEAQztaMvW5lm35J8LKsWs/5qEJRX9T8LWs8W0oqq36Riub
-G2wgvR6ndAIPcSjAYZqX7iOl7m6NZ0+0kN63HxdGqovwKIskpAekBGmhpYftED1n
-zh0r6UyMB3UnQ22KdOv8UOokIDxxdNX8728BdUYdT9Ggdkj5jLRB+VcwD0IUlNvo
-zzTpURV9HEd87uiLqd4AAHXSI0lIHI5U43z24HI/J6/YbYHT3Rlh6CIa/LuwO6vL
-gFkgqg0/oy6yJtjrHtzNVA67F0UaH62hR4YFgbC0d955SJnDidWOv/0j2DMpfdCc
-9kFAcPwUSyykvUSLnGIKWSG4D+6gzIeAeUx4oO7kMQKBgQDVNRkX8AGTHyLg+NXf
-spUWWcodwVioXl30Q7h6+4bt8OI61UbhQ7wX61wvJ1cySpa2KOYa2UdagQVhGhhL
-ADu363R77uXF/jZgzVfmjjyJ2nfDqRgHWRTlSkuq/jCOQCz7VIPHRZg5WL/9D4ms
-TAqMjpzqeMfFZI+w4/+xpcJIuQKBgQDTKBy+ZuerWrVT9icWKvLU58o5EVj/2yFy
-GJvKm+wRAAX2WzjNnR4HVd4DmMREVz1BPYby0j5gqjvtDsxYYu39+NT7JvMioLLK
-QPj+7k5geYgNqVgCxB1vP89RhY2X1RLrN9sTXOodgFPeXOQWNYITkGp3eQpx4nTJ
-+K/al3oB1wKBgAjnc8nVIyuyxDEjE0OJYMKTM2a0uXAmqMPXxC+Wq5bqVXhhidlE
-i+lv0eTCPtkB1nN7F8kNQ/aaps/cWCFhvBy9P5shagUvzbOTP9WIIS0cq53HRRKh
-fMbqqGhWv05hjb9dUzeSR341n6cA7B3++v3Nwu3j52vt/DZF/1q68nc5AoGAS0SU
-ImbKE/GsizZGLoe2sZ/CHN+LKwCwhlwxRGKaHmE0vuE7eUeVSaYZEo0lAPtb8WJ+
-NRYueASWgeTxgFwbW5mUScZTirdfo+rPFwhZVdhcYApKPgosN9i2DOgfVcz1BnWN
-mPRY25U/0BaqkyQVruWeneG+kGPZn5kPDktKiVcCgYEAkzwU9vCGhm7ZVALvx/zR
-wARz2zsL9ImBc0P4DK1ld8g90FEnHrEgeI9JEwz0zFHOCMLwlk7kG0Xev7vfjZ7G
-xSqtQYOH33Qp6rtBOgdt8hSyDFvakvDl6bqhAw52gelO3MTpAB1+ZsfZ5gFx13Jf
-idNFcaIrC52PtZIH7QCzdDY=
------END PRIVATE KEY-----
\ No newline at end of file
diff --git a/tests/tests/net/ipsec/assets/pem/client-a-end-cert.pem b/tests/tests/net/ipsec/assets/pem/client-a-end-cert.pem
deleted file mode 100644
index e82da85..0000000
--- a/tests/tests/net/ipsec/assets/pem/client-a-end-cert.pem
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDaDCCAlCgAwIBAgIIcorRI3n29E4wDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE
-BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0LmFu
-ZHJvaWQubmV0MB4XDTIwMDQxNDA1MDM0OVoXDTIzMDQxNDA1MDM0OVowRTELMAkG
-A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxJDAiBgNVBAMTG2NsaWVudC50ZXN0
-LmlrZS5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
-AK/cK+sIaiQlJYvy5+Dq70sJbgR7PO1uS2qkLRP7Wb3z5SNvz94nQvZRrFn1AFIE
-CpfESh5kUF6gJe7t7NR3mpQ98iEosCRBMDJT8qB+EeHiL4wkrmCE9sYMTyvaApRc
-6Qzozn/9kKma7Qpj/25AvoPluTERqhZ6AQ77BJeb6FNOAoO1Aoe9GJuB1xmRxjRw
-D0mwusL+ciQ/7uKlsFP5VO5XqACcohXSerzO8jcD9necBvka3SDepqqzn1K0NPRC
-25fMmS5kSjddKtKOif7w2NI3OpVsmP3kHv66If73VURsy0lgXPYyKkq8lAMrtmXG
-R7svFGPbEl+Swkpr3b+dzF8CAwEAAaNgMF4wHwYDVR0jBBgwFoAUcqSu1uRYT/DL
-bLoDNUz38nGvCKQwJgYDVR0RBB8wHYIbY2xpZW50LnRlc3QuaWtlLmFuZHJvaWQu
-bmV0MBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCa53tK
-I9RM9/MutZ5KNG2Gfs2cqaPyv8ZRhs90HDWZhkFVu7prywJAxOd2hxxHPsvgurio
-4bKAxnT4EXevgz5YoCbj2TPIL9TdFYh59zZ97XXMxk+SRdypgF70M6ETqKPs3hDP
-ZRMMoHvvYaqaPvp4StSBX9A44gSyjHxVYJkrjDZ0uffKg5lFL5IPvqfdmSRSpGab
-SyGTP4OLTy0QiNV3pBsJGdl0h5BzuTPR9OTl4xgeqqBQy2bDjmfJBuiYyCSCkPi7
-T3ohDYCymhuSkuktHPNG1aKllUJaw0tuZuNydlgdAveXPYfM36uvK0sfd9qr9pAy
-rmkYV2MAWguFeckh
------END CERTIFICATE-----
\ No newline at end of file
diff --git a/tests/tests/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem b/tests/tests/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem
deleted file mode 100644
index 707e575..0000000
--- a/tests/tests/net/ipsec/assets/pem/client-a-intermediate-ca-one.pem
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDaDCCAlCgAwIBAgIIIbjMyRn2770wDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE
-BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h
-bmRyb2lkLm5ldDAeFw0xOTA5MzAxODQzMThaFw0yNDA5MjgxODQzMThaMEExCzAJ
-BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSAwHgYDVQQDExdvbmUuY2EudGVz
-dC5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNN
-sRr5Z30rAEw2jrAh/BIekbEy/MvOucAr1w0lxH71p+ybRBx5Bj7G07UGXbL659gm
-meMV6nabY4HjQXNMq22POiJBZj+U+rw34br6waljBttxCmmJac1VvgqNsSspXjRy
-NbiVQdFjyKSX0NOPcEkwANk15mZbOgJBaYYc8jQCY2G/p8eARVBTLJCy8LEwEU6j
-XRv/4eYST79qpBFc7gQQj2FLmh9oppDIvcIVBHwtd1tBoVuehRSud1o8vQRkl/HJ
-Mrwp24nO5YYhmVNSFRtBpmWMSu1KknFUwkOebINUNsKXXHebVa7cP4XIQUL8mRT3
-5X9rFJFSQJE01S3NjNMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
-Af8EBAMCAQYwHQYDVR0OBBYEFHK3FIm7g8dxEIwK9zMAO8EWhRYxMB8GA1UdIwQY
-MBaAFEmfqEeF14Nj91ekIpR+sVhCEoAaMA0GCSqGSIb3DQEBCwUAA4IBAQAeMlXT
-TnxZo8oz0204gKZ63RzlgDpJ7SqA3qFG+pV+TiqGfSuVkXuIdOskjxJnA9VxUzrr
-LdMTCn5e0FK6wCYjZ2GT/CD7oD3vSMkzGbLGNcNJhhDHUq8BOLPkPzz/rwQFPBSb
-zr6hsiVXphEt/psGoN7Eu9blPeQaIwMfWnaufAwF664S/3dmCRbNMWSam1qzzz8q
-jr0cDOIMa//ZIAcM16cvoBK6pFGnUmuoJYYRtfpY5MmfCWz0sCJxENIX/lxyhd7N
-FdRALA1ZP3E//Tn2vQoeFjbKaAba527RE26HgHJ9zZDo1nn8J8J/YwYRJdBWM/3S
-LYebNiMtcyB5nIkj
------END CERTIFICATE-----
\ No newline at end of file
diff --git a/tests/tests/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem b/tests/tests/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem
deleted file mode 100644
index 39808f8..0000000
--- a/tests/tests/net/ipsec/assets/pem/client-a-intermediate-ca-two.pem
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDZzCCAk+gAwIBAgIIKWCREnNCs+wwDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE
-BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF29uZS5jYS50ZXN0LmFu
-ZHJvaWQubmV0MB4XDTE5MDkzMDE4NDQwMloXDTI0MDkyODE4NDQwMlowQTELMAkG
-A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0
-LmFuZHJvaWQubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLUa
-RqkYl2m7lUmMnkooqO0DNNY1aN9r7mJc3ndYn5gjkpb3yLgOYPDNLcQerV6uWk/u
-qKudNHed2dInGonl3oxwwv7++6oUvvtrSWLDZlRg16GsdIE1Y98DSMQWkSxevYy9
-Nh6FGTdlBFQVMpiMa8qHEkrOyKsy85yCW1sgzlpGTIBwbDAqYtwe3rgbwyHwUtfy
-0EU++DBcR4ll/pDqB0OQtW5E3AOq2GH1iaGeFLKSUQ5KAbdI8y4/b8IkSDffvxcc
-kXig7S54aLrNlL/ZjQ+H4Chgjj2A5wMucd81+Fb60Udej73ICL9PpMPnXQ1+BVYd
-MJ/txjLNmrOJG9yEHQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
-/wQEAwIBBjAdBgNVHQ4EFgQUcqSu1uRYT/DLbLoDNUz38nGvCKQwHwYDVR0jBBgw
-FoAUcrcUibuDx3EQjAr3MwA7wRaFFjEwDQYJKoZIhvcNAQELBQADggEBADY461GT
-Rw0dGnD07xaGJcI0i0pV+WnGSrl1s1PAIdMYihJAqYnh10fXbFXLm2WMWVmv/pxs
-FI/xDJno+pd4mCa/sIhm63ar/Nv+lFQmcpIlvSlKnhhV4SLNBeqbVhPBGTCHfrG4
-aIyCwm1KJsnkWbf03crhSskR/2CXIjX6lcAy7K3fE2u1ELpAdH0kMJR7VXkLFLUm
-gqe9YCluR0weMpe2sCaOGzdVzQSmMMCzGP5cxeFR5U6K40kMOpiW11JNmQ06xI/m
-YVkMNwoiV/ITT0/C/g9FxJmkO0mVSLEqxaLS/hNiQNDlroVM0rbxhzviXLI3R3AO
-50VvlOQYGxWed/I=
------END CERTIFICATE-----
\ No newline at end of file
diff --git a/tests/tests/net/ipsec/assets/pem/server-a-self-signed-ca.pem b/tests/tests/net/ipsec/assets/pem/server-a-self-signed-ca.pem
deleted file mode 100644
index 972fd55..0000000
--- a/tests/tests/net/ipsec/assets/pem/server-a-self-signed-ca.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDSDCCAjCgAwIBAgIITJQJ6HC1rjwwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE
-BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h
-bmRyb2lkLm5ldDAeFw0xOTA5MzAxNzU1NTJaFw0yOTA5MjcxNzU1NTJaMEIxCzAJ
-BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSEwHwYDVQQDExhyb290LmNhLnRl
-c3QuYW5kcm9pZC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCT
-q3hGF+JvLaB1xW7KGKmaxiQ7BxX2Sn7cbp7ggoVYXsFlBUuPPv3+Vg5PfPCPhsJ8
-/7w4HyKo3uc/vHs5HpQ7rSd9blhAkfmJci2ULLq73FB8Mix4CzPwMx29RrN1X9bU
-z4G0vJMczIBGxbZ0uw7n8bKcXBV7AIeax+J8lseEZ3k8iSuBkUJqGIpPFKTqByFZ
-A1Lvt47xkON5SZh6c/Oe+o6291wXaCOJUSAKv6PAWZkq9HeD2fqKA/ck9dBaz1M3
-YvzQ9V/7so3/dECjAfKia388h1I6XSGNUM+d5hpxMXpAFgG42eUXHpJ10OjDvSwd
-7ZSC91/kRQewUomEKBK1AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
-AQH/BAQDAgEGMB0GA1UdDgQWBBRJn6hHhdeDY/dXpCKUfrFYQhKAGjANBgkqhkiG
-9w0BAQsFAAOCAQEAig/94aGfHBhZuvbbhwAK4rUNpizmR567u0ZJ+QUEKyAlo9lT
-ZWYHSm7qTAZYvPEjzTQIptnAlxCHePXh3Cfwgo+r82lhG2rcdI03iRyvHWjM8gyk
-BXCJTi0Q08JHHpTP6GnAqpz58qEIFkk8P766zNXdhYrGPOydF+p7MFcb1Zv1gum3
-zmRLt0XUAMfjPUv1Bl8kTKFxH5lkMBLR1E0jnoJoTTfgRPrf9CuFSoh48n7YhoBT
-KV75xZY8b8+SuB0v6BvQmkpKZGoxBjuVsShyG7q1+4JTAtwhiP7BlkDvVkaBEi7t
-WIMFp2r2ZDisHgastNaeYFyzHYz9g1FCCrHQ4w==
------END CERTIFICATE-----
\ No newline at end of file
diff --git a/tests/tests/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java b/tests/tests/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java
deleted file mode 100644
index c24379d..0000000
--- a/tests/tests/net/ipsec/src/android/net/eap/cts/EapSessionConfigTest.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.eap.cts;
-
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-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.eap.EapSessionConfig;
-import android.net.eap.EapSessionConfig.EapAkaConfig;
-import android.net.eap.EapSessionConfig.EapAkaPrimeConfig;
-import android.net.eap.EapSessionConfig.EapMsChapV2Config;
-import android.net.eap.EapSessionConfig.EapSimConfig;
-import android.net.eap.EapSessionConfig.EapUiccConfig;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class EapSessionConfigTest {
- // These constants are IANA-defined values and are copies of hidden constants in
- // frameworks/opt/net/ike/src/java/com/android/internal/net/eap/message/EapData.java.
- private static final int EAP_TYPE_SIM = 18;
- private static final int EAP_TYPE_AKA = 23;
- private static final int EAP_TYPE_MSCHAP_V2 = 26;
- private static final int EAP_TYPE_AKA_PRIME = 50;
-
- private static final int SUB_ID = 1;
- private static final byte[] EAP_IDENTITY = "test@android.net".getBytes();
- private static final String NETWORK_NAME = "android.net";
- private static final String EAP_MSCHAPV2_USERNAME = "username";
- private static final String EAP_MSCHAPV2_PASSWORD = "password";
-
- @Test
- public void testBuildWithAllEapMethods() {
- EapSessionConfig result =
- new EapSessionConfig.Builder()
- .setEapIdentity(EAP_IDENTITY)
- .setEapSimConfig(SUB_ID, APPTYPE_USIM)
- .setEapAkaConfig(SUB_ID, APPTYPE_USIM)
- .setEapAkaPrimeConfig(
- SUB_ID,
- APPTYPE_USIM,
- NETWORK_NAME,
- true /* allowMismatchedNetworkNames */)
- .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD)
- .build();
-
- assertArrayEquals(EAP_IDENTITY, result.getEapIdentity());
-
- EapSimConfig eapSimConfig = result.getEapSimConfig();
- assertNotNull(eapSimConfig);
- assertEquals(EAP_TYPE_SIM, eapSimConfig.getMethodType());
- verifyEapUiccConfigCommon(eapSimConfig);
-
- EapAkaConfig eapAkaConfig = result.getEapAkaConfig();
- assertNotNull(eapAkaConfig);
- assertEquals(EAP_TYPE_AKA, eapAkaConfig.getMethodType());
- verifyEapUiccConfigCommon(eapAkaConfig);
-
- EapAkaPrimeConfig eapAkaPrimeConfig = result.getEapAkaPrimeConfig();
- assertNotNull(eapAkaPrimeConfig);
- assertEquals(EAP_TYPE_AKA_PRIME, eapAkaPrimeConfig.getMethodType());
- assertEquals(NETWORK_NAME, eapAkaPrimeConfig.getNetworkName());
- assertTrue(NETWORK_NAME, eapAkaPrimeConfig.allowsMismatchedNetworkNames());
- verifyEapUiccConfigCommon(eapAkaPrimeConfig);
-
- EapMsChapV2Config eapMsChapV2Config = result.getEapMsChapV2onfig();
- assertNotNull(eapMsChapV2Config);
- assertEquals(EAP_TYPE_MSCHAP_V2, eapMsChapV2Config.getMethodType());
- assertEquals(EAP_MSCHAPV2_USERNAME, eapMsChapV2Config.getUsername());
- assertEquals(EAP_MSCHAPV2_PASSWORD, eapMsChapV2Config.getPassword());
- }
-
- private void verifyEapUiccConfigCommon(EapUiccConfig config) {
- assertEquals(SUB_ID, config.getSubId());
- assertEquals(APPTYPE_USIM, config.getAppType());
- }
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java
deleted file mode 100644
index 7fb1b6d..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/ChildSessionParamsTest.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipsec.ike.cts;
-
-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.assertTrue;
-
-import android.net.LinkAddress;
-import android.net.ipsec.ike.ChildSaProposal;
-import android.net.ipsec.ike.ChildSessionParams;
-import android.net.ipsec.ike.TransportModeChildSessionParams;
-import android.net.ipsec.ike.TunnelModeChildSessionParams;
-import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Address;
-import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer;
-import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer;
-import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netmask;
-import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address;
-import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer;
-import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-@RunWith(AndroidJUnit4.class)
-public class ChildSessionParamsTest extends IkeTestBase {
- private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(3L);
- private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(1L);
-
- // Random proposal. Content doesn't matter
- private final ChildSaProposal mSaProposal =
- SaProposalTest.buildChildSaProposalWithCombinedModeCipher();
-
- private void verifyTunnelModeChildParamsWithDefaultValues(ChildSessionParams childParams) {
- assertTrue(childParams instanceof TunnelModeChildSessionParams);
- verifyChildParamsWithDefaultValues(childParams);
- }
-
- private void verifyTunnelModeChildParamsWithCustomizedValues(ChildSessionParams childParams) {
- assertTrue(childParams instanceof TunnelModeChildSessionParams);
- verifyChildParamsWithCustomizedValues(childParams);
- }
-
- private void verifyTransportModeChildParamsWithDefaultValues(ChildSessionParams childParams) {
- assertTrue(childParams instanceof TransportModeChildSessionParams);
- verifyChildParamsWithDefaultValues(childParams);
- }
-
- private void verifyTransportModeChildParamsWithCustomizedValues(
- ChildSessionParams childParams) {
- assertTrue(childParams instanceof TransportModeChildSessionParams);
- verifyChildParamsWithCustomizedValues(childParams);
- }
-
- private void verifyChildParamsWithDefaultValues(ChildSessionParams childParams) {
- assertEquals(Arrays.asList(mSaProposal), childParams.getSaProposals());
-
- // Do not do assertEquals to the default values to be avoid being a change-detector test
- assertTrue(childParams.getHardLifetimeSeconds() > childParams.getSoftLifetimeSeconds());
- assertTrue(childParams.getSoftLifetimeSeconds() > 0);
-
- assertEquals(
- Arrays.asList(DEFAULT_V4_TS, DEFAULT_V6_TS),
- childParams.getInboundTrafficSelectors());
- assertEquals(
- Arrays.asList(DEFAULT_V4_TS, DEFAULT_V6_TS),
- childParams.getOutboundTrafficSelectors());
- }
-
- private void verifyChildParamsWithCustomizedValues(ChildSessionParams childParams) {
- assertEquals(Arrays.asList(mSaProposal), childParams.getSaProposals());
-
- assertEquals(HARD_LIFETIME_SECONDS, childParams.getHardLifetimeSeconds());
- assertEquals(SOFT_LIFETIME_SECONDS, childParams.getSoftLifetimeSeconds());
-
- assertEquals(
- Arrays.asList(INBOUND_V4_TS, INBOUND_V6_TS),
- childParams.getInboundTrafficSelectors());
- assertEquals(
- Arrays.asList(OUTBOUND_V4_TS, OUTBOUND_V6_TS),
- childParams.getOutboundTrafficSelectors());
- }
-
- @Test
- public void testBuildTransportModeParamsWithDefaultValues() {
- TransportModeChildSessionParams childParams =
- new TransportModeChildSessionParams.Builder().addSaProposal(mSaProposal).build();
-
- verifyTransportModeChildParamsWithDefaultValues(childParams);
- }
-
- @Test
- public void testBuildTunnelModeParamsWithDefaultValues() {
- TunnelModeChildSessionParams childParams =
- new TunnelModeChildSessionParams.Builder().addSaProposal(mSaProposal).build();
-
- verifyTunnelModeChildParamsWithDefaultValues(childParams);
- assertTrue(childParams.getConfigurationRequests().isEmpty());
- }
-
- @Test
- public void testBuildTransportModeParamsWithCustomizedValues() {
- TransportModeChildSessionParams childParams =
- new TransportModeChildSessionParams.Builder()
- .addSaProposal(mSaProposal)
- .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS)
- .addInboundTrafficSelectors(INBOUND_V4_TS)
- .addInboundTrafficSelectors(INBOUND_V6_TS)
- .addOutboundTrafficSelectors(OUTBOUND_V4_TS)
- .addOutboundTrafficSelectors(OUTBOUND_V6_TS)
- .build();
-
- verifyTransportModeChildParamsWithCustomizedValues(childParams);
- }
-
- @Test
- public void testBuildTunnelModeParamsWithCustomizedValues() {
- TunnelModeChildSessionParams childParams =
- new TunnelModeChildSessionParams.Builder()
- .addSaProposal(mSaProposal)
- .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS)
- .addInboundTrafficSelectors(INBOUND_V4_TS)
- .addInboundTrafficSelectors(INBOUND_V6_TS)
- .addOutboundTrafficSelectors(OUTBOUND_V4_TS)
- .addOutboundTrafficSelectors(OUTBOUND_V6_TS)
- .build();
-
- verifyTunnelModeChildParamsWithCustomizedValues(childParams);
- }
-
- @Test
- public void testBuildChildSessionParamsWithConfigReq() {
- TunnelModeChildSessionParams childParams =
- new TunnelModeChildSessionParams.Builder()
- .addSaProposal(mSaProposal)
- .addInternalAddressRequest(AF_INET)
- .addInternalAddressRequest(AF_INET6)
- .addInternalAddressRequest(AF_INET6)
- .addInternalAddressRequest(IPV4_ADDRESS_REMOTE)
- .addInternalAddressRequest(IPV6_ADDRESS_REMOTE, IP6_PREFIX_LEN)
- .addInternalDnsServerRequest(AF_INET)
- .addInternalDnsServerRequest(AF_INET6)
- .addInternalDhcpServerRequest(AF_INET)
- .addInternalDhcpServerRequest(AF_INET)
- .build();
-
- verifyTunnelModeChildParamsWithDefaultValues(childParams);
-
- // Verify config request types and number of requests for each type
- Map<Class<? extends TunnelModeChildConfigRequest>, Integer> expectedAttributeCounts =
- new HashMap<>();
- expectedAttributeCounts.put(ConfigRequestIpv4Address.class, 2);
- expectedAttributeCounts.put(ConfigRequestIpv6Address.class, 3);
- expectedAttributeCounts.put(ConfigRequestIpv4Netmask.class, 1);
- expectedAttributeCounts.put(ConfigRequestIpv4DnsServer.class, 1);
- expectedAttributeCounts.put(ConfigRequestIpv6DnsServer.class, 1);
- expectedAttributeCounts.put(ConfigRequestIpv4DhcpServer.class, 2);
- verifyConfigRequestTypes(expectedAttributeCounts, childParams.getConfigurationRequests());
-
- // Verify specific IPv4 address request
- Set<Inet4Address> expectedV4Addresses = new HashSet<>();
- expectedV4Addresses.add(IPV4_ADDRESS_REMOTE);
- verifySpecificV4AddrConfigReq(expectedV4Addresses, childParams);
-
- // Verify specific IPv6 address request
- Set<LinkAddress> expectedV6Addresses = new HashSet<>();
- expectedV6Addresses.add(new LinkAddress(IPV6_ADDRESS_REMOTE, IP6_PREFIX_LEN));
- verifySpecificV6AddrConfigReq(expectedV6Addresses, childParams);
- }
-
- protected void verifySpecificV4AddrConfigReq(
- Set<Inet4Address> expectedAddresses, TunnelModeChildSessionParams childParams) {
- for (TunnelModeChildConfigRequest req : childParams.getConfigurationRequests()) {
- if (req instanceof ConfigRequestIpv4Address
- && ((ConfigRequestIpv4Address) req).getAddress() != null) {
- Inet4Address address = ((ConfigRequestIpv4Address) req).getAddress();
-
- // Fail if expectedAddresses does not contain this address
- assertTrue(expectedAddresses.remove(address));
- }
- }
-
- // Fail if any expected address is not found in result
- assertTrue(expectedAddresses.isEmpty());
- }
-
- protected void verifySpecificV6AddrConfigReq(
- Set<LinkAddress> expectedAddresses, TunnelModeChildSessionParams childParams) {
- for (TunnelModeChildConfigRequest req : childParams.getConfigurationRequests()) {
- if (req instanceof ConfigRequestIpv6Address
- && ((ConfigRequestIpv6Address) req).getAddress() != null) {
- ConfigRequestIpv6Address ipv6AddrReq = (ConfigRequestIpv6Address) req;
-
- // Fail if expectedAddresses does not contain this address
- LinkAddress address =
- new LinkAddress(ipv6AddrReq.getAddress(), ipv6AddrReq.getPrefixLength());
- assertTrue(expectedAddresses.remove(address));
- }
- }
-
- // Fail if any expected address is not found in result
- assertTrue(expectedAddresses.isEmpty());
- }
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java
deleted file mode 100644
index 0317def..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeIdentificationTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipsec.ike.cts;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import android.net.ipsec.ike.IkeDerAsn1DnIdentification;
-import android.net.ipsec.ike.IkeFqdnIdentification;
-import android.net.ipsec.ike.IkeIpv4AddrIdentification;
-import android.net.ipsec.ike.IkeIpv6AddrIdentification;
-import android.net.ipsec.ike.IkeKeyIdIdentification;
-import android.net.ipsec.ike.IkeRfc822AddrIdentification;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import javax.security.auth.x500.X500Principal;
-
-@RunWith(AndroidJUnit4.class)
-public final class IkeIdentificationTest extends IkeTestBase {
- @Test
- public void testIkeDerAsn1DnIdentification() throws Exception {
- X500Principal asn1Dn = new X500Principal(LOCAL_ASN1_DN_STRING);
-
- IkeDerAsn1DnIdentification ikeId = new IkeDerAsn1DnIdentification(asn1Dn);
- assertEquals(asn1Dn, ikeId.derAsn1Dn);
- }
-
- @Test
- public void testIkeFqdnIdentification() throws Exception {
- IkeFqdnIdentification ikeId = new IkeFqdnIdentification(LOCAL_HOSTNAME);
- assertEquals(LOCAL_HOSTNAME, ikeId.fqdn);
- }
-
- @Test
- public void testIkeIpv4AddrIdentification() throws Exception {
- IkeIpv4AddrIdentification ikeId = new IkeIpv4AddrIdentification(IPV4_ADDRESS_LOCAL);
- assertEquals(IPV4_ADDRESS_LOCAL, ikeId.ipv4Address);
- }
-
- @Test
- public void testIkeIpv6AddrIdentification() throws Exception {
- IkeIpv6AddrIdentification ikeId = new IkeIpv6AddrIdentification(IPV6_ADDRESS_LOCAL);
- assertEquals(IPV6_ADDRESS_LOCAL, ikeId.ipv6Address);
- }
-
- @Test
- public void testIkeKeyIdIdentification() throws Exception {
- IkeKeyIdIdentification ikeId = new IkeKeyIdIdentification(LOCAL_KEY_ID);
- assertArrayEquals(LOCAL_KEY_ID, ikeId.keyId);
- }
-
- @Test
- public void testIkeRfc822AddrIdentification() throws Exception {
- IkeRfc822AddrIdentification ikeId = new IkeRfc822AddrIdentification(LOCAL_RFC822_NAME);
- assertEquals(LOCAL_RFC822_NAME, ikeId.rfc822Name);
- }
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java
deleted file mode 100644
index 9be1dc7..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionDigitalSignatureTest.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipsec.ike.cts;
-
-import android.net.InetAddresses;
-import android.net.LinkAddress;
-import android.net.ipsec.ike.IkeDerAsn1DnIdentification;
-import android.net.ipsec.ike.IkeSession;
-import android.net.ipsec.ike.IkeSessionParams;
-import android.net.ipsec.ike.IkeTrafficSelector;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.internal.net.ipsec.ike.testutils.CertUtils;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.security.cert.X509Certificate;
-import java.security.interfaces.RSAPrivateKey;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import javax.security.auth.x500.X500Principal;
-
-/**
- * Explicitly test setting up transport mode Child SA so that devices do not have
- * FEATURE_IPSEC_TUNNELS will be test covered. Tunnel mode Child SA setup has been tested in
- * IkeSessionPskTest and authentication method is orthogonal to Child mode.
- */
-@RunWith(AndroidJUnit4.class)
-public class IkeSessionDigitalSignatureTest extends IkeSessionTestBase {
- private static final int EXPECTED_AUTH_REQ_FRAG_COUNT = 3;
-
- private static final String IKE_INIT_RESP =
- "46B8ECA1E0D72A18BF3FA1C2CB1EE86F21202220000000000000015022000030"
- + "0000002C010100040300000C0100000C800E0100030000080300000503000008"
- + "0200000400000008040000022800008800020000328451C8A976CE69E407966A"
- + "50D7320C4197A15A07267CE1B16BAFF9BDBBDEC1FDCDAAF7175ADF9AA8DB55DB"
- + "2D70C012D01D914C4EDEF6E8B226868EA1D01B2ED0C4C5C86E6BFE566010EC0C"
- + "33BA1C93666430B88BDA0470D82CC4F4416F49E3E361E3017C9F27811A66718B"
- + "389E1800915D776D59AA528A7E1D1B7815D35144290000249FE8FABE7F43D917"
- + "CE370DE2FD9C22BBC082951AC26C1BA26DE795470F2C25BC2900001C00004004"
- + "AE388EC86D6D1A470D44142D01AB2E85A7AC14182900001C0000400544A235A4"
- + "171C884286B170F48FFC181DB428D87D290000080000402E290000100000402F"
- + "00020003000400050000000800004014";
- private static final String IKE_AUTH_RESP_FRAG_1 =
- "46B8ECA1E0D72A18BF3FA1C2CB1EE86F3520232000000001000004E0240004C4"
- + "00010002DF6750A2D1D5675006F9F6230BB886FFD20CFB973FD04963CFD7A528"
- + "560598C58CC44178B2FCBBBBB271387AC81A664B7E7F1055B912F8C686E287C9"
- + "D31684C66339151AB86DA3CF1DA664052FA97687634558A1E9E6B37E16A86BD1"
- + "68D76DA5E2E1E0B7E98EB662D80D542307015D2BF134EBBBE425D6954FE8C2C4"
- + "D31D16C16AA0521C3C481F873ECF25BB8B05AC6083775C1821CAAB1E35A3955D"
- + "85ACC599574142E1DD5B262D6E5365CBF6EBE92FFCC16BC29EC3239456F3B202"
- + "492551C0F6D752ADCCA56D506D50CC8809EF6BC56EAD005586F7168F76445FD3"
- + "1366CC62D32C0C19B28210B8F813F97CD6A447C3857EFD6EC483DDA8ACD9870E"
- + "5A21B9C66F0FA44496C0C3D05E8859A1A4CFC88155D0C411BABC13033DD41FA4"
- + "AF08CE7734A146687F374F95634D1F26843203CA1FFD05CA3EB150CEA02FBF14"
- + "712B7A1C9BC7616A086E7FCA059E7D64EFF98DB895B32F8F7002762AF7D12F23"
- + "31E9DD25174C4CE273E5392BBB48F50B7A3E0187181216265F6A4FC7B91BE0AB"
- + "C601A580149D4B07411AE99DDB1944B977E86ADC9746605C60A92B569EEFAFFC"
- + "3A888D187B75D8F13249689FC28EBCD62B5E03AF171F3A561F0DEA3B1A75F531"
- + "971157DCE1E7BC6E7789FF3E8156015BC9C521EFE48996B41471D33BF09864E4"
- + "2436E8D7EB6218CDE7716DA754A924B123A63E25585BF27F4AC043A0C4AECE38"
- + "BB59DD62F5C0EC657206A76CED1BD26262237DA1CA6815435992A825758DEBEC"
- + "DDF598A22B8242AC4E34E70704DBA7B7B73DC3E067C1C98764F8791F84C99156"
- + "947D1FFC875F36FCE24B89369C1B5BF1D4C999DCA28E72A528D0E0163C66C067"
- + "E71B5E0025C13DA93313942F9EDA230B3ADC254821A4CB1A5DC9D0C5F4DC4E8E"
- + "CE46B7B8C72D3C5923C9B30DF1EF7B4EDEDA8BD05C86CA0162AE1BF8F277878E"
- + "607401BAA8F06E3EA873FA4C137324C4E0699277CDF649FE7F0F01945EE25FA7"
- + "0E4A89737E58185B11B4CB52FD5B0497D3E3CD1CEE7B1FBB3E969DB6F4C324A1"
- + "32DC6A0EA21F41332435FD99140C286F8ABBBA926953ADBEED17D30AAD953909"
- + "1347EF6D87163D6B1FF32D8B11FFB2E69FAEE7FE913D3826FBA7F9D11E0E3C57"
- + "27625B37D213710B5DD8965DAEFD3F491E8C029E2BF361039949BADEC31D60AC"
- + "355F26EE41339C03CC9D9B01C3C7F288F0E9D6DFEE78231BDA9AC10FED135913"
- + "2836B1A17CE060742B7E5B738A7177CCD59F70337BA251409C377A0FA5333204"
- + "D8622BA8C06DE0BEF4F32B6D4D77BE9DE977445D8A2A08C5C38341CB7974FBFB"
- + "22C8F983A7D6CEF068DDB2281E6673453521C831C1826861005AE5F37649BC64"
- + "0A6360B23284861441A440F1C5AADE1AB53CA63DB17F4C314D493C4C44DE5F20"
- + "75E084D080F92791F30BDD88373D50AB5A07BC72B0E7FFFA593103964E55603E"
- + "F7FEB7CA0762A1A7B86B6CCAD88CD6CBC7C6935D21F5F06B2700588A2530E619"
- + "DA1648AC809F3DDF56ACE5951737568FFEC7E2AB1AA0AE01B03A7F5A29CE73C0"
- + "5D2801B17CAAD0121082E9952FAB16BA1C386336C62D4CF3A5019CF61609433E"
- + "1C083237D47C4CF575097F7BF9000EF6B6C497A44E6480154A35669AD276BF05"
- + "6CC730B4E5962B6AF96CC6D236AE85CEFDA6877173F72D2F614F6696D1F9DF07"
- + "E107758B0978F69BC9DBE0CCBF252C40A3FDF7CE9104D3344F7B73593CCD73E0";
- private static final String IKE_AUTH_RESP_FRAG_2 =
- "46B8ECA1E0D72A18BF3FA1C2CB1EE86F3520232000000001000000F0000000D4"
- + "00020002155211EA41B37BC5F20568A6AE57038EEE208F94F9B444004F1EF391"
- + "2CABFCF857B9CD95FAAA9489ED10A3F5C93510820E22E23FC55ED8049E067D72"
- + "3645C00E1E08611916CE72D7F0A84123B63A8F3B9E78DBBE39967B7BB074AF4D"
- + "BF2178D991EDBDD01908A14A266D09236DB963B14AC33D894F0F83A580209EFD"
- + "61875BB56273AA336C22D6A4D890B93E0D42435667830CC32E4F608500E18569"
- + "3E6C1D88C0B5AE427333C86468E3474DAA4D1506AAB2A4021309A33DD759D0D0"
- + "A8C98BF7FBEA8109361A9F194D0FD756";
- private static final String DELETE_IKE_RESP =
- "46B8ECA1E0D72A18BF3FA1C2CB1EE86F2E202520000000020000004C00000030"
- + "342842D8DA37C8EFB92ED37C4FBB23CBDC90445137D6A0AF489F9F03641DBA9D"
- + "02F6F59FD8A7A78C7261CEB8";
-
- // Using IPv4 for transport mode Child SA. IPv6 is currently infeasible because the IKE server
- // that generates the test vectors is running in an IPv4 only network.
- private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS =
- new IkeTrafficSelector(
- MIN_PORT,
- MAX_PORT,
- InetAddresses.parseNumericAddress("172.58.35.103"),
- InetAddresses.parseNumericAddress("172.58.35.103"));
-
- // TODO(b/157510502): Add test for IKE Session setup with transport mode Child in IPv6 network
-
- private static final String LOCAL_ID_ASN1_DN =
- "CN=client.test.ike.android.net, O=Android, C=US";
- private static final String REMOTE_ID_ASN1_DN =
- "CN=server.test.ike.android.net, O=Android, C=US";
-
- private static X509Certificate sServerCaCert;
- private static X509Certificate sClientEndCert;
- private static X509Certificate sClientIntermediateCaCertOne;
- private static X509Certificate sClientIntermediateCaCertTwo;
- private static RSAPrivateKey sClientPrivateKey;
-
- @BeforeClass
- public static void setUpCertsBeforeClass() throws Exception {
- sServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem");
- sClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem");
- sClientIntermediateCaCertOne =
- CertUtils.createCertFromPemFile("client-a-intermediate-ca-one.pem");
- sClientIntermediateCaCertTwo =
- CertUtils.createCertFromPemFile("client-a-intermediate-ca-two.pem");
- sClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key");
- }
-
- private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) {
- IkeSessionParams ikeParams =
- new IkeSessionParams.Builder(sContext)
- .setNetwork(mTunNetwork)
- .setServerHostname(remoteAddress.getHostAddress())
- .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher())
- .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher())
- .setLocalIdentification(
- new IkeDerAsn1DnIdentification(new X500Principal(LOCAL_ID_ASN1_DN)))
- .setRemoteIdentification(
- new IkeDerAsn1DnIdentification(
- new X500Principal(REMOTE_ID_ASN1_DN)))
- .setAuthDigitalSignature(
- sServerCaCert,
- sClientEndCert,
- Arrays.asList(
- sClientIntermediateCaCertOne, sClientIntermediateCaCertTwo),
- sClientPrivateKey)
- .build();
-
- return new IkeSession(
- sContext,
- ikeParams,
- buildTransportModeChildParamsWithTs(
- TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS),
- mUserCbExecutor,
- mIkeSessionCallback,
- mFirstChildSessionCallback);
- }
-
- @Test
- public void testIkeSessionSetupAndChildSessionSetupWithTransportMode() throws Exception {
- // Open IKE Session
- IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress);
- performSetupIkeAndFirstChildBlocking(
- IKE_INIT_RESP,
- EXPECTED_AUTH_REQ_FRAG_COUNT /* expectedReqPktCnt */,
- true /* expectedAuthUseEncap */,
- IKE_AUTH_RESP_FRAG_1,
- IKE_AUTH_RESP_FRAG_2);
-
- // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2
- int expectedMsgId = 2;
-
- verifyIkeSessionSetupBlocking();
- verifyChildSessionSetupBlocking(
- mFirstChildSessionCallback,
- Arrays.asList(TRANSPORT_MODE_INBOUND_TS),
- Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS),
- new ArrayList<LinkAddress>());
- IpSecTransformCallRecord firstTransformRecordA =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- IpSecTransformCallRecord firstTransformRecordB =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
-
- // Close IKE Session
- ikeSession.close();
- performCloseIkeBlocking(expectedMsgId++, DELETE_IKE_RESP);
- verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB);
- }
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java
deleted file mode 100644
index cb77127..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionMschapV2Test.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipsec.ike.cts;
-
-import android.net.InetAddresses;
-import android.net.LinkAddress;
-import android.net.eap.EapSessionConfig;
-import android.net.ipsec.ike.IkeFqdnIdentification;
-import android.net.ipsec.ike.IkeSession;
-import android.net.ipsec.ike.IkeSessionParams;
-import android.net.ipsec.ike.IkeTrafficSelector;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.internal.net.ipsec.ike.testutils.CertUtils;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * Explicitly test setting up transport mode Child SA so that devices do not have
- * FEATURE_IPSEC_TUNNELS will be test covered. Tunnel mode Child SA setup has been tested in
- * IkeSessionPskTest and authentication method is orthogonal to Child mode.
- */
-@RunWith(AndroidJUnit4.class)
-public class IkeSessionMschapV2Test extends IkeSessionTestBase {
- private static final String IKE_INIT_RESP =
- "46B8ECA1E0D72A1873F643FF94D249A921202220000000000000015022000030"
- + "0000002C010100040300000C0100000C800E0080030000080300000203000008"
- + "0200000200000008040000022800008800020000CC6E71E67E32CED6BCE33FBD"
- + "A74113867E3FA3AE21C7C9AB44A7F8835DF602BFD6F6528B67FEE39821232380"
- + "C99E8FFC0A5D767F8F38906DA41946C2299DF18C15FA69BAC08D3EDB32E8C8CA"
- + "28431831561C04CB0CDE393F817151CD8DAF7A311838411F1C39BFDB5EBCF6A6"
- + "1DF66DEB067362649D64607D599B56C4227819D0290000241197004CF31AD00F"
- + "5E0C92E198488D8A2B6F6A25C82762AA49F565BCE9D857D72900001C00004004"
- + "A0D98FEABBFB92A6C0976EE83D2AACFCCF969A6B2900001C0000400575EBF73F"
- + "8EE5CC73917DE9D3F91FCD4A16A0444D290000080000402E290000100000402F"
- + "00020003000400050000000800004014";
- private static final String IKE_AUTH_RESP_1_FRAG_1 =
- "46B8ECA1E0D72A1873F643FF94D249A93520232000000001000004E0240004C4"
- + "00010002C4159CB756773B3F1911F4595107BC505D7A28C72F05182966076679"
- + "CA68ED92E4BC5CD441C9CB315F2F449A8A521CAFED3C5F285E295FC3791D3415"
- + "E3BACF66A08410DF4E35F7D88FE40DA28851C91C77A6549E186AC1B7846DF3FA"
- + "0A347A5ABBCAEE19E70F0EE5966DC6242A115F29523709302EDAD2E36C8F0395"
- + "CF5C42EC2D2898ECDD8A6AEDD686A70B589A981558667647F32F41E0D8913E94"
- + "A6693F53E59EA8938037F562CF1DC5E6E2CDC630B5FFB08949E3172249422F7D"
- + "EA069F9BAD5F96E48BADC7164A9269669AD0DF295A80C54D1D23CEA3F28AC485"
- + "86D2A9850DA23823037AB7D1577B7B2364C92C36B84238357129EB4A64D33310"
- + "B95DCD50CD53E78C32EFE7DC1627D9432E9BFDEE130045DE967B19F92A9D1270"
- + "F1E2C6BFBAA56802F3E63510578EF1ECB6872852F286EEC790AA1FE0CAF391CB"
- + "E276554922713BA4770CFE71E23F043DC620E22CC02A74F60725D18331B7F2C9"
- + "276EB6FBB7CBDAA040046D7ECBE1A5D7064E04E542807C5101B941D1C81B9D5E"
- + "90347B22BD4E638E2EDC98E369B51AA29BDB2CF8AA610D4B893EB83A4650717C"
- + "38B4D145EE939C18DCEDF6C79933CEB3D7C116B1F188DF9DDD560951B54E4A7D"
- + "80C999A32AB02BF39D7B498DAD36F1A5CBE2F64557D6401AE9DD6E0CEADA3F90"
- + "540FE9114BB6B8719C9064796354F4A180A6600CAD092F8302564E409B71ACB7"
- + "590F19B3AC88E7A606C718D0B97F7E4B4830F11D851C59F2255846DA22E2C805"
- + "0CA2AF2ACF3B6C769D11B75B5AC9AB82ED3D90014994B1BF6FED58FBEF2D72EF"
- + "8BDFE51F9A101393A7CA1ACF78FAEBF3E3CC25E09407D1E14AF351A159A13EE3"
- + "9B919BA8B49942792E7527C2FB6D418C4DF427669A4BF5A1AFBBB973BAF17918"
- + "9C9D520CAC2283B89A539ECE785EBE48FBB77D880A17D55C84A51F46068A4B87"
- + "FF48FEEE50E1E034CC8AFF5DA92105F55EC4823E67BDFE942CA8BE0DAECBBD52"
- + "E8AAF306049DC6C4CF87D987B0AC54FCE92E6AE8507965AAAC6AB8BD3405712F"
- + "EE170B70BC64BDCBD86D80C7AAAF341131F9A1210D7430B17218413AE1363183"
- + "5C98FA2428B1E9E987ADC9070E232310A28F4C3163E18366FFB112BADD7C5E0F"
- + "D13093A7C1428F87856BA0A7E46955589ACA267CE7A04320C4BCDBB60C672404"
- + "778F8D511AAB09349DAB482445D7F606F28E7FBBB18FC0F4EC0AF04F44C282F9"
- + "39C6E3B955C84DADEA350667236583069B74F492D600127636FA31F63E560851"
- + "2FC28B8EA5B4D01D110990B6EA46B9C2E7C7C856C240EF7A8147BA2C4344B85A"
- + "453C862024B5B6814D13CDEAEF7683D539BB50CAFFC0416F269F2F9EDEC5FA30"
- + "022FD7B4B186CD2020E7ED8D81ED90822EDD8B76F840DD68F09694CFF9B4F33E"
- + "11DF4E601A4212881A6D4E9259001705C41E9E23D18A7F3D4A3463649A38211A"
- + "5A90D0F17739A677C74E23F31C01D60B5A0F1E6A4D44FED9D25BF1E63418E1FC"
- + "0B19F6F4B71DE53C62B14B82279538A82DD4BE19AB6E00AFC20F124AAB7DF21A"
- + "42259BE4F40EC69B16917256F23E2C37376311D62E0A3A0EF8C2AD0C090221D5"
- + "C5ECA08F08178A4D31FFDB150C609827D18AD83C7B0A43AEE0406BD3FB494B53"
- + "A279FDD6447E234C926AD8CE47FFF779BB45B1FC8457C6E7D257D1359959D977"
- + "CEF6906A3367DC4D454993EFDC6F1EA94E17EB3DCB00A289346B4CFD7F19B16E";
- private static final String IKE_AUTH_RESP_1_FRAG_2 =
- "46B8ECA1E0D72A1873F643FF94D249A935202320000000010000008000000064"
- + "00020002C61F66025E821A5E69A4DE1F591A2C32C983C3154A5003660137D685"
- + "A5262B9FDF5EDC699DE4D8BD38F549E3CBD12024B45B4C86561C36C3EED839DA"
- + "9860C6AA0B764C662D08F1B6A98F68CF6E3038F737C0B415AD8A8B7D702BD92A";
- private static final String IKE_AUTH_RESP_2 =
- "46B8ECA1E0D72A1873F643FF94D249A92E202320000000020000008C30000070"
- + "62B90C2229FD23025BC2FD7FE6341E9EE04B17264CD619BCE18975A5F88BE438"
- + "D4AD4A5310057255AF568C293A29B10107E3EE3675C10AA2B26404D90C0528CC"
- + "F7605A86C96A1F2635CCC6CFC90EE65E5C2A2262EB33FE520EB708423A83CB63"
- + "274ECCBB102AF5DF35742657";
- private static final String IKE_AUTH_RESP_3 =
- "46B8ECA1E0D72A1873F643FF94D249A92E202320000000030000004C30000030"
- + "AB52C3C80123D3432C05AF457CE93C352395F73E861CD49561BA528CFE68D17D"
- + "78BBF6FC41E81C2B9EA051A2";
- private static final String IKE_AUTH_RESP_4 =
- "46B8ECA1E0D72A1873F643FF94D249A92E20232000000004000000CC270000B0"
- + "8D3342A7AB2666AC754F4B55C5C6B1A61255E62FBCA53D5CDEEDE60DADB7915C"
- + "7F962076A58BF7D39A05ED1B60FF349B6DE311AF7CEBC72B4BB9723A728A5D3E"
- + "9E508B2D7A11843D279B56ADA07E608D61F5CA7638F10372A440AD1DCE44E190"
- + "7B7B7A68B126EBBB86638D667D5B528D233BA8D32D7E0FAC4E1448E87396EEE6"
- + "0985B79841E1229D7962AACFD8F872722EC8D5B19D4C82D6C4ADCB276127A1A7"
- + "3FC84CDF85B2299BC96B64AC";
- private static final String DELETE_IKE_RESP =
- "46B8ECA1E0D72A1873F643FF94D249A92E202520000000050000004C00000030"
- + "622CE06C8CB132AA00567E9BC83F58B32BD7DB5130C76E385B306434DA227361"
- + "D50CC19D408A8D4F36F9697F";
-
- // This value is align with the test vectors hex that are generated in an IPv4 environment
- private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS =
- new IkeTrafficSelector(
- MIN_PORT,
- MAX_PORT,
- InetAddresses.parseNumericAddress("172.58.35.67"),
- InetAddresses.parseNumericAddress("172.58.35.67"));
-
- private static final EapSessionConfig EAP_CONFIG =
- new EapSessionConfig.Builder()
- .setEapIdentity(EAP_IDENTITY)
- .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD)
- .build();
-
- private static X509Certificate sServerCaCert;
-
- @BeforeClass
- public static void setUpCertBeforeClass() throws Exception {
- sServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem");
- }
-
- 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))
- .setAuthEap(sServerCaCert, EAP_CONFIG)
- .build();
- return new IkeSession(
- sContext,
- ikeParams,
- buildTransportModeChildParamsWithTs(
- TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS),
- mUserCbExecutor,
- mIkeSessionCallback,
- mFirstChildSessionCallback);
- }
-
- @Test
- public void testIkeSessionSetupAndChildSessionSetupWithTransportMode() throws Exception {
- // Open IKE Session
- IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress);
- int expectedMsgId = 0;
- mTunUtils.awaitReqAndInjectResp(
- IKE_DETERMINISTIC_INITIATOR_SPI,
- expectedMsgId++,
- false /* expectedUseEncap */,
- IKE_INIT_RESP);
-
- mTunUtils.awaitReqAndInjectResp(
- IKE_DETERMINISTIC_INITIATOR_SPI,
- expectedMsgId++,
- true /* expectedUseEncap */,
- IKE_AUTH_RESP_1_FRAG_1,
- IKE_AUTH_RESP_1_FRAG_2);
-
- mTunUtils.awaitReqAndInjectResp(
- IKE_DETERMINISTIC_INITIATOR_SPI,
- expectedMsgId++,
- true /* expectedUseEncap */,
- IKE_AUTH_RESP_2);
- mTunUtils.awaitReqAndInjectResp(
- IKE_DETERMINISTIC_INITIATOR_SPI,
- expectedMsgId++,
- true /* expectedUseEncap */,
- IKE_AUTH_RESP_3);
- mTunUtils.awaitReqAndInjectResp(
- IKE_DETERMINISTIC_INITIATOR_SPI,
- expectedMsgId++,
- true /* expectedUseEncap */,
- IKE_AUTH_RESP_4);
-
- verifyIkeSessionSetupBlocking();
- verifyChildSessionSetupBlocking(
- mFirstChildSessionCallback,
- Arrays.asList(TRANSPORT_MODE_INBOUND_TS),
- Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS),
- new ArrayList<LinkAddress>());
- IpSecTransformCallRecord firstTransformRecordA =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- IpSecTransformCallRecord firstTransformRecordB =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
-
- // Close IKE Session
- ikeSession.close();
- performCloseIkeBlocking(expectedMsgId++, DELETE_IKE_RESP);
- verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB);
- }
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java
deleted file mode 100644
index c767b78..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionParamsTest.java
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipsec.ike.cts;
-
-import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID;
-import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH;
-import static android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig;
-import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig;
-import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig;
-import static android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig;
-import static android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.eap.EapSessionConfig;
-import android.net.ipsec.ike.IkeFqdnIdentification;
-import android.net.ipsec.ike.IkeIdentification;
-import android.net.ipsec.ike.IkeSaProposal;
-import android.net.ipsec.ike.IkeSessionParams;
-import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv4PcscfServer;
-import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv6PcscfServer;
-import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.internal.net.ipsec.ike.testutils.CertUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.security.cert.X509Certificate;
-import java.security.interfaces.RSAPrivateKey;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-@RunWith(AndroidJUnit4.class)
-public final class IkeSessionParamsTest extends IkeSessionTestBase {
- private static final int HARD_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(20L);
- private static final int SOFT_LIFETIME_SECONDS = (int) TimeUnit.HOURS.toSeconds(10L);
- private static final int DPD_DELAY_SECONDS = (int) TimeUnit.MINUTES.toSeconds(10L);
- private static final int[] RETRANS_TIMEOUT_MS_LIST = new int[] {500, 500, 500, 500, 500, 500};
-
- private static final Map<Class<? extends IkeConfigRequest>, Integer> EXPECTED_REQ_COUNT =
- new HashMap<>();
- private static final HashSet<InetAddress> EXPECTED_PCSCF_SERVERS = new HashSet<>();
-
- static {
- EXPECTED_REQ_COUNT.put(ConfigRequestIpv4PcscfServer.class, 3);
- EXPECTED_REQ_COUNT.put(ConfigRequestIpv6PcscfServer.class, 3);
-
- EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV4_ADDRESS_1);
- EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV4_ADDRESS_2);
- EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV6_ADDRESS_1);
- EXPECTED_PCSCF_SERVERS.add(PCSCF_IPV6_ADDRESS_2);
- }
-
- // Arbitrary proposal and remote ID. Local ID is chosen to match the client end cert in the
- // following CL
- private static final IkeSaProposal SA_PROPOSAL =
- SaProposalTest.buildIkeSaProposalWithNormalModeCipher();
- private static final IkeIdentification LOCAL_ID = new IkeFqdnIdentification(LOCAL_HOSTNAME);
- private static final IkeIdentification REMOTE_ID = new IkeFqdnIdentification(REMOTE_HOSTNAME);
-
- private static final EapSessionConfig EAP_ALL_METHODS_CONFIG =
- createEapOnlySafeMethodsBuilder()
- .setEapMsChapV2Config(EAP_MSCHAPV2_USERNAME, EAP_MSCHAPV2_PASSWORD)
- .build();
- private static final EapSessionConfig EAP_ONLY_SAFE_METHODS_CONFIG =
- createEapOnlySafeMethodsBuilder().build();
-
- private X509Certificate mServerCaCert;
- private X509Certificate mClientEndCert;
- private X509Certificate mClientIntermediateCaCertOne;
- private X509Certificate mClientIntermediateCaCertTwo;
- private RSAPrivateKey mClientPrivateKey;
-
- @Before
- public void setUp() throws Exception {
- // This address is never used except for setting up the test network
- setUpTestNetwork(IPV4_ADDRESS_LOCAL);
-
- mServerCaCert = CertUtils.createCertFromPemFile("server-a-self-signed-ca.pem");
- mClientEndCert = CertUtils.createCertFromPemFile("client-a-end-cert.pem");
- mClientIntermediateCaCertOne =
- CertUtils.createCertFromPemFile("client-a-intermediate-ca-one.pem");
- mClientIntermediateCaCertTwo =
- CertUtils.createCertFromPemFile("client-a-intermediate-ca-two.pem");
- mClientPrivateKey = CertUtils.createRsaPrivateKeyFromKeyFile("client-a-private-key.key");
- }
-
- @After
- public void tearDown() throws Exception {
- tearDownTestNetwork();
- }
-
- private static EapSessionConfig.Builder createEapOnlySafeMethodsBuilder() {
- return new EapSessionConfig.Builder()
- .setEapIdentity(EAP_IDENTITY)
- .setEapSimConfig(SUB_ID, APPTYPE_USIM)
- .setEapAkaConfig(SUB_ID, APPTYPE_USIM)
- .setEapAkaPrimeConfig(
- SUB_ID, APPTYPE_USIM, NETWORK_NAME, true /* allowMismatchedNetworkNames */);
- }
-
- /**
- * Create a Builder that has minimum configurations to build an IkeSessionParams.
- *
- * <p>Authentication method is arbitrarily selected. Using other method (e.g. setAuthEap) also
- * works.
- */
- private IkeSessionParams.Builder createIkeParamsBuilderMinimum() {
- return new IkeSessionParams.Builder(sContext)
- .setNetwork(mTunNetwork)
- .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress())
- .addSaProposal(SA_PROPOSAL)
- .setLocalIdentification(LOCAL_ID)
- .setRemoteIdentification(REMOTE_ID)
- .setAuthPsk(IKE_PSK);
- }
-
- /**
- * Verify the minimum configurations to build an IkeSessionParams.
- *
- * @see #createIkeParamsBuilderMinimum
- */
- private void verifyIkeParamsMinimum(IkeSessionParams sessionParams) {
- assertEquals(mTunNetwork, sessionParams.getNetwork());
- assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname());
- assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals());
- assertEquals(LOCAL_ID, sessionParams.getLocalIdentification());
- assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification());
-
- IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
- assertTrue(localConfig instanceof IkeAuthPskConfig);
- assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) localConfig).getPsk());
- IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
- assertTrue(remoteConfig instanceof IkeAuthPskConfig);
- assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk());
- }
-
- @Test
- public void testBuildWithMinimumSet() throws Exception {
- IkeSessionParams sessionParams = createIkeParamsBuilderMinimum().build();
-
- verifyIkeParamsMinimum(sessionParams);
-
- // Verify default values that do not need explicit configuration. Do not do assertEquals
- // to be avoid being a change-detector test
- assertTrue(sessionParams.getHardLifetimeSeconds() > sessionParams.getSoftLifetimeSeconds());
- assertTrue(sessionParams.getSoftLifetimeSeconds() > 0);
- assertTrue(sessionParams.getDpdDelaySeconds() > 0);
- assertTrue(sessionParams.getRetransmissionTimeoutsMillis().length > 0);
- for (int timeout : sessionParams.getRetransmissionTimeoutsMillis()) {
- assertTrue(timeout > 0);
- }
- assertTrue(sessionParams.getConfigurationRequests().isEmpty());
- assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID));
- }
-
- @Test
- public void testSetLifetimes() throws Exception {
- IkeSessionParams sessionParams =
- createIkeParamsBuilderMinimum()
- .setLifetimeSeconds(HARD_LIFETIME_SECONDS, SOFT_LIFETIME_SECONDS)
- .build();
-
- verifyIkeParamsMinimum(sessionParams);
- assertEquals(HARD_LIFETIME_SECONDS, sessionParams.getHardLifetimeSeconds());
- assertEquals(SOFT_LIFETIME_SECONDS, sessionParams.getSoftLifetimeSeconds());
- }
-
- @Test
- public void testSetDpdDelay() throws Exception {
- IkeSessionParams sessionParams =
- createIkeParamsBuilderMinimum().setDpdDelaySeconds(DPD_DELAY_SECONDS).build();
-
- verifyIkeParamsMinimum(sessionParams);
- assertEquals(DPD_DELAY_SECONDS, sessionParams.getDpdDelaySeconds());
- }
-
- @Test
- public void testSetRetransmissionTimeouts() throws Exception {
- IkeSessionParams sessionParams =
- createIkeParamsBuilderMinimum()
- .setRetransmissionTimeoutsMillis(RETRANS_TIMEOUT_MS_LIST)
- .build();
-
- verifyIkeParamsMinimum(sessionParams);
- assertArrayEquals(RETRANS_TIMEOUT_MS_LIST, sessionParams.getRetransmissionTimeoutsMillis());
- }
-
- @Test
- public void testSetPcscfConfigRequests() throws Exception {
- IkeSessionParams sessionParams =
- createIkeParamsBuilderMinimum()
- .setRetransmissionTimeoutsMillis(RETRANS_TIMEOUT_MS_LIST)
- .addPcscfServerRequest(AF_INET)
- .addPcscfServerRequest(PCSCF_IPV4_ADDRESS_1)
- .addPcscfServerRequest(PCSCF_IPV6_ADDRESS_1)
- .addPcscfServerRequest(AF_INET6)
- .addPcscfServerRequest(PCSCF_IPV4_ADDRESS_2)
- .addPcscfServerRequest(PCSCF_IPV6_ADDRESS_2)
- .build();
-
- verifyIkeParamsMinimum(sessionParams);
- verifyConfigRequestTypes(EXPECTED_REQ_COUNT, sessionParams.getConfigurationRequests());
-
- Set<InetAddress> resultAddresses = new HashSet<>();
- for (IkeConfigRequest req : sessionParams.getConfigurationRequests()) {
- if (req instanceof ConfigRequestIpv4PcscfServer
- && ((ConfigRequestIpv4PcscfServer) req).getAddress() != null) {
- resultAddresses.add(((ConfigRequestIpv4PcscfServer) req).getAddress());
- } else if (req instanceof ConfigRequestIpv6PcscfServer
- && ((ConfigRequestIpv6PcscfServer) req).getAddress() != null) {
- resultAddresses.add(((ConfigRequestIpv6PcscfServer) req).getAddress());
- }
- }
- assertEquals(EXPECTED_PCSCF_SERVERS, resultAddresses);
- }
-
- @Test
- public void testAddIkeOption() throws Exception {
- IkeSessionParams sessionParams =
- createIkeParamsBuilderMinimum()
- .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
- .build();
-
- verifyIkeParamsMinimum(sessionParams);
- assertTrue(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID));
- }
-
- @Test
- public void testRemoveIkeOption() throws Exception {
- IkeSessionParams sessionParams =
- createIkeParamsBuilderMinimum()
- .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
- .removeIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
- .build();
-
- verifyIkeParamsMinimum(sessionParams);
- assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID));
- }
-
- /**
- * Create a Builder that has minimum configurations to build an IkeSessionParams, except for
- * authentication method.
- */
- private IkeSessionParams.Builder createIkeParamsBuilderMinimumWithoutAuth() {
- return new IkeSessionParams.Builder(sContext)
- .setNetwork(mTunNetwork)
- .setServerHostname(IPV4_ADDRESS_REMOTE.getHostAddress())
- .addSaProposal(SA_PROPOSAL)
- .setLocalIdentification(LOCAL_ID)
- .setRemoteIdentification(REMOTE_ID);
- }
-
- /**
- * Verify the minimum configurations to build an IkeSessionParams, except for authentication
- * method.
- *
- * @see #createIkeParamsBuilderMinimumWithoutAuth
- */
- private void verifyIkeParamsMinimumWithoutAuth(IkeSessionParams sessionParams) {
- assertEquals(mTunNetwork, sessionParams.getNetwork());
- assertEquals(IPV4_ADDRESS_REMOTE.getHostAddress(), sessionParams.getServerHostname());
- assertEquals(Arrays.asList(SA_PROPOSAL), sessionParams.getSaProposals());
- assertEquals(LOCAL_ID, sessionParams.getLocalIdentification());
- assertEquals(REMOTE_ID, sessionParams.getRemoteIdentification());
- }
-
- @Test
- public void testBuildWithPsk() throws Exception {
- IkeSessionParams sessionParams =
- createIkeParamsBuilderMinimumWithoutAuth().setAuthPsk(IKE_PSK).build();
-
- verifyIkeParamsMinimumWithoutAuth(sessionParams);
-
- IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
- assertTrue(localConfig instanceof IkeAuthPskConfig);
- assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) localConfig).getPsk());
- IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
- assertTrue(remoteConfig instanceof IkeAuthPskConfig);
- assertArrayEquals(IKE_PSK, ((IkeAuthPskConfig) remoteConfig).getPsk());
- }
-
- @Test
- public void testBuildWithEap() throws Exception {
- IkeSessionParams sessionParams =
- createIkeParamsBuilderMinimumWithoutAuth()
- .setAuthEap(mServerCaCert, EAP_ALL_METHODS_CONFIG)
- .build();
-
- verifyIkeParamsMinimumWithoutAuth(sessionParams);
-
- IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
- assertTrue(localConfig instanceof IkeAuthEapConfig);
- assertEquals(EAP_ALL_METHODS_CONFIG, ((IkeAuthEapConfig) localConfig).getEapConfig());
- IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
- assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig);
- assertEquals(
- mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert());
- }
-
- @Test
- public void testBuildWithEapOnlyAuth() throws Exception {
- IkeSessionParams sessionParams =
- createIkeParamsBuilderMinimumWithoutAuth()
- .setAuthEap(mServerCaCert, EAP_ONLY_SAFE_METHODS_CONFIG)
- .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH)
- .build();
-
- assertTrue(sessionParams.hasIkeOption(IKE_OPTION_EAP_ONLY_AUTH));
- verifyIkeParamsMinimumWithoutAuth(sessionParams);
-
- IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
- assertTrue(localConfig instanceof IkeAuthEapConfig);
- assertEquals(EAP_ONLY_SAFE_METHODS_CONFIG, ((IkeAuthEapConfig) localConfig).getEapConfig());
- IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
- assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig);
- assertEquals(
- mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert());
- }
-
- @Test
- public void testThrowBuildEapOnlyAuthWithUnsafeMethod() throws Exception {
- try {
- IkeSessionParams sessionParams =
- createIkeParamsBuilderMinimumWithoutAuth()
- .setAuthEap(mServerCaCert, EAP_ALL_METHODS_CONFIG)
- .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH)
- .build();
- fail("Expected to fail because EAP only unsafe method is proposed");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testBuildWithDigitalSignature() throws Exception {
- IkeSessionParams sessionParams =
- createIkeParamsBuilderMinimumWithoutAuth()
- .setAuthDigitalSignature(mServerCaCert, mClientEndCert, mClientPrivateKey)
- .build();
-
- verifyIkeParamsMinimumWithoutAuth(sessionParams);
-
- IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
- assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig);
- IkeAuthDigitalSignLocalConfig localSignConfig = (IkeAuthDigitalSignLocalConfig) localConfig;
- assertEquals(mClientEndCert, localSignConfig.getClientEndCertificate());
- assertEquals(Collections.EMPTY_LIST, localSignConfig.getIntermediateCertificates());
- assertEquals(mClientPrivateKey, localSignConfig.getPrivateKey());
-
- IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
- assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig);
- assertEquals(
- mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert());
- }
-
- @Test
- public void testBuildWithDigitalSignatureAndIntermediateCerts() throws Exception {
- List<X509Certificate> intermediateCerts =
- Arrays.asList(mClientIntermediateCaCertOne, mClientIntermediateCaCertTwo);
-
- IkeSessionParams sessionParams =
- createIkeParamsBuilderMinimumWithoutAuth()
- .setAuthDigitalSignature(
- mServerCaCert, mClientEndCert, intermediateCerts, mClientPrivateKey)
- .build();
-
- verifyIkeParamsMinimumWithoutAuth(sessionParams);
-
- IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
- assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig);
- IkeAuthDigitalSignLocalConfig localSignConfig = (IkeAuthDigitalSignLocalConfig) localConfig;
- assertEquals(mClientEndCert, localSignConfig.getClientEndCertificate());
- assertEquals(intermediateCerts, localSignConfig.getIntermediateCertificates());
- assertEquals(mClientPrivateKey, localSignConfig.getPrivateKey());
-
- IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
- assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig);
- assertEquals(
- mServerCaCert, ((IkeAuthDigitalSignRemoteConfig) remoteConfig).getRemoteCaCert());
- }
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java
deleted file mode 100644
index 13f953a..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipsec.ike.cts;
-
-import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import android.net.LinkAddress;
-import android.net.ipsec.ike.ChildSessionParams;
-import android.net.ipsec.ike.IkeFqdnIdentification;
-import android.net.ipsec.ike.IkeSession;
-import android.net.ipsec.ike.IkeSessionParams;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.platform.test.annotations.AppModeFull;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-@RunWith(AndroidJUnit4.class)
-@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 =
- "46B8ECA1E0D72A18B45427679F9245D421202220000000000000015022000030"
- + "0000002C010100040300000C0100000C800E0080030000080300000203000008"
- + "0200000200000008040000022800008800020000A7AA3435D088EC1A2B7C2A47"
- + "1FA1B85F1066C9B2006E7C353FB5B5FDBC2A88347ED2C6F5B7A265D03AE34039"
- + "6AAC0145CFCC93F8BDB219DDFF22A603B8856A5DC59B6FAB7F17C5660CF38670"
- + "8794FC72F273ADEB7A4F316519794AED6F8AB61F95DFB360FAF18C6C8CABE471"
- + "6E18FE215348C2E582171A57FC41146B16C4AFE429000024A634B61C0E5C90C6"
- + "8D8818B0955B125A9B1DF47BBD18775710792E651083105C2900001C00004004"
- + "406FA3C5685A16B9B72C7F2EEE9993462C619ABE2900001C00004005AF905A87"
- + "0A32222AA284A7070585601208A282F0290000080000402E290000100000402F"
- + "00020003000400050000000800004014";
- private static final String SUCCESS_IKE_AUTH_RESP =
- "46B8ECA1E0D72A18B45427679F9245D42E20232000000001000000EC240000D0"
- + "0D06D37198F3F0962DE8170D66F1A9008267F98CDD956D984BDCED2FC7FAF84A"
- + "A6664EF25049B46B93C9ED420488E0C172AA6635BF4011C49792EF2B88FE7190"
- + "E8859FEEF51724FD20C46E7B9A9C3DC4708EF7005707A18AB747C903ABCEAC5C"
- + "6ECF5A5FC13633DCE3844A920ED10EF202F115DBFBB5D6D2D7AB1F34EB08DE7C"
- + "A54DCE0A3A582753345CA2D05A0EFDB9DC61E81B2483B7D13EEE0A815D37252C"
- + "23D2F29E9C30658227D2BB0C9E1A481EAA80BC6BE9006BEDC13E925A755A0290"
- + "AEC4164D29997F52ED7DCC2E";
- private static final String SUCCESS_CREATE_CHILD_RESP =
- "46B8ECA1E0D72A18B45427679F9245D42E20242000000002000000CC210000B0"
- + "484565D4AF6546274674A8DE339E9C9584EE2326AB9260F41C4D0B6C5B02D1D"
- + "2E8394E3CDE3094895F2ACCABCDCA8E82960E5196E9622BD13745FC8D6A2BED"
- + "E561FF5D9975421BC463C959A3CBA3478256B6D278159D99B512DDF56AC1658"
- + "63C65A986F395FE8B1476124B91F83FD7865304EB95B22CA4DD9601DA7A2533"
- + "ABF4B36EB1B8CD09522F6A600032316C74E562E6756D9D49D945854E2ABDC4C"
- + "3AF36305353D60D40B58BE44ABF82";
- private static final String SUCCESS_DELETE_CHILD_RESP =
- "46B8ECA1E0D72A18B45427679F9245D42E202520000000030000004C2A000030"
- + "0C5CEB882DBCA65CE32F4C53909335F1365C91C555316C5E9D9FB553F7AA916"
- + "EF3A1D93460B7FABAF0B4B854";
- private static final String SUCCESS_DELETE_IKE_RESP =
- "46B8ECA1E0D72A18B45427679F9245D42E202520000000040000004C00000030"
- + "9352D71100777B00ABCC6BD7DBEA697827FFAAA48DF9A54D1D68161939F5DC8"
- + "6743A7CEB2BE34AC00095A5B8";
-
- private IkeSession openIkeSessionWithTunnelModeChild(InetAddress remoteAddress) {
- return openIkeSession(remoteAddress, buildTunnelModeChildSessionParams());
- }
-
- private IkeSession openIkeSessionWithTransportModeChild(InetAddress remoteAddress) {
- return openIkeSession(remoteAddress, buildTransportModeChildParamsWithDefaultTs());
- }
-
- private IkeSession openIkeSession(InetAddress remoteAddress, ChildSessionParams childParams) {
- 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,
- childParams,
- mUserCbExecutor,
- mIkeSessionCallback,
- mFirstChildSessionCallback);
- }
-
- @BeforeClass
- public static void setUpTunnelPermissionBeforeClass() throws Exception {
- // 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
- // right appop permissions.
- setAppOp(OP_MANAGE_IPSEC_TUNNELS, true);
- }
-
- // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass
- // methods.
- @AfterClass
- public static void tearDownTunnelPermissionAfterClass() throws Exception {
- setAppOp(OP_MANAGE_IPSEC_TUNNELS, false);
- }
-
- @Test
- public void testIkeSessionSetupAndChildSessionSetupWithTunnelMode() throws Exception {
- if (!hasTunnelsFeature()) return;
-
- // Open IKE Session
- IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress);
- performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP);
-
- // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2
- int expectedMsgId = 2;
-
- verifyIkeSessionSetupBlocking();
- verifyChildSessionSetupBlocking(
- mFirstChildSessionCallback,
- Arrays.asList(TUNNEL_MODE_INBOUND_TS),
- Arrays.asList(TUNNEL_MODE_OUTBOUND_TS),
- Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR));
-
- IpSecTransformCallRecord firstTransformRecordA =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- IpSecTransformCallRecord firstTransformRecordB =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
-
- // Open additional Child Session
- TestChildSessionCallback additionalChildCb = new TestChildSessionCallback();
- ikeSession.openChildSession(buildTunnelModeChildSessionParams(), additionalChildCb);
- mTunUtils.awaitReqAndInjectResp(
- IKE_DETERMINISTIC_INITIATOR_SPI,
- expectedMsgId++,
- true /* expectedUseEncap */,
- SUCCESS_CREATE_CHILD_RESP);
-
- // Verify opening additional Child Session
- 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_DETERMINISTIC_INITIATOR_SPI,
- expectedMsgId++,
- true /* expectedUseEncap */,
- SUCCESS_DELETE_CHILD_RESP);
-
- verifyDeleteIpSecTransformPair(
- additionalChildCb, additionalTransformRecordA, additionalTransformRecordB);
- additionalChildCb.awaitOnClosed();
-
- // Close IKE Session
- ikeSession.close();
- performCloseIkeBlocking(expectedMsgId++, SUCCESS_DELETE_IKE_RESP);
- verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB);
- }
-
- @Test
- public void testIkeSessionSetupAndChildSessionSetupWithTunnelModeV6() throws Exception {
- if (!hasTunnelsFeature()) return;
-
- final String ikeInitResp =
- "46B8ECA1E0D72A186F7B6C2CEB77EB9021202220000000000000011822000030"
- + "0000002C010100040300000C0100000C800E0100030000080300000C03000008"
- + "0200000500000008040000022800008800020000DABAA04B38B491E2403F2125"
- + "96ECF1C8EF7B1DC19A422FDD46E1756C826BB3A16404361B775D9950577B5CDF"
- + "6AAA1642BD1427BDA8BC55354A97C1025E19C1E2EE2DF8A0C9406E545D829F52"
- + "75695008E3B742984B8DD1770F3514213B0DF3EE8B199416DF200D248115C057"
- + "1C193E4F96802E5EF48DD99CAC251882A8F7CCC329000024BC6F0F1D3653C2C7"
- + "679E02CDB6A3B32B2FEE9AF52F0326D4D9AE073D56CE8922290000080000402E"
- + "290000100000402F00020003000400050000000800004014";
- final String ikeAuthResp =
- "46B8ECA1E0D72A186F7B6C2CEB77EB902E202320000000010000015024000134"
- + "4D115AFDCDAD0310760BB664EB7D405A340869AD6EDF0AAEAD0663A9253DADCB"
- + "73EBE5CD29D4FA1CDEADE0B94391B5C4CF77BCC1596ACE3CE6A7891E44888FA5"
- + "46632C0EF4E6193C023C9DC59142C37D1C49D6EF5CD324EC6FC35C89E1721C78"
- + "91FDCDB723D8062709950F4AA9273D26A54C9C7E86862DBC15F7B6641D2B9BAD"
- + "E55069008201D12968D97B537B1518FE87B0FFA03C3EE6012C06721B1E2A3F68"
- + "92108BC4A4F7063F7F94562D8B60F291A1377A836CF12BCDA7E15C1A8F3C77BB"
- + "6DB7F2C833CCE4CDDED7506536621A3356CE2BC1874E7B1A1A9B447D7DF6AB09"
- + "638B8AD94A781B28BB91B514B611B24DF8E8A047A10AE27BBF15C754D3D2F792"
- + "D3E1CCADDAE934C98AE53A8FC3419C88AFF0355564F82A629C998012DA7BB704"
- + "5307270DF326377E3E1994476902035B";
- final String deleteIkeResp =
- "46B8ECA1E0D72A186F7B6C2CEB77EB902E202520000000020000005000000034"
- + "CF15C299F35688E5140A48B61C95F004121BF8236201415E5CD45BA41AAB16D4"
- + "90B44B9E6D5D92B5B97D24196A58C73F";
-
- mLocalAddress = IPV6_ADDRESS_LOCAL;
- mRemoteAddress = IPV6_ADDRESS_REMOTE;
-
- // Teardown current test network that uses IPv4 address and set up new network with IPv6
- // address.
- tearDownTestNetwork();
- setUpTestNetwork(mLocalAddress);
-
- // Open IKE Session
- IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress);
- performSetupIkeAndFirstChildBlocking(
- ikeInitResp,
- 1 /* expectedAuthReqPktCnt */,
- false /* expectedAuthUseEncap */,
- ikeAuthResp);
-
- // Local request message ID starts from 2 because there is one IKE_INIT message and a single
- // IKE_AUTH message.
- int expectedMsgId = 2;
-
- verifyIkeSessionSetupBlocking();
- verifyChildSessionSetupBlocking(
- mFirstChildSessionCallback,
- Arrays.asList(TUNNEL_MODE_INBOUND_TS_V6),
- Arrays.asList(TUNNEL_MODE_OUTBOUND_TS_V6),
- Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR_V6),
- Arrays.asList(EXPECTED_DNS_SERVERS_ONE, EXPECTED_DNS_SERVERS_TWO));
-
- IpSecTransformCallRecord firstTransformRecordA =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- IpSecTransformCallRecord firstTransformRecordB =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
-
- // Close IKE Session
- ikeSession.close();
- performCloseIkeBlocking(expectedMsgId++, false /* expectedUseEncap */, deleteIkeResp);
- verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB);
- }
-
- @Test
- public void testIkeSessionKillWithTunnelMode() throws Exception {
- if (!hasTunnelsFeature()) return;
-
- // Open IKE Session
- IkeSession ikeSession = openIkeSessionWithTunnelModeChild(mRemoteAddress);
- performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP);
-
- ikeSession.kill();
- mFirstChildSessionCallback.awaitOnClosed();
- mIkeSessionCallback.awaitOnClosed();
- }
-
- @Test
- public void testIkeInitFail() throws Exception {
- final String ikeInitFailRespHex =
- "46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E";
-
- // Open IKE Session
- IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress);
- int expectedMsgId = 0;
- mTunUtils.awaitReqAndInjectResp(
- IKE_DETERMINISTIC_INITIATOR_SPI,
- expectedMsgId++,
- false /* expectedUseEncap */,
- ikeInitFailRespHex);
-
- mFirstChildSessionCallback.awaitOnClosed();
-
- IkeProtocolException protocolException =
- (IkeProtocolException) mIkeSessionCallback.awaitOnClosedException();
- assertEquals(ERROR_TYPE_NO_PROPOSAL_CHOSEN, protocolException.getErrorType());
- assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData());
- }
-
- @Test
- public void testIkeAuthHandlesAuthFailNotification() throws Exception {
- final String ikeInitRespHex =
- "46B8ECA1E0D72A18CF94CE3159486F002120222000000000000001502200"
- + "00300000002C010100040300000C0100000C800E01000300000803000005"
- + "0300000802000004000000080400000228000088000200001821AA854691"
- + "FA3292DF710F0AC149ACBD0CB421608B8796C1912AF04C5B4B23936FDEC4"
- + "7CB640E3EAFB56BBB562825E87AF68B40E4BAB80A49BAD44407450A4195A"
- + "1DD54BD99F48D28C9F0FBA315A3401C1C3C4AD55911F514A8DF2D2467C46"
- + "A73DDC1452AE81336E0F0D5EC896D2E7A77628AF2F9089F48943399DF216"
- + "EFCD2900002418D2B7E4E6AF0FEFF5962CF8D68F7793B1293FEDE13331D4"
- + "AB0CE9436C2EE1EC2900001C0000400457BD9AEF5B362A83DD7F3DDAA4A9"
- + "9B6B4041DAF32900001C000040055A81893582701E44D4B6729A22FE06DE"
- + "82A03A36290000080000402E290000100000402F00020003000400050000"
- + "000800004014";
- final String ikeAuthFailRespHex =
- "46B8ECA1E0D72A18CF94CE3159486F002E202320000000010000004C2900"
- + "00301B9E4C8242D3BE62E7F0A537FE8B92C6EAB7153105DA421DCE43A06D"
- + "AB6E4808BAC0CA1DAD6ADD0A126A41BD";
-
- // Open IKE Session
- IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress);
- performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthFailRespHex);
-
- mFirstChildSessionCallback.awaitOnClosed();
- IkeProtocolException protocolException =
- (IkeProtocolException) mIkeSessionCallback.awaitOnClosedException();
- assertEquals(ERROR_TYPE_AUTHENTICATION_FAILED, protocolException.getErrorType());
- assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData());
- }
-
- @Test
- public void testIkeAuthHandlesFirstChildCreationFail() throws Exception {
- final String ikeInitRespHex =
- "46B8ECA1E0D72A18F5ABBF896A1240BE2120222000000000000001502200"
- + "00300000002C010100040300000C0100000C800E0100030000080300000C"
- + "03000008020000050000000804000002280000880002000074950F016B85"
- + "605E57E24651843AB70E41B552EDEE227DFE51E6CBEC00E75FFEFC7D5453"
- + "109B15F721FCD811FC9F113BE06050882F2FC5F5FF25857E555CCFB5AB64"
- + "8B0D1D7A819A3B05DE1FE89A4A627C60D5AA06CD0F66ACD3748722F9CD4F"
- + "F30AE7477CBC12049821F07AD6C9F0ED732321A6A36FA817722E025AC34B"
- + "ABE62900002432E3807F595070E95EDA341A787599B24B1151B535B0222B"
- + "65C003401B9B38F82900001C000040043BB760DB3037B51768DFFAB4B21D"
- + "B1716EA1C1382900001C0000400531098EB04DF1BE3F304606BD59B454A8"
- + "CC7E7311290000080000402E290000100000402F00020003000400050000"
- + "000800004014";
- final String ikeAuthCreateChildFailHex =
- "46B8ECA1E0D72A18F5ABBF896A1240BE2E20232000000001000000B02400"
- + "009400B0861242E0C88ECB3848D772B560CAD65B6AC9DFFDC8622A394B8E"
- + "64E550BDD69FCD7E768129787ED9062992C1D6DB0F0631C2E05765B403CF"
- + "EF1D0A055B32F6698FF7DB5B8FB1B6A83A81634D00E22C86E35B3BFBEC73"
- + "EAC6806678926945BC7A57003DC1A3528A1EC423EE56C1075B36C0B57A6B"
- + "C6DD990182F6FABFFA167D199C7D629E5B830AAD2AFBD31CEBA6";
-
- // Open IKE Session
- IkeSession ikeSession = openIkeSessionWithTransportModeChild(mRemoteAddress);
- performSetupIkeAndFirstChildBlocking(ikeInitRespHex, ikeAuthCreateChildFailHex);
-
- // Even though the child creation failed, the authentication succeeded, so the IKE Session's
- // onOpened() callback is still expected
- verifyIkeSessionSetupBlocking();
-
- // Verify Child Creation failed
- IkeProtocolException protocolException =
- (IkeProtocolException) mFirstChildSessionCallback.awaitOnClosedException();
- assertEquals(ERROR_TYPE_TS_UNACCEPTABLE, protocolException.getErrorType());
- assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData());
-
- ikeSession.kill();
- mIkeSessionCallback.awaitOnClosed();
- }
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java
deleted file mode 100644
index f954fcd..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionRekeyTest.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipsec.ike.cts;
-
-import static com.android.internal.util.HexDump.hexStringToByteArray;
-
-import android.net.InetAddresses;
-import android.net.LinkAddress;
-import android.net.ipsec.ike.IkeFqdnIdentification;
-import android.net.ipsec.ike.IkeSession;
-import android.net.ipsec.ike.IkeSessionParams;
-import android.net.ipsec.ike.IkeTrafficSelector;
-import android.net.ipsec.ike.cts.IkeTunUtils.PortPair;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * Explicitly test transport mode Child SA so that devices without FEATURE_IPSEC_TUNNELS can be test
- * covered. Tunnel mode Child SA setup has been tested in IkeSessionPskTest. Rekeying process is
- * independent from Child SA mode.
- */
-@RunWith(AndroidJUnit4.class)
-public class IkeSessionRekeyTest extends IkeSessionTestBase {
- // This value is align with the test vectors hex that are generated in an IPv4 environment
- private static final IkeTrafficSelector TRANSPORT_MODE_INBOUND_TS =
- new IkeTrafficSelector(
- MIN_PORT,
- MAX_PORT,
- InetAddresses.parseNumericAddress("172.58.35.40"),
- InetAddresses.parseNumericAddress("172.58.35.40"));
-
- 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,
- buildTransportModeChildParamsWithTs(
- TRANSPORT_MODE_INBOUND_TS, TRANSPORT_MODE_OUTBOUND_TS),
- mUserCbExecutor,
- mIkeSessionCallback,
- mFirstChildSessionCallback);
- }
-
- private byte[] buildInboundPkt(PortPair outPktSrcDestPortPair, String inboundDataHex)
- throws Exception {
- // Build inbound packet by flipping the outbound packet addresses and ports
- return IkeTunUtils.buildIkePacket(
- mRemoteAddress,
- mLocalAddress,
- outPktSrcDestPortPair.dstPort,
- outPktSrcDestPortPair.srcPort,
- true /* useEncap */,
- hexStringToByteArray(inboundDataHex));
- }
-
- @Test
- public void testRekeyIke() throws Exception {
- final String ikeInitResp =
- "46B8ECA1E0D72A1866B5248CF6C7472D21202220000000000000015022000030"
- + "0000002C010100040300000C0100000C800E0100030000080300000C03000008"
- + "0200000500000008040000022800008800020000920D3E830E7276908209212D"
- + "E5A7F2A48706CFEF1BE8CB6E3B173B8B4E0D8C2DC626271FF1B13A88619E569E"
- + "7B03C3ED2C127390749CDC7CDC711D0A8611E4457FFCBC4F0981B3288FBF58EA"
- + "3E8B70E27E76AE70117FBBCB753660ADDA37EB5EB3A81BED6A374CCB7E132C2A"
- + "94BFCE402DC76B19C158B533F6B1F2ABF01ACCC329000024B302CA2FB85B6CF4"
- + "02313381246E3C53828D787F6DFEA6BD62D6405254AEE6242900001C00004004"
- + "7A1682B06B58596533D00324886EF1F20EF276032900001C00004005BF633E31"
- + "F9984B29A62E370BB2770FC09BAEA665290000080000402E290000100000402F"
- + "00020003000400050000000800004014";
- final String ikeAuthResp =
- "46B8ECA1E0D72A1866B5248CF6C7472D2E20232000000001000000F0240000D4"
- + "10166CA8647F56123DE74C17FA5E256043ABF73216C812EE32EE1BB01EAF4A82"
- + "DC107AB3ADBFEE0DEA5EEE10BDD5D43178F4C975C7C775D252273BB037283C7F"
- + "236FE34A6BCE4833816897075DB2055B9FFD66DFA45A0A89A8F70AFB59431EED"
- + "A20602FB614369D12906D3355CF7298A5D25364ABBCC75A9D88E0E6581449FCD"
- + "4E361A39E00EFD1FD0A69651F63DB46C12470226AA21BA5EFF48FAF0B6DDF61C"
- + "B0A69392CE559495EEDB4D1C1D80688434D225D57210A424C213F7C993D8A456"
- + "38153FBD194C5E247B592D1D048DB4C8";
- final String rekeyIkeCreateReq =
- "46B8ECA1E0D72A1866B5248CF6C7472D2E202400000000000000013021000114"
- + "13743670039E308A8409BA5FD47B67F956B36FEE88AC3B70BB5D789B8218A135"
- + "1B3D83E260E87B3EDB1BF064F09D4DC2611AEDBC99951B4B2DE767BD4AA2ACC3"
- + "3653549CFC66B75869DF003CDC9A137A9CC27776AD5732B34203E74BE8CA4858"
- + "1D5C0D9C9CA52D680EB299B4B21C7FA25FFEE174D57015E0FF2EAED653AAD95C"
- + "071ABE269A8C2C9FBC1188E07550EB992F910D4CA9689E44BA66DE0FABB2BDF9"
- + "8DD377186DBB25EF9B68B027BB2A27981779D8303D88D7CE860010A42862D50B"
- + "1E0DBFD3D27C36F14809D7F493B2B96A65534CF98B0C32AD5219AD77F681AC04"
- + "9D5CB89A0230A91A243FA7F16251B0D9B4B65E7330BEEAC9663EF4578991EAC8"
- + "46C19EBB726E7D113F1D0D601102C05E";
- final String rekeyIkeDeleteReq =
- "46B8ECA1E0D72A1866B5248CF6C7472D2E20250000000001000000502A000034"
- + "02E40C0C7B1ED977729F705BB9B643FAC513A1070A6EB28ECD2AEA8A441ADC05"
- + "7841382A7967BBF116AE52496590B2AD";
- final String deleteIkeReq =
- "7D3DEDC65407D1FC9361C8CF8C47162A2E20250800000000000000502A000034"
- + "201915C9E4E9173AA9EE79F3E02FE2D4954B22085C66D164762C34D347C16E9F"
- + "FC5F7F114428C54D8D915860C57B1BC1";
- final long newIkeDeterministicInitSpi = Long.parseLong("7D3DEDC65407D1FC", 16);
-
- // Open IKE Session
- IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress);
- PortPair localRemotePorts = performSetupIkeAndFirstChildBlocking(ikeInitResp, ikeAuthResp);
-
- // Local request message ID starts from 2 because there is one IKE_INIT message and a single
- // IKE_AUTH message.
- int expectedReqMsgId = 2;
- int expectedRespMsgId = 0;
-
- verifyIkeSessionSetupBlocking();
- verifyChildSessionSetupBlocking(
- mFirstChildSessionCallback,
- Arrays.asList(TRANSPORT_MODE_INBOUND_TS),
- Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS),
- new ArrayList<LinkAddress>());
- IpSecTransformCallRecord firstTransformRecordA =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- IpSecTransformCallRecord firstTransformRecordB =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
-
- // Inject rekey IKE requests
- mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyIkeCreateReq));
- mTunUtils.awaitResp(
- IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */);
- mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyIkeDeleteReq));
- mTunUtils.awaitResp(
- IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */);
-
- // IKE has been rekeyed, reset message IDs
- expectedReqMsgId = 0;
- expectedRespMsgId = 0;
-
- // Inject delete IKE request
- mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, deleteIkeReq));
- mTunUtils.awaitResp(
- newIkeDeterministicInitSpi, expectedRespMsgId++, true /* expectedUseEncap */);
-
- verifyDeleteIpSecTransformPair(
- mFirstChildSessionCallback, firstTransformRecordA, firstTransformRecordB);
- mFirstChildSessionCallback.awaitOnClosed();
- mIkeSessionCallback.awaitOnClosed();
- }
-
- @Test
- public void testRekeyTransportModeChildSa() throws Exception {
- final String ikeInitResp =
- "46B8ECA1E0D72A18CECD871146CF83A121202220000000000000015022000030"
- + "0000002C010100040300000C0100000C800E0100030000080300000C03000008"
- + "0200000500000008040000022800008800020000C4904458957746BCF1C12972"
- + "1D4E19EB8A584F78DE673053396D167CE0F34552DBC69BA63FE7C673B4CF4A99"
- + "62481518EE985357876E8C47BAAA0DBE9C40AE47B12E52165874703586E8F786"
- + "045F72EEEB238C5D1823352BED44B71B3214609276ADC0B3D42DAC820168C4E2"
- + "660730DAAC92492403288805EBB9053F1AB060DA290000242D9364ACB93519FF"
- + "8F8B019BAA43A40D699F59714B327B8382216EF427ED52282900001C00004004"
- + "06D91438A0D6B734E152F76F5CC55A72A2E38A0A2900001C000040052EFF78B3"
- + "55B37F3CE75AFF26C721B050F892C0D6290000080000402E290000100000402F"
- + "00020003000400050000000800004014";
- final String ikeAuthResp =
- "46B8ECA1E0D72A18CECD871146CF83A12E20232000000001000000F0240000D4"
- + "A17BC258BA2714CF536663639DD5F665A60C75E93557CD5141990A8CEEDD2017"
- + "93F5B181C8569FBCD6C2A00198EC2B62D42BEFAC016B8B6BF6A7BC9CEDE3413A"
- + "6C495A6B8EC941864DC3E08F57D015EA6520C4B05884960B85478FCA53DA5F17"
- + "9628BB1097DA77461C71837207A9EB80720B3E6E661816EE4E14AC995B5E8441"
- + "A4C3F9097CC148142BA300076C94A23EC4ADE82B1DD2B121F7E9102860A8C3BF"
- + "58DDC207285A3176E924C44DE820322524E1AA438EFDFBA781B36084AED80846"
- + "3B77FCED9682B6E4E476408EF3F1037E";
- final String rekeyChildCreateReq =
- "46B8ECA1E0D72A18CECD871146CF83A12E202400000000000000015029000134"
- + "319D74B6B155B86942143CEC1D29D21F073F24B7BEDC9BFE0F0FDD8BDB5458C0"
- + "8DB93506E1A43DD0640FE7370C97F9B34FF4EC9B2DB7257A87B75632301FB68A"
- + "86B54871249534CA3D01C9BEB127B669F46470E1C8AAF72574C3CEEC15B901CF"
- + "5A0D6ADAE59C3CA64AC8C86689C860FAF9500E608DFE63F2DCD30510FD6FFCD5"
- + "A50838574132FD1D069BCACD4C7BAF45C9B1A7689FAD132E3F56DBCFAF905A8C"
- + "4145D4BA1B74A54762F8F43308D94DE05649C49D885121CE30681D51AC1E3E68"
- + "AB82F9A19B99579AFE257F32DBD1037814DA577379E4F42DEDAC84502E49C933"
- + "9EA83F6F5DB4401B660CB1681B023B8603D205DFDD1DE86AD8DE22B6B754F30D"
- + "05EAE81A709C2CEE81386133DC3DC7B5EF8F166E48E54A0722DD0C64F4D00638"
- + "40F272144C47F6ECED72A248180645DB";
- final String rekeyChildDeleteReq =
- "46B8ECA1E0D72A18CECD871146CF83A12E20250000000001000000502A000034"
- + "02D98DAF0432EBD991CA4F2D89C1E0EFABC6E91A3327A85D8914FB2F1485BE1B"
- + "8D3415D548F7CE0DC4224E7E9D0D3355";
- final String deleteIkeReq =
- "46B8ECA1E0D72A18CECD871146CF83A12E20250000000002000000502A000034"
- + "095041F4026B4634F04B0AB4F9349484F7BE9AEF03E3733EEE293330043B75D2"
- + "ABF5F965ED51127629585E1B1BBA787F";
-
- // Open IKE Session
- IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress);
- PortPair localRemotePorts = performSetupIkeAndFirstChildBlocking(ikeInitResp, ikeAuthResp);
-
- // IKE INIT and IKE AUTH takes two exchanges. Local request message ID starts from 2
- int expectedReqMsgId = 2;
- int expectedRespMsgId = 0;
-
- verifyIkeSessionSetupBlocking();
- verifyChildSessionSetupBlocking(
- mFirstChildSessionCallback,
- Arrays.asList(TRANSPORT_MODE_INBOUND_TS),
- Arrays.asList(TRANSPORT_MODE_OUTBOUND_TS),
- new ArrayList<LinkAddress>());
- IpSecTransformCallRecord oldTransformRecordA =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- IpSecTransformCallRecord oldTransformRecordB =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- verifyCreateIpSecTransformPair(oldTransformRecordA, oldTransformRecordB);
-
- // Inject rekey Child requests
- mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyChildCreateReq));
- mTunUtils.awaitResp(
- IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */);
- mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, rekeyChildDeleteReq));
- mTunUtils.awaitResp(
- IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */);
-
- // Verify IpSecTransforms are renewed
- IpSecTransformCallRecord newTransformRecordA =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- IpSecTransformCallRecord newTransformRecordB =
- mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
- verifyCreateIpSecTransformPair(newTransformRecordA, newTransformRecordB);
- verifyDeleteIpSecTransformPair(
- mFirstChildSessionCallback, oldTransformRecordA, oldTransformRecordB);
-
- // Inject delete IKE request
- mTunUtils.injectPacket(buildInboundPkt(localRemotePorts, deleteIkeReq));
- mTunUtils.awaitResp(
- IKE_DETERMINISTIC_INITIATOR_SPI, expectedRespMsgId++, true /* expectedUseEncap */);
-
- verifyDeleteIpSecTransformPair(
- mFirstChildSessionCallback, newTransformRecordA, newTransformRecordB);
- mFirstChildSessionCallback.awaitOnClosed();
- mIkeSessionCallback.awaitOnClosed();
- }
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java
deleted file mode 100644
index a81063b..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipsec.ike.cts;
-
-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;
-import android.net.TestNetworkInterface;
-import android.net.TestNetworkManager;
-import android.net.annotations.PolicyDirection;
-import android.net.ipsec.ike.ChildSessionCallback;
-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.TransportModeChildSessionParams;
-import android.net.ipsec.ike.TunnelModeChildSessionParams;
-import android.net.ipsec.ike.cts.IkeTunUtils.PortPair;
-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 androidx.test.InstrumentationRegistry;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.compatibility.common.util.SystemUtil;
-import com.android.testutils.ArrayTrackRecord;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-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;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Package private base class for testing IkeSessionParams and IKE exchanges.
- *
- * <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")
-abstract class IkeSessionTestBase extends IkeTestBase {
- // Package-wide common expected results that will be shared by all IKE/Child SA creation tests
- static final String EXPECTED_REMOTE_APP_VERSION_EMPTY = "";
- static final byte[] EXPECTED_PROTOCOL_ERROR_DATA_NONE = new byte[0];
-
- static final InetAddress EXPECTED_DNS_SERVERS_ONE =
- InetAddresses.parseNumericAddress("8.8.8.8");
- static final InetAddress EXPECTED_DNS_SERVERS_TWO =
- InetAddresses.parseNumericAddress("8.8.4.4");
-
- static final InetAddress EXPECTED_INTERNAL_ADDR =
- InetAddresses.parseNumericAddress("198.51.100.10");
- static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR =
- new LinkAddress(EXPECTED_INTERNAL_ADDR, IP4_PREFIX_LEN);
- static final InetAddress EXPECTED_INTERNAL_ADDR_V6 =
- InetAddresses.parseNumericAddress("2001:db8::2");
- static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR_V6 =
- new LinkAddress(EXPECTED_INTERNAL_ADDR_V6, IP6_PREFIX_LEN);
-
- 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 IkeTrafficSelector TUNNEL_MODE_INBOUND_TS_V6 =
- new IkeTrafficSelector(
- MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR_V6, EXPECTED_INTERNAL_ADDR_V6);
- static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS_V6 = DEFAULT_V6_TS;
-
- // This value is align with the test vectors hex that are generated in an IPv4 environment
- static final IkeTrafficSelector TRANSPORT_MODE_OUTBOUND_TS =
- new IkeTrafficSelector(
- MIN_PORT,
- MAX_PORT,
- InetAddresses.parseNumericAddress("10.138.0.2"),
- InetAddresses.parseNumericAddress("10.138.0.2"));
-
- static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16);
-
- // Static state to reduce setup/teardown
- static Context sContext = InstrumentationRegistry.getContext();
- static ConnectivityManager sCM =
- (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- static TestNetworkManager sTNM;
-
- private static final int TIMEOUT_MS = 500;
-
- // Constants to be used for providing different IP addresses for each tests
- private static final byte IP_ADDR_LAST_BYTE_MAX = (byte) 100;
- private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_LOCAL =
- InetAddresses.parseNumericAddress("192.0.2.1").getAddress();
- private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_REMOTE =
- InetAddresses.parseNumericAddress("198.51.100.1").getAddress();
- private static final byte[] NEXT_AVAILABLE_IP4_ADDR_LOCAL = INITIAL_AVAILABLE_IP4_ADDR_LOCAL;
- private static final byte[] NEXT_AVAILABLE_IP4_ADDR_REMOTE = INITIAL_AVAILABLE_IP4_ADDR_REMOTE;
-
- ParcelFileDescriptor mTunFd;
- TestNetworkCallback mTunNetworkCallback;
- Network mTunNetwork;
- IkeTunUtils mTunUtils;
-
- InetAddress mLocalAddress;
- InetAddress mRemoteAddress;
-
- Executor mUserCbExecutor;
- TestIkeSessionCallback mIkeSessionCallback;
- TestChildSessionCallback mFirstChildSessionCallback;
-
- // This method is guaranteed to run in subclasses and will run before subclasses' @BeforeClass
- // methods.
- @BeforeClass
- public static void setUpPermissionBeforeClass() throws Exception {
- InstrumentationRegistry.getInstrumentation()
- .getUiAutomation()
- .adoptShellPermissionIdentity();
- sTNM = sContext.getSystemService(TestNetworkManager.class);
- }
-
- // This method is guaranteed to run in subclasses and will run after subclasses' @AfterClass
- // methods.
- @AfterClass
- public static void tearDownPermissionAfterClass() throws Exception {
- InstrumentationRegistry.getInstrumentation()
- .getUiAutomation()
- .dropShellPermissionIdentity();
- }
-
- @Before
- public void setUp() throws Exception {
- mLocalAddress = getNextAvailableIpv4AddressLocal();
- mRemoteAddress = getNextAvailableIpv4AddressRemote();
- setUpTestNetwork(mLocalAddress);
-
- mUserCbExecutor = Executors.newSingleThreadExecutor();
- mIkeSessionCallback = new TestIkeSessionCallback();
- mFirstChildSessionCallback = new TestChildSessionCallback();
- }
-
- @After
- public void tearDown() throws Exception {
- tearDownTestNetwork();
- }
-
- void setUpTestNetwork(InetAddress localAddr) throws Exception {
- int prefixLen = localAddr instanceof Inet4Address ? IP4_PREFIX_LEN : IP6_PREFIX_LEN;
-
- TestNetworkInterface testIface =
- sTNM.createTunInterface(new LinkAddress[] {new LinkAddress(localAddr, prefixLen)});
-
- mTunFd = testIface.getFileDescriptor();
- mTunNetworkCallback =
- TestNetworkUtils.setupAndGetTestNetwork(
- sCM, sTNM, testIface.getInterfaceName(), new Binder());
- mTunNetwork = mTunNetworkCallback.getNetworkBlocking();
- mTunUtils = new IkeTunUtils(mTunFd);
- }
-
- void tearDownTestNetwork() throws Exception {
- sCM.unregisterNetworkCallback(mTunNetworkCallback);
-
- sTNM.teardownTestNetwork(mTunNetwork);
- mTunFd.close();
- }
-
- static void setAppOp(int appop, boolean allow) {
- String opName = AppOpsManager.opToName(appop);
- for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) {
- String cmd =
- String.format(
- "appops set %s %s %s",
- pkg, // Package name
- opName, // Appop
- (allow ? "allow" : "deny")); // Action
-
- SystemUtil.runShellCommand(cmd);
- }
- }
-
- Inet4Address getNextAvailableIpv4AddressLocal() throws Exception {
- return (Inet4Address)
- getNextAvailableAddress(
- NEXT_AVAILABLE_IP4_ADDR_LOCAL,
- INITIAL_AVAILABLE_IP4_ADDR_LOCAL,
- false /* isIp6 */);
- }
-
- Inet4Address getNextAvailableIpv4AddressRemote() throws Exception {
- return (Inet4Address)
- getNextAvailableAddress(
- NEXT_AVAILABLE_IP4_ADDR_REMOTE,
- INITIAL_AVAILABLE_IP4_ADDR_REMOTE,
- false /* isIp6 */);
- }
-
- InetAddress getNextAvailableAddress(
- byte[] nextAddressBytes, byte[] initialAddressBytes, boolean isIp6) throws Exception {
- int addressLen = isIp6 ? IP6_ADDRESS_LEN : IP4_ADDRESS_LEN;
-
- synchronized (nextAddressBytes) {
- if (nextAddressBytes[addressLen - 1] == IP_ADDR_LAST_BYTE_MAX) {
- resetNextAvailableAddress(nextAddressBytes, initialAddressBytes);
- }
-
- InetAddress address = InetAddress.getByAddress(nextAddressBytes);
- nextAddressBytes[addressLen - 1]++;
- return address;
- }
- }
-
- private void resetNextAvailableAddress(byte[] nextAddressBytes, byte[] initialAddressBytes) {
- synchronized (nextAddressBytes) {
- System.arraycopy(
- nextAddressBytes, 0, initialAddressBytes, 0, initialAddressBytes.length);
- }
- }
-
- TransportModeChildSessionParams buildTransportModeChildParamsWithTs(
- IkeTrafficSelector inboundTs, IkeTrafficSelector outboundTs) {
- return new TransportModeChildSessionParams.Builder()
- .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher())
- .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher())
- .addInboundTrafficSelectors(inboundTs)
- .addOutboundTrafficSelectors(outboundTs)
- .build();
- }
-
- TransportModeChildSessionParams buildTransportModeChildParamsWithDefaultTs() {
- return new TransportModeChildSessionParams.Builder()
- .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher())
- .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher())
- .build();
- }
-
- TunnelModeChildSessionParams buildTunnelModeChildSessionParams() {
- return new TunnelModeChildSessionParams.Builder()
- .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher())
- .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher())
- .addInternalAddressRequest(AF_INET)
- .addInternalAddressRequest(AF_INET6)
- .build();
- }
-
- PortPair performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes)
- throws Exception {
- return performSetupIkeAndFirstChildBlocking(
- ikeInitRespHex,
- 1 /* expectedAuthReqPktCnt */,
- true /*expectedAuthUseEncap*/,
- ikeAuthRespHexes);
- }
-
- PortPair performSetupIkeAndFirstChildBlocking(
- String ikeInitRespHex, boolean expectedAuthUseEncap, String... ikeAuthRespHexes)
- throws Exception {
- return performSetupIkeAndFirstChildBlocking(
- ikeInitRespHex,
- 1 /* expectedAuthReqPktCnt */,
- expectedAuthUseEncap,
- ikeAuthRespHexes);
- }
-
- PortPair performSetupIkeAndFirstChildBlocking(
- String ikeInitRespHex,
- int expectedAuthReqPktCnt,
- boolean expectedAuthUseEncap,
- String... ikeAuthRespHexes)
- throws Exception {
- mTunUtils.awaitReqAndInjectResp(
- IKE_DETERMINISTIC_INITIATOR_SPI,
- 0 /* expectedMsgId */,
- false /* expectedUseEncap */,
- ikeInitRespHex);
-
- byte[] ikeAuthReqPkt =
- mTunUtils
- .awaitReqAndInjectResp(
- IKE_DETERMINISTIC_INITIATOR_SPI,
- 1 /* expectedMsgId */,
- expectedAuthUseEncap,
- expectedAuthReqPktCnt,
- ikeAuthRespHexes)
- .get(0);
- return IkeTunUtils.getSrcDestPortPair(ikeAuthReqPkt);
- }
-
- void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception {
- performCloseIkeBlocking(expectedMsgId, true /* expectedUseEncap*/, deleteIkeRespHex);
- }
-
- void performCloseIkeBlocking(
- int expectedMsgId, boolean expectedUseEncap, String deleteIkeRespHex) throws Exception {
- mTunUtils.awaitReqAndInjectResp(
- IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId, 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<>();
- private CompletableFuture<Boolean> mFutureOnClosedCall = new CompletableFuture<>();
- private CompletableFuture<IkeException> mFutureOnClosedException =
- new CompletableFuture<>();
-
- private int mOnErrorExceptionsCount = 0;
- private ArrayTrackRecord<IkeProtocolException> mOnErrorExceptionsTrackRecord =
- new ArrayTrackRecord<>();
-
- @Override
- public void onOpened(@NonNull IkeSessionConfiguration sessionConfiguration) {
- mFutureIkeConfig.complete(sessionConfiguration);
- }
-
- @Override
- public void onClosed() {
- mFutureOnClosedCall.complete(true /* unused */);
- }
-
- @Override
- public void onClosedExceptionally(@NonNull IkeException exception) {
- mFutureOnClosedException.complete(exception);
- }
-
- @Override
- public void onError(@NonNull IkeProtocolException exception) {
- mOnErrorExceptionsTrackRecord.add(exception);
- }
-
- public IkeSessionConfiguration awaitIkeConfig() throws Exception {
- return mFutureIkeConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- }
-
- public IkeException awaitOnClosedException() throws Exception {
- return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- }
-
- public IkeProtocolException awaitNextOnErrorException() {
- return mOnErrorExceptionsTrackRecord.poll(
- (long) TIMEOUT_MS,
- mOnErrorExceptionsCount++,
- (transform) -> {
- return true;
- });
- }
-
- public void awaitOnClosed() throws Exception {
- mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- }
- }
-
- /** 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<>();
- private CompletableFuture<Boolean> mFutureOnClosedCall = new CompletableFuture<>();
- private CompletableFuture<IkeException> mFutureOnClosedException =
- new CompletableFuture<>();
-
- private int mCreatedIpSecTransformCount = 0;
- private int mDeletedIpSecTransformCount = 0;
- private ArrayTrackRecord<IpSecTransformCallRecord> mCreatedIpSecTransformsTrackRecord =
- new ArrayTrackRecord<>();
- private ArrayTrackRecord<IpSecTransformCallRecord> mDeletedIpSecTransformsTrackRecord =
- new ArrayTrackRecord<>();
-
- @Override
- public void onOpened(@NonNull ChildSessionConfiguration sessionConfiguration) {
- mFutureChildConfig.complete(sessionConfiguration);
- }
-
- @Override
- public void onClosed() {
- mFutureOnClosedCall.complete(true /* unused */);
- }
-
- @Override
- public void onClosedExceptionally(@NonNull IkeException exception) {
- mFutureOnClosedException.complete(exception);
- }
-
- @Override
- public void onIpSecTransformCreated(@NonNull IpSecTransform ipSecTransform, int direction) {
- mCreatedIpSecTransformsTrackRecord.add(
- new IpSecTransformCallRecord(ipSecTransform, direction));
- }
-
- @Override
- public void onIpSecTransformDeleted(@NonNull IpSecTransform ipSecTransform, int direction) {
- mDeletedIpSecTransformsTrackRecord.add(
- new IpSecTransformCallRecord(ipSecTransform, direction));
- }
-
- public ChildSessionConfiguration awaitChildConfig() throws Exception {
- return mFutureChildConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- }
-
- public IkeException awaitOnClosedException() throws Exception {
- return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- }
-
- public IpSecTransformCallRecord awaitNextCreatedIpSecTransform() {
- return mCreatedIpSecTransformsTrackRecord.poll(
- (long) TIMEOUT_MS,
- mCreatedIpSecTransformCount++,
- (transform) -> {
- return true;
- });
- }
-
- public IpSecTransformCallRecord awaitNextDeletedIpSecTransform() {
- return mDeletedIpSecTransformsTrackRecord.poll(
- (long) TIMEOUT_MS,
- mDeletedIpSecTransformCount++,
- (transform) -> {
- return true;
- });
- }
-
- public void awaitOnClosed() throws Exception {
- mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- }
- }
-
- /**
- * This class represents a created or deleted IpSecTransfrom that is provided by
- * ChildSessionCallback
- */
- static class IpSecTransformCallRecord {
- public final IpSecTransform ipSecTransform;
- public final int direction;
-
- IpSecTransformCallRecord(IpSecTransform ipSecTransform, @PolicyDirection int direction) {
- 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 {
- verifyChildSessionSetupBlocking(
- childCallback,
- expectedInboundTs,
- expectedOutboundTs,
- expectedInternalAddresses,
- new ArrayList<InetAddress>() /* expectedDnsServers */);
- }
-
- void verifyChildSessionSetupBlocking(
- TestChildSessionCallback childCallback,
- List<IkeTrafficSelector> expectedInboundTs,
- List<IkeTrafficSelector> expectedOutboundTs,
- List<LinkAddress> expectedInternalAddresses,
- List<InetAddress> expectedDnsServers)
- throws Exception {
- ChildSessionConfiguration childConfig = childCallback.awaitChildConfig();
- assertNotNull(childConfig);
- assertEquals(expectedInboundTs, childConfig.getInboundTrafficSelectors());
- assertEquals(expectedOutboundTs, childConfig.getOutboundTrafficSelectors());
- assertEquals(expectedInternalAddresses, childConfig.getInternalAddresses());
- assertEquals(expectedDnsServers, childConfig.getInternalDnsServers());
- assertTrue(childConfig.getInternalSubnets().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 hostname based creation
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java
deleted file mode 100644
index c70e537..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeTestBase.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipsec.ike.cts;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.net.InetAddresses;
-import android.net.ipsec.ike.IkeTrafficSelector;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/** Shared parameters and util methods for testing different components of IKE */
-abstract class IkeTestBase {
- static final int MIN_PORT = 0;
- static final int MAX_PORT = 65535;
- private static final int INBOUND_TS_START_PORT = MIN_PORT;
- private static final int INBOUND_TS_END_PORT = 65520;
- private static final int OUTBOUND_TS_START_PORT = 16;
- private static final int OUTBOUND_TS_END_PORT = MAX_PORT;
-
- static final int IP4_ADDRESS_LEN = 4;
- static final int IP6_ADDRESS_LEN = 16;
- static final int IP4_PREFIX_LEN = 32;
- static final int IP6_PREFIX_LEN = 64;
-
- static final byte[] IKE_PSK = "ikeAndroidPsk".getBytes();
-
- static final String LOCAL_HOSTNAME = "client.test.ike.android.net";
- static final String REMOTE_HOSTNAME = "server.test.ike.android.net";
- static final String LOCAL_ASN1_DN_STRING = "CN=client.test.ike.android.net, O=Android, C=US";
- static final String LOCAL_RFC822_NAME = "client.test.ike@example.com";
- static final byte[] LOCAL_KEY_ID = "Local Key ID".getBytes();
-
- static final int SUB_ID = 1;
- static final byte[] EAP_IDENTITY = "test@android.net".getBytes();
- static final String NETWORK_NAME = "android.net";
- static final String EAP_MSCHAPV2_USERNAME = "mschapv2user";
- static final String EAP_MSCHAPV2_PASSWORD = "password";
-
- static final Inet4Address IPV4_ADDRESS_LOCAL =
- (Inet4Address) (InetAddresses.parseNumericAddress("192.0.2.100"));
- static final Inet4Address IPV4_ADDRESS_REMOTE =
- (Inet4Address) (InetAddresses.parseNumericAddress("198.51.100.100"));
- static final Inet6Address IPV6_ADDRESS_LOCAL =
- (Inet6Address) (InetAddresses.parseNumericAddress("2001:db8::100"));
- static final Inet6Address IPV6_ADDRESS_REMOTE =
- (Inet6Address) (InetAddresses.parseNumericAddress("2001:db8:255::100"));
-
- static final InetAddress PCSCF_IPV4_ADDRESS_1 = InetAddresses.parseNumericAddress("192.0.2.1");
- static final InetAddress PCSCF_IPV4_ADDRESS_2 = InetAddresses.parseNumericAddress("192.0.2.2");
- static final InetAddress PCSCF_IPV6_ADDRESS_1 =
- InetAddresses.parseNumericAddress("2001:DB8::1");
- static final InetAddress PCSCF_IPV6_ADDRESS_2 =
- InetAddresses.parseNumericAddress("2001:DB8::2");
-
- static final IkeTrafficSelector DEFAULT_V4_TS =
- new IkeTrafficSelector(
- MIN_PORT,
- MAX_PORT,
- InetAddresses.parseNumericAddress("0.0.0.0"),
- InetAddresses.parseNumericAddress("255.255.255.255"));
- static final IkeTrafficSelector DEFAULT_V6_TS =
- new IkeTrafficSelector(
- MIN_PORT,
- MAX_PORT,
- InetAddresses.parseNumericAddress("::"),
- InetAddresses.parseNumericAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
- static final IkeTrafficSelector INBOUND_V4_TS =
- new IkeTrafficSelector(
- INBOUND_TS_START_PORT,
- INBOUND_TS_END_PORT,
- InetAddresses.parseNumericAddress("192.0.2.10"),
- InetAddresses.parseNumericAddress("192.0.2.20"));
- static final IkeTrafficSelector OUTBOUND_V4_TS =
- new IkeTrafficSelector(
- OUTBOUND_TS_START_PORT,
- OUTBOUND_TS_END_PORT,
- InetAddresses.parseNumericAddress("198.51.100.0"),
- InetAddresses.parseNumericAddress("198.51.100.255"));
-
- static final IkeTrafficSelector INBOUND_V6_TS =
- new IkeTrafficSelector(
- INBOUND_TS_START_PORT,
- INBOUND_TS_END_PORT,
- InetAddresses.parseNumericAddress("2001:db8::10"),
- InetAddresses.parseNumericAddress("2001:db8::128"));
- static final IkeTrafficSelector OUTBOUND_V6_TS =
- new IkeTrafficSelector(
- OUTBOUND_TS_START_PORT,
- OUTBOUND_TS_END_PORT,
- InetAddresses.parseNumericAddress("2001:db8:255::64"),
- InetAddresses.parseNumericAddress("2001:db8:255::255"));
-
- // Verify Config requests in TunnelModeChildSessionParams and IkeSessionParams
- <T> void verifyConfigRequestTypes(
- Map<Class<? extends T>, Integer> expectedReqCntMap, List<? extends T> resultReqList) {
- Map<Class<? extends T>, Integer> resultReqCntMap = new HashMap<>();
-
- // Verify that every config request type in resultReqList is expected, and build
- // resultReqCntMap at the same time
- for (T resultReq : resultReqList) {
- boolean isResultReqExpected = false;
-
- for (Class<? extends T> expectedReqInterface : expectedReqCntMap.keySet()) {
- if (expectedReqInterface.isInstance(resultReq)) {
- isResultReqExpected = true;
-
- resultReqCntMap.put(
- expectedReqInterface,
- resultReqCntMap.getOrDefault(expectedReqInterface, 0) + 1);
- }
- }
-
- if (!isResultReqExpected) {
- fail("Failed due to unexpected config request " + resultReq);
- }
- }
-
- assertEquals(expectedReqCntMap, resultReqCntMap);
-
- // TODO: Think of a neat way to validate both counts and values in this method. Probably can
- // build Runnables as validators for count and values.
- }
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java
deleted file mode 100644
index 41cbf0b..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.ipsec.ike.cts;
-
-import static android.net.ipsec.ike.cts.PacketUtils.BytePayload;
-import static android.net.ipsec.ike.cts.PacketUtils.IP4_HDRLEN;
-import static android.net.ipsec.ike.cts.PacketUtils.IP6_HDRLEN;
-import static android.net.ipsec.ike.cts.PacketUtils.Ip4Header;
-import static android.net.ipsec.ike.cts.PacketUtils.Ip6Header;
-import static android.net.ipsec.ike.cts.PacketUtils.IpHeader;
-import static android.net.ipsec.ike.cts.PacketUtils.Payload;
-import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN;
-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;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.Predicate;
-
-public class IkeTunUtils extends TunUtils {
- private static final int PORT_LEN = 2;
-
- private static final int NON_ESP_MARKER_LEN = 4;
- private static final byte[] NON_ESP_MARKER = new byte[NON_ESP_MARKER_LEN];
-
- private static final int IKE_INIT_SPI_OFFSET = 0;
- private static final int IKE_FIRST_PAYLOAD_OFFSET = 16;
- private static final int IKE_IS_RESP_BYTE_OFFSET = 19;
- private static final int IKE_MSG_ID_OFFSET = 20;
- private static final int IKE_HEADER_LEN = 28;
- private static final int IKE_FRAG_NUM_OFFSET = 32;
- private static final int IKE_PAYLOAD_TYPE_SKF = 53;
-
- private static final int RSP_FLAG_MASK = 0x20;
-
- public IkeTunUtils(ParcelFileDescriptor tunFd) {
- super(tunFd);
- }
-
- /**
- * Await the expected IKE request inject an IKE response (or a list of response fragments)
- *
- * @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without
- * IP/UDP headers or NON ESP MARKER.
- */
- public byte[] awaitReqAndInjectResp(
- long expectedInitIkeSpi,
- int expectedMsgId,
- boolean expectedUseEncap,
- String... ikeRespDataFragmentsHex)
- throws Exception {
- return awaitReqAndInjectResp(
- expectedInitIkeSpi,
- expectedMsgId,
- expectedUseEncap,
- 1 /* expectedReqPktCnt */,
- ikeRespDataFragmentsHex)
- .get(0);
- }
-
- /**
- * Await the expected IKE request (or the list of IKE request fragments) and inject an IKE
- * response (or a list of response fragments)
- *
- * @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without
- * IP/UDP headers or NON ESP MARKER.
- */
- public List<byte[]> awaitReqAndInjectResp(
- long expectedInitIkeSpi,
- int expectedMsgId,
- boolean expectedUseEncap,
- int expectedReqPktCnt,
- String... ikeRespDataFragmentsHex)
- throws Exception {
- List<byte[]> reqList = new ArrayList<>(expectedReqPktCnt);
- if (expectedReqPktCnt == 1) {
- // Expecting one complete IKE packet
- byte[] req =
- awaitIkePacket(
- (pkt) -> {
- return isExpectedIkePkt(
- pkt,
- expectedInitIkeSpi,
- expectedMsgId,
- false /* expectedResp */,
- expectedUseEncap);
- });
- reqList.add(req);
- } else {
- // Expecting "expectedReqPktCnt" number of request fragments
- for (int i = 0; i < expectedReqPktCnt; i++) {
- // IKE Fragment number always starts from 1
- int expectedFragNum = i + 1;
- byte[] req =
- awaitIkePacket(
- (pkt) -> {
- return isExpectedIkeFragPkt(
- pkt,
- expectedInitIkeSpi,
- expectedMsgId,
- false /* expectedResp */,
- expectedUseEncap,
- expectedFragNum);
- });
- reqList.add(req);
- }
- }
-
- // All request fragments have the same addresses and ports
- byte[] request = reqList.get(0);
-
- // Build response header by flipping address and port
- InetAddress srcAddr = getAddress(request, false /* shouldGetSource */);
- InetAddress dstAddr = getAddress(request, true /* shouldGetSource */);
- int srcPort = getPort(request, false /* shouldGetSource */);
- int dstPort = getPort(request, true /* shouldGetSource */);
- for (String resp : ikeRespDataFragmentsHex) {
- byte[] response =
- buildIkePacket(
- srcAddr,
- dstAddr,
- srcPort,
- dstPort,
- expectedUseEncap,
- hexStringToByteArray(resp));
- injectPacket(response);
- }
-
- return reqList;
- }
-
- /** Await the expected IKE response */
- public byte[] awaitResp(long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap)
- throws Exception {
- return awaitIkePacket(
- (pkt) -> {
- return isExpectedIkePkt(
- pkt,
- expectedInitIkeSpi,
- expectedMsgId,
- true /* expectedResp*/,
- expectedUseEncap);
- });
- }
-
- 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(pktVerifier, startIndex);
- if (ikePkt != null) {
- return ikePkt; // We've found the packet we're looking for.
- }
-
- startIndex = mPackets.size();
-
- // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout
- long waitTimeout = endTime - System.currentTimeMillis();
- if (waitTimeout > 0) {
- mPackets.wait(waitTimeout);
- }
- }
-
- fail("No matching packet found");
- }
-
- throw new IllegalStateException(
- "Hit an impossible case where fail() didn't throw an exception");
- }
-
- private static boolean isExpectedIkePkt(
- byte[] pkt,
- long expectedInitIkeSpi,
- int expectedMsgId,
- boolean expectedResp,
- boolean expectedUseEncap) {
- int ipProtocolOffset = isIpv6(pkt) ? IP6_PROTO_OFFSET : IP4_PROTO_OFFSET;
- int ikeOffset = getIkeOffset(pkt, expectedUseEncap);
-
- return pkt[ipProtocolOffset] == IPPROTO_UDP
- && expectedUseEncap == hasNonEspMarker(pkt)
- && isExpectedSpiAndMsgId(
- pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp);
- }
-
- private static boolean isExpectedIkeFragPkt(
- byte[] pkt,
- long expectedInitIkeSpi,
- int expectedMsgId,
- boolean expectedResp,
- boolean expectedUseEncap,
- int expectedFragNum) {
- return isExpectedIkePkt(
- pkt, expectedInitIkeSpi, expectedMsgId, expectedResp, expectedUseEncap)
- && isExpectedFragNum(pkt, getIkeOffset(pkt, expectedUseEncap), expectedFragNum);
- }
-
- private static int getIkeOffset(byte[] pkt, boolean useEncap) {
- if (isIpv6(pkt)) {
- // IPv6 UDP expectedUseEncap not supported by kernels; assume non-expectedUseEncap.
- return IP6_HDRLEN + UDP_HDRLEN;
- } else {
- // Use default IPv4 header length (assuming no options)
- int ikeOffset = IP4_HDRLEN + UDP_HDRLEN;
- return useEncap ? ikeOffset + NON_ESP_MARKER_LEN : ikeOffset;
- }
- }
-
- private static boolean hasNonEspMarker(byte[] pkt) {
- ByteBuffer buffer = ByteBuffer.wrap(pkt);
- int ikeOffset = IP4_HDRLEN + UDP_HDRLEN;
- if (buffer.remaining() < ikeOffset) return false;
-
- buffer.get(new byte[ikeOffset]); // Skip IP and UDP header
- byte[] nonEspMarker = new byte[NON_ESP_MARKER_LEN];
- if (buffer.remaining() < NON_ESP_MARKER_LEN) return false;
-
- buffer.get(nonEspMarker);
- return Arrays.equals(NON_ESP_MARKER, nonEspMarker);
- }
-
- private static boolean isExpectedSpiAndMsgId(
- byte[] pkt,
- int ikeOffset,
- long expectedInitIkeSpi,
- int expectedMsgId,
- boolean expectedResp) {
- if (pkt.length <= ikeOffset + IKE_HEADER_LEN) return false;
-
- ByteBuffer buffer = ByteBuffer.wrap(pkt);
- buffer.get(new byte[ikeOffset]); // Skip IP, UDP header (and NON_ESP_MARKER)
- buffer.mark(); // Mark this position so that later we can reset back here
-
- // Check SPI
- buffer.get(new byte[IKE_INIT_SPI_OFFSET]);
- long initSpi = buffer.getLong();
- if (expectedInitIkeSpi != initSpi) {
- return false;
- }
-
- // Check direction
- buffer.reset();
- buffer.get(new byte[IKE_IS_RESP_BYTE_OFFSET]);
- byte flagsByte = buffer.get();
- boolean isResp = ((flagsByte & RSP_FLAG_MASK) != 0);
- if (expectedResp != isResp) {
- return false;
- }
-
- // Check message ID
- buffer.reset();
- buffer.get(new byte[IKE_MSG_ID_OFFSET]);
-
- // Both the expected message ID and the packet's msgId are signed integers, so directly
- // compare them.
- int msgId = buffer.getInt();
- if (expectedMsgId != msgId) {
- return false;
- }
-
- return true;
- }
-
- private static boolean isExpectedFragNum(byte[] pkt, int ikeOffset, int expectedFragNum) {
- ByteBuffer buffer = ByteBuffer.wrap(pkt);
- buffer.get(new byte[ikeOffset]);
- buffer.mark(); // Mark this position so that later we can reset back here
-
- // Check if it is a fragment packet
- buffer.get(new byte[IKE_FIRST_PAYLOAD_OFFSET]);
- int firstPayload = Byte.toUnsignedInt(buffer.get());
- if (firstPayload != IKE_PAYLOAD_TYPE_SKF) {
- return false;
- }
-
- // Check fragment number
- buffer.reset();
- buffer.get(new byte[IKE_FRAG_NUM_OFFSET]);
- int fragNum = Short.toUnsignedInt(buffer.getShort());
- return expectedFragNum == fragNum;
- }
-
- public static class PortPair {
- public final int srcPort;
- public final int dstPort;
-
- public PortPair(int sourcePort, int destinationPort) {
- srcPort = sourcePort;
- dstPort = destinationPort;
- }
- }
-
- public static PortPair getSrcDestPortPair(byte[] outboundIkePkt) throws Exception {
- return new PortPair(
- getPort(outboundIkePkt, true /* shouldGetSource */),
- getPort(outboundIkePkt, false /* shouldGetSource */));
- }
-
- private static InetAddress getAddress(byte[] pkt, boolean shouldGetSource) throws Exception {
- int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN;
- int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET;
- int ipOffset = shouldGetSource ? srcIpOffset : srcIpOffset + ipLen;
-
- ByteBuffer buffer = ByteBuffer.wrap(pkt);
- buffer.get(new byte[ipOffset]);
- byte[] ipAddrBytes = new byte[ipLen];
- buffer.get(ipAddrBytes);
- return InetAddress.getByAddress(ipAddrBytes);
- }
-
- private static int getPort(byte[] pkt, boolean shouldGetSource) {
- ByteBuffer buffer = ByteBuffer.wrap(pkt);
- int srcPortOffset = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN;
- int portOffset = shouldGetSource ? srcPortOffset : srcPortOffset + PORT_LEN;
-
- buffer.get(new byte[portOffset]);
- return Short.toUnsignedInt(buffer.getShort());
- }
-
- public static byte[] buildIkePacket(
- InetAddress srcAddr,
- InetAddress dstAddr,
- int srcPort,
- int dstPort,
- boolean useEncap,
- byte[] ikePacket)
- throws Exception {
- if (useEncap) {
- ByteBuffer buffer = ByteBuffer.allocate(NON_ESP_MARKER_LEN + ikePacket.length);
- buffer.put(NON_ESP_MARKER);
- buffer.put(ikePacket);
- ikePacket = buffer.array();
- }
-
- UdpHeader udpPkt = new UdpHeader(srcPort, dstPort, new BytePayload(ikePacket));
- IpHeader ipPkt = getIpHeader(udpPkt.getProtocolId(), srcAddr, dstAddr, udpPkt);
- return ipPkt.getPacketBytes();
- }
-
- private static IpHeader getIpHeader(
- int protocol, InetAddress src, InetAddress dst, Payload payload) {
- if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) {
- throw new IllegalArgumentException("Invalid src/dst address combination");
- }
-
- if (src instanceof Inet6Address) {
- return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload);
- } else {
- return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload);
- }
- }
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java
deleted file mode 100644
index 35e6719..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/PacketUtils.java
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipsec.ike.cts;
-
-import static android.system.OsConstants.IPPROTO_IPV6;
-import static android.system.OsConstants.IPPROTO_UDP;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ShortBuffer;
-import java.security.GeneralSecurityException;
-import java.security.SecureRandom;
-import java.util.Arrays;
-
-import javax.crypto.Cipher;
-import javax.crypto.Mac;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * This code is a exact copy of {@link PacketUtils} in
- * cts/tests/tests/net/src/android/net/cts/PacketUtils.java.
- *
- * <p>TODO(b/148689509): Statically include the PacketUtils source file instead of copying it.
- */
-public class PacketUtils {
- private static final String TAG = PacketUtils.class.getSimpleName();
-
- private static final int DATA_BUFFER_LEN = 4096;
-
- static final int IP4_HDRLEN = 20;
- static final int IP6_HDRLEN = 40;
- static final int UDP_HDRLEN = 8;
- static final int TCP_HDRLEN = 20;
- static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12;
-
- // Not defined in OsConstants
- static final int IPPROTO_IPV4 = 4;
- static final int IPPROTO_ESP = 50;
-
- // Encryption parameters
- static final int AES_GCM_IV_LEN = 8;
- static final int AES_CBC_IV_LEN = 16;
- static final int AES_GCM_BLK_SIZE = 4;
- static final int AES_CBC_BLK_SIZE = 16;
-
- // Encryption algorithms
- static final String AES = "AES";
- static final String AES_CBC = "AES/CBC/NoPadding";
- static final String HMAC_SHA_256 = "HmacSHA256";
-
- public interface Payload {
- byte[] getPacketBytes(IpHeader header) throws Exception;
-
- void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception;
-
- short length();
-
- int getProtocolId();
- }
-
- public abstract static class IpHeader {
-
- public final byte proto;
- public final InetAddress srcAddr;
- public final InetAddress dstAddr;
- public final Payload payload;
-
- public IpHeader(int proto, InetAddress src, InetAddress dst, Payload payload) {
- this.proto = (byte) proto;
- this.srcAddr = src;
- this.dstAddr = dst;
- this.payload = payload;
- }
-
- public abstract byte[] getPacketBytes() throws Exception;
-
- public abstract int getProtocolId();
- }
-
- public static class Ip4Header extends IpHeader {
- private short checksum;
-
- public Ip4Header(int proto, Inet4Address src, Inet4Address dst, Payload payload) {
- super(proto, src, dst, payload);
- }
-
- public byte[] getPacketBytes() throws Exception {
- ByteBuffer resultBuffer = buildHeader();
- payload.addPacketBytes(this, resultBuffer);
-
- return getByteArrayFromBuffer(resultBuffer);
- }
-
- public ByteBuffer buildHeader() {
- ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
-
- // Version, IHL
- bb.put((byte) (0x45));
-
- // DCSP, ECN
- bb.put((byte) 0);
-
- // Total Length
- bb.putShort((short) (IP4_HDRLEN + payload.length()));
-
- // Empty for Identification, Flags and Fragment Offset
- bb.putShort((short) 0);
- bb.put((byte) 0x40);
- bb.put((byte) 0x00);
-
- // TTL
- bb.put((byte) 64);
-
- // Protocol
- bb.put(proto);
-
- // Header Checksum
- final int ipChecksumOffset = bb.position();
- bb.putShort((short) 0);
-
- // Src/Dst addresses
- bb.put(srcAddr.getAddress());
- bb.put(dstAddr.getAddress());
-
- bb.putShort(ipChecksumOffset, calculateChecksum(bb));
-
- return bb;
- }
-
- private short calculateChecksum(ByteBuffer bb) {
- int checksum = 0;
-
- // Calculate sum of 16-bit values, excluding checksum. IPv4 headers are always 32-bit
- // aligned, so no special cases needed for unaligned values.
- ShortBuffer shortBuffer = ByteBuffer.wrap(getByteArrayFromBuffer(bb)).asShortBuffer();
- while (shortBuffer.hasRemaining()) {
- short val = shortBuffer.get();
-
- // Wrap as needed
- checksum = addAndWrapForChecksum(checksum, val);
- }
-
- return onesComplement(checksum);
- }
-
- public int getProtocolId() {
- return IPPROTO_IPV4;
- }
- }
-
- public static class Ip6Header extends IpHeader {
- public Ip6Header(int nextHeader, Inet6Address src, Inet6Address dst, Payload payload) {
- super(nextHeader, src, dst, payload);
- }
-
- public byte[] getPacketBytes() throws Exception {
- ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
-
- // Version | Traffic Class (First 4 bits)
- bb.put((byte) 0x60);
-
- // Traffic class (Last 4 bits), Flow Label
- bb.put((byte) 0);
- bb.put((byte) 0);
- bb.put((byte) 0);
-
- // Payload Length
- bb.putShort((short) payload.length());
-
- // Next Header
- bb.put(proto);
-
- // Hop Limit
- bb.put((byte) 64);
-
- // Src/Dst addresses
- bb.put(srcAddr.getAddress());
- bb.put(dstAddr.getAddress());
-
- // Payload
- payload.addPacketBytes(this, bb);
-
- return getByteArrayFromBuffer(bb);
- }
-
- public int getProtocolId() {
- return IPPROTO_IPV6;
- }
- }
-
- public static class BytePayload implements Payload {
- public final byte[] payload;
-
- public BytePayload(byte[] payload) {
- this.payload = payload;
- }
-
- public int getProtocolId() {
- return -1;
- }
-
- public byte[] getPacketBytes(IpHeader header) {
- ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
-
- addPacketBytes(header, bb);
- return getByteArrayFromBuffer(bb);
- }
-
- public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) {
- resultBuffer.put(payload);
- }
-
- public short length() {
- return (short) payload.length;
- }
- }
-
- public static class UdpHeader implements Payload {
-
- public final short srcPort;
- public final short dstPort;
- public final Payload payload;
-
- public UdpHeader(int srcPort, int dstPort, Payload payload) {
- this.srcPort = (short) srcPort;
- this.dstPort = (short) dstPort;
- this.payload = payload;
- }
-
- public int getProtocolId() {
- return IPPROTO_UDP;
- }
-
- public short length() {
- return (short) (payload.length() + 8);
- }
-
- public byte[] getPacketBytes(IpHeader header) throws Exception {
- ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
-
- addPacketBytes(header, bb);
- return getByteArrayFromBuffer(bb);
- }
-
- public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception {
- // Source, Destination port
- resultBuffer.putShort(srcPort);
- resultBuffer.putShort(dstPort);
-
- // Payload Length
- resultBuffer.putShort(length());
-
- // Get payload bytes for checksum + payload
- ByteBuffer payloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN);
- payload.addPacketBytes(header, payloadBuffer);
- byte[] payloadBytes = getByteArrayFromBuffer(payloadBuffer);
-
- // Checksum
- resultBuffer.putShort(calculateChecksum(header, payloadBytes));
-
- // Payload
- resultBuffer.put(payloadBytes);
- }
-
- private short calculateChecksum(IpHeader header, byte[] payloadBytes) throws Exception {
- int newChecksum = 0;
- ShortBuffer srcBuffer = ByteBuffer.wrap(header.srcAddr.getAddress()).asShortBuffer();
- ShortBuffer dstBuffer = ByteBuffer.wrap(header.dstAddr.getAddress()).asShortBuffer();
-
- while (srcBuffer.hasRemaining() || dstBuffer.hasRemaining()) {
- short val = srcBuffer.hasRemaining() ? srcBuffer.get() : dstBuffer.get();
-
- // Wrap as needed
- newChecksum = addAndWrapForChecksum(newChecksum, val);
- }
-
- // Add pseudo-header values. Proto is 0-padded, so just use the byte.
- newChecksum = addAndWrapForChecksum(newChecksum, header.proto);
- newChecksum = addAndWrapForChecksum(newChecksum, length());
- newChecksum = addAndWrapForChecksum(newChecksum, srcPort);
- newChecksum = addAndWrapForChecksum(newChecksum, dstPort);
- newChecksum = addAndWrapForChecksum(newChecksum, length());
-
- ShortBuffer payloadShortBuffer = ByteBuffer.wrap(payloadBytes).asShortBuffer();
- while (payloadShortBuffer.hasRemaining()) {
- newChecksum = addAndWrapForChecksum(newChecksum, payloadShortBuffer.get());
- }
- if (payload.length() % 2 != 0) {
- newChecksum =
- addAndWrapForChecksum(
- newChecksum, (payloadBytes[payloadBytes.length - 1] << 8));
- }
-
- return onesComplement(newChecksum);
- }
- }
-
- public static class EspHeader implements Payload {
- public final int nextHeader;
- public final int spi;
- public final int seqNum;
- public final byte[] key;
- public final byte[] payload;
-
- /**
- * Generic constructor for ESP headers.
- *
- * <p>For Tunnel mode, payload will be a full IP header + attached payloads
- *
- * <p>For Transport mode, payload will be only the attached payloads, but with the checksum
- * calculated using the pre-encryption IP header
- */
- public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) {
- this.nextHeader = nextHeader;
- this.spi = spi;
- this.seqNum = seqNum;
- this.key = key;
- this.payload = payload;
- }
-
- public int getProtocolId() {
- return IPPROTO_ESP;
- }
-
- public short length() {
- // ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len)
- return (short)
- calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128);
- }
-
- public byte[] getPacketBytes(IpHeader header) throws Exception {
- ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
-
- addPacketBytes(header, bb);
- return getByteArrayFromBuffer(bb);
- }
-
- public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception {
- ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN);
- espPayloadBuffer.putInt(spi);
- espPayloadBuffer.putInt(seqNum);
- espPayloadBuffer.put(getCiphertext(key));
-
- espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16);
- resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer));
- }
-
- private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException {
- Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256);
- SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256);
- sha256HMAC.init(authKey);
-
- return sha256HMAC.doFinal(authenticatedSection);
- }
-
- /**
- * Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks
- *
- * <p>The ciphertext does NOT include the SPI/Sequence numbers, or the ICV.
- */
- private byte[] getCiphertext(byte[] key) throws GeneralSecurityException {
- int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE);
- ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen);
- paddedPayload.put(payload);
-
- // Add padding - consecutive integers from 0x01
- int pad = 1;
- while (paddedPayload.position() < paddedPayload.limit()) {
- paddedPayload.put((byte) pad++);
- }
-
- paddedPayload.position(paddedPayload.limit() - 2);
- paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length
- paddedPayload.put((byte) nextHeader);
-
- // Generate Initialization Vector
- byte[] iv = new byte[AES_CBC_IV_LEN];
- new SecureRandom().nextBytes(iv);
- IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
- SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES);
-
- // Encrypt payload
- Cipher cipher = Cipher.getInstance(AES_CBC);
- cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
- byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload));
-
- // Build ciphertext
- ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length);
- cipherText.put(iv);
- cipherText.put(encrypted);
-
- return getByteArrayFromBuffer(cipherText);
- }
- }
-
- private static int addAndWrapForChecksum(int currentChecksum, int value) {
- currentChecksum += value & 0x0000ffff;
-
- // Wrap anything beyond the first 16 bits, and add to lower order bits
- return (currentChecksum >>> 16) + (currentChecksum & 0x0000ffff);
- }
-
- private static short onesComplement(int val) {
- val = (val >>> 16) + (val & 0xffff);
-
- if (val == 0) return 0;
- return (short) ((~val) & 0xffff);
- }
-
- public static int calculateEspPacketSize(
- int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) {
- final int ESP_HDRLEN = 4 + 4; // SPI + Seq#
- final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length
- payloadLen += cryptIvLength; // Initialization Vector
-
- // Align to block size of encryption algorithm
- payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize);
- return payloadLen + ESP_HDRLEN + ICV_LEN;
- }
-
- private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) {
- payloadLen += 2; // ESP trailer
-
- // Align to block size of encryption algorithm
- return payloadLen + calculateEspPadLen(payloadLen, cryptBlockSize);
- }
-
- private static int calculateEspPadLen(int payloadLen, int cryptBlockSize) {
- return (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize;
- }
-
- private static byte[] getByteArrayFromBuffer(ByteBuffer buffer) {
- return Arrays.copyOfRange(buffer.array(), 0, buffer.position());
- }
-
- /*
- * Debug printing
- */
- private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
-
- public static String bytesToHex(byte[] bytes) {
- StringBuilder sb = new StringBuilder();
- for (byte b : bytes) {
- sb.append(hexArray[b >>> 4]);
- sb.append(hexArray[b & 0x0F]);
- sb.append(' ');
- }
- return sb.toString();
- }
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java
deleted file mode 100644
index e0d3be0..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/SaProposalTest.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipsec.ike.cts;
-
-import static android.net.ipsec.ike.SaProposal.DH_GROUP_1024_BIT_MODP;
-import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
-import static android.net.ipsec.ike.SaProposal.DH_GROUP_NONE;
-import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_3DES;
-import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
-import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
-import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
-import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
-import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
-import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96;
-import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
-import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192;
-import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256;
-import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_NONE;
-import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128;
-import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_192;
-import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256;
-import static android.net.ipsec.ike.SaProposal.KEY_LEN_UNUSED;
-import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;
-import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1;
-import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256;
-import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384;
-import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.net.ipsec.ike.ChildSaProposal;
-import android.net.ipsec.ike.IkeSaProposal;
-import android.util.Pair;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-public class SaProposalTest {
- private static final List<Pair<Integer, Integer>> NORMAL_MODE_CIPHERS = new ArrayList<>();
- private static final List<Pair<Integer, Integer>> COMBINED_MODE_CIPHERS = new ArrayList<>();
- private static final List<Integer> INTEGRITY_ALGOS = new ArrayList<>();
- private static final List<Integer> DH_GROUPS = new ArrayList<>();
- private static final List<Integer> DH_GROUPS_WITH_NONE = new ArrayList<>();
- private static final List<Integer> PRFS = new ArrayList<>();
-
- static {
- NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED));
- NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128));
- NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192));
- NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256));
-
- COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128));
- COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192));
- COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256));
-
- INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA1_96);
- INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_AES_XCBC_96);
- INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
- INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192);
- INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256);
-
- DH_GROUPS.add(DH_GROUP_1024_BIT_MODP);
- DH_GROUPS.add(DH_GROUP_2048_BIT_MODP);
-
- DH_GROUPS_WITH_NONE.add(DH_GROUP_NONE);
- DH_GROUPS_WITH_NONE.addAll(DH_GROUPS);
-
- PRFS.add(PSEUDORANDOM_FUNCTION_HMAC_SHA1);
- PRFS.add(PSEUDORANDOM_FUNCTION_AES128_XCBC);
- PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_256);
- PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_384);
- PRFS.add(PSEUDORANDOM_FUNCTION_SHA2_512);
- }
-
- // Package private
- static IkeSaProposal buildIkeSaProposalWithNormalModeCipher() {
- return buildIkeSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, PRFS, DH_GROUPS);
- }
-
- // Package private
- static IkeSaProposal buildIkeSaProposalWithCombinedModeCipher() {
- return buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */);
- }
-
- private static IkeSaProposal buildIkeSaProposalWithCombinedModeCipher(
- boolean hasIntegrityNone) {
- List<Integer> integerAlgos = new ArrayList<>();
- if (hasIntegrityNone) {
- integerAlgos.add(INTEGRITY_ALGORITHM_NONE);
- }
- return buildIkeSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, PRFS, DH_GROUPS);
- }
-
- private static IkeSaProposal buildIkeSaProposal(
- List<Pair<Integer, Integer>> ciphers,
- List<Integer> integrityAlgos,
- List<Integer> prfs,
- List<Integer> dhGroups) {
- IkeSaProposal.Builder builder = new IkeSaProposal.Builder();
-
- for (Pair<Integer, Integer> pair : ciphers) {
- builder.addEncryptionAlgorithm(pair.first, pair.second);
- }
- for (int algo : integrityAlgos) {
- builder.addIntegrityAlgorithm(algo);
- }
- for (int algo : prfs) {
- builder.addPseudorandomFunction(algo);
- }
- for (int algo : dhGroups) {
- builder.addDhGroup(algo);
- }
-
- return builder.build();
- }
-
- // Package private
- static ChildSaProposal buildChildSaProposalWithNormalModeCipher() {
- return buildChildSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, DH_GROUPS_WITH_NONE);
- }
-
- // Package private
- static ChildSaProposal buildChildSaProposalWithCombinedModeCipher() {
- return buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */);
- }
-
- private static ChildSaProposal buildChildSaProposalWithCombinedModeCipher(
- boolean hasIntegrityNone) {
- List<Integer> integerAlgos = new ArrayList<>();
- if (hasIntegrityNone) {
- integerAlgos.add(INTEGRITY_ALGORITHM_NONE);
- }
-
- return buildChildSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, DH_GROUPS_WITH_NONE);
- }
-
- private static ChildSaProposal buildChildSaProposal(
- List<Pair<Integer, Integer>> ciphers,
- List<Integer> integrityAlgos,
- List<Integer> dhGroups) {
- ChildSaProposal.Builder builder = new ChildSaProposal.Builder();
-
- for (Pair<Integer, Integer> pair : ciphers) {
- builder.addEncryptionAlgorithm(pair.first, pair.second);
- }
- for (int algo : integrityAlgos) {
- builder.addIntegrityAlgorithm(algo);
- }
- for (int algo : dhGroups) {
- builder.addDhGroup(algo);
- }
-
- return builder.build();
- }
-
- // Package private
- static ChildSaProposal buildChildSaProposalWithOnlyCiphers() {
- return buildChildSaProposal(
- COMBINED_MODE_CIPHERS, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
- }
-
- @Test
- public void testBuildIkeSaProposalWithNormalModeCipher() {
- IkeSaProposal saProposal = buildIkeSaProposalWithNormalModeCipher();
-
- assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
- assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms());
- assertEquals(PRFS, saProposal.getPseudorandomFunctions());
- assertEquals(DH_GROUPS, saProposal.getDhGroups());
- }
-
- @Test
- public void testBuildIkeSaProposalWithCombinedModeCipher() {
- IkeSaProposal saProposal =
- buildIkeSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */);
-
- assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
- assertEquals(PRFS, saProposal.getPseudorandomFunctions());
- assertEquals(DH_GROUPS, saProposal.getDhGroups());
- assertTrue(saProposal.getIntegrityAlgorithms().isEmpty());
- }
-
- @Test
- public void testBuildIkeSaProposalWithCombinedModeCipherAndIntegrityNone() {
- IkeSaProposal saProposal =
- buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */);
-
- assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
- assertEquals(PRFS, saProposal.getPseudorandomFunctions());
- assertEquals(DH_GROUPS, saProposal.getDhGroups());
- assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms());
- }
-
- @Test
- public void testBuildChildSaProposalWithNormalModeCipher() {
- ChildSaProposal saProposal = buildChildSaProposalWithNormalModeCipher();
-
- assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
- assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms());
- assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups());
- }
-
- @Test
- public void testBuildChildProposalWithCombinedModeCipher() {
- ChildSaProposal saProposal =
- buildChildSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */);
-
- assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
- assertTrue(saProposal.getIntegrityAlgorithms().isEmpty());
- assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups());
- }
-
- @Test
- public void testBuildChildProposalWithCombinedModeCipherAndIntegrityNone() {
- ChildSaProposal saProposal =
- buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */);
-
- assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
- assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms());
- assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups());
- }
-
- @Test
- public void testBuildChildSaProposalWithOnlyCiphers() {
- ChildSaProposal saProposal = buildChildSaProposalWithOnlyCiphers();
-
- assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
- assertTrue(saProposal.getIntegrityAlgorithms().isEmpty());
- assertTrue(saProposal.getDhGroups().isEmpty());
- }
-
- // TODO(b/148689509): Test throwing exception when algorithm combination is invalid
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java
deleted file mode 100644
index 5b08cdc..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/TestNetworkUtils.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipsec.ike.cts;
-
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import static android.net.NetworkCapabilities.TRANSPORT_TEST;
-
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkRequest;
-import android.net.TestNetworkManager;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
-
-// TODO(b/148689509): Share this class with net CTS test (e.g. IpSecManagerTunnelTest)
-public class TestNetworkUtils {
- private static final int TIMEOUT_MS = 500;
-
- /** Callback to receive requested test network. */
- public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
- private final CompletableFuture<Network> futureNetwork = new CompletableFuture<>();
-
- @Override
- public void onAvailable(Network network) {
- futureNetwork.complete(network);
- }
-
- public Network getNetworkBlocking() throws Exception {
- return futureNetwork.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- }
- }
-
- /**
- * Set up test network.
- *
- * <p>Caller MUST have MANAGE_TEST_NETWORKS permission to use this method.
- *
- * @param connMgr ConnectivityManager to request network.
- * @param testNetworkMgr TestNetworkManager to set up test network.
- * @param ifname the name of the interface to be used for the Network LinkProperties.
- * @param binder a binder object guarding the lifecycle of this test network.
- * @return TestNetworkCallback to retrieve the test network.
- * @throws RemoteException if test network setup failed.
- * @see android.net.TestNetworkManager
- */
- public static TestNetworkCallback setupAndGetTestNetwork(
- ConnectivityManager connMgr,
- TestNetworkManager testNetworkMgr,
- String ifname,
- IBinder binder)
- throws RemoteException {
- NetworkRequest nr =
- new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_TEST)
- .removeCapability(NET_CAPABILITY_TRUSTED)
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .setNetworkSpecifier(ifname)
- .build();
-
- TestNetworkCallback cb = new TestNetworkCallback();
- connMgr.requestNetwork(nr, cb);
-
- // Setup the test network after network request is filed to prevent Network from being
- // reaped due to no requests matching it.
- testNetworkMgr.setupTestNetwork(ifname, binder);
-
- return cb;
- }
-}
diff --git a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java b/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java
deleted file mode 100644
index 5539dbc..0000000
--- a/tests/tests/net/ipsec/src/android/net/ipsec/ike/cts/TunUtils.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.ipsec.ike.cts;
-
-import static android.net.ipsec.ike.cts.PacketUtils.IP4_HDRLEN;
-import static android.net.ipsec.ike.cts.PacketUtils.IP6_HDRLEN;
-import static android.net.ipsec.ike.cts.PacketUtils.IPPROTO_ESP;
-import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN;
-import static android.system.OsConstants.IPPROTO_UDP;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-
-import android.os.ParcelFileDescriptor;
-
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.function.Predicate;
-
-/**
- * This code is a exact copy of {@link TunUtils} in
- * cts/tests/tests/net/src/android/net/cts/TunUtils.java, except the import path of PacketUtils is
- * the path to the copy of PacktUtils.
- *
- * <p>TODO(b/148689509): Statically include the TunUtils source file instead of copying it.
- */
-public class TunUtils {
- private static final String TAG = TunUtils.class.getSimpleName();
-
- private static final int DATA_BUFFER_LEN = 4096;
- static final int TIMEOUT = 500;
-
- static final int IP4_PROTO_OFFSET = 9;
- static final int IP6_PROTO_OFFSET = 6;
-
- static final int IP4_ADDR_OFFSET = 12;
- static final int IP4_ADDR_LEN = 4;
- static final int IP6_ADDR_OFFSET = 8;
- static final int IP6_ADDR_LEN = 16;
-
- final List<byte[]> mPackets = new ArrayList<>();
- private final ParcelFileDescriptor mTunFd;
- private final Thread mReaderThread;
-
- public TunUtils(ParcelFileDescriptor tunFd) {
- mTunFd = tunFd;
-
- // Start background reader thread
- mReaderThread =
- new Thread(
- () -> {
- try {
- // Loop will exit and thread will quit when tunFd is closed.
- // Receiving either EOF or an exception will exit this reader loop.
- // FileInputStream in uninterruptable, so there's no good way to
- // ensure that this thread shuts down except upon FD closure.
- while (true) {
- byte[] intercepted = receiveFromTun();
- if (intercepted == null) {
- // Exit once we've hit EOF
- return;
- } else if (intercepted.length > 0) {
- // Only save packet if we've received any bytes.
- synchronized (mPackets) {
- mPackets.add(intercepted);
- mPackets.notifyAll();
- }
- }
- }
- } catch (IOException ignored) {
- // Simply exit this reader thread
- return;
- }
- });
- mReaderThread.start();
- }
-
- private byte[] receiveFromTun() throws IOException {
- FileInputStream in = new FileInputStream(mTunFd.getFileDescriptor());
- byte[] inBytes = new byte[DATA_BUFFER_LEN];
- int bytesRead = in.read(inBytes);
-
- if (bytesRead < 0) {
- return null; // return null for EOF
- } else if (bytesRead >= DATA_BUFFER_LEN) {
- throw new IllegalStateException("Too big packet. Fragmentation unsupported");
- }
- return Arrays.copyOf(inBytes, bytesRead);
- }
-
- byte[] getFirstMatchingPacket(Predicate<byte[]> verifier, int startIndex) {
- synchronized (mPackets) {
- for (int i = startIndex; i < mPackets.size(); i++) {
- byte[] pkt = mPackets.get(i);
- if (verifier.test(pkt)) {
- return pkt;
- }
- }
- }
- return null;
- }
-
- /**
- * Checks if the specified bytes were ever sent in plaintext.
- *
- * <p>Only checks for known plaintext bytes to prevent triggering on ICMP/RA packets or the like
- *
- * @param plaintext the plaintext bytes to check for
- * @param startIndex the index in the list to check for
- */
- public boolean hasPlaintextPacket(byte[] plaintext, int startIndex) {
- Predicate<byte[]> verifier =
- (pkt) -> {
- return Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext))
- != -1;
- };
- return getFirstMatchingPacket(verifier, startIndex) != null;
- }
-
- public byte[] getEspPacket(int spi, boolean encap, int startIndex) {
- return getFirstMatchingPacket(
- (pkt) -> {
- return isEsp(pkt, spi, encap);
- },
- startIndex);
- }
-
- public byte[] awaitEspPacketNoPlaintext(
- int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception {
- long endTime = System.currentTimeMillis() + TIMEOUT;
- int startIndex = 0;
-
- synchronized (mPackets) {
- while (System.currentTimeMillis() < endTime) {
- byte[] espPkt = getEspPacket(spi, useEncap, startIndex);
- if (espPkt != null) {
- // Validate packet size
- assertEquals(expectedPacketSize, espPkt.length);
-
- // Always check plaintext from start
- assertFalse(hasPlaintextPacket(plaintext, 0));
- return espPkt; // We've found the packet we're looking for.
- }
-
- startIndex = mPackets.size();
-
- // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout
- long waitTimeout = endTime - System.currentTimeMillis();
- if (waitTimeout > 0) {
- mPackets.wait(waitTimeout);
- }
- }
-
- fail("No such ESP packet found with SPI " + spi);
- }
- return null;
- }
-
- private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) {
- // Check SPI byte by byte.
- return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff)
- && pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff)
- && pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff)
- && pkt[espOffset + 3] == (byte) (spi & 0xff);
- }
-
- private static boolean isEsp(byte[] pkt, int spi, boolean encap) {
- if (isIpv6(pkt)) {
- // IPv6 UDP encap not supported by kernels; assume non-encap.
- return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi);
- } else {
- // Use default IPv4 header length (assuming no options)
- if (encap) {
- return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP
- && isSpiEqual(pkt, IP4_HDRLEN + UDP_HDRLEN, spi);
- } else {
- return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP4_HDRLEN, spi);
- }
- }
- }
-
- static boolean isIpv6(byte[] pkt) {
- // First nibble shows IP version. 0x60 for IPv6
- return (pkt[0] & (byte) 0xF0) == (byte) 0x60;
- }
-
- private static byte[] getReflectedPacket(byte[] pkt) {
- byte[] reflected = Arrays.copyOf(pkt, pkt.length);
-
- if (isIpv6(pkt)) {
- // Set reflected packet's dst to that of the original's src
- System.arraycopy(
- pkt, // src
- IP6_ADDR_OFFSET + IP6_ADDR_LEN, // src offset
- reflected, // dst
- IP6_ADDR_OFFSET, // dst offset
- IP6_ADDR_LEN); // len
- // Set reflected packet's src IP to that of the original's dst IP
- System.arraycopy(
- pkt, // src
- IP6_ADDR_OFFSET, // src offset
- reflected, // dst
- IP6_ADDR_OFFSET + IP6_ADDR_LEN, // dst offset
- IP6_ADDR_LEN); // len
- } else {
- // Set reflected packet's dst to that of the original's src
- System.arraycopy(
- pkt, // src
- IP4_ADDR_OFFSET + IP4_ADDR_LEN, // src offset
- reflected, // dst
- IP4_ADDR_OFFSET, // dst offset
- IP4_ADDR_LEN); // len
- // Set reflected packet's src IP to that of the original's dst IP
- System.arraycopy(
- pkt, // src
- IP4_ADDR_OFFSET, // src offset
- reflected, // dst
- IP4_ADDR_OFFSET + IP4_ADDR_LEN, // dst offset
- IP4_ADDR_LEN); // len
- }
- return reflected;
- }
-
- /** Takes all captured packets, flips the src/dst, and re-injects them. */
- public void reflectPackets() throws IOException {
- synchronized (mPackets) {
- for (byte[] pkt : mPackets) {
- injectPacket(getReflectedPacket(pkt));
- }
- }
- }
-
- public void injectPacket(byte[] pkt) throws IOException {
- FileOutputStream out = new FileOutputStream(mTunFd.getFileDescriptor());
- out.write(pkt);
- out.flush();
- }
-
- /** Resets the intercepted packets. */
- public void reset() throws IOException {
- synchronized (mPackets) {
- mPackets.clear();
- }
- }
-}
diff --git a/tests/tests/net/jarjar-rules-shared.txt b/tests/tests/net/jarjar-rules-shared.txt
deleted file mode 100644
index 11dba74..0000000
--- a/tests/tests/net/jarjar-rules-shared.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-# Module library in frameworks/libs/net
-rule com.android.net.module.util.** android.net.cts.util.@1
\ No newline at end of file
diff --git a/tests/tests/net/jni/Android.bp b/tests/tests/net/jni/Android.bp
deleted file mode 100644
index 3953aeb..0000000
--- a/tests/tests/net/jni/Android.bp
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_library_shared {
- name: "libnativedns_jni",
-
- srcs: ["NativeDnsJni.c"],
- sdk_version: "current",
-
- shared_libs: [
- "libnativehelper_compat_libc++",
- "liblog",
- ],
- stl: "libc++_static",
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-unused-parameter",
- ],
-
-}
-
-cc_library_shared {
- name: "libnativemultinetwork_jni",
-
- srcs: ["NativeMultinetworkJni.cpp"],
- sdk_version: "current",
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-format",
- ],
- shared_libs: [
- "libandroid",
- "libnativehelper_compat_libc++",
- "liblog",
- ],
- stl: "libc++_static",
-}
diff --git a/tests/tests/net/jni/NativeDnsJni.c b/tests/tests/net/jni/NativeDnsJni.c
deleted file mode 100644
index 4ec800e..0000000
--- a/tests/tests/net/jni/NativeDnsJni.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <arpa/inet.h>
-#include <jni.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <android/log.h>
-
-#define LOG_TAG "NativeDns-JNI"
-#define LOGD(fmt, ...) \
- __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##__VA_ARGS__)
-
-const char *GoogleDNSIpV4Address="8.8.8.8";
-const char *GoogleDNSIpV4Address2="8.8.4.4";
-const char *GoogleDNSIpV6Address="2001:4860:4860::8888";
-const char *GoogleDNSIpV6Address2="2001:4860:4860::8844";
-
-JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclass class)
-{
- const char *node = "www.google.com";
- char *service = NULL;
- struct addrinfo *answer;
-
- int res = getaddrinfo(node, service, NULL, &answer);
- LOGD("getaddrinfo(www.google.com) gave res=%d (%s)", res, gai_strerror(res));
- if (res != 0) return JNI_FALSE;
-
- // check for v4 & v6
- {
- int foundv4 = 0;
- int foundv6 = 0;
- struct addrinfo *current = answer;
- while (current != NULL) {
- char buf[256];
- if (current->ai_addr->sa_family == AF_INET) {
- inet_ntop(current->ai_family, &((struct sockaddr_in *)current->ai_addr)->sin_addr,
- buf, sizeof(buf));
- foundv4 = 1;
- LOGD(" %s", buf);
- } else if (current->ai_addr->sa_family == AF_INET6) {
- inet_ntop(current->ai_family, &((struct sockaddr_in6 *)current->ai_addr)->sin6_addr,
- buf, sizeof(buf));
- foundv6 = 1;
- LOGD(" %s", buf);
- }
- current = current->ai_next;
- }
-
- freeaddrinfo(answer);
- answer = NULL;
- if (foundv4 != 1 && foundv6 != 1) {
- LOGD("getaddrinfo(www.google.com) didn't find either v4 or v6 address");
- return JNI_FALSE;
- }
- }
-
- node = "ipv6.google.com";
- res = getaddrinfo(node, service, NULL, &answer);
- LOGD("getaddrinfo(ipv6.google.com) gave res=%d", res);
- if (res != 0) return JNI_FALSE;
-
- {
- int foundv4 = 0;
- int foundv6 = 0;
- struct addrinfo *current = answer;
- while (current != NULL) {
- char buf[256];
- if (current->ai_addr->sa_family == AF_INET) {
- inet_ntop(current->ai_family, &((struct sockaddr_in *)current->ai_addr)->sin_addr,
- buf, sizeof(buf));
- LOGD(" %s", buf);
- foundv4 = 1;
- } else if (current->ai_addr->sa_family == AF_INET6) {
- inet_ntop(current->ai_family, &((struct sockaddr_in6 *)current->ai_addr)->sin6_addr,
- buf, sizeof(buf));
- LOGD(" %s", buf);
- foundv6 = 1;
- }
- current = current->ai_next;
- }
-
- freeaddrinfo(answer);
- answer = NULL;
- if (foundv4 == 1 || foundv6 != 1) {
- LOGD("getaddrinfo(ipv6.google.com) didn't find only v6");
- return JNI_FALSE;
- }
- }
-
- // getnameinfo
- struct sockaddr_in sa4;
- sa4.sin_family = AF_INET;
- sa4.sin_port = 0;
- inet_pton(AF_INET, GoogleDNSIpV4Address, &(sa4.sin_addr));
-
- struct sockaddr_in6 sa6;
- sa6.sin6_family = AF_INET6;
- sa6.sin6_port = 0;
- sa6.sin6_flowinfo = 0;
- sa6.sin6_scope_id = 0;
- inet_pton(AF_INET6, GoogleDNSIpV6Address2, &(sa6.sin6_addr));
-
- char buf[NI_MAXHOST];
- int flags = NI_NAMEREQD;
-
- res = getnameinfo((const struct sockaddr*)&sa4, sizeof(sa4), buf, sizeof(buf), NULL, 0, flags);
- if (res != 0) {
- LOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV4Address, res,
- gai_strerror(res));
- return JNI_FALSE;
- }
- if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) {
- LOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s",
- GoogleDNSIpV4Address, buf);
- return JNI_FALSE;
- }
-
- memset(buf, 0, sizeof(buf));
- res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf), NULL, 0, flags);
- if (res != 0) {
- LOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2,
- res, gai_strerror(res));
- return JNI_FALSE;
- }
- if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) {
- LOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s",
- GoogleDNSIpV6Address2, buf);
- return JNI_FALSE;
- }
-
- // gethostbyname
- struct hostent *my_hostent = gethostbyname("www.youtube.com");
- if (my_hostent == NULL) {
- LOGD("gethostbyname(www.youtube.com) gave null response");
- return JNI_FALSE;
- }
- if ((my_hostent->h_addr_list == NULL) || (*my_hostent->h_addr_list == NULL)) {
- LOGD("gethostbyname(www.youtube.com) gave 0 addresses");
- return JNI_FALSE;
- }
- {
- char **current = my_hostent->h_addr_list;
- while (*current != NULL) {
- char buf[256];
- inet_ntop(my_hostent->h_addrtype, *current, buf, sizeof(buf));
- LOGD("gethostbyname(www.youtube.com) gave %s", buf);
- current++;
- }
- }
-
- // gethostbyaddr
- char addr6[16];
- inet_pton(AF_INET6, GoogleDNSIpV6Address, addr6);
- my_hostent = gethostbyaddr(addr6, sizeof(addr6), AF_INET6);
- if (my_hostent == NULL) {
- LOGD("gethostbyaddr(%s (GoogleDNS) ) gave null response", GoogleDNSIpV6Address);
- return JNI_FALSE;
- }
-
- LOGD("gethostbyaddr(%s (GoogleDNS) ) gave %s for name", GoogleDNSIpV6Address,
- my_hostent->h_name ? my_hostent->h_name : "null");
-
- if (my_hostent->h_name == NULL) return JNI_FALSE;
- return JNI_TRUE;
-}
diff --git a/tests/tests/net/jni/NativeMultinetworkJni.cpp b/tests/tests/net/jni/NativeMultinetworkJni.cpp
deleted file mode 100644
index 60e31bc..0000000
--- a/tests/tests/net/jni/NativeMultinetworkJni.cpp
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#define LOG_TAG "MultinetworkApiTest"
-
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <jni.h>
-#include <netdb.h>
-#include <poll.h> /* poll */
-#include <resolv.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-
-#include <string>
-
-#include <android/log.h>
-#include <android/multinetwork.h>
-#include <nativehelper/JNIHelp.h>
-
-#define LOGD(fmt, ...) \
- __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##__VA_ARGS__)
-
-#define EXPECT_GE(env, actual, expected, msg) \
- do { \
- if (actual < expected) { \
- jniThrowExceptionFmt(env, "java/lang/AssertionError", \
- "%s:%d: %s EXPECT_GE: expected %d, got %d", \
- __FILE__, __LINE__, msg, expected, actual); \
- } \
- } while (0)
-
-#define EXPECT_GT(env, actual, expected, msg) \
- do { \
- if (actual <= expected) { \
- jniThrowExceptionFmt(env, "java/lang/AssertionError", \
- "%s:%d: %s EXPECT_GT: expected %d, got %d", \
- __FILE__, __LINE__, msg, expected, actual); \
- } \
- } while (0)
-
-#define EXPECT_EQ(env, expected, actual, msg) \
- do { \
- if (actual != expected) { \
- jniThrowExceptionFmt(env, "java/lang/AssertionError", \
- "%s:%d: %s EXPECT_EQ: expected %d, got %d", \
- __FILE__, __LINE__, msg, expected, actual); \
- } \
- } while (0)
-
-static const int MAXPACKET = 8 * 1024;
-static const int TIMEOUT_MS = 15000;
-static const char kHostname[] = "connectivitycheck.android.com";
-static const char kNxDomainName[] = "test1-nx.metric.gstatic.com";
-static const char kGoogleName[] = "www.google.com";
-
-int makeQuery(const char* name, int qtype, uint8_t* buf, size_t buflen) {
- return res_mkquery(ns_o_query, name, ns_c_in, qtype, NULL, 0, NULL, buf, buflen);
-}
-
-int getAsyncResponse(JNIEnv* env, int fd, int timeoutMs, int* rcode, uint8_t* buf, size_t bufLen) {
- struct pollfd wait_fd = { .fd = fd, .events = POLLIN };
-
- poll(&wait_fd, 1, timeoutMs);
- if (wait_fd.revents & POLLIN) {
- int n = android_res_nresult(fd, rcode, buf, bufLen);
- // Verify that android_res_nresult() closed the fd
- char dummy;
- EXPECT_EQ(env, -1, read(fd, &dummy, sizeof(dummy)), "res_nresult check for closing fd");
- EXPECT_EQ(env, EBADF, errno, "res_nresult check for errno");
- return n;
- }
-
- return -ETIMEDOUT;
-}
-
-int extractIpAddressAnswers(uint8_t* buf, size_t bufLen, int family) {
- ns_msg handle;
- if (ns_initparse((const uint8_t*) buf, bufLen, &handle) < 0) {
- return -errno;
- }
- const int ancount = ns_msg_count(handle, ns_s_an);
- // Answer count = 0 is valid(e.g. response of query with root)
- if (!ancount) {
- return 0;
- }
- ns_rr rr;
- bool hasValidAns = false;
- for (int i = 0; i < ancount; i++) {
- if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) {
- // If there is no valid answer, test will fail.
- continue;
- }
- const uint8_t* rdata = ns_rr_rdata(rr);
- char buffer[INET6_ADDRSTRLEN];
- if (inet_ntop(family, (const char*) rdata, buffer, sizeof(buffer)) == NULL) {
- return -errno;
- }
- hasValidAns = true;
- }
- return hasValidAns ? 0 : -EBADMSG;
-}
-
-int expectAnswersValid(JNIEnv* env, int fd, int family, int expectedRcode) {
- int rcode = -1;
- uint8_t buf[MAXPACKET] = {};
- int res = getAsyncResponse(env, fd, TIMEOUT_MS, &rcode, buf, MAXPACKET);
- if (res < 0) {
- return res;
- }
-
- EXPECT_EQ(env, expectedRcode, rcode, "rcode is not expected");
-
- if (expectedRcode == ns_r_noerror && res > 0) {
- return extractIpAddressAnswers(buf, res, family);
- }
- return 0;
-}
-
-int expectAnswersNotValid(JNIEnv* env, int fd, int expectedErrno) {
- int rcode = -1;
- uint8_t buf[MAXPACKET] = {};
- int res = getAsyncResponse(env, fd, TIMEOUT_MS, &rcode, buf, MAXPACKET);
- if (res != expectedErrno) {
- LOGD("res:%d, expectedErrno = %d", res, expectedErrno);
- return (res > 0) ? -EREMOTEIO : res;
- }
- return 0;
-}
-
-extern "C"
-JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck(
- JNIEnv* env, jclass, jlong nethandle) {
- net_handle_t handle = (net_handle_t) nethandle;
-
- // V4
- int fd = android_res_nquery(handle, kHostname, ns_c_in, ns_t_a, 0);
- EXPECT_GE(env, fd, 0, "v4 res_nquery");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror),
- "v4 res_nquery check answers");
-
- // V6
- fd = android_res_nquery(handle, kHostname, ns_c_in, ns_t_aaaa, 0);
- EXPECT_GE(env, fd, 0, "v6 res_nquery");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror),
- "v6 res_nquery check answers");
-}
-
-extern "C"
-JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNsendCheck(
- JNIEnv* env, jclass, jlong nethandle) {
- net_handle_t handle = (net_handle_t) nethandle;
- // V4
- uint8_t buf1[MAXPACKET] = {};
-
- int len1 = makeQuery(kGoogleName, ns_t_a, buf1, sizeof(buf1));
- EXPECT_GT(env, len1, 0, "v4 res_mkquery 1st");
-
- uint8_t buf2[MAXPACKET] = {};
- int len2 = makeQuery(kHostname, ns_t_a, buf2, sizeof(buf2));
- EXPECT_GT(env, len2, 0, "v4 res_mkquery 2nd");
-
- int fd1 = android_res_nsend(handle, buf1, len1, 0);
- EXPECT_GE(env, fd1, 0, "v4 res_nsend 1st");
- int fd2 = android_res_nsend(handle, buf2, len2, 0);
- EXPECT_GE(env, fd2, 0, "v4 res_nsend 2nd");
-
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd2, AF_INET, ns_r_noerror),
- "v4 res_nsend 2nd check answers");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET, ns_r_noerror),
- "v4 res_nsend 1st check answers");
-
- // V6
- memset(buf1, 0, sizeof(buf1));
- memset(buf2, 0, sizeof(buf2));
- len1 = makeQuery(kGoogleName, ns_t_aaaa, buf1, sizeof(buf1));
- EXPECT_GT(env, len1, 0, "v6 res_mkquery 1st");
- len2 = makeQuery(kHostname, ns_t_aaaa, buf2, sizeof(buf2));
- EXPECT_GT(env, len2, 0, "v6 res_mkquery 2nd");
-
- fd1 = android_res_nsend(handle, buf1, len1, 0);
- EXPECT_GE(env, fd1, 0, "v6 res_nsend 1st");
- fd2 = android_res_nsend(handle, buf2, len2, 0);
- EXPECT_GE(env, fd2, 0, "v6 res_nsend 2nd");
-
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd2, AF_INET6, ns_r_noerror),
- "v6 res_nsend 2nd check answers");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET6, ns_r_noerror),
- "v6 res_nsend 1st check answers");
-}
-
-extern "C"
-JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNnxDomainCheck(
- JNIEnv* env, jclass, jlong nethandle) {
- net_handle_t handle = (net_handle_t) nethandle;
-
- // res_nquery V4 NXDOMAIN
- int fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_a, 0);
- EXPECT_GE(env, fd, 0, "v4 res_nquery NXDOMAIN");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
- "v4 res_nquery NXDOMAIN check answers");
-
- // res_nquery V6 NXDOMAIN
- fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_aaaa, 0);
- EXPECT_GE(env, fd, 0, "v6 res_nquery NXDOMAIN");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET6, ns_r_nxdomain),
- "v6 res_nquery NXDOMAIN check answers");
-
- uint8_t buf[MAXPACKET] = {};
- // res_nsend V4 NXDOMAIN
- int len = makeQuery(kNxDomainName, ns_t_a, buf, sizeof(buf));
- EXPECT_GT(env, len, 0, "v4 res_mkquery NXDOMAIN");
- fd = android_res_nsend(handle, buf, len, 0);
- EXPECT_GE(env, fd, 0, "v4 res_nsend NXDOMAIN");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
- "v4 res_nsend NXDOMAIN check answers");
-
- // res_nsend V6 NXDOMAIN
- memset(buf, 0, sizeof(buf));
- len = makeQuery(kNxDomainName, ns_t_aaaa, buf, sizeof(buf));
- EXPECT_GT(env, len, 0, "v6 res_mkquery NXDOMAIN");
- fd = android_res_nsend(handle, buf, len, 0);
- EXPECT_GE(env, fd, 0, "v6 res_nsend NXDOMAIN");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET6, ns_r_nxdomain),
- "v6 res_nsend NXDOMAIN check answers");
-}
-
-
-extern "C"
-JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck(
- JNIEnv* env, jclass, jlong nethandle) {
- net_handle_t handle = (net_handle_t) nethandle;
-
- int fd = android_res_nquery(handle, kGoogleName, ns_c_in, ns_t_a, 0);
- errno = 0;
- android_res_cancel(fd);
- int err = errno;
- EXPECT_EQ(env, 0, err, "res_cancel");
- // DO NOT call cancel or result with the same fd more than once,
- // otherwise it will hit fdsan double-close fd.
-}
-
-extern "C"
-JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck(
- JNIEnv* env, jclass, jlong nethandle) {
- net_handle_t handle = (net_handle_t) nethandle;
-
- // It is the equivalent of "dig . a", Query with an empty name.
- int fd = android_res_nquery(handle, "", ns_c_in, ns_t_a, 0);
- EXPECT_GE(env, fd, 0, "res_nquery root");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror),
- "res_nquery root check answers");
-
- // Label limit 63
- std::string exceedingLabelQuery = "www." + std::string(70, 'g') + ".com";
- // Name limit 255
- std::string exceedingDomainQuery = "www." + std::string(255, 'g') + ".com";
-
- fd = android_res_nquery(handle, exceedingLabelQuery.c_str(), ns_c_in, ns_t_a, 0);
- EXPECT_EQ(env, -EMSGSIZE, fd, "res_nquery exceedingLabelQuery");
- fd = android_res_nquery(handle, exceedingDomainQuery.c_str(), ns_c_in, ns_t_aaaa, 0);
- EXPECT_EQ(env, -EMSGSIZE, fd, "res_nquery exceedingDomainQuery");
-
- uint8_t buf[10] = {};
- // empty BLOB
- fd = android_res_nsend(handle, buf, 10, 0);
- EXPECT_GE(env, fd, 0, "res_nsend empty BLOB");
- EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL),
- "res_nsend empty BLOB check answers");
-
- uint8_t largeBuf[2 * MAXPACKET] = {};
- // A buffer larger than 8KB
- fd = android_res_nsend(handle, largeBuf, sizeof(largeBuf), 0);
- EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend buffer larger than 8KB");
-
- // 5000 bytes filled with 0. This returns EMSGSIZE because FrameworkListener limits the size of
- // commands to 4096 bytes.
- fd = android_res_nsend(handle, largeBuf, 5000, 0);
- EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend 5000 bytes filled with 0");
-
- // 500 bytes filled with 0
- fd = android_res_nsend(handle, largeBuf, 500, 0);
- EXPECT_GE(env, fd, 0, "res_nsend 500 bytes filled with 0");
- EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL),
- "res_nsend 500 bytes filled with 0 check answers");
-
- // 5000 bytes filled with 0xFF
- uint8_t ffBuf[5001] = {};
- memset(ffBuf, 0xFF, sizeof(ffBuf));
- ffBuf[5000] = '\0';
- fd = android_res_nsend(handle, ffBuf, sizeof(ffBuf), 0);
- EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend 5000 bytes filled with 0xFF");
-
- // 500 bytes filled with 0xFF
- ffBuf[500] = '\0';
- fd = android_res_nsend(handle, ffBuf, 501, 0);
- EXPECT_GE(env, fd, 0, "res_nsend 500 bytes filled with 0xFF");
- EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL),
- "res_nsend 500 bytes filled with 0xFF check answers");
-}
-
-extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runGetaddrinfoCheck(
- JNIEnv*, jclass, jlong nethandle) {
- net_handle_t handle = (net_handle_t) nethandle;
- struct addrinfo *res = NULL;
-
- errno = 0;
- int rval = android_getaddrinfofornetwork(handle, kHostname, NULL, NULL, &res);
- const int saved_errno = errno;
- freeaddrinfo(res);
-
- LOGD("android_getaddrinfofornetwork(%" PRIu64 ", %s) returned rval=%d errno=%d",
- handle, kHostname, rval, saved_errno);
- return rval == 0 ? 0 : -saved_errno;
-}
-
-extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetprocnetwork(
- JNIEnv*, jclass, jlong nethandle) {
- net_handle_t handle = (net_handle_t) nethandle;
-
- errno = 0;
- int rval = android_setprocnetwork(handle);
- const int saved_errno = errno;
- LOGD("android_setprocnetwork(%" PRIu64 ") returned rval=%d errno=%d",
- handle, rval, saved_errno);
- return rval == 0 ? 0 : -saved_errno;
-}
-
-extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetsocknetwork(
- JNIEnv*, jclass, jlong nethandle) {
- net_handle_t handle = (net_handle_t) nethandle;
-
- errno = 0;
- int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
- if (fd < 0) {
- LOGD("socket() failed, errno=%d", errno);
- return -errno;
- }
-
- errno = 0;
- int rval = android_setsocknetwork(handle, fd);
- const int saved_errno = errno;
- LOGD("android_setprocnetwork(%" PRIu64 ", %d) returned rval=%d errno=%d",
- handle, fd, rval, saved_errno);
- close(fd);
- return rval == 0 ? 0 : -saved_errno;
-}
-
-// Use sizeof("x") - 1 because we need a compile-time constant, and strlen("x")
-// isn't guaranteed to fold to a constant.
-static const int kSockaddrStrLen = INET6_ADDRSTRLEN + sizeof("[]:65535") - 1;
-
-void sockaddr_ntop(const struct sockaddr *sa, socklen_t salen, char *dst, const size_t size) {
- char addrstr[INET6_ADDRSTRLEN];
- char portstr[sizeof("65535")];
- char buf[kSockaddrStrLen+1];
-
- int ret = getnameinfo(sa, salen,
- addrstr, sizeof(addrstr),
- portstr, sizeof(portstr),
- NI_NUMERICHOST | NI_NUMERICSERV);
- if (ret == 0) {
- snprintf(buf, sizeof(buf),
- (sa->sa_family == AF_INET6) ? "[%s]:%s" : "%s:%s",
- addrstr, portstr);
- } else {
- sprintf(buf, "???");
- }
-
- strlcpy(dst, buf, size);
-}
-
-extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck(
- JNIEnv*, jclass, jlong nethandle) {
- const struct addrinfo kHints = {
- .ai_flags = AI_ADDRCONFIG,
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_DGRAM,
- .ai_protocol = IPPROTO_UDP,
- };
- struct addrinfo *res = NULL;
- net_handle_t handle = (net_handle_t) nethandle;
-
- static const char kPort[] = "443";
- int rval = android_getaddrinfofornetwork(handle, kHostname, kPort, &kHints, &res);
- if (rval != 0) {
- LOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d",
- handle, kHostname, rval, errno);
- freeaddrinfo(res);
- return -errno;
- }
-
- // Rely upon getaddrinfo sorting the best destination to the front.
- int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
- if (fd < 0) {
- LOGD("socket(%d, %d, %d) failed, errno=%d",
- res->ai_family, res->ai_socktype, res->ai_protocol, errno);
- freeaddrinfo(res);
- return -errno;
- }
-
- rval = android_setsocknetwork(handle, fd);
- LOGD("android_setprocnetwork(%llu, %d) returned rval=%d errno=%d",
- handle, fd, rval, errno);
- if (rval != 0) {
- close(fd);
- freeaddrinfo(res);
- return -errno;
- }
-
- char addrstr[kSockaddrStrLen+1];
- sockaddr_ntop(res->ai_addr, res->ai_addrlen, addrstr, sizeof(addrstr));
- LOGD("Attempting connect() to %s ...", addrstr);
-
- rval = connect(fd, res->ai_addr, res->ai_addrlen);
- if (rval != 0) {
- close(fd);
- freeaddrinfo(res);
- return -errno;
- }
- freeaddrinfo(res);
-
- struct sockaddr_storage src_addr;
- socklen_t src_addrlen = sizeof(src_addr);
- if (getsockname(fd, (struct sockaddr *)&src_addr, &src_addrlen) != 0) {
- close(fd);
- return -errno;
- }
- sockaddr_ntop((const struct sockaddr *)&src_addr, sizeof(src_addr), addrstr, sizeof(addrstr));
- LOGD("... from %s", addrstr);
-
- // Don't let reads or writes block indefinitely.
- const struct timeval timeo = { 2, 0 }; // 2 seconds
- setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
- setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo));
-
- // For reference see:
- // https://datatracker.ietf.org/doc/html/draft-ietf-quic-invariants
- uint8_t quic_packet[1200] = {
- 0xc0, // long header
- 0xaa, 0xda, 0xca, 0xca, // reserved-space version number
- 0x08, // destination connection ID length
- 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID
- 0x00, // source connection ID length
- };
-
- arc4random_buf(quic_packet + 6, 8); // random connection ID
-
- uint8_t response[1500];
- ssize_t sent, rcvd;
- static const int MAX_RETRIES = 5;
- int i, errnum = 0;
-
- for (i = 0; i < MAX_RETRIES; i++) {
- sent = send(fd, quic_packet, sizeof(quic_packet), 0);
- if (sent < (ssize_t)sizeof(quic_packet)) {
- errnum = errno;
- LOGD("send(QUIC packet) returned sent=%zd, errno=%d", sent, errnum);
- close(fd);
- return -errnum;
- }
-
- rcvd = recv(fd, response, sizeof(response), 0);
- if (rcvd > 0) {
- break;
- } else {
- errnum = errno;
- LOGD("[%d/%d] recv(QUIC response) returned rcvd=%zd, errno=%d",
- i + 1, MAX_RETRIES, rcvd, errnum);
- }
- }
- if (rcvd < 15) {
- LOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum);
- if (rcvd <= 0) {
- LOGD("Does this network block UDP port %s?", kPort);
- }
- close(fd);
- return -EPROTO;
- }
-
- int conn_id_cmp = memcmp(quic_packet + 6, response + 7, 8);
- if (conn_id_cmp != 0) {
- LOGD("sent and received connection IDs do not match");
- close(fd);
- return -EPROTO;
- }
-
- // TODO: Replace this quick 'n' dirty test with proper QUIC-capable code.
-
- close(fd);
- return 0;
-}
diff --git a/tests/tests/net/native/dns/Android.bp b/tests/tests/net/native/dns/Android.bp
deleted file mode 100644
index 1704a2b..0000000
--- a/tests/tests/net/native/dns/Android.bp
+++ /dev/null
@@ -1,40 +0,0 @@
-cc_defaults {
- name: "dns_async_defaults",
-
- cflags: [
- "-fstack-protector-all",
- "-g",
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wnullable-to-nonnull-conversion",
- "-Wsign-compare",
- "-Wthread-safety",
- "-Wunused-parameter",
- ],
- srcs: [
- "NativeDnsAsyncTest.cpp",
- ],
- shared_libs: [
- "libandroid",
- "liblog",
- "libutils",
- ],
-}
-
-cc_test {
- name: "CtsNativeNetDnsTestCases",
- defaults: ["dns_async_defaults"],
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
- test_suites: [
- "cts",
- "mts",
- ],
-}
diff --git a/tests/tests/net/native/dns/AndroidTest.xml b/tests/tests/net/native/dns/AndroidTest.xml
deleted file mode 100644
index 6d03c23..0000000
--- a/tests/tests/net/native/dns/AndroidTest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for CTS Native Network dns test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="networking" />
- <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="cleanup" value="true" />
- <option name="push" value="CtsNativeNetDnsTestCases->/data/local/tmp/CtsNativeNetDnsTestCases" />
- <option name="append-bitness" value="true" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="CtsNativeNetDnsTestCases" />
- <option name="runtime-hint" value="1m" />
- </test>
-</configuration>
diff --git a/tests/tests/net/native/dns/NativeDnsAsyncTest.cpp b/tests/tests/net/native/dns/NativeDnsAsyncTest.cpp
deleted file mode 100644
index e501475..0000000
--- a/tests/tests/net/native/dns/NativeDnsAsyncTest.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#include <error.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <netinet/in.h>
-#include <poll.h> /* poll */
-#include <resolv.h>
-#include <string.h>
-#include <sys/socket.h>
-
-#include <android/multinetwork.h>
-#include <gtest/gtest.h>
-
-namespace {
-constexpr int MAXPACKET = 8 * 1024;
-constexpr int PTON_MAX = 16;
-constexpr int TIMEOUT_MS = 10000;
-
-int getAsyncResponse(int fd, int timeoutMs, int* rcode, uint8_t* buf, size_t bufLen) {
- struct pollfd wait_fd[1];
- wait_fd[0].fd = fd;
- wait_fd[0].events = POLLIN;
- short revents;
- int ret;
- ret = poll(wait_fd, 1, timeoutMs);
- revents = wait_fd[0].revents;
- if (revents & POLLIN) {
- int n = android_res_nresult(fd, rcode, buf, bufLen);
- // Verify that android_res_nresult() closed the fd
- char dummy;
- EXPECT_EQ(-1, read(fd, &dummy, sizeof dummy));
- EXPECT_EQ(EBADF, errno);
- return n;
- }
-
- return -1;
-}
-
-std::vector<std::string> extractIpAddressAnswers(uint8_t* buf, size_t bufLen, int ipType) {
- ns_msg handle;
- if (ns_initparse((const uint8_t*) buf, bufLen, &handle) < 0) {
- return {};
- }
- const int ancount = ns_msg_count(handle, ns_s_an);
- ns_rr rr;
- std::vector<std::string> answers;
- for (int i = 0; i < ancount; i++) {
- if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) {
- continue;
- }
- const uint8_t* rdata = ns_rr_rdata(rr);
- char buffer[INET6_ADDRSTRLEN];
- if (inet_ntop(ipType, (const char*) rdata, buffer, sizeof(buffer))) {
- answers.push_back(buffer);
- }
- }
- return answers;
-}
-
-void expectAnswersValid(int fd, int ipType, int expectedRcode) {
- int rcode = -1;
- uint8_t buf[MAXPACKET] = {};
- int res = getAsyncResponse(fd, TIMEOUT_MS, &rcode, buf, MAXPACKET);
- EXPECT_GE(res, 0);
- EXPECT_EQ(rcode, expectedRcode);
-
- if (expectedRcode == ns_r_noerror) {
- auto answers = extractIpAddressAnswers(buf, res, ipType);
- EXPECT_GE(answers.size(), 0U);
- for (auto &answer : answers) {
- char pton[PTON_MAX];
- EXPECT_EQ(1, inet_pton(ipType, answer.c_str(), pton));
- }
- }
-}
-
-void expectAnswersNotValid(int fd, int expectedErrno) {
- int rcode = -1;
- uint8_t buf[MAXPACKET] = {};
- int res = getAsyncResponse(fd, TIMEOUT_MS, &rcode, buf, MAXPACKET);
- EXPECT_EQ(expectedErrno, res);
-}
-
-} // namespace
-
-TEST (NativeDnsAsyncTest, Async_Query) {
- // V4
- int fd1 = android_res_nquery(
- NETWORK_UNSPECIFIED, "www.google.com", ns_c_in, ns_t_a, 0);
- EXPECT_GE(fd1, 0);
- int fd2 = android_res_nquery(
- NETWORK_UNSPECIFIED, "www.youtube.com", ns_c_in, ns_t_a, 0);
- EXPECT_GE(fd2, 0);
- expectAnswersValid(fd2, AF_INET, ns_r_noerror);
- expectAnswersValid(fd1, AF_INET, ns_r_noerror);
-
- // V6
- fd1 = android_res_nquery(
- NETWORK_UNSPECIFIED, "www.google.com", ns_c_in, ns_t_aaaa, 0);
- EXPECT_GE(fd1, 0);
- fd2 = android_res_nquery(
- NETWORK_UNSPECIFIED, "www.youtube.com", ns_c_in, ns_t_aaaa, 0);
- EXPECT_GE(fd2, 0);
- expectAnswersValid(fd2, AF_INET6, ns_r_noerror);
- expectAnswersValid(fd1, AF_INET6, ns_r_noerror);
-}
-
-TEST (NativeDnsAsyncTest, Async_Send) {
- // V4
- uint8_t buf1[MAXPACKET] = {};
- int len1 = res_mkquery(ns_o_query, "www.googleapis.com",
- ns_c_in, ns_t_a, nullptr, 0, nullptr, buf1, sizeof(buf1));
- EXPECT_GT(len1, 0);
-
- uint8_t buf2[MAXPACKET] = {};
- int len2 = res_mkquery(ns_o_query, "play.googleapis.com",
- ns_c_in, ns_t_a, nullptr, 0, nullptr, buf2, sizeof(buf2));
- EXPECT_GT(len2, 0);
-
- int fd1 = android_res_nsend(NETWORK_UNSPECIFIED, buf1, len1, 0);
- EXPECT_GE(fd1, 0);
- int fd2 = android_res_nsend(NETWORK_UNSPECIFIED, buf2, len2, 0);
- EXPECT_GE(fd2, 0);
-
- expectAnswersValid(fd2, AF_INET, ns_r_noerror);
- expectAnswersValid(fd1, AF_INET, ns_r_noerror);
-
- // V6
- memset(buf1, 0, sizeof(buf1));
- memset(buf2, 0, sizeof(buf2));
- len1 = res_mkquery(ns_o_query, "www.googleapis.com",
- ns_c_in, ns_t_aaaa, nullptr, 0, nullptr, buf1, sizeof(buf1));
- EXPECT_GT(len1, 0);
- len2 = res_mkquery(ns_o_query, "play.googleapis.com",
- ns_c_in, ns_t_aaaa, nullptr, 0, nullptr, buf2, sizeof(buf2));
- EXPECT_GT(len2, 0);
-
- fd1 = android_res_nsend(NETWORK_UNSPECIFIED, buf1, len1, 0);
- EXPECT_GE(fd1, 0);
- fd2 = android_res_nsend(NETWORK_UNSPECIFIED, buf2, len2, 0);
- EXPECT_GE(fd2, 0);
-
- expectAnswersValid(fd2, AF_INET6, ns_r_noerror);
- expectAnswersValid(fd1, AF_INET6, ns_r_noerror);
-}
-
-TEST (NativeDnsAsyncTest, Async_NXDOMAIN) {
- uint8_t buf[MAXPACKET] = {};
- int len = res_mkquery(ns_o_query, "test1-nx.metric.gstatic.com",
- ns_c_in, ns_t_a, nullptr, 0, nullptr, buf, sizeof(buf));
- EXPECT_GT(len, 0);
- int fd1 = android_res_nsend(NETWORK_UNSPECIFIED, buf, len, ANDROID_RESOLV_NO_CACHE_LOOKUP);
- EXPECT_GE(fd1, 0);
-
- len = res_mkquery(ns_o_query, "test2-nx.metric.gstatic.com",
- ns_c_in, ns_t_a, nullptr, 0, nullptr, buf, sizeof(buf));
- EXPECT_GT(len, 0);
- int fd2 = android_res_nsend(NETWORK_UNSPECIFIED, buf, len, ANDROID_RESOLV_NO_CACHE_LOOKUP);
- EXPECT_GE(fd2, 0);
-
- expectAnswersValid(fd2, AF_INET, ns_r_nxdomain);
- expectAnswersValid(fd1, AF_INET, ns_r_nxdomain);
-
- fd1 = android_res_nquery(
- NETWORK_UNSPECIFIED, "test3-nx.metric.gstatic.com",
- ns_c_in, ns_t_aaaa, ANDROID_RESOLV_NO_CACHE_LOOKUP);
- EXPECT_GE(fd1, 0);
- fd2 = android_res_nquery(
- NETWORK_UNSPECIFIED, "test4-nx.metric.gstatic.com",
- ns_c_in, ns_t_aaaa, ANDROID_RESOLV_NO_CACHE_LOOKUP);
- EXPECT_GE(fd2, 0);
- expectAnswersValid(fd2, AF_INET6, ns_r_nxdomain);
- expectAnswersValid(fd1, AF_INET6, ns_r_nxdomain);
-}
-
-TEST (NativeDnsAsyncTest, Async_Cancel) {
- int fd = android_res_nquery(
- NETWORK_UNSPECIFIED, "www.google.com", ns_c_in, ns_t_a, 0);
- errno = 0;
- android_res_cancel(fd);
- int err = errno;
- EXPECT_EQ(err, 0);
- // DO NOT call cancel or result with the same fd more than once,
- // otherwise it will hit fdsan double-close fd.
-}
-
-TEST (NativeDnsAsyncTest, Async_Query_MALFORMED) {
- // Empty string to create BLOB and query, we will get empty result and rcode = 0
- // on DNSTLS.
- int fd = android_res_nquery(
- NETWORK_UNSPECIFIED, "", ns_c_in, ns_t_a, 0);
- EXPECT_GE(fd, 0);
- expectAnswersValid(fd, AF_INET, ns_r_noerror);
-
- std::string exceedingLabelQuery = "www." + std::string(70, 'g') + ".com";
- std::string exceedingDomainQuery = "www." + std::string(255, 'g') + ".com";
-
- fd = android_res_nquery(NETWORK_UNSPECIFIED,
- exceedingLabelQuery.c_str(), ns_c_in, ns_t_a, 0);
- EXPECT_EQ(-EMSGSIZE, fd);
- fd = android_res_nquery(NETWORK_UNSPECIFIED,
- exceedingDomainQuery.c_str(), ns_c_in, ns_t_a, 0);
- EXPECT_EQ(-EMSGSIZE, fd);
-}
-
-TEST (NativeDnsAsyncTest, Async_Send_MALFORMED) {
- uint8_t buf[10] = {};
- // empty BLOB
- int fd = android_res_nsend(NETWORK_UNSPECIFIED, buf, 10, 0);
- EXPECT_GE(fd, 0);
- expectAnswersNotValid(fd, -EINVAL);
-
- std::vector<uint8_t> largeBuf(2 * MAXPACKET, 0);
- // A buffer larger than 8KB
- fd = android_res_nsend(
- NETWORK_UNSPECIFIED, largeBuf.data(), largeBuf.size(), 0);
- EXPECT_EQ(-EMSGSIZE, fd);
-
- // 5000 bytes filled with 0. This returns EMSGSIZE because FrameworkListener limits the size of
- // commands to 4096 bytes.
- fd = android_res_nsend(NETWORK_UNSPECIFIED, largeBuf.data(), 5000, 0);
- EXPECT_EQ(-EMSGSIZE, fd);
-
- // 500 bytes filled with 0
- fd = android_res_nsend(NETWORK_UNSPECIFIED, largeBuf.data(), 500, 0);
- EXPECT_GE(fd, 0);
- expectAnswersNotValid(fd, -EINVAL);
-
- // 5000 bytes filled with 0xFF
- std::vector<uint8_t> ffBuf(5000, 0xFF);
- fd = android_res_nsend(
- NETWORK_UNSPECIFIED, ffBuf.data(), ffBuf.size(), 0);
- EXPECT_EQ(-EMSGSIZE, fd);
-
- // 500 bytes filled with 0xFF
- fd = android_res_nsend(NETWORK_UNSPECIFIED, ffBuf.data(), 500, 0);
- EXPECT_GE(fd, 0);
- expectAnswersNotValid(fd, -EINVAL);
-}
diff --git a/tests/tests/net/native/qtaguid/Android.bp b/tests/tests/net/native/qtaguid/Android.bp
deleted file mode 100644
index 23a0cf7..0000000
--- a/tests/tests/net/native/qtaguid/Android.bp
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Build the unit tests.
-
-cc_test {
- name: "CtsNativeNetTestCases",
-
- compile_multilib: "both",
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
-
- srcs: ["src/NativeQtaguidTest.cpp"],
-
- shared_libs: [
- "libutils",
- "liblog",
- ],
-
- static_libs: [
- "libgtest",
- "libqtaguid",
- ],
-
- // Tag this module as a cts test artifact
- test_suites: [
- "cts",
- "vts10",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- ],
-
-}
diff --git a/tests/tests/net/native/qtaguid/AndroidTest.xml b/tests/tests/net/native/qtaguid/AndroidTest.xml
deleted file mode 100644
index fa4b2cf..0000000
--- a/tests/tests/net/native/qtaguid/AndroidTest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for CTS Native Network xt_qtaguid test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="networking" />
- <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="cleanup" value="true" />
- <option name="push" value="CtsNativeNetTestCases->/data/local/tmp/CtsNativeNetTestCases" />
- <option name="append-bitness" value="true" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="CtsNativeNetTestCases" />
- <option name="runtime-hint" value="1m" />
- </test>
-</configuration>
diff --git a/tests/tests/net/native/qtaguid/src/NativeQtaguidTest.cpp b/tests/tests/net/native/qtaguid/src/NativeQtaguidTest.cpp
deleted file mode 100644
index 7dc6240..0000000
--- a/tests/tests/net/native/qtaguid/src/NativeQtaguidTest.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <arpa/inet.h>
-#include <error.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/socket.h>
-
-#include <gtest/gtest.h>
-#include <qtaguid/qtaguid.h>
-
-int canAccessQtaguidFile() {
- int fd = open("/proc/net/xt_qtaguid/ctrl", O_RDONLY | O_CLOEXEC);
- close(fd);
- return fd != -1;
-}
-
-#define SKIP_IF_QTAGUID_NOT_SUPPORTED() \
- do { \
- int res = canAccessQtaguidFile(); \
- ASSERT_LE(0, res); \
- if (!res) { \
- GTEST_LOG_(INFO) << "This test is skipped since kernel may not have the module\n"; \
- return; \
- } \
- } while (0)
-
-int getCtrlSkInfo(int tag, uid_t uid, uint64_t* sk_addr, int* ref_cnt) {
- FILE *fp;
- fp = fopen("/proc/net/xt_qtaguid/ctrl", "r");
- if (!fp)
- return -ENOENT;
- uint64_t full_tag = (uint64_t)tag << 32 | uid;
- char pattern[40];
- snprintf(pattern, sizeof(pattern), " tag=0x%" PRIx64 " (uid=%" PRIu32 ")", full_tag, uid);
-
- size_t len;
- char *line_buffer = NULL;
- while(getline(&line_buffer, &len, fp) != -1) {
- if (strstr(line_buffer, pattern) == NULL)
- continue;
- int res;
- pid_t dummy_pid;
- uint64_t k_tag;
- uint32_t k_uid;
- const int TOTAL_PARAM = 5;
- res = sscanf(line_buffer, "sock=%" PRIx64 " tag=0x%" PRIx64 " (uid=%" PRIu32 ") "
- "pid=%u f_count=%u", sk_addr, &k_tag, &k_uid,
- &dummy_pid, ref_cnt);
- if (!(res == TOTAL_PARAM && k_tag == full_tag && k_uid == uid))
- return -EINVAL;
- free(line_buffer);
- return 0;
- }
- free(line_buffer);
- return -ENOENT;
-}
-
-void checkNoSocketPointerLeaks(int family) {
- int sockfd = socket(family, SOCK_STREAM, 0);
- uid_t uid = getuid();
- int tag = arc4random();
- int ref_cnt;
- uint64_t sk_addr;
- uint64_t expect_addr = 0;
-
- EXPECT_EQ(0, legacy_tagSocket(sockfd, tag, uid));
- EXPECT_EQ(0, getCtrlSkInfo(tag, uid, &sk_addr, &ref_cnt));
- EXPECT_EQ(expect_addr, sk_addr);
- close(sockfd);
- EXPECT_EQ(-ENOENT, getCtrlSkInfo(tag, uid, &sk_addr, &ref_cnt));
-}
-
-TEST (NativeQtaguidTest, close_socket_without_untag) {
- SKIP_IF_QTAGUID_NOT_SUPPORTED();
-
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
- uid_t uid = getuid();
- int tag = arc4random();
- int ref_cnt;
- uint64_t dummy_sk;
- EXPECT_EQ(0, legacy_tagSocket(sockfd, tag, uid));
- EXPECT_EQ(0, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt));
- EXPECT_EQ(2, ref_cnt);
- close(sockfd);
- EXPECT_EQ(-ENOENT, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt));
-}
-
-TEST (NativeQtaguidTest, close_socket_without_untag_ipv6) {
- SKIP_IF_QTAGUID_NOT_SUPPORTED();
-
- int sockfd = socket(AF_INET6, SOCK_STREAM, 0);
- uid_t uid = getuid();
- int tag = arc4random();
- int ref_cnt;
- uint64_t dummy_sk;
- EXPECT_EQ(0, legacy_tagSocket(sockfd, tag, uid));
- EXPECT_EQ(0, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt));
- EXPECT_EQ(2, ref_cnt);
- close(sockfd);
- EXPECT_EQ(-ENOENT, getCtrlSkInfo(tag, uid, &dummy_sk, &ref_cnt));
-}
-
-TEST (NativeQtaguidTest, no_socket_addr_leak) {
- SKIP_IF_QTAGUID_NOT_SUPPORTED();
-
- checkNoSocketPointerLeaks(AF_INET);
- checkNoSocketPointerLeaks(AF_INET6);
-}
-
-int main(int argc, char **argv) {
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/tests/tests/net/src/android/net/cts/AirplaneModeTest.java b/tests/tests/net/src/android/net/cts/AirplaneModeTest.java
deleted file mode 100644
index 524e549..0000000
--- a/tests/tests/net/src/android/net/cts/AirplaneModeTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.platform.test.annotations.AppModeFull;
-import android.provider.Settings;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.lang.Thread;
-
-@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
-public class AirplaneModeTest extends AndroidTestCase {
- private static final String TAG = "AirplaneModeTest";
- private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
- private static final String FEATURE_WIFI = "android.hardware.wifi";
- private static final int TIMEOUT_MS = 10 * 1000;
- private boolean mHasFeature;
- private Context mContext;
- private ContentResolver resolver;
-
- public void setup() {
- mContext= getContext();
- resolver = mContext.getContentResolver();
- mHasFeature = (mContext.getPackageManager().hasSystemFeature(FEATURE_BLUETOOTH)
- || mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI));
- }
-
- public void testAirplaneMode() {
- setup();
- if (!mHasFeature) {
- Log.i(TAG, "The device doesn't support network bluetooth or wifi feature");
- return;
- }
-
- for (int testCount = 0; testCount < 2; testCount++) {
- if (!doOneTest()) {
- fail("Airplane mode failed to change in " + TIMEOUT_MS + "msec");
- return;
- }
- }
- }
-
- private boolean doOneTest() {
- boolean airplaneModeOn = isAirplaneModeOn();
- setAirplaneModeOn(!airplaneModeOn);
-
- try {
- Thread.sleep(TIMEOUT_MS);
- } catch (InterruptedException e) {
- Log.e(TAG, "Sleep time interrupted.", e);
- }
-
- if (airplaneModeOn == isAirplaneModeOn()) {
- return false;
- }
- return true;
- }
-
- private void setAirplaneModeOn(boolean enabling) {
- // Change the system setting for airplane mode
- Settings.Global.putInt(resolver, Settings.Global.AIRPLANE_MODE_ON, enabling ? 1 : 0);
- }
-
- private boolean isAirplaneModeOn() {
- // Read the system setting for airplane mode
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/CaptivePortalApiTest.kt b/tests/tests/net/src/android/net/cts/CaptivePortalApiTest.kt
deleted file mode 100644
index 99fcd4c..0000000
--- a/tests/tests/net/src/android/net/cts/CaptivePortalApiTest.kt
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts
-
-import android.Manifest.permission.MANAGE_TEST_NETWORKS
-import android.Manifest.permission.NETWORK_SETTINGS
-import android.content.Context
-import android.content.pm.PackageManager
-import android.net.ConnectivityManager
-import android.net.EthernetManager
-import android.net.InetAddresses
-import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
-import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
-import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
-import android.net.NetworkCapabilities.TRANSPORT_TEST
-import android.net.NetworkRequest
-import android.net.TestNetworkInterface
-import android.net.TestNetworkManager
-import android.net.Uri
-import android.net.dhcp.DhcpDiscoverPacket
-import android.net.dhcp.DhcpPacket
-import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE
-import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_DISCOVER
-import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_REQUEST
-import android.net.dhcp.DhcpRequestPacket
-import android.os.Build
-import android.os.HandlerThread
-import android.platform.test.annotations.AppModeFull
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.runner.AndroidJUnit4
-import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.android.compatibility.common.util.ThrowingRunnable
-import com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress
-import com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address
-import com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DhcpClientPacketFilter
-import com.android.testutils.DhcpOptionFilter
-import com.android.testutils.RecorderCallback.CallbackEntry
-import com.android.testutils.TapPacketReader
-import com.android.testutils.TestableNetworkCallback
-import fi.iki.elonen.NanoHTTPD
-import org.junit.After
-import org.junit.Assume.assumeFalse
-import org.junit.Assume.assumeTrue
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import java.net.Inet4Address
-import java.util.concurrent.ArrayBlockingQueue
-import java.util.concurrent.TimeUnit
-import kotlin.test.assertEquals
-import kotlin.test.assertNotNull
-import kotlin.test.assertTrue
-import kotlin.test.fail
-
-private const val MAX_PACKET_LENGTH = 1500
-private const val TEST_TIMEOUT_MS = 10_000L
-
-private const val TEST_LEASE_TIMEOUT_SECS = 3600 * 12
-private const val TEST_PREFIX_LENGTH = 24
-
-private const val TEST_LOGIN_URL = "https://login.capport.android.com"
-private const val TEST_VENUE_INFO_URL = "https://venueinfo.capport.android.com"
-private const val TEST_DOMAIN_NAME = "lan"
-private const val TEST_MTU = 1500.toShort()
-
-@AppModeFull(reason = "Instant apps cannot create test networks")
-@RunWith(AndroidJUnit4::class)
-class CaptivePortalApiTest {
- @JvmField
- @Rule
- val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q)
-
- private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
- private val tnm by lazy { context.assertHasService(TestNetworkManager::class.java) }
- private val eth by lazy { context.assertHasService(EthernetManager::class.java) }
- private val cm by lazy { context.assertHasService(ConnectivityManager::class.java) }
-
- private val handlerThread = HandlerThread(CaptivePortalApiTest::class.java.simpleName)
- private val serverIpAddr = InetAddresses.parseNumericAddress("192.0.2.222") as Inet4Address
- private val clientIpAddr = InetAddresses.parseNumericAddress("192.0.2.111") as Inet4Address
- private val httpServer = HttpServer()
- private val ethRequest = NetworkRequest.Builder()
- // ETHERNET|TEST transport networks do not have NET_CAPABILITY_TRUSTED
- .removeCapability(NET_CAPABILITY_TRUSTED)
- .addTransportType(TRANSPORT_ETHERNET)
- .addTransportType(TRANSPORT_TEST).build()
- private val ethRequestCb = TestableNetworkCallback()
-
- private lateinit var iface: TestNetworkInterface
- private lateinit var reader: TapPacketReader
- private lateinit var capportUrl: Uri
-
- private var testSkipped = false
-
- @Before
- fun setUp() {
- // This test requires using a tap interface as an ethernet interface.
- val pm = context.getPackageManager()
- testSkipped = !pm.hasSystemFeature(PackageManager.FEATURE_ETHERNET) &&
- context.getSystemService(EthernetManager::class.java) == null
- assumeFalse(testSkipped)
-
- // Register a request so the network does not get torn down
- cm.requestNetwork(ethRequest, ethRequestCb)
- runAsShell(NETWORK_SETTINGS, MANAGE_TEST_NETWORKS) {
- eth.setIncludeTestInterfaces(true)
- // Keeping a reference to the test interface also makes sure the ParcelFileDescriptor
- // does not go out of scope, which would cause it to close the underlying FileDescriptor
- // in its finalizer.
- iface = tnm.createTapInterface()
- }
-
- handlerThread.start()
- reader = TapPacketReader(
- handlerThread.threadHandler,
- iface.fileDescriptor.fileDescriptor,
- MAX_PACKET_LENGTH)
- handlerThread.threadHandler.post { reader.start() }
- httpServer.start()
-
- // Pad the listening port to make sure it is always of length 5. This ensures the URL has
- // always the same length so the test can use constant IP and UDP header lengths.
- // The maximum port number is 65535 so a length of 5 is always enough.
- capportUrl = Uri.parse("http://localhost:${httpServer.listeningPort}/testapi.html?par=val")
- }
-
- @After
- fun tearDown() {
- if (testSkipped) return
- cm.unregisterNetworkCallback(ethRequestCb)
-
- runAsShell(NETWORK_SETTINGS) { eth.setIncludeTestInterfaces(false) }
-
- httpServer.stop()
- handlerThread.threadHandler.post { reader.stop() }
- handlerThread.quitSafely()
-
- iface.fileDescriptor.close()
- }
-
- @Test
- fun testApiCallbacks() {
- // Handle the DHCP handshake that includes the capport API URL
- val discover = reader.assertDhcpPacketReceived(
- DhcpDiscoverPacket::class.java, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_DISCOVER)
- reader.sendResponse(makeOfferPacket(discover.clientMac, discover.transactionId))
-
- val request = reader.assertDhcpPacketReceived(
- DhcpRequestPacket::class.java, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_REQUEST)
- assertEquals(discover.transactionId, request.transactionId)
- assertEquals(clientIpAddr, request.mRequestedIp)
- reader.sendResponse(makeAckPacket(request.clientMac, request.transactionId))
-
- // Expect a request to the capport API
- val capportReq = httpServer.recordedRequests.poll(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS)
- assertNotNull(capportReq, "The device did not fetch captive portal API data within timeout")
- assertEquals(capportUrl.path, capportReq.uri)
- assertEquals(capportUrl.query, capportReq.queryParameterString)
-
- // Expect network callbacks with capport info
- val testCb = TestableNetworkCallback(TEST_TIMEOUT_MS)
- // LinkProperties do not contain captive portal info if the callback is registered without
- // NETWORK_SETTINGS permissions.
- val lp = runAsShell(NETWORK_SETTINGS) {
- cm.registerNetworkCallback(ethRequest, testCb)
-
- try {
- val ncCb = testCb.eventuallyExpect<CallbackEntry.CapabilitiesChanged> {
- it.caps.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)
- }
- testCb.eventuallyExpect<CallbackEntry.LinkPropertiesChanged> {
- it.network == ncCb.network && it.lp.captivePortalData != null
- }.lp
- } finally {
- cm.unregisterNetworkCallback(testCb)
- }
- }
-
- assertEquals(capportUrl, lp.captivePortalApiUrl)
- with(lp.captivePortalData) {
- assertNotNull(this)
- assertTrue(isCaptive)
- assertEquals(Uri.parse(TEST_LOGIN_URL), userPortalUrl)
- assertEquals(Uri.parse(TEST_VENUE_INFO_URL), venueInfoUrl)
- }
- }
-
- private fun makeOfferPacket(clientMac: ByteArray, transactionId: Int) =
- DhcpPacket.buildOfferPacket(DhcpPacket.ENCAP_L2, transactionId,
- false /* broadcast */, serverIpAddr, IPV4_ADDR_ANY /* relayIp */, clientIpAddr,
- clientMac, TEST_LEASE_TIMEOUT_SECS,
- getPrefixMaskAsInet4Address(TEST_PREFIX_LENGTH),
- getBroadcastAddress(clientIpAddr, TEST_PREFIX_LENGTH),
- listOf(serverIpAddr) /* gateways */, listOf(serverIpAddr) /* dnsServers */,
- serverIpAddr, TEST_DOMAIN_NAME, null /* hostname */, true /* metered */,
- TEST_MTU, capportUrl.toString())
-
- private fun makeAckPacket(clientMac: ByteArray, transactionId: Int) =
- DhcpPacket.buildAckPacket(DhcpPacket.ENCAP_L2, transactionId,
- false /* broadcast */, serverIpAddr, IPV4_ADDR_ANY /* relayIp */, clientIpAddr,
- clientIpAddr /* requestClientIp */, clientMac, TEST_LEASE_TIMEOUT_SECS,
- getPrefixMaskAsInet4Address(TEST_PREFIX_LENGTH),
- getBroadcastAddress(clientIpAddr, TEST_PREFIX_LENGTH),
- listOf(serverIpAddr) /* gateways */, listOf(serverIpAddr) /* dnsServers */,
- serverIpAddr, TEST_DOMAIN_NAME, null /* hostname */, true /* metered */,
- TEST_MTU, false /* rapidCommit */, capportUrl.toString())
-
- private fun parseDhcpPacket(bytes: ByteArray) = DhcpPacket.decodeFullPacket(
- bytes, MAX_PACKET_LENGTH, DhcpPacket.ENCAP_L2)
-}
-
-/**
- * A minimal HTTP server running on localhost (loopback), on a random available port.
- *
- * The server records each request in [recordedRequests] and will not serve any further request
- * until the last one is removed from the queue for verification.
- */
-private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) {
- val recordedRequests = ArrayBlockingQueue<IHTTPSession>(1 /* capacity */)
-
- override fun serve(session: IHTTPSession): Response {
- recordedRequests.offer(session)
- return newFixedLengthResponse("""
- |{
- | "captive": true,
- | "user-portal-url": "$TEST_LOGIN_URL",
- | "venue-info-url": "$TEST_VENUE_INFO_URL"
- |}
- """.trimMargin())
- }
-}
-
-private fun <T : DhcpPacket> TapPacketReader.assertDhcpPacketReceived(
- packetType: Class<T>,
- timeoutMs: Long,
- type: Byte
-): T {
- val packetBytes = popPacket(timeoutMs, DhcpClientPacketFilter()
- .and(DhcpOptionFilter(DHCP_MESSAGE_TYPE, type)))
- ?: fail("${packetType.simpleName} not received within timeout")
- val packet = DhcpPacket.decodeFullPacket(packetBytes, packetBytes.size, DhcpPacket.ENCAP_L2)
- assertTrue(packetType.isInstance(packet),
- "Expected ${packetType.simpleName} but got ${packet.javaClass.simpleName}")
- return packetType.cast(packet)
-}
-
-private fun <T> Context.assertHasService(manager: Class<T>): T {
- return getSystemService(manager) ?: fail("Service $manager not found")
-}
-
-/**
- * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax.
- */
-private fun <T> runAsShell(vararg permissions: String, task: () -> T): T {
- var ret: T? = null
- runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions)
- return ret ?: fail("ThrowingRunnable was not run")
-}
diff --git a/tests/tests/net/src/android/net/cts/CaptivePortalTest.kt b/tests/tests/net/src/android/net/cts/CaptivePortalTest.kt
deleted file mode 100644
index 4a7d38a..0000000
--- a/tests/tests/net/src/android/net/cts/CaptivePortalTest.kt
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-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
-import android.content.pm.PackageManager.FEATURE_TELEPHONY
-import android.content.pm.PackageManager.FEATURE_WIFI
-import android.net.ConnectivityManager
-import android.net.ConnectivityManager.NetworkCallback
-import android.net.Network
-import android.net.NetworkCapabilities
-import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
-import android.net.NetworkCapabilities.TRANSPORT_WIFI
-import android.net.NetworkRequest
-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
-import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY
-import android.text.TextUtils
-import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
-import androidx.test.runner.AndroidJUnit4
-import com.android.compatibility.common.util.SystemUtil
-import com.android.testutils.isDevSdkInRange
-import fi.iki.elonen.NanoHTTPD
-import fi.iki.elonen.NanoHTTPD.Response.IStatus
-import fi.iki.elonen.NanoHTTPD.Response.Status
-import junit.framework.AssertionFailedError
-import org.junit.After
-import org.junit.Assume.assumeTrue
-import org.junit.Before
-import org.junit.runner.RunWith
-import java.util.concurrent.CompletableFuture
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.TimeoutException
-import kotlin.test.Test
-import kotlin.test.assertNotEquals
-import kotlin.test.assertTrue
-
-private const val TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING = "test_captive_portal_https_url"
-private const val TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING = "test_captive_portal_http_url"
-private const val TEST_URL_EXPIRATION_TIME = "test_url_expiration_time"
-
-private const val TEST_HTTPS_URL_PATH = "https_path"
-private const val TEST_HTTP_URL_PATH = "http_path"
-private const val TEST_PORTAL_URL_PATH = "portal_path"
-
-private const val LOCALHOST_HOSTNAME = "localhost"
-
-// Re-connecting to the AP, obtaining an IP address, revalidating can take a long time
-private const val WIFI_CONNECT_TIMEOUT_MS = 120_000L
-private const val TEST_TIMEOUT_MS = 10_000L
-
-private fun <T> CompletableFuture<T>.assertGet(timeoutMs: Long, message: String): T {
- try {
- return get(timeoutMs, TimeUnit.MILLISECONDS)
- } catch (e: TimeoutException) {
- throw AssertionFailedError(message)
- }
-}
-
-@AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
-@RunWith(AndroidJUnit4::class)
-class CaptivePortalTest {
- private val context: android.content.Context by lazy { getInstrumentation().context }
- private val wm by lazy { context.getSystemService(WifiManager::class.java) }
- private val cm by lazy { context.getSystemService(ConnectivityManager::class.java) }
- private val pm by lazy { context.packageManager }
- private val utils by lazy { CtsNetUtils(context) }
-
- private val server = HttpServer()
-
- @Before
- fun setUp() {
- doAsShell(READ_DEVICE_CONFIG) {
- // Verify that the test URLs are not normally set on the device, but do not fail if the
- // test URLs are set to what this test uses (URLs on localhost), in case the test was
- // interrupted manually and rerun.
- assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING)
- assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING)
- }
- clearTestUrls()
- server.start()
- }
-
- @After
- fun tearDown() {
- clearTestUrls()
- if (pm.hasSystemFeature(FEATURE_WIFI)) {
- reconnectWifi()
- }
- server.stop()
- }
-
- private fun assertEmptyOrLocalhostUrl(urlKey: String) {
- val url = DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, urlKey)
- assertTrue(TextUtils.isEmpty(url) || LOCALHOST_HOSTNAME == Uri.parse(url).host,
- "$urlKey must not be set in production scenarios (current value: $url)")
- }
-
- private fun clearTestUrls() {
- setHttpsUrl(null)
- setHttpUrl(null)
- setUrlExpiration(null)
- }
-
- @Test
- fun testCaptivePortalIsNotDefaultNetwork() {
- assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY))
- assumeTrue(pm.hasSystemFeature(FEATURE_WIFI))
- utils.connectToWifi()
- utils.connectToCell()
-
- // Have network validation use a local server that serves a HTTPS error / HTTP redirect
- server.addResponse(TEST_PORTAL_URL_PATH, Status.OK,
- content = "Test captive portal content")
- server.addResponse(TEST_HTTPS_URL_PATH, Status.INTERNAL_ERROR)
- server.addResponse(TEST_HTTP_URL_PATH, Status.REDIRECT,
- locationHeader = server.makeUrl(TEST_PORTAL_URL_PATH))
- setHttpsUrl(server.makeUrl(TEST_HTTPS_URL_PATH))
- setHttpUrl(server.makeUrl(TEST_HTTP_URL_PATH))
- // URL expiration needs to be in the next 10 minutes
- setUrlExpiration(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(9))
-
- // Expect the portal content to be fetched at some point after detecting the portal.
- // Some implementations may fetch the URL before startCaptivePortalApp is called.
- val portalContentRequestCv = server.addExpectRequestCv(TEST_PORTAL_URL_PATH)
-
- // Wait for a captive portal to be detected on the network
- val wifiNetworkFuture = CompletableFuture<Network>()
- val wifiCb = object : NetworkCallback() {
- override fun onCapabilitiesChanged(
- network: Network,
- nc: NetworkCapabilities
- ) {
- if (nc.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) {
- wifiNetworkFuture.complete(network)
- }
- }
- }
- cm.requestNetwork(NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build(), wifiCb)
-
- try {
- reconnectWifi()
- val network = wifiNetworkFuture.assertGet(WIFI_CONNECT_TIMEOUT_MS,
- "Captive portal not detected after ${WIFI_CONNECT_TIMEOUT_MS}ms")
-
- val wifiDefaultMessage = "Wifi should not be the default network when a captive " +
- "portal was detected and another network (mobile data) can provide internet " +
- "access."
- assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage)
-
- val startPortalAppPermission =
- if (isDevSdkInRange(0, 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.")
-
- assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage)
- } finally {
- cm.unregisterNetworkCallback(wifiCb)
- server.stop()
- // disconnectFromCell should be called after connectToCell
- utils.disconnectFromCell()
- }
- }
-
- private fun setHttpsUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING, url)
- private fun setHttpUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING, url)
- private fun setUrlExpiration(timestamp: Long?) = setConfig(TEST_URL_EXPIRATION_TIME,
- timestamp?.toString())
-
- private fun setConfig(configKey: String, value: String?) {
- doAsShell(WRITE_DEVICE_CONFIG) {
- DeviceConfig.setProperty(
- NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */)
- }
- }
-
- private fun doAsShell(vararg permissions: String, action: () -> Unit) {
- // Wrap the below call to allow for more kotlin-like syntax
- SystemUtil.runWithShellPermissionIdentity(action, permissions)
- }
-
- private fun reconnectWifi() {
- utils.ensureWifiDisconnected(null /* wifiNetworkToCheck */)
- utils.ensureWifiConnected()
- }
-
- /**
- * A minimal HTTP server running on localhost (loopback), on a random available port.
- */
- private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) {
- // Map of URL path -> HTTP response code
- private val responses = HashMap<String, Response>()
-
- // Map of path -> CV to open as soon as a request to the path is received
- private val waitForRequestCv = HashMap<String, ConditionVariable>()
-
- /**
- * Create a URL string that, when fetched, will hit this server with the given URL [path].
- */
- fun makeUrl(path: String): String {
- return Uri.Builder()
- .scheme("http")
- .encodedAuthority("localhost:$listeningPort")
- .query(path)
- .build()
- .toString()
- }
-
- fun addResponse(
- path: String,
- statusCode: IStatus,
- locationHeader: String? = null,
- content: String = ""
- ) {
- val response = newFixedLengthResponse(statusCode, "text/plain", content)
- locationHeader?.let { response.addHeader("Location", it) }
- responses[path] = response
- }
-
- /**
- * Create a [ConditionVariable] that will open when a request to [path] is received.
- */
- fun addExpectRequestCv(path: String): ConditionVariable {
- return ConditionVariable().apply { waitForRequestCv[path] = this }
- }
-
- override fun serve(session: IHTTPSession): Response {
- waitForRequestCv[session.queryParameterString]?.open()
- return responses[session.queryParameterString]
- // Default response is a 404
- ?: super.serve(session)
- }
- }
-}
\ No newline at end of file
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
deleted file mode 100644
index bd56f4b..0000000
--- a/tests/tests/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
+++ /dev/null
@@ -1,576 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.NETWORK_VALIDATION_RESULT_VALID;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_TCP_METRICS;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
-import static android.net.ConnectivityDiagnosticsManager.persistableBundleEquals;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_TEST;
-import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
-
-import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
-import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-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.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityDiagnosticsManager;
-import android.net.ConnectivityManager;
-import android.net.LinkAddress;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.net.TestNetworkInterface;
-import android.net.TestNetworkManager;
-import android.os.Binder;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.PersistableBundle;
-import android.os.Process;
-import android.platform.test.annotations.AppModeFull;
-import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.Pair;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.internal.telephony.uicc.IccUtils;
-import com.android.internal.util.ArrayUtils;
-import com.android.testutils.ArrayTrackRecord;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-import com.android.testutils.DevSdkIgnoreRunner;
-import com.android.testutils.SkipPresubmit;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.security.MessageDigest;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-
-@RunWith(DevSdkIgnoreRunner.class)
-@IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q
-@AppModeFull(reason = "CHANGE_NETWORK_STATE, MANAGE_TEST_NETWORKS not grantable to instant apps")
-public class ConnectivityDiagnosticsManagerTest {
- private static final int CALLBACK_TIMEOUT_MILLIS = 5000;
- private static final int NO_CALLBACK_INVOKED_TIMEOUT = 500;
- private static final long TIMESTAMP = 123456789L;
- private static final int DNS_CONSECUTIVE_TIMEOUTS = 5;
- private static final int COLLECTION_PERIOD_MILLIS = 5000;
- private static final int FAIL_RATE_PERCENTAGE = 100;
- private static final int UNKNOWN_DETECTION_METHOD = 4;
- private static final int FILTERED_UNKNOWN_DETECTION_METHOD = 0;
- private static final int CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT = 5000;
- private static final int DELAY_FOR_ADMIN_UIDS_MILLIS = 2000;
-
- private static final Executor INLINE_EXECUTOR = x -> x.run();
-
- private static final NetworkRequest TEST_NETWORK_REQUEST =
- new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_TEST)
- .removeCapability(NET_CAPABILITY_TRUSTED)
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .build();
-
- private static final String SHA_256 = "SHA-256";
-
- private static final NetworkRequest CELLULAR_NETWORK_REQUEST =
- new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
-
- private static final IBinder BINDER = new Binder();
-
- private Context mContext;
- private ConnectivityManager mConnectivityManager;
- private ConnectivityDiagnosticsManager mCdm;
- private CarrierConfigManager mCarrierConfigManager;
- private PackageManager mPackageManager;
- private TelephonyManager mTelephonyManager;
-
- // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests
- // for it.
- private TestNetworkCallback mTestNetworkCallback;
- private Network mTestNetwork;
- private ParcelFileDescriptor mTestNetworkFD;
-
- private List<TestConnectivityDiagnosticsCallback> mRegisteredCallbacks;
-
- @Before
- public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getContext();
- mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
- mCdm = mContext.getSystemService(ConnectivityDiagnosticsManager.class);
- mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
- mPackageManager = mContext.getPackageManager();
- mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
-
- mTestNetworkCallback = new TestNetworkCallback();
- mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, mTestNetworkCallback);
-
- mRegisteredCallbacks = new ArrayList<>();
- }
-
- @After
- public void tearDown() throws Exception {
- mConnectivityManager.unregisterNetworkCallback(mTestNetworkCallback);
- if (mTestNetwork != null) {
- runWithShellPermissionIdentity(() -> {
- final TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class);
- tnm.teardownTestNetwork(mTestNetwork);
- });
- mTestNetwork = null;
- }
-
- if (mTestNetworkFD != null) {
- mTestNetworkFD.close();
- mTestNetworkFD = null;
- }
-
- for (TestConnectivityDiagnosticsCallback cb : mRegisteredCallbacks) {
- mCdm.unregisterConnectivityDiagnosticsCallback(cb);
- }
- }
-
- @Test
- public void testRegisterConnectivityDiagnosticsCallback() throws Exception {
- mTestNetworkFD = setUpTestNetwork().getFileDescriptor();
- mTestNetwork = mTestNetworkCallback.waitForAvailable();
-
- final TestConnectivityDiagnosticsCallback cb =
- createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST);
-
- final String interfaceName =
- mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName();
-
- cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName);
- cb.assertNoCallback();
- }
-
- @SkipPresubmit(reason = "Flaky: b/159718782; add to presubmit after fixing")
- @Test
- public void testRegisterCallbackWithCarrierPrivileges() throws Exception {
- assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY));
-
- final int subId = SubscriptionManager.getDefaultSubscriptionId();
- if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- fail("Need an active subscription. Please ensure that the device has working mobile"
- + " data.");
- }
-
- final CarrierConfigReceiver carrierConfigReceiver = new CarrierConfigReceiver(subId);
- mContext.registerReceiver(
- carrierConfigReceiver,
- new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
-
- final TestNetworkCallback testNetworkCallback = new TestNetworkCallback();
-
- try {
- doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable(
- subId, carrierConfigReceiver, testNetworkCallback);
- } finally {
- runWithShellPermissionIdentity(
- () -> mCarrierConfigManager.overrideConfig(subId, null),
- android.Manifest.permission.MODIFY_PHONE_STATE);
- mConnectivityManager.unregisterNetworkCallback(testNetworkCallback);
- mContext.unregisterReceiver(carrierConfigReceiver);
- }
- }
-
- private String getCertHashForThisPackage() throws Exception {
- final PackageInfo pkgInfo =
- mPackageManager.getPackageInfo(
- mContext.getOpPackageName(), PackageManager.GET_SIGNATURES);
- final MessageDigest md = MessageDigest.getInstance(SHA_256);
- final byte[] certHash = md.digest(pkgInfo.signatures[0].toByteArray());
- return IccUtils.bytesToHexString(certHash);
- }
-
- private void doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable(
- int subId,
- @NonNull CarrierConfigReceiver carrierConfigReceiver,
- @NonNull TestNetworkCallback testNetworkCallback)
- throws Exception {
- final PersistableBundle carrierConfigs = new PersistableBundle();
- carrierConfigs.putStringArray(
- CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY,
- new String[] {getCertHashForThisPackage()});
-
- runWithShellPermissionIdentity(
- () -> {
- mCarrierConfigManager.overrideConfig(subId, carrierConfigs);
- mCarrierConfigManager.notifyConfigChangedForSubId(subId);
- },
- android.Manifest.permission.MODIFY_PHONE_STATE);
-
- // TODO(b/157779832): This should use android.permission.CHANGE_NETWORK_STATE. However, the
- // shell does not have CHANGE_NETWORK_STATE, so use CONNECTIVITY_INTERNAL until the shell
- // permissions are updated.
- runWithShellPermissionIdentity(
- () -> mConnectivityManager.requestNetwork(
- CELLULAR_NETWORK_REQUEST, testNetworkCallback),
- android.Manifest.permission.CONNECTIVITY_INTERNAL);
-
- final Network network = testNetworkCallback.waitForAvailable();
- assertNotNull(network);
-
- assertTrue("Didn't receive broadcast for ACTION_CARRIER_CONFIG_CHANGED for subId=" + subId,
- carrierConfigReceiver.waitForCarrierConfigChanged());
- assertTrue("Don't have Carrier Privileges after adding cert for this package",
- mTelephonyManager.createForSubscriptionId(subId).hasCarrierPrivileges());
-
- // Wait for CarrierPrivilegesTracker to receive the ACTION_CARRIER_CONFIG_CHANGED
- // broadcast. CPT then needs to update the corresponding DataConnection, which then
- // updates ConnectivityService. Unfortunately, this update to the NetworkCapabilities in
- // CS does not trigger NetworkCallback#onCapabilitiesChanged as changing the
- // administratorUids is not a publicly visible change. In lieu of a better signal to
- // detministically wait for, use Thread#sleep here.
- // TODO(b/157949581): replace this Thread#sleep with a deterministic signal
- Thread.sleep(DELAY_FOR_ADMIN_UIDS_MILLIS);
-
- final TestConnectivityDiagnosticsCallback connDiagsCallback =
- createAndRegisterConnectivityDiagnosticsCallback(CELLULAR_NETWORK_REQUEST);
-
- final String interfaceName =
- mConnectivityManager.getLinkProperties(network).getInterfaceName();
- connDiagsCallback.expectOnConnectivityReportAvailable(
- network, interfaceName, TRANSPORT_CELLULAR);
- connDiagsCallback.assertNoCallback();
- }
-
- @Test
- public void testRegisterDuplicateConnectivityDiagnosticsCallback() {
- final TestConnectivityDiagnosticsCallback cb =
- createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST);
-
- try {
- mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb);
- fail("Registering the same callback twice should throw an IllegalArgumentException");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testUnregisterConnectivityDiagnosticsCallback() {
- final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback();
- mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb);
- mCdm.unregisterConnectivityDiagnosticsCallback(cb);
- }
-
- @Test
- public void testUnregisterUnknownConnectivityDiagnosticsCallback() {
- // Expected to silently ignore the unregister() call
- mCdm.unregisterConnectivityDiagnosticsCallback(new TestConnectivityDiagnosticsCallback());
- }
-
- @Test
- public void testOnConnectivityReportAvailable() throws Exception {
- final TestConnectivityDiagnosticsCallback cb =
- createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST);
-
- mTestNetworkFD = setUpTestNetwork().getFileDescriptor();
- mTestNetwork = mTestNetworkCallback.waitForAvailable();
-
- final String interfaceName =
- mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName();
-
- cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName);
- cb.assertNoCallback();
- }
-
- @Test
- public void testOnDataStallSuspected_DnsEvents() throws Exception {
- final PersistableBundle extras = new PersistableBundle();
- extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, DNS_CONSECUTIVE_TIMEOUTS);
-
- verifyOnDataStallSuspected(DETECTION_METHOD_DNS_EVENTS, TIMESTAMP, extras);
- }
-
- @Test
- public void testOnDataStallSuspected_TcpMetrics() throws Exception {
- final PersistableBundle extras = new PersistableBundle();
- extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS, COLLECTION_PERIOD_MILLIS);
- extras.putInt(KEY_TCP_PACKET_FAIL_RATE, FAIL_RATE_PERCENTAGE);
-
- verifyOnDataStallSuspected(DETECTION_METHOD_TCP_METRICS, TIMESTAMP, extras);
- }
-
- @Test
- public void testOnDataStallSuspected_UnknownDetectionMethod() throws Exception {
- verifyOnDataStallSuspected(
- UNKNOWN_DETECTION_METHOD,
- FILTERED_UNKNOWN_DETECTION_METHOD,
- TIMESTAMP,
- PersistableBundle.EMPTY);
- }
-
- private void verifyOnDataStallSuspected(
- int detectionMethod, long timestampMillis, @NonNull PersistableBundle extras)
- throws Exception {
- // Input detection method is expected to match received detection method
- verifyOnDataStallSuspected(detectionMethod, detectionMethod, timestampMillis, extras);
- }
-
- private void verifyOnDataStallSuspected(
- int inputDetectionMethod,
- int expectedDetectionMethod,
- long timestampMillis,
- @NonNull PersistableBundle extras)
- throws Exception {
- mTestNetworkFD = setUpTestNetwork().getFileDescriptor();
- mTestNetwork = mTestNetworkCallback.waitForAvailable();
-
- final TestConnectivityDiagnosticsCallback cb =
- createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST);
-
- final String interfaceName =
- mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName();
-
- cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName);
-
- runWithShellPermissionIdentity(
- () -> mConnectivityManager.simulateDataStall(
- inputDetectionMethod, timestampMillis, mTestNetwork, extras),
- android.Manifest.permission.MANAGE_TEST_NETWORKS);
-
- cb.expectOnDataStallSuspected(
- mTestNetwork, interfaceName, expectedDetectionMethod, timestampMillis, extras);
- cb.assertNoCallback();
- }
-
- @Test
- public void testOnNetworkConnectivityReportedTrue() throws Exception {
- verifyOnNetworkConnectivityReported(true /* hasConnectivity */);
- }
-
- @Test
- public void testOnNetworkConnectivityReportedFalse() throws Exception {
- verifyOnNetworkConnectivityReported(false /* hasConnectivity */);
- }
-
- private void verifyOnNetworkConnectivityReported(boolean hasConnectivity) throws Exception {
- mTestNetworkFD = setUpTestNetwork().getFileDescriptor();
- mTestNetwork = mTestNetworkCallback.waitForAvailable();
-
- final TestConnectivityDiagnosticsCallback cb =
- createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST);
-
- // onConnectivityReportAvailable always invoked when the test network is established
- final String interfaceName =
- mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName();
- cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName);
- cb.assertNoCallback();
-
- mConnectivityManager.reportNetworkConnectivity(mTestNetwork, hasConnectivity);
-
- cb.expectOnNetworkConnectivityReported(mTestNetwork, hasConnectivity);
-
- // if hasConnectivity does not match the network's known connectivity, it will be
- // revalidated which will trigger another onConnectivityReportAvailable callback.
- if (!hasConnectivity) {
- cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName);
- }
-
- cb.assertNoCallback();
- }
-
- private TestConnectivityDiagnosticsCallback createAndRegisterConnectivityDiagnosticsCallback(
- NetworkRequest request) {
- final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback();
- mCdm.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, cb);
- mRegisteredCallbacks.add(cb);
- return cb;
- }
-
- /**
- * Registers a test NetworkAgent with ConnectivityService with limited capabilities, which leads
- * to the Network being validated.
- */
- @NonNull
- private TestNetworkInterface setUpTestNetwork() throws Exception {
- final int[] administratorUids = new int[] {Process.myUid()};
- return callWithShellPermissionIdentity(
- () -> {
- final TestNetworkManager tnm =
- mContext.getSystemService(TestNetworkManager.class);
- final TestNetworkInterface tni = tnm.createTunInterface(new LinkAddress[0]);
- tnm.setupTestNetwork(tni.getInterfaceName(), administratorUids, BINDER);
- return tni;
- });
- }
-
- private static class TestConnectivityDiagnosticsCallback
- extends ConnectivityDiagnosticsCallback {
- private final ArrayTrackRecord<Object>.ReadHead mHistory =
- new ArrayTrackRecord<Object>().newReadHead();
-
- @Override
- public void onConnectivityReportAvailable(ConnectivityReport report) {
- mHistory.add(report);
- }
-
- @Override
- public void onDataStallSuspected(DataStallReport report) {
- mHistory.add(report);
- }
-
- @Override
- public void onNetworkConnectivityReported(Network network, boolean hasConnectivity) {
- mHistory.add(new Pair<Network, Boolean>(network, hasConnectivity));
- }
-
- public void expectOnConnectivityReportAvailable(
- @NonNull Network network, @NonNull String interfaceName) {
- expectOnConnectivityReportAvailable(network, interfaceName, TRANSPORT_TEST);
- }
-
- public void expectOnConnectivityReportAvailable(
- @NonNull Network network, @NonNull String interfaceName, int transportType) {
- final ConnectivityReport result =
- (ConnectivityReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true);
- assertEquals(network, result.getNetwork());
-
- final NetworkCapabilities nc = result.getNetworkCapabilities();
- assertNotNull(nc);
- assertTrue(nc.hasTransport(transportType));
- assertNotNull(result.getLinkProperties());
- assertEquals(interfaceName, result.getLinkProperties().getInterfaceName());
-
- final PersistableBundle extras = result.getAdditionalInfo();
- assertTrue(extras.containsKey(KEY_NETWORK_VALIDATION_RESULT));
- final int validationResult = extras.getInt(KEY_NETWORK_VALIDATION_RESULT);
- assertEquals("Network validation result is not 'valid'",
- NETWORK_VALIDATION_RESULT_VALID, validationResult);
-
- assertTrue(extras.containsKey(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK));
- final int probesSucceeded = extras.getInt(KEY_NETWORK_VALIDATION_RESULT);
- assertTrue("PROBES_SUCCEEDED mask not in expected range", probesSucceeded >= 0);
-
- assertTrue(extras.containsKey(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK));
- final int probesAttempted = extras.getInt(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK);
- assertTrue("PROBES_ATTEMPTED mask not in expected range", probesAttempted >= 0);
- }
-
- public void expectOnDataStallSuspected(
- @NonNull Network network,
- @NonNull String interfaceName,
- int detectionMethod,
- long timestampMillis,
- @NonNull PersistableBundle extras) {
- final DataStallReport result =
- (DataStallReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true);
- assertEquals(network, result.getNetwork());
- assertEquals(detectionMethod, result.getDetectionMethod());
- assertEquals(timestampMillis, result.getReportTimestamp());
-
- final NetworkCapabilities nc = result.getNetworkCapabilities();
- assertNotNull(nc);
- assertTrue(nc.hasTransport(TRANSPORT_TEST));
- assertNotNull(result.getLinkProperties());
- assertEquals(interfaceName, result.getLinkProperties().getInterfaceName());
-
- assertTrue(persistableBundleEquals(extras, result.getStallDetails()));
- }
-
- public void expectOnNetworkConnectivityReported(
- @NonNull Network network, boolean hasConnectivity) {
- final Pair<Network, Boolean> result =
- (Pair<Network, Boolean>) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true);
- assertEquals(network, result.first /* network */);
- assertEquals(hasConnectivity, result.second /* hasConnectivity */);
- }
-
- public void assertNoCallback() {
- // If no more callbacks exist, there should be nothing left in the ReadHead
- assertNull("Unexpected event in history",
- mHistory.poll(NO_CALLBACK_INVOKED_TIMEOUT, x -> true));
- }
- }
-
- private class CarrierConfigReceiver extends BroadcastReceiver {
- private final CountDownLatch mLatch = new CountDownLatch(1);
- private final int mSubId;
-
- CarrierConfigReceiver(int subId) {
- mSubId = subId;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
- return;
- }
-
- final int subId =
- intent.getIntExtra(
- CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
- SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- if (mSubId != subId) return;
-
- final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
- if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfigs)) return;
-
- final String[] certs =
- carrierConfigs.getStringArray(
- CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY);
- try {
- if (ArrayUtils.contains(certs, getCertHashForThisPackage())) {
- mLatch.countDown();
- }
- } catch (Exception e) {
- }
- }
-
- boolean waitForCarrierConfigChanged() throws Exception {
- return mLatch.await(CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT, TimeUnit.MILLISECONDS);
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
deleted file mode 100644
index 3880664..0000000
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ /dev/null
@@ -1,1374 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-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_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;
-import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION;
-import static android.net.cts.util.CtsNetUtils.TEST_HOST;
-import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
-import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
-import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-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;
-import android.app.PendingIntent;
-import android.app.UiAutomation;
-import android.content.ContentResolver;
-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;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.IpSecManager;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkConfig;
-import android.net.NetworkInfo;
-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;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.VintfRuntimeInfo;
-import android.platform.test.annotations.AppModeFull;
-import android.provider.Settings;
-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 com.android.testutils.SkipPresubmit;
-
-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;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-@RunWith(AndroidJUnit4.class)
-public class ConnectivityManagerTest {
-
- private static final String TAG = ConnectivityManagerTest.class.getSimpleName();
-
- public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE;
- public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI;
-
- private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1
- private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000;
- 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;
-
- // 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.
- private static final int MIN_NUM_NETWORK_TYPES = 1;
-
- // Minimum supported keepalive counts for wifi and cellular.
- public static final int MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT = 1;
- public static final int MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT = 3;
-
- private static final String NETWORK_METERED_MULTIPATH_PREFERENCE_RES_NAME =
- "config_networkMeteredMultipathPreference";
- private static final String KEEPALIVE_ALLOWED_UNPRIVILEGED_RES_NAME =
- "config_allowedUnprivilegedKeepalivePerUid";
- private static final String KEEPALIVE_RESERVED_PER_SLOT_RES_NAME =
- "config_reservedPrivilegedKeepaliveSlots";
-
- private Context mContext;
- private Instrumentation mInstrumentation;
- private ConnectivityManager mCm;
- private WifiManager mWifiManager;
- private PackageManager mPackageManager;
- private final HashMap<Integer, NetworkConfig> mNetworks =
- new HashMap<Integer, NetworkConfig>();
- boolean mWifiWasDisabled;
- private UiAutomation mUiAutomation;
- private CtsNetUtils mCtsNetUtils;
-
- @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);
- mWifiWasDisabled = false;
-
- // Get com.android.internal.R.array.networkAttributes
- int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android");
- String[] naStrings = mContext.getResources().getStringArray(resId);
- //TODO: What is the "correct" way to determine if this is a wifi only device?
- boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false);
- for (String naString : naStrings) {
- try {
- NetworkConfig n = new NetworkConfig(naString);
- if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) {
- continue;
- }
- mNetworks.put(n.type, n);
- } catch (Exception e) {}
- }
- mUiAutomation = mInstrumentation.getUiAutomation();
- }
-
- @After
- public void tearDown() throws Exception {
- // Return WiFi to its original disabled state after tests that explicitly connect.
- if (mWifiWasDisabled) {
- mCtsNetUtils.disconnectFromWifi(null);
- }
- if (mCtsNetUtils.cellConnectAttempted()) {
- mCtsNetUtils.disconnectFromCell();
- }
- }
-
- /**
- * Make sure WiFi is connected to an access point if it is not already. If
- * WiFi is enabled as a result of this function, it will be disabled
- * automatically in tearDown().
- */
- private Network ensureWifiConnected() {
- 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));
- assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_MMS));
- assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_SUPL));
- assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_DUN));
- assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_HIPRI));
- assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIMAX));
- assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_BLUETOOTH));
- assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_DUMMY));
- assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_ETHERNET));
- assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_FOTA));
- assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IMS));
- assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_CBS));
- assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI_P2P));
- assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IA));
- assertFalse(mCm.isNetworkTypeValid(-1));
- assertTrue(mCm.isNetworkTypeValid(0));
- assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE));
- assertFalse(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE+1));
-
- NetworkInfo[] ni = mCm.getAllNetworkInfo();
-
- for (NetworkInfo n: ni) {
- assertTrue(ConnectivityManager.isNetworkTypeValid(n.getType()));
- }
-
- }
-
- @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();
-
- assertNotNull("You must have an active network connection to complete CTS", ni);
- assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType()));
- 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);
-
- NetworkInfo ni = mCm.getNetworkInfo(network);
- assertNotNull("Network returned from getActiveNetwork was invalid", ni);
-
- // Similar to testGetActiveNetworkInfo above.
- assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType()));
- assertTrue(ni.getState() == State.CONNECTED);
- }
-
- @Test
- public void testGetNetworkInfo() {
- for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) {
- if (shouldBeSupported(type)) {
- NetworkInfo ni = mCm.getNetworkInfo(type);
- assertTrue("Info shouldn't be null for " + type, ni != null);
- State state = ni.getState();
- assertTrue("Bad state for " + type, State.UNKNOWN.ordinal() >= state.ordinal()
- && state.ordinal() >= State.CONNECTING.ordinal());
- DetailedState ds = ni.getDetailedState();
- assertTrue("Bad detailed state for " + type,
- DetailedState.FAILED.ordinal() >= ds.ordinal()
- && ds.ordinal() >= DetailedState.IDLE.ordinal());
- } else {
- assertNull("Info should be null for " + type, mCm.getNetworkInfo(type));
- }
- }
- }
-
- @Test
- public void testGetAllNetworkInfo() {
- NetworkInfo[] ni = mCm.getAllNetworkInfo();
- assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES);
- for (int type = 0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
- int desiredFoundCount = (shouldBeSupported(type) ? 1 : 0);
- int foundCount = 0;
- for (NetworkInfo i : ni) {
- if (i.getType() == type) foundCount++;
- }
- if (foundCount != desiredFoundCount) {
- Log.e(TAG, "failure in testGetAllNetworkInfo. Dump of returned NetworkInfos:");
- for (NetworkInfo networkInfo : ni) Log.e(TAG, " " + networkInfo);
- }
- assertTrue("Unexpected foundCount of " + foundCount + " for type " + type,
- foundCount == desiredFoundCount);
- }
- }
-
- /**
- * Tests that connections can be opened on WiFi and cellphone networks,
- * and that they are made from different IP addresses.
- */
- @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
- @Test
- @SkipPresubmit(reason = "Virtual devices use a single internet connection for all networks")
- public void testOpenConnection() throws Exception {
- boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
- && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
- if (!canRunTest) {
- Log.i(TAG,"testOpenConnection cannot execute unless device supports both WiFi "
- + "and a cellular connection");
- return;
- }
-
- Network wifiNetwork = mCtsNetUtils.connectToWifi();
- Network cellNetwork = mCtsNetUtils.connectToCell();
- // This server returns the requestor's IP address as the response body.
- URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text");
- String wifiAddressString = httpGet(wifiNetwork, url);
- String cellAddressString = httpGet(cellNetwork, url);
-
- assertFalse(String.format("Same address '%s' on two different networks (%s, %s)",
- wifiAddressString, wifiNetwork, cellNetwork),
- wifiAddressString.equals(cellAddressString));
-
- // Sanity check that the IP addresses that the requests appeared to come from
- // are actually on the respective networks.
- assertOnNetwork(wifiAddressString, wifiNetwork);
- assertOnNetwork(cellAddressString, cellNetwork);
-
- assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork));
- }
-
- /**
- * Performs a HTTP GET to the specified URL on the specified Network, and returns
- * the response body decoded as UTF-8.
- */
- private static String httpGet(Network network, URL httpUrl) throws IOException {
- HttpURLConnection connection = (HttpURLConnection) network.openConnection(httpUrl);
- try {
- InputStream inputStream = connection.getInputStream();
- return Streams.readFully(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
- } finally {
- connection.disconnect();
- }
- }
-
- private void assertOnNetwork(String adressString, Network network) throws UnknownHostException {
- InetAddress address = InetAddress.getByName(adressString);
- LinkProperties linkProperties = mCm.getLinkProperties(network);
- // To make sure that the request went out on the right network, check that
- // the IP address seen by the server is assigned to the expected network.
- // We can only do this for IPv6 addresses, because in IPv4 we will likely
- // have a private IPv4 address, and that won't match what the server sees.
- if (address instanceof Inet6Address) {
- assertContains(linkProperties.getAddresses(), address);
- }
- }
-
- private static<T> void assertContains(Collection<T> collection, T element) {
- assertTrue(element + " not found in " + collection, collection.contains(element));
- }
-
- private void assertStartUsingNetworkFeatureUnsupported(int networkType, String feature) {
- try {
- mCm.startUsingNetworkFeature(networkType, feature);
- fail("startUsingNetworkFeature is no longer supported in the current API version");
- } catch (UnsupportedOperationException expected) {}
- }
-
- private void assertStopUsingNetworkFeatureUnsupported(int networkType, String feature) {
- try {
- mCm.startUsingNetworkFeature(networkType, feature);
- fail("stopUsingNetworkFeature is no longer supported in the current API version");
- } catch (UnsupportedOperationException expected) {}
- }
-
- private void assertRequestRouteToHostUnsupported(int networkType, int hostAddress) {
- try {
- mCm.requestRouteToHost(networkType, hostAddress);
- fail("requestRouteToHost is no longer supported in the current API version");
- } catch (UnsupportedOperationException expected) {}
- }
-
- @Test
- public void testStartUsingNetworkFeature() {
-
- final String invalidateFeature = "invalidateFeature";
- final String mmsFeature = "enableMMS";
-
- assertStartUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature);
- assertStopUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature);
- assertStartUsingNetworkFeatureUnsupported(TYPE_WIFI, mmsFeature);
- }
-
- private boolean shouldEthernetBeSupported() {
- // Instant mode apps aren't allowed to query the Ethernet service due to selinux policies.
- // When in instant mode, don't fail if the Ethernet service is available. Instead, rely on
- // the fact that Ethernet should be supported if the device has a hardware Ethernet port, or
- // if the device can be a USB host and thus can use USB Ethernet adapters.
- //
- // Note that this test this will still fail in instant mode if a device supports Ethernet
- // via other hardware means. We are not currently aware of any such device.
- return (mContext.getSystemService(Context.ETHERNET_SERVICE) != null) ||
- mPackageManager.hasSystemFeature(FEATURE_ETHERNET) ||
- mPackageManager.hasSystemFeature(FEATURE_USB_HOST);
- }
-
- private boolean shouldBeSupported(int networkType) {
- return mNetworks.containsKey(networkType) ||
- (networkType == ConnectivityManager.TYPE_VPN) ||
- (networkType == ConnectivityManager.TYPE_ETHERNET && shouldEthernetBeSupported());
- }
-
- @Test
- public void testIsNetworkSupported() {
- for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
- boolean supported = mCm.isNetworkSupported(type);
- if (shouldBeSupported(type)) {
- assertTrue("Network type " + type + " should be supported", supported);
- } else {
- assertFalse("Network type " + type + " should not be supported", supported);
- }
- }
- }
-
- @Test
- public void testRequestRouteToHost() {
- for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
- assertRequestRouteToHostUnsupported(type, HOST_ADDRESS);
- }
- }
-
- @Test
- public void testTest() {
- mCm.getBackgroundDataSetting();
- }
-
- private NetworkRequest makeWifiNetworkRequest() {
- return new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
- }
-
- /**
- * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to
- * see if we get a callback for the TRANSPORT_WIFI transport type being available.
- *
- * <p>In order to test that a NetworkCallback occurs, we need some change in the network
- * state (either a transport or capability is now available). The most straightforward is
- * WiFi. We could add a version that uses the telephony data connection but it's not clear
- * 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");
- return;
- }
-
- // We will register for a WIFI network being available or lost.
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
-
- final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultTrackingCallback);
-
- Network wifiNetwork = null;
-
- try {
- ensureWifiConnected();
-
- // Now we should expect to get a network callback about availability of the wifi
- // network even if it was already connected as a state-based action when the callback
- // is registered.
- wifiNetwork = callback.waitForAvailable();
- assertNotNull("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI",
- wifiNetwork);
-
- assertNotNull("Did not receive NetworkCallback.onAvailable for any default network",
- defaultTrackingCallback.waitForAvailable());
- } catch (InterruptedException e) {
- fail("Broadcast receiver or NetworkCallback wait was interrupted.");
- } finally {
- mCm.unregisterNetworkCallback(callback);
- mCm.unregisterNetworkCallback(defaultTrackingCallback);
- }
- }
-
- /**
- * Tests both registerNetworkCallback and unregisterNetworkCallback similarly to
- * {@link #testRegisterNetworkCallback} except that a {@code PendingIntent} is used instead
- * 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");
- return;
- }
-
- // Create a ConnectivityActionReceiver that has an IntentFilter for our locally defined
- // action, NETWORK_CALLBACK_ACTION.
- IntentFilter filter = new IntentFilter();
- filter.addAction(NETWORK_CALLBACK_ACTION);
-
- ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
- mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
- mContext.registerReceiver(receiver, filter);
-
- // Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION.
- Intent intent = new Intent(NETWORK_CALLBACK_ACTION);
- PendingIntent pendingIntent = PendingIntent.getBroadcast(
- mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
-
- // We will register for a WIFI network being available or lost.
- mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent);
-
- try {
- ensureWifiConnected();
-
- // Now we expect to get the Intent delivered notifying of the availability of the wifi
- // network even if it was already connected as a state-based action when the callback
- // is registered.
- assertTrue("Did not receive expected Intent " + intent + " for TRANSPORT_WIFI",
- receiver.waitForState());
- } catch (InterruptedException e) {
- fail("Broadcast receiver or NetworkCallback wait was interrupted.");
- } finally {
- mCm.unregisterNetworkCallback(pendingIntent);
- pendingIntent.cancel();
- mContext.unregisterReceiver(receiver);
- }
- }
-
- /**
- * Exercises the requestNetwork with NetworkCallback API. This checks to
- * 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()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build(), callback);
-
- try {
- // Wait to get callback for availability of internet
- Network internetNetwork = callback.waitForAvailable();
- assertNotNull("Did not receive NetworkCallback#onAvailable for INTERNET",
- internetNetwork);
- } catch (InterruptedException e) {
- fail("NetworkCallback wait was interrupted.");
- } finally {
- mCm.unregisterNetworkCallback(callback);
- }
- }
-
- /**
- * Exercises the requestNetwork with NetworkCallback API with timeout - expected to
- * 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) {
- mCtsNetUtils.disconnectFromWifi(null);
- }
-
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.requestNetwork(new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .build(), callback, 100);
-
- try {
- // Wait to get callback for unavailability of requested network
- assertTrue("Did not receive NetworkCallback#onUnavailable",
- callback.waitForUnavailable());
- } catch (InterruptedException e) {
- fail("NetworkCallback wait was interrupted.");
- } finally {
- mCm.unregisterNetworkCallback(callback);
- if (previousWifiEnabledState) {
- mCtsNetUtils.connectToWifi();
- }
- }
- }
-
- private InetAddress getFirstV4Address(Network network) {
- LinkProperties linkProperties = mCm.getLinkProperties(network);
- for (InetAddress address : linkProperties.getAddresses()) {
- if (address instanceof Inet4Address) {
- return address;
- }
- }
- return null;
- }
-
- /** 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()
- .addCapability(NET_CAPABILITY_INTERNET).build();
- NetworkCallback callback = new NetworkCallback();
- mCm.requestNetwork(request, callback);
- mCm.unregisterNetworkCallback(callback);
- // Verify we cannot request restricted networks:
- request = new NetworkRequest.Builder().addCapability(NET_CAPABILITY_IMS).build();
- callback = new NetworkCallback();
- try {
- mCm.requestNetwork(request, callback);
- fail("No exception thrown when restricted network requested.");
- } catch (SecurityException expected) {}
- }
-
- // Returns "true", "false" or "none"
- private String getWifiMeteredStatus(String ssid) throws Exception {
- // Interestingly giving the SSID as an argument to list wifi-networks
- // only works iff the network in question has the "false" policy.
- // Also unfortunately runShellCommand does not pass the command to the interpreter
- // so it's not possible to | grep the ssid.
- final String command = "cmd netpolicy list wifi-networks";
- final String policyString = runShellCommand(mInstrumentation, command);
-
- final Matcher m = Pattern.compile("^" + ssid + ";(true|false|none)$",
- Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
- if (!m.find()) {
- fail("Unexpected format from cmd netpolicy");
- }
- return m.group(1);
- }
-
- // metered should be "true", "false" or "none"
- private void setWifiMeteredStatus(String ssid, String metered) throws Exception {
- final String setCommand = "cmd netpolicy set metered-network " + ssid + " " + metered;
- runShellCommand(mInstrumentation, setCommand);
- assertEquals(getWifiMeteredStatus(ssid), metered);
- }
-
- private String unquoteSSID(String ssid) {
- // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
- // Otherwise it's guaranteed not to start with a quote.
- if (ssid.charAt(0) == '"') {
- return ssid.substring(1, ssid.length() - 1);
- } else {
- return ssid;
- }
- }
-
- private void waitForActiveNetworkMetered(int targetTransportType, boolean requestedMeteredness)
- throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
- final NetworkCallback networkCallback = new NetworkCallback() {
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
- if (!nc.hasTransport(targetTransportType)) return;
-
- final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
- if (metered == requestedMeteredness) {
- latch.countDown();
- }
- }
- };
- // Registering a callback here guarantees onCapabilitiesChanged is called immediately
- // with the current setting. Therefore, if the setting has already been changed,
- // this method will return right away, and if not it will wait for the setting to change.
- mCm.registerDefaultNetworkCallback(networkCallback);
- if (!latch.await(NETWORK_CHANGE_METEREDNESS_TIMEOUT, TimeUnit.MILLISECONDS)) {
- fail("Timed out waiting for active network metered status to change to "
- + requestedMeteredness + " ; network = " + mCm.getActiveNetwork());
- }
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- private void assertMultipathPreferenceIsEventually(Network network, int oldValue,
- int expectedValue) {
- // Sanity check : if oldValue == expectedValue, there is no way to guarantee the test
- // is not flaky.
- assertNotSame(oldValue, expectedValue);
-
- for (int i = 0; i < NUM_TRIES_MULTIPATH_PREF_CHECK; ++i) {
- final int actualValue = mCm.getMultipathPreference(network);
- if (actualValue == expectedValue) {
- return;
- }
- if (actualValue != oldValue) {
- fail("Multipath preference is neither previous (" + oldValue
- + ") nor expected (" + expectedValue + ")");
- }
- SystemClock.sleep(INTERVAL_MULTIPATH_PREF_CHECK_MS);
- }
- fail("Timed out waiting for multipath preference to change. expected = "
- + expectedValue + " ; actual = " + mCm.getMultipathPreference(network));
- }
-
- private int getCurrentMeteredMultipathPreference(ContentResolver resolver) {
- final String rawMeteredPref = Settings.Global.getString(resolver,
- NETWORK_METERED_MULTIPATH_PREFERENCE);
- return TextUtils.isEmpty(rawMeteredPref)
- ? getIntResourceForName(NETWORK_METERED_MULTIPATH_PREFERENCE_RES_NAME)
- : Integer.parseInt(rawMeteredPref);
- }
-
- private int findNextPrefValue(ContentResolver resolver) {
- // A bit of a nuclear hammer, but race conditions in CTS are bad. To be able to
- // detect a correct setting value without race conditions, the next pref must
- // be a valid value (range 0..3) that is different from the old setting of the
- // metered preference and from the unmetered preference.
- final int meteredPref = getCurrentMeteredMultipathPreference(resolver);
- final int unmeteredPref = ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED;
- if (0 != meteredPref && 0 != unmeteredPref) return 0;
- if (1 != meteredPref && 1 != unmeteredPref) return 1;
- return 2;
- }
-
- /**
- * Verify that getMultipathPreference does return appropriate values
- * 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();
- final String ssid = unquoteSSID(mWifiManager.getConnectionInfo().getSSID());
- final String oldMeteredSetting = getWifiMeteredStatus(ssid);
- final String oldMeteredMultipathPreference = Settings.Global.getString(
- resolver, NETWORK_METERED_MULTIPATH_PREFERENCE);
- try {
- final int initialMeteredPreference = getCurrentMeteredMultipathPreference(resolver);
- int newMeteredPreference = findNextPrefValue(resolver);
- Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
- Integer.toString(newMeteredPreference));
- setWifiMeteredStatus(ssid, "true");
- waitForActiveNetworkMetered(TRANSPORT_WIFI, true);
- // Wifi meterness changes from unmetered to metered will disconnect and reconnect since
- // R.
- final Network network = ensureWifiConnected();
- assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID()));
- assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
- NET_CAPABILITY_NOT_METERED), false);
- assertMultipathPreferenceIsEventually(network, initialMeteredPreference,
- newMeteredPreference);
-
- final int oldMeteredPreference = newMeteredPreference;
- newMeteredPreference = findNextPrefValue(resolver);
- Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
- Integer.toString(newMeteredPreference));
- assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
- NET_CAPABILITY_NOT_METERED), false);
- assertMultipathPreferenceIsEventually(network,
- oldMeteredPreference, newMeteredPreference);
-
- setWifiMeteredStatus(ssid, "false");
- // No disconnect from unmetered to metered.
- waitForActiveNetworkMetered(TRANSPORT_WIFI, false);
- assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
- NET_CAPABILITY_NOT_METERED), true);
- assertMultipathPreferenceIsEventually(network, newMeteredPreference,
- ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED);
- } finally {
- Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
- oldMeteredMultipathPreference);
- setWifiMeteredStatus(ssid, oldMeteredSetting);
- }
- }
-
- // TODO: move the following socket keep alive test to dedicated test class.
- /**
- * Callback used in tcp keepalive offload that allows caller to wait callback fires.
- */
- private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback {
- public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
-
- public static class CallbackValue {
- public final CallbackType callbackType;
- public final int error;
-
- private CallbackValue(final CallbackType type, final int error) {
- this.callbackType = type;
- this.error = error;
- }
-
- public static class OnStartedCallback extends CallbackValue {
- OnStartedCallback() { super(CallbackType.ON_STARTED, 0); }
- }
-
- public static class OnStoppedCallback extends CallbackValue {
- OnStoppedCallback() { super(CallbackType.ON_STOPPED, 0); }
- }
-
- public static class OnErrorCallback extends CallbackValue {
- OnErrorCallback(final int error) { super(CallbackType.ON_ERROR, error); }
- }
-
- @Override
- public boolean equals(Object o) {
- return o.getClass() == this.getClass()
- && this.callbackType == ((CallbackValue) o).callbackType
- && this.error == ((CallbackValue) o).error;
- }
-
- @Override
- public String toString() {
- return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error);
- }
- }
-
- private final LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
-
- @Override
- public void onStarted() {
- mCallbacks.add(new CallbackValue.OnStartedCallback());
- }
-
- @Override
- public void onStopped() {
- mCallbacks.add(new CallbackValue.OnStoppedCallback());
- }
-
- @Override
- public void onError(final int error) {
- mCallbacks.add(new CallbackValue.OnErrorCallback(error));
- }
-
- public CallbackValue pollCallback() {
- try {
- return mCallbacks.poll(KEEPALIVE_CALLBACK_TIMEOUT_MS,
- TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- fail("Callback not seen after " + KEEPALIVE_CALLBACK_TIMEOUT_MS + " ms");
- }
- return null;
- }
- private void expectCallback(CallbackValue expectedCallback) {
- final CallbackValue actualCallback = pollCallback();
- assertEquals(expectedCallback, actualCallback);
- }
-
- public void expectStarted() {
- expectCallback(new CallbackValue.OnStartedCallback());
- }
-
- public void expectStopped() {
- expectCallback(new CallbackValue.OnStoppedCallback());
- }
-
- public void expectError(int error) {
- expectCallback(new CallbackValue.OnErrorCallback(error));
- }
- }
-
- private InetAddress getAddrByName(final String hostname, final int family) throws Exception {
- final InetAddress[] allAddrs = InetAddress.getAllByName(hostname);
- for (InetAddress addr : allAddrs) {
- if (family == AF_INET && addr instanceof Inet4Address) return addr;
-
- if (family == AF_INET6 && addr instanceof Inet6Address) return addr;
-
- if (family == AF_UNSPEC) return addr;
- }
- return null;
- }
-
- private Socket getConnectedSocket(final Network network, final String host, final int port,
- final int family) throws Exception {
- final Socket s = network.getSocketFactory().createSocket();
- try {
- final InetAddress addr = getAddrByName(host, family);
- if (addr == null) fail("Fail to get destination address for " + family);
-
- final InetSocketAddress sockAddr = new InetSocketAddress(addr, port);
- s.connect(sockAddr);
- } catch (Exception e) {
- s.close();
- throw e;
- }
- return s;
- }
-
- private int getSupportedKeepalivesForNet(@NonNull Network network) throws Exception {
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
-
- // Get number of supported concurrent keepalives for testing network.
- final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext);
- return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(
- keepalivesPerTransport, nc);
- }
-
- private static boolean isTcpKeepaliveSupportedByKernel() {
- final String kVersionString = VintfRuntimeInfo.getKernelVersion();
- return compareMajorMinorVersion(kVersionString, "4.8") >= 0;
- }
-
- private static Pair<Integer, Integer> getVersionFromString(String version) {
- // Only gets major and minor number of the version string.
- final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*");
- final Matcher m = versionPattern.matcher(version);
- if (m.matches()) {
- final int major = Integer.parseInt(m.group(1));
- final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3));
- return new Pair<>(major, minor);
- } else {
- return new Pair<>(0, 0);
- }
- }
-
- // TODO: Move to util class.
- private static int compareMajorMinorVersion(final String s1, final String s2) {
- final Pair<Integer, Integer> v1 = getVersionFromString(s1);
- final Pair<Integer, Integer> v2 = getVersionFromString(s2);
-
- if (v1.first == v2.first) {
- return Integer.compare(v1.second, v2.second);
- } else {
- return Integer.compare(v1.first, v2.first);
- }
- }
-
- /**
- * 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"));
- assertEquals(1, compareMajorMinorVersion("5.0", "4.8"));
- assertEquals(1, compareMajorMinorVersion("5", "4.8"));
- assertEquals(0, compareMajorMinorVersion("5", "5.0"));
- assertEquals(1, compareMajorMinorVersion("5-beta1", "4.8"));
- assertEquals(0, compareMajorMinorVersion("4.8.0.0", "4.8"));
- assertEquals(0, compareMajorMinorVersion("4.8-RC1", "4.8"));
- assertEquals(0, compareMajorMinorVersion("4.8", "4.8"));
- assertEquals(-1, compareMajorMinorVersion("3.10", "4.8.0"));
- assertEquals(-1, compareMajorMinorVersion("4.7.10.10", "4.8"));
- }
-
- /**
- * Verifies that the keepalive API cannot create any keepalive when the maximum number of
- * 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"
- + " supports WiFi");
- return;
- }
-
- final Network network = ensureWifiConnected();
- if (getSupportedKeepalivesForNet(network) != 0) return;
- final InetAddress srcAddr = getFirstV4Address(network);
- assumeTrue("This test requires native IPv4", srcAddr != null);
-
- 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
- @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
- public void testCreateTcpKeepalive() throws Exception {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi");
- return;
- }
-
- 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.
- runWithShellPermissionIdentity(() -> {
- assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1));
- });
- Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel "
- + VintfRuntimeInfo.getKernelVersion());
- return;
- }
-
- final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8");
- // So far only ipv4 tcp keepalive offload is supported.
- // TODO: add test case for ipv6 tcp keepalive offload when it is supported.
- try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT, AF_INET)) {
-
- // 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();
-
- // App should not able to write during keepalive offload.
- final OutputStream out = s.getOutputStream();
- try {
- out.write(requestBytes);
- fail("Should not able to write");
- } catch (IOException e) { }
- // App should not able to read during keepalive offload.
- final InputStream in = s.getInputStream();
- byte[] responseBytes = new byte[4096];
- try {
- in.read(responseBytes);
- fail("Should not able to read");
- } catch (IOException e) { }
-
- // Stop.
- sk.stop();
- callback.expectStopped();
- } finally {
- mUiAutomation.dropShellPermissionIdentity();
- }
-
- // Ensure socket is still connected.
- assertTrue(s.isConnected());
- assertFalse(s.isClosed());
-
- // Let socket be not idle.
- try {
- final OutputStream out = s.getOutputStream();
- out.write(requestBytes);
- } catch (IOException e) {
- fail("Failed to write data " + e);
- }
- // Make sure response data arrives.
- final MessageQueue fdHandlerQueue = Looper.getMainLooper().getQueue();
- final FileDescriptor fd = s.getFileDescriptor$();
- final CountDownLatch mOnReceiveLatch = new CountDownLatch(1);
- fdHandlerQueue.addOnFileDescriptorEventListener(fd, EVENT_INPUT, (readyFd, events) -> {
- mOnReceiveLatch.countDown();
- return 0; // Unregister listener.
- });
- if (!mOnReceiveLatch.await(2, TimeUnit.SECONDS)) {
- fdHandlerQueue.removeOnFileDescriptorEventListener(fd);
- fail("Timeout: no response data");
- }
-
- // 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();
- }
- }
- }
-
- private ArrayList<SocketKeepalive> createConcurrentKeepalivesOfType(
- int requestCount, @NonNull TestSocketKeepaliveCallback callback,
- Supplier<SocketKeepalive> kaFactory) {
- final ArrayList<SocketKeepalive> kalist = new ArrayList<>();
-
- int remainingRetries = MAX_KEEPALIVE_RETRY_COUNT;
-
- // Test concurrent keepalives with the given supplier.
- while (kalist.size() < requestCount) {
- final SocketKeepalive ka = kaFactory.get();
- ka.start(MIN_KEEPALIVE_INTERVAL);
- TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback();
- assertNotNull(cv);
- if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) {
- if (kalist.size() == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) {
- // Unsupported.
- break;
- } else if (cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) {
- // Limit reached or temporary unavailable due to stopped slot is not yet
- // released.
- if (remainingRetries > 0) {
- SystemClock.sleep(INTERVAL_KEEPALIVE_RETRY_MS);
- remainingRetries--;
- continue;
- }
- break;
- }
- }
- if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) {
- kalist.add(ka);
- } else {
- fail("Unexpected error when creating " + (kalist.size() + 1) + " "
- + ka.getClass().getSimpleName() + ": " + cv);
- }
- }
-
- return kalist;
- }
-
- private @NonNull ArrayList<SocketKeepalive> createConcurrentNattSocketKeepalives(
- @NonNull Network network, @NonNull InetAddress srcAddr, int requestCount,
- @NonNull TestSocketKeepaliveCallback callback) throws Exception {
-
- final Executor executor = mContext.getMainExecutor();
-
- // Initialize a real NaT-T socket.
- final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
- final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket();
- final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET);
- assertNotNull(srcAddr);
- assertNotNull(dstAddr);
-
- // Test concurrent Nat-T keepalives.
- final ArrayList<SocketKeepalive> result = createConcurrentKeepalivesOfType(requestCount,
- callback, () -> mCm.createSocketKeepalive(network, nattSocket,
- srcAddr, dstAddr, executor, callback));
-
- nattSocket.close();
- return result;
- }
-
- private @NonNull ArrayList<SocketKeepalive> createConcurrentTcpSocketKeepalives(
- @NonNull Network network, int requestCount,
- @NonNull TestSocketKeepaliveCallback callback) {
- final Executor executor = mContext.getMainExecutor();
-
- // Create concurrent TCP keepalives.
- return createConcurrentKeepalivesOfType(requestCount, callback, () -> {
- // Assert that TCP connections can be established. The file descriptor of tcp
- // sockets will be duplicated and kept valid in service side if the keepalives are
- // successfully started.
- try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT,
- AF_INET)) {
- return mCm.createSocketKeepalive(network, tcpSocket, executor, callback);
- } catch (Exception e) {
- fail("Unexpected error when creating TCP socket: " + e);
- }
- return null;
- });
- }
-
- /**
- * Creates concurrent keepalives until the specified counts of each type of keepalives are
- * reached or the expected error callbacks are received for each type of keepalives.
- *
- * @return the total number of keepalives created.
- */
- private int createConcurrentSocketKeepalives(
- @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, srcAddr, nattCount, callback));
- kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback));
-
- final int ret = kalist.size();
-
- // Clean up.
- for (final SocketKeepalive ka : kalist) {
- ka.stop();
- callback.expectStopped();
- }
- kalist.clear();
-
- return ret;
- }
-
- /**
- * Verifies that the concurrent keepalive slots meet the minimum requirement, and don't
- * get leaked after iterations.
- */
- @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
- @Test
- @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
- public void testSocketKeepaliveLimitWifi() throws Exception {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device"
- + " supports WiFi");
- return;
- }
-
- final Network network = ensureWifiConnected();
- final int supported = getSupportedKeepalivesForNet(network);
- if (supported == 0) {
- return;
- }
- final InetAddress srcAddr = getFirstV4Address(network);
- assumeTrue("This test requires native IPv4", srcAddr != null);
-
- runWithShellPermissionIdentity(() -> {
- // 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, 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()) 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, srcAddr,
- supported / 2, supported - supported / 2));
-
- // Verifies that keepalives don't get leaked in second round.
- assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0,
- supported));
- assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
- supported / 2, supported - supported / 2));
- });
- }
-
- /**
- * Verifies that the concurrent keepalive slots meet the minimum telephony requirement, and
- * don't get leaked after iterations.
- */
- @AppModeFull(reason = "Cannot request network in instant app mode")
- @Test
- @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
- public void testSocketKeepaliveLimitTelephony() throws Exception {
- if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) {
- Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device"
- + " supports telephony");
- return;
- }
-
- final int firstSdk = Build.VERSION.FIRST_SDK_INT;
- if (firstSdk < Build.VERSION_CODES.Q) {
- Log.i(TAG, "testSocketKeepaliveLimitTelephony: skip test for devices launching"
- + " before Q: " + firstSdk);
- return;
- }
-
- final Network network = mCtsNetUtils.connectToCell();
- final int supported = getSupportedKeepalivesForNet(network);
- final InetAddress srcAddr = getFirstV4Address(network);
- assumeTrue("This test requires native IPv4", srcAddr != null);
-
- 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) {
- final Resources r = mContext.getResources();
- final int resId = r.getIdentifier(resName, "integer", "android");
- return r.getInteger(resId);
- }
-
- /**
- * Verifies that the keepalive slots are limited as customized for unprivileged requests.
- */
- @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
- @Test
- @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
- public void testSocketKeepaliveUnprivileged() throws Exception {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device"
- + " supports WiFi");
- return;
- }
-
- final Network network = ensureWifiConnected();
- final int supported = getSupportedKeepalivesForNet(network);
- 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.
- final int allowedUnprivilegedPerUid =
- getIntResourceForName(KEEPALIVE_ALLOWED_UNPRIVILEGED_RES_NAME);
- final int reservedPrivilegedSlots =
- getIntResourceForName(KEEPALIVE_RESERVED_PER_SLOT_RES_NAME);
- // Verifies that unprivileged request per uid cannot exceed the limit customized in the
- // resource. Currently, unprivileged keepalive slots are limited to Nat-T only, this test
- // does not apply to TCP.
- assertGreaterOrEqual(supported, reservedPrivilegedSlots);
- assertGreaterOrEqual(supported, allowedUnprivilegedPerUid);
- final int expectedUnprivileged =
- Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots);
- assertEquals(expectedUnprivileged,
- 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/tests/net/src/android/net/cts/CredentialsTest.java b/tests/tests/net/src/android/net/cts/CredentialsTest.java
deleted file mode 100644
index 91c3621..0000000
--- a/tests/tests/net/src/android/net/cts/CredentialsTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.net.Credentials;
-import android.test.AndroidTestCase;
-
-public class CredentialsTest extends AndroidTestCase {
-
- public void testCredentials() {
- // new the Credentials instance
- // Test with zero inputs
- Credentials cred = new Credentials(0, 0, 0);
- assertEquals(0, cred.getGid());
- assertEquals(0, cred.getPid());
- assertEquals(0, cred.getUid());
-
- // Test with big integer
- cred = new Credentials(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
- assertEquals(Integer.MAX_VALUE, cred.getGid());
- assertEquals(Integer.MAX_VALUE, cred.getPid());
- assertEquals(Integer.MAX_VALUE, cred.getUid());
-
- // Test with big negative integer
- cred = new Credentials(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
- assertEquals(Integer.MIN_VALUE, cred.getGid());
- assertEquals(Integer.MIN_VALUE, cred.getPid());
- assertEquals(Integer.MIN_VALUE, cred.getUid());
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/DnsResolverTest.java b/tests/tests/net/src/android/net/cts/DnsResolverTest.java
deleted file mode 100644
index 4acbbcf..0000000
--- a/tests/tests/net/src/android/net/cts/DnsResolverTest.java
+++ /dev/null
@@ -1,756 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static android.net.DnsResolver.CLASS_IN;
-import static android.net.DnsResolver.FLAG_EMPTY;
-import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP;
-import static android.net.DnsResolver.TYPE_A;
-import static android.net.DnsResolver.TYPE_AAAA;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.system.OsConstants.ETIMEDOUT;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.ContentResolver;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.DnsResolver;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.net.ParseException;
-import android.net.cts.util.CtsNetUtils;
-import android.os.CancellationSignal;
-import android.os.Handler;
-import android.os.Looper;
-import android.platform.test.annotations.AppModeFull;
-import android.provider.Settings;
-import android.system.ErrnoException;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import com.android.net.module.util.DnsPacket;
-import com.android.testutils.SkipPresubmit;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-
-@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
-public class DnsResolverTest extends AndroidTestCase {
- private static final String TAG = "DnsResolverTest";
- private static final char[] HEX_CHARS = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
-
- static final String TEST_DOMAIN = "www.google.com";
- static final String TEST_NX_DOMAIN = "test1-nx.metric.gstatic.com";
- static final String INVALID_PRIVATE_DNS_SERVER = "invalid.google";
- static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google";
- static final byte[] TEST_BLOB = new byte[]{
- /* Header */
- 0x55, 0x66, /* Transaction ID */
- 0x01, 0x00, /* Flags */
- 0x00, 0x01, /* Questions */
- 0x00, 0x00, /* Answer RRs */
- 0x00, 0x00, /* Authority RRs */
- 0x00, 0x00, /* Additional RRs */
- /* Queries */
- 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
- 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
- 0x00, 0x01, /* Type */
- 0x00, 0x01 /* Class */
- };
- static final int TIMEOUT_MS = 12_000;
- static final int CANCEL_TIMEOUT_MS = 3_000;
- static final int CANCEL_RETRY_TIMES = 5;
- static final int QUERY_TIMES = 10;
- static final int NXDOMAIN = 3;
-
- private ContentResolver mCR;
- private ConnectivityManager mCM;
- private CtsNetUtils mCtsNetUtils;
- private Executor mExecutor;
- private Executor mExecutorInline;
- private DnsResolver mDns;
-
- private String mOldMode;
- private String mOldDnsSpecifier;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
- mDns = DnsResolver.getInstance();
- mExecutor = new Handler(Looper.getMainLooper())::post;
- mExecutorInline = (Runnable r) -> r.run();
- mCR = getContext().getContentResolver();
- mCtsNetUtils = new CtsNetUtils(getContext());
- mCtsNetUtils.storePrivateDnsSetting();
- }
-
- @Override
- protected void tearDown() throws Exception {
- mCtsNetUtils.restorePrivateDnsSetting();
- super.tearDown();
- }
-
- private static String byteArrayToHexString(byte[] bytes) {
- char[] hexChars = new char[bytes.length * 2];
- for (int i = 0; i < bytes.length; ++i) {
- int b = bytes[i] & 0xFF;
- hexChars[i * 2] = HEX_CHARS[b >>> 4];
- hexChars[i * 2 + 1] = HEX_CHARS[b & 0x0F];
- }
- return new String(hexChars);
- }
-
- private Network[] getTestableNetworks() {
- final ArrayList<Network> testableNetworks = new ArrayList<Network>();
- for (Network network : mCM.getAllNetworks()) {
- final NetworkCapabilities nc = mCM.getNetworkCapabilities(network);
- if (nc != null
- && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
- testableNetworks.add(network);
- }
- }
-
- assertTrue(
- "This test requires that at least one network be connected. " +
- "Please ensure that the device is connected to a network.",
- testableNetworks.size() >= 1);
- // In order to test query with null network, add null as an element.
- // Test cases which query with null network will go on default network.
- testableNetworks.add(null);
- return testableNetworks.toArray(new Network[0]);
- }
-
- static private void assertGreaterThan(String msg, int first, int second) {
- assertTrue(msg + " Excepted " + first + " to be greater than " + second, first > second);
- }
-
- private static class DnsParseException extends Exception {
- public DnsParseException(String msg) {
- super(msg);
- }
- }
-
- private static class DnsAnswer extends DnsPacket {
- DnsAnswer(@NonNull byte[] data) throws DnsParseException {
- super(data);
-
- // Check QR field.(query (0), or a response (1)).
- if ((mHeader.flags & (1 << 15)) == 0) {
- throw new DnsParseException("Not an answer packet");
- }
- }
-
- int getRcode() {
- return mHeader.rcode;
- }
-
- int getANCount() {
- return mHeader.getRecordCount(ANSECTION);
- }
-
- int getQDCount() {
- return mHeader.getRecordCount(QDSECTION);
- }
- }
-
- /**
- * A query callback that ensures that the query is cancelled and that onAnswer is never
- * called. If the query succeeds before it is cancelled, needRetry will return true so the
- * test can retry.
- */
- class VerifyCancelCallback implements DnsResolver.Callback<byte[]> {
- private final CountDownLatch mLatch = new CountDownLatch(1);
- private final String mMsg;
- private final CancellationSignal mCancelSignal;
- private int mRcode;
- private DnsAnswer mDnsAnswer;
- private String mErrorMsg = null;
-
- VerifyCancelCallback(@NonNull String msg, @Nullable CancellationSignal cancel) {
- mMsg = msg;
- mCancelSignal = cancel;
- }
-
- VerifyCancelCallback(@NonNull String msg) {
- this(msg, null);
- }
-
- public boolean waitForAnswer(int timeout) throws InterruptedException {
- return mLatch.await(timeout, TimeUnit.MILLISECONDS);
- }
-
- public boolean waitForAnswer() throws InterruptedException {
- return waitForAnswer(TIMEOUT_MS);
- }
-
- public boolean needRetry() throws InterruptedException {
- return mLatch.await(CANCEL_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- }
-
- @Override
- public void onAnswer(@NonNull byte[] answer, int rcode) {
- if (mCancelSignal != null && mCancelSignal.isCanceled()) {
- mErrorMsg = mMsg + " should not have returned any answers";
- mLatch.countDown();
- return;
- }
-
- mRcode = rcode;
- try {
- mDnsAnswer = new DnsAnswer(answer);
- } catch (ParseException | DnsParseException e) {
- mErrorMsg = mMsg + e.getMessage();
- mLatch.countDown();
- return;
- }
- Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer));
- mLatch.countDown();
- }
-
- @Override
- public void onError(@NonNull DnsResolver.DnsException error) {
- mErrorMsg = mMsg + error.getMessage();
- mLatch.countDown();
- }
-
- private void assertValidAnswer() {
- assertNull(mErrorMsg);
- assertNotNull(mMsg + " No valid answer", mDnsAnswer);
- assertEquals(mMsg + " Unexpected error: reported rcode" + mRcode +
- " blob's rcode " + mDnsAnswer.getRcode(), mRcode, mDnsAnswer.getRcode());
- }
-
- public void assertHasAnswer() {
- assertValidAnswer();
- // Check rcode field.(0, No error condition).
- assertEquals(mMsg + " Response error, rcode: " + mRcode, mRcode, 0);
- // Check answer counts.
- assertGreaterThan(mMsg + " No answer found", mDnsAnswer.getANCount(), 0);
- // Check question counts.
- assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0);
- }
-
- public void assertNXDomain() {
- assertValidAnswer();
- // Check rcode field.(3, NXDomain).
- assertEquals(mMsg + " Unexpected rcode: " + mRcode, mRcode, NXDOMAIN);
- // Check answer counts. Expect 0 answer.
- assertEquals(mMsg + " Not an empty answer", mDnsAnswer.getANCount(), 0);
- // Check question counts.
- assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0);
- }
-
- public void assertEmptyAnswer() {
- assertValidAnswer();
- // Check rcode field.(0, No error condition).
- assertEquals(mMsg + " Response error, rcode: " + mRcode, mRcode, 0);
- // Check answer counts. Expect 0 answer.
- assertEquals(mMsg + " Not an empty answer", mDnsAnswer.getANCount(), 0);
- // Check question counts.
- assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0);
- }
- }
-
- public void testRawQuery() throws Exception {
- doTestRawQuery(mExecutor);
- }
-
- public void testRawQueryInline() throws Exception {
- doTestRawQuery(mExecutorInline);
- }
-
- public void testRawQueryBlob() throws Exception {
- doTestRawQueryBlob(mExecutor);
- }
-
- public void testRawQueryBlobInline() throws Exception {
- doTestRawQueryBlob(mExecutorInline);
- }
-
- public void testRawQueryRoot() throws Exception {
- doTestRawQueryRoot(mExecutor);
- }
-
- public void testRawQueryRootInline() throws Exception {
- doTestRawQueryRoot(mExecutorInline);
- }
-
- public void testRawQueryNXDomain() throws Exception {
- doTestRawQueryNXDomain(mExecutor);
- }
-
- public void testRawQueryNXDomainInline() throws Exception {
- doTestRawQueryNXDomain(mExecutorInline);
- }
-
- public void testRawQueryNXDomainWithPrivateDns() throws Exception {
- doTestRawQueryNXDomainWithPrivateDns(mExecutor);
- }
-
- public void testRawQueryNXDomainInlineWithPrivateDns() throws Exception {
- doTestRawQueryNXDomainWithPrivateDns(mExecutorInline);
- }
-
- public void doTestRawQuery(Executor executor) throws InterruptedException {
- final String msg = "RawQuery " + TEST_DOMAIN;
- for (Network network : getTestableNetworks()) {
- final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
- mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
- executor, null, callback);
-
- assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
- callback.waitForAnswer());
- callback.assertHasAnswer();
- }
- }
-
- public void doTestRawQueryBlob(Executor executor) throws InterruptedException {
- final byte[] blob = new byte[]{
- /* Header */
- 0x55, 0x66, /* Transaction ID */
- 0x01, 0x00, /* Flags */
- 0x00, 0x01, /* Questions */
- 0x00, 0x00, /* Answer RRs */
- 0x00, 0x00, /* Authority RRs */
- 0x00, 0x00, /* Additional RRs */
- /* Queries */
- 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
- 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
- 0x00, 0x01, /* Type */
- 0x00, 0x01 /* Class */
- };
- final String msg = "RawQuery blob " + byteArrayToHexString(blob);
- for (Network network : getTestableNetworks()) {
- final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
- mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, executor, null, callback);
-
- assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
- callback.waitForAnswer());
- callback.assertHasAnswer();
- }
- }
-
- public void doTestRawQueryRoot(Executor executor) throws InterruptedException {
- final String dname = "";
- final String msg = "RawQuery empty dname(ROOT) ";
- for (Network network : getTestableNetworks()) {
- final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
- mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
- executor, null, callback);
-
- assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
- callback.waitForAnswer());
- // Except no answer record because the root does not have AAAA records.
- callback.assertEmptyAnswer();
- }
- }
-
- public void doTestRawQueryNXDomain(Executor executor) throws InterruptedException {
- final String msg = "RawQuery " + TEST_NX_DOMAIN;
-
- for (Network network : getTestableNetworks()) {
- final NetworkCapabilities nc = (network != null)
- ? mCM.getNetworkCapabilities(network)
- : mCM.getNetworkCapabilities(mCM.getActiveNetwork());
- assertNotNull("Couldn't determine NetworkCapabilities for " + network, nc);
- // Some cellular networks configure their DNS servers never to return NXDOMAIN, so don't
- // test NXDOMAIN on these DNS servers.
- // b/144521720
- if (nc.hasTransport(TRANSPORT_CELLULAR)) continue;
- final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
- mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
- executor, null, callback);
-
- assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
- callback.waitForAnswer());
- callback.assertNXDomain();
- }
- }
-
- public void doTestRawQueryNXDomainWithPrivateDns(Executor executor)
- throws InterruptedException {
- 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
- 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, true);
- final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
- mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
- executor, null, callback);
-
- assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
- callback.waitForAnswer());
- callback.assertNXDomain();
- }
- }
-
- public void testRawQueryCancel() throws InterruptedException {
- final String msg = "Test cancel RawQuery " + TEST_DOMAIN;
- // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect
- // that the query is cancelled before it succeeds. If it is not cancelled before it
- // succeeds, retry the test until it is.
- for (Network network : getTestableNetworks()) {
- boolean retry = false;
- int round = 0;
- do {
- if (++round > CANCEL_RETRY_TIMES) {
- fail(msg + " cancel failed " + CANCEL_RETRY_TIMES + " times");
- }
- final CountDownLatch latch = new CountDownLatch(1);
- final CancellationSignal cancelSignal = new CancellationSignal();
- final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal);
- mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_EMPTY,
- mExecutor, cancelSignal, callback);
- mExecutor.execute(() -> {
- cancelSignal.cancel();
- latch.countDown();
- });
-
- retry = callback.needRetry();
- assertTrue(msg + " query was not cancelled",
- latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- } while (retry);
- }
- }
-
- public void testRawQueryBlobCancel() throws InterruptedException {
- final String msg = "Test cancel RawQuery blob " + byteArrayToHexString(TEST_BLOB);
- // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect
- // that the query is cancelled before it succeeds. If it is not cancelled before it
- // succeeds, retry the test until it is.
- for (Network network : getTestableNetworks()) {
- boolean retry = false;
- int round = 0;
- do {
- if (++round > CANCEL_RETRY_TIMES) {
- fail(msg + " cancel failed " + CANCEL_RETRY_TIMES + " times");
- }
- final CountDownLatch latch = new CountDownLatch(1);
- final CancellationSignal cancelSignal = new CancellationSignal();
- final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal);
- mDns.rawQuery(network, TEST_BLOB, FLAG_EMPTY, mExecutor, cancelSignal, callback);
- mExecutor.execute(() -> {
- cancelSignal.cancel();
- latch.countDown();
- });
-
- retry = callback.needRetry();
- assertTrue(msg + " cancel is not done",
- latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- } while (retry);
- }
- }
-
- public void testCancelBeforeQuery() throws InterruptedException {
- final String msg = "Test cancelled RawQuery " + TEST_DOMAIN;
- for (Network network : getTestableNetworks()) {
- final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
- final CancellationSignal cancelSignal = new CancellationSignal();
- cancelSignal.cancel();
- mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_EMPTY,
- mExecutor, cancelSignal, callback);
-
- assertTrue(msg + " should not return any answers",
- !callback.waitForAnswer(CANCEL_TIMEOUT_MS));
- }
- }
-
- /**
- * A query callback for InetAddress that ensures that the query is
- * cancelled and that onAnswer is never called. If the query succeeds
- * before it is cancelled, needRetry will return true so the
- * test can retry.
- */
- class VerifyCancelInetAddressCallback implements DnsResolver.Callback<List<InetAddress>> {
- private final CountDownLatch mLatch = new CountDownLatch(1);
- private final String mMsg;
- private final List<InetAddress> mAnswers;
- private final CancellationSignal mCancelSignal;
- private String mErrorMsg = null;
-
- VerifyCancelInetAddressCallback(@NonNull String msg, @Nullable CancellationSignal cancel) {
- this.mMsg = msg;
- this.mCancelSignal = cancel;
- mAnswers = new ArrayList<>();
- }
-
- public boolean waitForAnswer() throws InterruptedException {
- return mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- }
-
- public boolean needRetry() throws InterruptedException {
- return mLatch.await(CANCEL_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- }
-
- public boolean isAnswerEmpty() {
- return mAnswers.isEmpty();
- }
-
- public boolean hasIpv6Answer() {
- for (InetAddress answer : mAnswers) {
- if (answer instanceof Inet6Address) return true;
- }
- return false;
- }
-
- public boolean hasIpv4Answer() {
- for (InetAddress answer : mAnswers) {
- if (answer instanceof Inet4Address) return true;
- }
- return false;
- }
-
- public void assertNoError() {
- assertNull(mErrorMsg);
- }
-
- @Override
- public void onAnswer(@NonNull List<InetAddress> answerList, int rcode) {
- if (mCancelSignal != null && mCancelSignal.isCanceled()) {
- mErrorMsg = mMsg + " should not have returned any answers";
- mLatch.countDown();
- return;
- }
- for (InetAddress addr : answerList) {
- Log.d(TAG, "Reported addr: " + addr.toString());
- }
- mAnswers.clear();
- mAnswers.addAll(answerList);
- mLatch.countDown();
- }
-
- @Override
- public void onError(@NonNull DnsResolver.DnsException error) {
- mErrorMsg = mMsg + error.getMessage();
- }
- }
-
- public void testQueryForInetAddress() throws Exception {
- doTestQueryForInetAddress(mExecutor);
- }
-
- public void testQueryForInetAddressInline() throws Exception {
- doTestQueryForInetAddress(mExecutorInline);
- }
-
- public void testQueryForInetAddressIpv4() throws Exception {
- doTestQueryForInetAddressIpv4(mExecutor);
- }
-
- public void testQueryForInetAddressIpv4Inline() throws Exception {
- doTestQueryForInetAddressIpv4(mExecutorInline);
- }
-
- public void testQueryForInetAddressIpv6() throws Exception {
- doTestQueryForInetAddressIpv6(mExecutor);
- }
-
- public void testQueryForInetAddressIpv6Inline() throws Exception {
- doTestQueryForInetAddressIpv6(mExecutorInline);
- }
-
- public void testContinuousQueries() throws Exception {
- doTestContinuousQueries(mExecutor);
- }
-
- @SkipPresubmit(reason = "Flaky: b/159762682; add to presubmit after fixing")
- public void testContinuousQueriesInline() throws Exception {
- doTestContinuousQueries(mExecutorInline);
- }
-
- public void doTestQueryForInetAddress(Executor executor) throws InterruptedException {
- final String msg = "Test query for InetAddress " + TEST_DOMAIN;
- for (Network network : getTestableNetworks()) {
- final VerifyCancelInetAddressCallback callback =
- new VerifyCancelInetAddressCallback(msg, null);
- mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, executor, null, callback);
-
- assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
- callback.waitForAnswer());
- callback.assertNoError();
- assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
- }
- }
-
- public void testQueryCancelForInetAddress() throws InterruptedException {
- final String msg = "Test cancel query for InetAddress " + TEST_DOMAIN;
- // Start a DNS query and the cancel it immediately. Use VerifyCancelInetAddressCallback to
- // expect that the query is cancelled before it succeeds. If it is not cancelled before it
- // succeeds, retry the test until it is.
- for (Network network : getTestableNetworks()) {
- boolean retry = false;
- int round = 0;
- do {
- if (++round > CANCEL_RETRY_TIMES) {
- fail(msg + " cancel failed " + CANCEL_RETRY_TIMES + " times");
- }
- final CountDownLatch latch = new CountDownLatch(1);
- final CancellationSignal cancelSignal = new CancellationSignal();
- final VerifyCancelInetAddressCallback callback =
- new VerifyCancelInetAddressCallback(msg, cancelSignal);
- mDns.query(network, TEST_DOMAIN, FLAG_EMPTY, mExecutor, cancelSignal, callback);
- mExecutor.execute(() -> {
- cancelSignal.cancel();
- latch.countDown();
- });
-
- retry = callback.needRetry();
- assertTrue(msg + " query was not cancelled",
- latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- } while (retry);
- }
- }
-
- public void doTestQueryForInetAddressIpv4(Executor executor) throws InterruptedException {
- final String msg = "Test query for IPv4 InetAddress " + TEST_DOMAIN;
- for (Network network : getTestableNetworks()) {
- final VerifyCancelInetAddressCallback callback =
- new VerifyCancelInetAddressCallback(msg, null);
- mDns.query(network, TEST_DOMAIN, TYPE_A, FLAG_NO_CACHE_LOOKUP,
- executor, null, callback);
-
- assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
- callback.waitForAnswer());
- callback.assertNoError();
- assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
- assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer());
- }
- }
-
- public void doTestQueryForInetAddressIpv6(Executor executor) throws InterruptedException {
- final String msg = "Test query for IPv6 InetAddress " + TEST_DOMAIN;
- for (Network network : getTestableNetworks()) {
- final VerifyCancelInetAddressCallback callback =
- new VerifyCancelInetAddressCallback(msg, null);
- mDns.query(network, TEST_DOMAIN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
- executor, null, callback);
-
- assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
- callback.waitForAnswer());
- callback.assertNoError();
- assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
- assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer());
- }
- }
-
- public void testPrivateDnsBypass() throws InterruptedException {
- final Network[] testNetworks = getTestableNetworks();
-
- // Set an 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
- // private DNS bypassable network or bind one.
- if (network == null) continue;
-
- // wait for private DNS setting propagating
- mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
- network, INVALID_PRIVATE_DNS_SERVER, false);
-
- final CountDownLatch latch = new CountDownLatch(1);
- final DnsResolver.Callback<List<InetAddress>> errorCallback =
- new DnsResolver.Callback<List<InetAddress>>() {
- @Override
- public void onAnswer(@NonNull List<InetAddress> answerList, int rcode) {
- fail(msg + " should not get valid answer");
- }
-
- @Override
- public void onError(@NonNull DnsResolver.DnsException error) {
- assertEquals(DnsResolver.ERROR_SYSTEM, error.code);
- assertEquals(ETIMEDOUT, ((ErrnoException) error.getCause()).errno);
- latch.countDown();
- }
- };
- // Private DNS strict mode with invalid DNS server is set
- // Expect no valid answer returned but ErrnoException with ETIMEDOUT
- mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, errorCallback);
-
- assertTrue(msg + " invalid server round. No response after " + TIMEOUT_MS + "ms.",
- latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
- final VerifyCancelInetAddressCallback callback =
- new VerifyCancelInetAddressCallback(msg, null);
- // Bypass privateDns, expect query works fine
- mDns.query(network.getPrivateDnsBypassingCopy(),
- TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback);
-
- assertTrue(msg + " bypass private DNS round. No answer after " + TIMEOUT_MS + "ms.",
- callback.waitForAnswer());
- callback.assertNoError();
- assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
-
- // To ensure private DNS bypass still work even if passing null network.
- // Bind process network with a private DNS bypassable network.
- mCM.bindProcessToNetwork(network.getPrivateDnsBypassingCopy());
- final VerifyCancelInetAddressCallback callbackWithNullNetwork =
- new VerifyCancelInetAddressCallback(msg + " with null network ", null);
- mDns.query(null,
- TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callbackWithNullNetwork);
-
- assertTrue(msg + " with null network bypass private DNS round. No answer after " +
- TIMEOUT_MS + "ms.", callbackWithNullNetwork.waitForAnswer());
- callbackWithNullNetwork.assertNoError();
- assertTrue(msg + " with null network returned 0 results",
- !callbackWithNullNetwork.isAnswerEmpty());
-
- // Reset process network to default.
- mCM.bindProcessToNetwork(null);
- }
- }
-
- public void doTestContinuousQueries(Executor executor) throws InterruptedException {
- final String msg = "Test continuous " + QUERY_TIMES + " queries " + TEST_DOMAIN;
- for (Network network : getTestableNetworks()) {
- for (int i = 0; i < QUERY_TIMES ; ++i) {
- final VerifyCancelInetAddressCallback callback =
- new VerifyCancelInetAddressCallback(msg, null);
- // query v6/v4 in turn
- boolean queryV6 = (i % 2 == 0);
- mDns.query(network, TEST_DOMAIN, queryV6 ? TYPE_AAAA : TYPE_A,
- FLAG_NO_CACHE_LOOKUP, executor, null, callback);
-
- assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
- callback.waitForAnswer());
- callback.assertNoError();
- assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
- assertTrue(msg + " returned " + (queryV6 ? "Ipv4" : "Ipv6") + " results",
- queryV6 ? !callback.hasIpv4Answer() : !callback.hasIpv6Answer());
- }
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/DnsTest.java b/tests/tests/net/src/android/net/cts/DnsTest.java
deleted file mode 100644
index fde27e9..0000000
--- a/tests/tests/net/src/android/net/cts/DnsTest.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkInfo;
-import android.os.SystemClock;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import com.android.testutils.SkipPresubmit;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public class DnsTest extends AndroidTestCase {
-
- static {
- System.loadLibrary("nativedns_jni");
- }
-
- private static final boolean DBG = false;
- private static final String TAG = "DnsTest";
- private static final String PROXY_NETWORK_TYPE = "PROXY";
-
- private ConnectivityManager mCm;
-
- public void setUp() {
- mCm = getContext().getSystemService(ConnectivityManager.class);
- }
-
- /**
- * @return true on success
- */
- private static native boolean testNativeDns();
-
- /**
- * Verify:
- * DNS works - forwards and backwards, giving ipv4 and ipv6
- * Test that DNS work on v4 and v6 networks
- * Test Native dns calls (4)
- * Todo:
- * Cache is flushed when we change networks
- * have per-network caches
- * No cache when there's no network
- * Perf - measure size of first and second tier caches and their effect
- * Assert requires network permission
- */
- @SkipPresubmit(reason = "IPv6 support may be missing on presubmit virtual hardware")
- public void testDnsWorks() throws Exception {
- ensureIpv6Connectivity();
-
- InetAddress addrs[] = {};
- try {
- addrs = InetAddress.getAllByName("www.google.com");
- } catch (UnknownHostException e) {}
- assertTrue("[RERUN] DNS could not resolve www.google.com. Check internet connection",
- addrs.length != 0);
- boolean foundV4 = false, foundV6 = false;
- for (InetAddress addr : addrs) {
- if (addr instanceof Inet4Address) foundV4 = true;
- else if (addr instanceof Inet6Address) foundV6 = true;
- if (DBG) Log.e(TAG, "www.google.com gave " + addr.toString());
- }
-
- // We should have at least one of the addresses to connect!
- assertTrue("www.google.com must have IPv4 and/or IPv6 address", foundV4 || foundV6);
-
- // Skip the rest of the test if the active network for watch is PROXY.
- // TODO: Check NetworkInfo type in addition to type name once ag/601257 is merged.
- if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
- && activeNetworkInfoIsProxy()) {
- Log.i(TAG, "Skipping test because the active network type name is PROXY.");
- return;
- }
-
- // Clear test state so we don't get confused with the previous results.
- addrs = new InetAddress[0];
- foundV4 = foundV6 = false;
- try {
- addrs = InetAddress.getAllByName("ipv6.google.com");
- } catch (UnknownHostException e) {}
- String msg =
- "[RERUN] DNS could not resolve ipv6.google.com, check the network supports IPv6. lp=" +
- mCm.getActiveLinkProperties();
- assertTrue(msg, addrs.length != 0);
- for (InetAddress addr : addrs) {
- msg = "[RERUN] ipv6.google.com returned IPv4 address: " + addr.getHostAddress() +
- ", check your network's DNS server. lp=" + mCm.getActiveLinkProperties();
- assertFalse (msg, addr instanceof Inet4Address);
- foundV6 |= (addr instanceof Inet6Address);
- if (DBG) Log.e(TAG, "ipv6.google.com gave " + addr.toString());
- }
-
- assertTrue(foundV6);
-
- assertTrue(testNativeDns());
- }
-
- private static final String[] URLS = { "www.google.com", "ipv6.google.com", "www.yahoo.com",
- "facebook.com", "youtube.com", "blogspot.com", "baidu.com", "wikipedia.org",
-// live.com fails rev lookup.
- "twitter.com", "qq.com", "msn.com", "yahoo.co.jp", "linkedin.com",
- "taobao.com", "google.co.in", "sina.com.cn", "amazon.com", "wordpress.com",
- "google.co.uk", "ebay.com", "yandex.ru", "163.com", "google.co.jp", "google.fr",
- "microsoft.com", "paypal.com", "google.com.br", "flickr.com",
- "mail.ru", "craigslist.org", "fc2.com", "google.it",
-// "apple.com", fails rev lookup
- "google.es",
- "imdb.com", "google.ru", "soho.com", "bbc.co.uk", "vkontakte.ru", "ask.com",
- "tumblr.com", "weibo.com", "go.com", "xvideos.com", "livejasmin.com", "cnn.com",
- "youku.com", "blogspot.com", "soso.com", "google.ca", "aol.com", "tudou.com",
- "xhamster.com", "megaupload.com", "ifeng.com", "zedo.com", "mediafire.com", "ameblo.jp",
- "pornhub.com", "google.co.id", "godaddy.com", "adobe.com", "rakuten.co.jp", "about.com",
- "espn.go.com", "4shared.com", "alibaba.com","ebay.de", "yieldmanager.com",
- "wordpress.org", "livejournal.com", "google.com.tr", "google.com.mx", "renren.com",
- "livedoor.com", "google.com.au", "youporn.com", "uol.com.br", "cnet.com", "conduit.com",
- "google.pl", "myspace.com", "nytimes.com", "ebay.co.uk", "chinaz.com", "hao123.com",
- "thepiratebay.org", "doubleclick.com", "alipay.com", "netflix.com", "cnzz.com",
- "huffingtonpost.com", "twitpic.com", "weather.com", "babylon.com", "amazon.de",
- "dailymotion.com", "orkut.com", "orkut.com.br", "google.com.sa", "odnoklassniki.ru",
- "amazon.co.jp", "google.nl", "goo.ne.jp", "stumbleupon.com", "tube8.com", "tmall.com",
- "imgur.com", "globo.com", "secureserver.net", "fileserve.com", "tianya.cn", "badoo.com",
- "ehow.com", "photobucket.com", "imageshack.us", "xnxx.com", "deviantart.com",
- "filestube.com", "addthis.com", "douban.com", "vimeo.com", "sogou.com",
- "stackoverflow.com", "reddit.com", "dailymail.co.uk", "redtube.com", "megavideo.com",
- "taringa.net", "pengyou.com", "amazon.co.uk", "fbcdn.net", "aweber.com", "spiegel.de",
- "rapidshare.com", "mixi.jp", "360buy.com", "google.cn", "digg.com", "answers.com",
- "bit.ly", "indiatimes.com", "skype.com", "yfrog.com", "optmd.com", "google.com.eg",
- "google.com.pk", "58.com", "hotfile.com", "google.co.th",
- "bankofamerica.com", "sourceforge.net", "maktoob.com", "warriorforum.com", "rediff.com",
- "google.co.za", "56.com", "torrentz.eu", "clicksor.com", "avg.com",
- "download.com", "ku6.com", "statcounter.com", "foxnews.com", "google.com.ar",
- "nicovideo.jp", "reference.com", "liveinternet.ru", "ucoz.ru", "xinhuanet.com",
- "xtendmedia.com", "naver.com", "youjizz.com", "domaintools.com", "sparkstudios.com",
- "rambler.ru", "scribd.com", "kaixin001.com", "mashable.com", "adultfirendfinder.com",
- "files.wordpress.com", "guardian.co.uk", "bild.de", "yelp.com", "wikimedia.org",
- "chase.com", "onet.pl", "ameba.jp", "pconline.com.cn", "free.fr", "etsy.com",
- "typepad.com", "youdao.com", "megaclick.com", "digitalpoint.com", "blogfa.com",
- "salesforce.com", "adf.ly", "ganji.com", "wikia.com", "archive.org", "terra.com.br",
- "w3schools.com", "ezinearticles.com", "wjs.com", "google.com.my", "clickbank.com",
- "squidoo.com", "hulu.com", "repubblica.it", "google.be", "allegro.pl", "comcast.net",
- "narod.ru", "zol.com.cn", "orange.fr", "soufun.com", "hatena.ne.jp", "google.gr",
- "in.com", "techcrunch.com", "orkut.co.in", "xunlei.com",
- "reuters.com", "google.com.vn", "hostgator.com", "kaskus.us", "espncricinfo.com",
- "hootsuite.com", "qiyi.com", "gmx.net", "xing.com", "php.net", "soku.com", "web.de",
- "libero.it", "groupon.com", "51.la", "slideshare.net", "booking.com", "seesaa.net",
- "126.com", "telegraph.co.uk", "wretch.cc", "twimg.com", "rutracker.org", "angege.com",
- "nba.com", "dell.com", "leboncoin.fr", "people.com", "google.com.tw", "walmart.com",
- "daum.net", "2ch.net", "constantcontact.com", "nifty.com", "mywebsearch.com",
- "tripadvisor.com", "google.se", "paipai.com", "google.com.ua", "ning.com", "hp.com",
- "google.at", "joomla.org", "icio.us", "hudong.com", "csdn.net", "getfirebug.com",
- "ups.com", "cj.com", "google.ch", "camzap.com", "wordreference.com", "tagged.com",
- "wp.pl", "mozilla.com", "google.ru", "usps.com", "china.com", "themeforest.net",
- "search-results.com", "tribalfusion.com", "thefreedictionary.com", "isohunt.com",
- "linkwithin.com", "cam4.com", "plentyoffish.com", "wellsfargo.com", "metacafe.com",
- "depositfiles.com", "freelancer.com", "opendns.com", "homeway.com", "engadget.com",
- "10086.cn", "360.cn", "marca.com", "dropbox.com", "ign.com", "match.com", "google.pt",
- "facemoods.com", "hardsextube.com", "google.com.ph", "lockerz.com", "istockphoto.com",
- "partypoker.com", "netlog.com", "outbrain.com", "elpais.com", "fiverr.com",
- "biglobe.ne.jp", "corriere.it", "love21cn.com", "yesky.com", "spankwire.com",
- "ig.com.br", "imagevenue.com", "hubpages.com", "google.co.ve"};
-
-// TODO - this works, but is slow and cts doesn't do anything with the result.
-// Maybe require a min performance, a min cache size (detectable) and/or move
-// to perf testing
- private static final int LOOKUP_COUNT_GOAL = URLS.length;
- public void skiptestDnsPerf() {
- ArrayList<String> results = new ArrayList<String>();
- int failures = 0;
- try {
- for (int numberOfUrls = URLS.length; numberOfUrls > 0; numberOfUrls--) {
- failures = 0;
- int iterationLimit = LOOKUP_COUNT_GOAL / numberOfUrls;
- long startTime = SystemClock.elapsedRealtimeNanos();
- for (int iteration = 0; iteration < iterationLimit; iteration++) {
- for (int urlIndex = 0; urlIndex < numberOfUrls; urlIndex++) {
- try {
- InetAddress addr = InetAddress.getByName(URLS[urlIndex]);
- } catch (UnknownHostException e) {
- Log.e(TAG, "failed first lookup of " + URLS[urlIndex]);
- failures++;
- try {
- InetAddress addr = InetAddress.getByName(URLS[urlIndex]);
- } catch (UnknownHostException ee) {
- failures++;
- Log.e(TAG, "failed SECOND lookup of " + URLS[urlIndex]);
- }
- }
- }
- }
- long endTime = SystemClock.elapsedRealtimeNanos();
- float nsPer = ((float)(endTime-startTime) / iterationLimit) / numberOfUrls/ 1000;
- String thisResult = new String("getByName for " + numberOfUrls + " took " +
- (endTime - startTime)/1000 + "(" + nsPer + ") with " +
- failures + " failures\n");
- Log.d(TAG, thisResult);
- results.add(thisResult);
- }
- // build up a list of addresses
- ArrayList<byte[]> addressList = new ArrayList<byte[]>();
- for (String url : URLS) {
- try {
- InetAddress addr = InetAddress.getByName(url);
- addressList.add(addr.getAddress());
- } catch (UnknownHostException e) {
- Log.e(TAG, "Exception making reverseDNS list: " + e.toString());
- }
- }
- for (int numberOfAddrs = addressList.size(); numberOfAddrs > 0; numberOfAddrs--) {
- int iterationLimit = LOOKUP_COUNT_GOAL / numberOfAddrs;
- failures = 0;
- long startTime = SystemClock.elapsedRealtimeNanos();
- for (int iteration = 0; iteration < iterationLimit; iteration++) {
- for (int addrIndex = 0; addrIndex < numberOfAddrs; addrIndex++) {
- try {
- InetAddress addr = InetAddress.getByAddress(addressList.get(addrIndex));
- String hostname = addr.getHostName();
- } catch (UnknownHostException e) {
- failures++;
- Log.e(TAG, "Failure doing reverse DNS lookup: " + e.toString());
- try {
- InetAddress addr =
- InetAddress.getByAddress(addressList.get(addrIndex));
- String hostname = addr.getHostName();
-
- } catch (UnknownHostException ee) {
- failures++;
- Log.e(TAG, "Failure doing SECOND reverse DNS lookup: " +
- ee.toString());
- }
- }
- }
- }
- long endTime = SystemClock.elapsedRealtimeNanos();
- float nsPer = ((endTime-startTime) / iterationLimit) / numberOfAddrs / 1000;
- String thisResult = new String("getHostName for " + numberOfAddrs + " took " +
- (endTime - startTime)/1000 + "(" + nsPer + ") with " +
- failures + " failures\n");
- Log.d(TAG, thisResult);
- results.add(thisResult);
- }
- for (String result : results) Log.d(TAG, result);
-
- InetAddress exit = InetAddress.getByName("exitrightnow.com");
- Log.e(TAG, " exit address= "+exit.toString());
-
- } catch (Exception e) {
- Log.e(TAG, "bad URL in testDnsPerf: " + e.toString());
- }
- }
-
- private boolean activeNetworkInfoIsProxy() {
- NetworkInfo info = mCm.getActiveNetworkInfo();
- if (PROXY_NETWORK_TYPE.equals(info.getTypeName())) {
- return true;
- }
-
- return false;
- }
-
- private void ensureIpv6Connectivity() throws InterruptedException {
- CountDownLatch latch = new CountDownLatch(1);
- final int TIMEOUT_MS = 5_000;
-
- final NetworkCallback callback = new NetworkCallback() {
- @Override
- public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
- if (lp.hasGlobalIpv6Address()) {
- latch.countDown();
- }
- }
- };
- mCm.registerDefaultNetworkCallback(callback);
-
- String msg = "Default network did not provide IPv6 connectivity after " + TIMEOUT_MS
- + "ms. Please connect to an IPv6-capable network. lp="
- + mCm.getActiveLinkProperties();
- try {
- assertTrue(msg, latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- } finally {
- mCm.unregisterNetworkCallback(callback);
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/IkeTunUtils.java b/tests/tests/net/src/android/net/cts/IkeTunUtils.java
deleted file mode 100644
index fc25292..0000000
--- a/tests/tests/net/src/android/net/cts/IkeTunUtils.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.cts;
-
-import static android.net.cts.PacketUtils.BytePayload;
-import static android.net.cts.PacketUtils.IP4_HDRLEN;
-import static android.net.cts.PacketUtils.IP6_HDRLEN;
-import static android.net.cts.PacketUtils.IpHeader;
-import static android.net.cts.PacketUtils.UDP_HDRLEN;
-import static android.net.cts.PacketUtils.UdpHeader;
-import static android.net.cts.PacketUtils.getIpHeader;
-import static android.system.OsConstants.IPPROTO_UDP;
-
-import android.os.ParcelFileDescriptor;
-
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-
-// TODO: Merge this with the version in the IPsec module (IKEv2 library) CTS tests.
-/** An extension of the TunUtils class with IKE-specific packet handling. */
-public class IkeTunUtils extends TunUtils {
- private static final int PORT_LEN = 2;
-
- private static final byte[] NON_ESP_MARKER = new byte[] {0, 0, 0, 0};
-
- private static final int IKE_HEADER_LEN = 28;
- private static final int IKE_SPI_LEN = 8;
- private static final int IKE_IS_RESP_BYTE_OFFSET = 19;
- private static final int IKE_MSG_ID_OFFSET = 20;
- private static final int IKE_MSG_ID_LEN = 4;
-
- public IkeTunUtils(ParcelFileDescriptor tunFd) {
- super(tunFd);
- }
-
- /**
- * Await an expected IKE request and inject an IKE response.
- *
- * @param respIkePkt IKE response packet without IP/UDP headers or NON ESP MARKER.
- */
- public byte[] awaitReqAndInjectResp(long expectedInitIkeSpi, int expectedMsgId,
- boolean encapExpected, byte[] respIkePkt) throws Exception {
- final byte[] request = awaitIkePacket(expectedInitIkeSpi, expectedMsgId, encapExpected);
-
- // Build response header by flipping address and port
- final InetAddress srcAddr = getDstAddress(request);
- final InetAddress dstAddr = getSrcAddress(request);
- final int srcPort = getDstPort(request);
- final int dstPort = getSrcPort(request);
-
- final byte[] response =
- buildIkePacket(srcAddr, dstAddr, srcPort, dstPort, encapExpected, respIkePkt);
- injectPacket(response);
- return request;
- }
-
- private byte[] awaitIkePacket(long expectedInitIkeSpi, int expectedMsgId, boolean expectEncap)
- throws Exception {
- return super.awaitPacket(pkt -> isIke(pkt, expectedInitIkeSpi, expectedMsgId, expectEncap));
- }
-
- private static boolean isIke(
- byte[] pkt, long expectedInitIkeSpi, int expectedMsgId, boolean encapExpected) {
- final int ipProtocolOffset;
- final int ikeOffset;
-
- if (isIpv6(pkt)) {
- ipProtocolOffset = IP6_PROTO_OFFSET;
- ikeOffset = IP6_HDRLEN + UDP_HDRLEN;
- } else {
- if (encapExpected && !hasNonEspMarkerv4(pkt)) {
- return false;
- }
-
- // Use default IPv4 header length (assuming no options)
- final int encapMarkerLen = encapExpected ? NON_ESP_MARKER.length : 0;
- ipProtocolOffset = IP4_PROTO_OFFSET;
- ikeOffset = IP4_HDRLEN + UDP_HDRLEN + encapMarkerLen;
- }
-
- return pkt[ipProtocolOffset] == IPPROTO_UDP
- && areSpiAndMsgIdEqual(pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId);
- }
-
- /** Checks if the provided IPv4 packet has a UDP-encapsulation NON-ESP marker */
- private static boolean hasNonEspMarkerv4(byte[] ipv4Pkt) {
- final int nonEspMarkerOffset = IP4_HDRLEN + UDP_HDRLEN;
- if (ipv4Pkt.length < nonEspMarkerOffset + NON_ESP_MARKER.length) {
- return false;
- }
-
- final byte[] nonEspMarker = Arrays.copyOfRange(
- ipv4Pkt, nonEspMarkerOffset, nonEspMarkerOffset + NON_ESP_MARKER.length);
- return Arrays.equals(NON_ESP_MARKER, nonEspMarker);
- }
-
- private static boolean areSpiAndMsgIdEqual(
- byte[] pkt, int ikeOffset, long expectedIkeInitSpi, int expectedMsgId) {
- if (pkt.length <= ikeOffset + IKE_HEADER_LEN) {
- return false;
- }
-
- final ByteBuffer buffer = ByteBuffer.wrap(pkt);
- final long spi = buffer.getLong(ikeOffset);
- final int msgId = buffer.getInt(ikeOffset + IKE_MSG_ID_OFFSET);
-
- return expectedIkeInitSpi == spi && expectedMsgId == msgId;
- }
-
- private static InetAddress getSrcAddress(byte[] pkt) throws Exception {
- return getAddress(pkt, true);
- }
-
- private static InetAddress getDstAddress(byte[] pkt) throws Exception {
- return getAddress(pkt, false);
- }
-
- private static InetAddress getAddress(byte[] pkt, boolean getSrcAddr) throws Exception {
- final int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN;
- final int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET;
- final int ipOffset = getSrcAddr ? srcIpOffset : srcIpOffset + ipLen;
-
- if (pkt.length < ipOffset + ipLen) {
- // Should be impossible; getAddress() is only called with a full IKE request including
- // the IP and UDP headers.
- throw new IllegalArgumentException("Packet was too short to contain IP address");
- }
-
- return InetAddress.getByAddress(Arrays.copyOfRange(pkt, ipOffset, ipOffset + ipLen));
- }
-
- private static int getSrcPort(byte[] pkt) throws Exception {
- return getPort(pkt, true);
- }
-
- private static int getDstPort(byte[] pkt) throws Exception {
- return getPort(pkt, false);
- }
-
- private static int getPort(byte[] pkt, boolean getSrcPort) {
- final int srcPortOffset = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN;
- final int portOffset = getSrcPort ? srcPortOffset : srcPortOffset + PORT_LEN;
-
- if (pkt.length < portOffset + PORT_LEN) {
- // Should be impossible; getPort() is only called with a full IKE request including the
- // IP and UDP headers.
- throw new IllegalArgumentException("Packet was too short to contain port");
- }
-
- final ByteBuffer buffer = ByteBuffer.wrap(pkt);
- return Short.toUnsignedInt(buffer.getShort(portOffset));
- }
-
- private static byte[] buildIkePacket(
- InetAddress srcAddr,
- InetAddress dstAddr,
- int srcPort,
- int dstPort,
- boolean useEncap,
- byte[] payload)
- throws Exception {
- // Append non-ESP marker if encap is enabled
- if (useEncap) {
- final ByteBuffer buffer = ByteBuffer.allocate(NON_ESP_MARKER.length + payload.length);
- buffer.put(NON_ESP_MARKER);
- buffer.put(payload);
- payload = buffer.array();
- }
-
- final UdpHeader udpPkt = new UdpHeader(srcPort, dstPort, new BytePayload(payload));
- final IpHeader ipPkt = getIpHeader(udpPkt.getProtocolId(), srcAddr, dstAddr, udpPkt);
- return ipPkt.getPacketBytes();
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/Ikev2VpnTest.java b/tests/tests/net/src/android/net/cts/Ikev2VpnTest.java
deleted file mode 100644
index 9eab024..0000000
--- a/tests/tests/net/src/android/net/cts/Ikev2VpnTest.java
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
-
-import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
-
-import static org.junit.Assert.assertArrayEquals;
-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;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.Ikev2VpnProfile;
-import android.net.IpSecAlgorithm;
-import android.net.LinkAddress;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.net.ProxyInfo;
-import android.net.TestNetworkInterface;
-import android.net.TestNetworkManager;
-import android.net.VpnManager;
-import android.net.cts.util.CtsNetUtils;
-import android.os.Build;
-import android.os.Process;
-import android.platform.test.annotations.AppModeFull;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.internal.util.HexDump;
-import com.android.org.bouncycastle.x509.X509V1CertificateGenerator;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-import com.android.testutils.DevSdkIgnoreRunner;
-
-import org.junit.After;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.math.BigInteger;
-import java.net.InetAddress;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import javax.security.auth.x500.X500Principal;
-
-@RunWith(DevSdkIgnoreRunner.class)
-@IgnoreUpTo(Build.VERSION_CODES.Q)
-@AppModeFull(reason = "Appops state changes disallowed for instant apps (OP_ACTIVATE_PLATFORM_VPN)")
-public class Ikev2VpnTest {
- private static final String TAG = Ikev2VpnTest.class.getSimpleName();
-
- // Test vectors for IKE negotiation in test mode.
- private static final String SUCCESSFUL_IKE_INIT_RESP_V4 =
- "46b8eca1e0d72a18b2b5d9006d47a0022120222000000000000002d0220000300000002c01010004030000"
- + "0c0100000c800e0100030000080300000c030000080200000400000008040000102800020800"
- + "100000b8070f159fe5141d8754ca86f72ecc28d66f514927e96cbe9eec0adb42bf2c276a0ab7"
- + "a97fa93555f4be9218c14e7f286bb28c6b4fb13825a420f2ffc165854f200bab37d69c8963d4"
- + "0acb831d983163aa50622fd35c182efe882cf54d6106222abcfaa597255d302f1b95ab71c142"
- + "c279ea5839a180070bff73f9d03fab815f0d5ee2adec7e409d1e35979f8bd92ffd8aab13d1a0"
- + "0657d816643ae767e9ae84d2ccfa2bcce1a50572be8d3748ae4863c41ae90da16271e014270f"
- + "77edd5cd2e3299f3ab27d7203f93d770bacf816041cdcecd0f9af249033979da4369cb242dd9"
- + "6d172e60513ff3db02de63e50eb7d7f596ada55d7946cad0af0669d1f3e2804846ab3f2a930d"
- + "df56f7f025f25c25ada694e6231abbb87ee8cfd072c8481dc0b0f6b083fdc3bd89b080e49feb"
- + "0288eef6fdf8a26ee2fc564a11e7385215cf2deaf2a9965638fc279c908ccdf04094988d91a2"
- + "464b4a8c0326533aff5119ed79ecbd9d99a218b44f506a5eb09351e67da86698b4c58718db25"
- + "d55f426fb4c76471b27a41fbce00777bc233c7f6e842e39146f466826de94f564cad8b92bfbe"
- + "87c99c4c7973ec5f1eea8795e7da82819753aa7c4fcfdab77066c56b939330c4b0d354c23f83"
- + "ea82fa7a64c4b108f1188379ea0eb4918ee009d804100e6bf118771b9058d42141c847d5ec37"
- + "6e5ec591c71fc9dac01063c2bd31f9c783b28bf1182900002430f3d5de3449462b31dd28bc27"
- + "297b6ad169bccce4f66c5399c6e0be9120166f2900001c0000400428b8df2e66f69c8584a186"
- + "c5eac66783551d49b72900001c000040054e7a622e802d5cbfb96d5f30a6e433994370173529"
- + "0000080000402e290000100000402f00020003000400050000000800004014";
- private static final String SUCCESSFUL_IKE_INIT_RESP_V6 =
- "46b8eca1e0d72a1800d9ea1babce26bf2120222000000000000002d0220000300000002c01010004030000"
- + "0c0100000c800e0100030000080300000c030000080200000400000008040000102800020800"
- + "100000ea0e6dd9ca5930a9a45c323a41f64bfd8cdef7730f5fbff37d7c377da427f489a42aa8"
- + "c89233380e6e925990d49de35c2cdcf63a61302c731a4b3569df1ee1bf2457e55a6751838ede"
- + "abb75cc63ba5c9e4355e8e784f383a5efe8a44727dc14aeaf8dacc2620fb1c8875416dc07739"
- + "7fe4decc1bd514a9c7d270cf21fd734c63a25c34b30b68686e54e8a198f37f27cb491fe27235"
- + "fab5476b036d875ccab9a68d65fbf3006197f9bebbf94de0d3802b4fafe1d48d931ce3a1a346"
- + "2d65bd639e9bd7fa46299650a9dbaf9b324e40b466942d91a59f41ef8042f8474c4850ed0f63"
- + "e9238949d41cd8bbaea9aefdb65443a6405792839563aa5dc5c36b5ce8326ccf8a94d9622b85"
- + "038d390d5fc0299e14e1f022966d4ac66515f6108ca04faec44821fe5bbf2ed4f84ff5671219"
- + "608cb4c36b44a31ba010c9088f8d5ff943bb9ff857f74be1755f57a5783874adc57f42bb174e"
- + "4ad3215de628707014dbcb1707bd214658118fdd7a42b3e1638b991ce5b812a667f1145be811"
- + "685e3cd3baf9b18d062657b64c206a4d19a531c252a6a51a04aeaf42c618620cdbab65baca23"
- + "82c57ed888422aeaacf7f1bc3fe2247ff7e7eaca218b74d7b31d02f2b0afa123f802529e7e6c"
- + "3259d418290740ddbf55686e26998d7edcbbf895664972fed666f2f20af40503aa2af436ec6d"
- + "4ec981ab19b9088755d94ae7a7c2066ea331d4e56e290000243fefe5555fce552d57a84e682c"
- + "d4a6dfb3f2f94a94464d5bec3d88b88e9559642900001c00004004eb4afff764e7b79bca78b1"
- + "3a89100d36d678ae982900001c00004005d177216a3c26f782076e12570d40bfaaa148822929"
- + "0000080000402e290000100000402f00020003000400050000000800004014";
- private static final String SUCCESSFUL_IKE_AUTH_RESP_V4 =
- "46b8eca1e0d72a18b2b5d9006d47a0022e20232000000001000000e0240000c420a2500a3da4c66fa6929e"
- + "600f36349ba0e38de14f78a3ad0416cba8c058735712a3d3f9a0a6ed36de09b5e9e02697e7c4"
- + "2d210ac86cfbd709503cfa51e2eab8cfdc6427d136313c072968f6506a546eb5927164200592"
- + "6e36a16ee994e63f029432a67bc7d37ca619e1bd6e1678df14853067ecf816b48b81e8746069"
- + "406363e5aa55f13cb2afda9dbebee94256c29d630b17dd7f1ee52351f92b6e1c3d8551c513f1"
- + "d74ac52a80b2041397e109fe0aeb3c105b0d4be0ae343a943398764281";
- private static final String SUCCESSFUL_IKE_AUTH_RESP_V6 =
- "46b8eca1e0d72a1800d9ea1babce26bf2e20232000000001000000f0240000d4aaf6eaa6c06b50447e6f54"
- + "827fd8a9d9d6ac8015c1ebb3e8cb03fc6e54b49a107441f50004027cc5021600828026367f03"
- + "bc425821cd7772ee98637361300c9b76056e874fea2bd4a17212370b291894264d8c023a01d1"
- + "c3b691fd4b7c0b534e8c95af4c4638e2d125cb21c6267e2507cd745d72e8da109c47b9259c6c"
- + "57a26f6bc5b337b9b9496d54bdde0333d7a32e6e1335c9ee730c3ecd607a8689aa7b0577b74f"
- + "3bf437696a9fd5fc0aee3ed346cd9e15d1dda293df89eb388a8719388a60ca7625754de12cdb"
- + "efe4c886c5c401";
- private static final long IKE_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16);
-
- private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1");
- private static final InetAddress LOCAL_OUTER_6 =
- InetAddress.parseNumericAddress("2001:db8::1");
-
- private static final int IP4_PREFIX_LEN = 32;
- private static final int IP6_PREFIX_LEN = 128;
-
- // TODO: Use IPv6 address when we can generate test vectors (GCE does not allow IPv6 yet).
- private static final String TEST_SERVER_ADDR_V4 = "192.0.2.2";
- private static final String TEST_SERVER_ADDR_V6 = "2001:db8::2";
- private static final String TEST_IDENTITY = "client.cts.android.com";
- private static final List<String> TEST_ALLOWED_ALGORITHMS =
- Arrays.asList(IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
-
- private static final ProxyInfo TEST_PROXY_INFO =
- ProxyInfo.buildDirectProxy("proxy.cts.android.com", 1234);
- private static final int TEST_MTU = 1300;
-
- private static final byte[] TEST_PSK = "ikeAndroidPsk".getBytes();
- private static final String TEST_USER = "username";
- private static final String TEST_PASSWORD = "pa55w0rd";
-
- // Static state to reduce setup/teardown
- private static final Context sContext = InstrumentationRegistry.getContext();
- private static final ConnectivityManager sCM =
- (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- private static final VpnManager sVpnMgr =
- (VpnManager) sContext.getSystemService(Context.VPN_MANAGEMENT_SERVICE);
- private static final CtsNetUtils mCtsNetUtils = new CtsNetUtils(sContext);
-
- private final X509Certificate mServerRootCa;
- private final CertificateAndKey mUserCertKey;
-
- public Ikev2VpnTest() throws Exception {
- // Build certificates
- mServerRootCa = generateRandomCertAndKeyPair().cert;
- mUserCertKey = generateRandomCertAndKeyPair();
- }
-
- @After
- public void tearDown() {
- setAppop(AppOpsManager.OP_ACTIVATE_VPN, false);
- setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false);
- }
-
- /**
- * Sets the given appop using shell commands
- *
- * <p>This method must NEVER be called from within a shell permission, as it will attempt to
- * acquire, and then drop the shell permission identity. This results in the caller losing the
- * shell permission identity due to these calls not being reference counted.
- */
- public void setAppop(int appop, boolean allow) {
- // Requires shell permission to update appops.
- runWithShellPermissionIdentity(() -> {
- mCtsNetUtils.setAppopPrivileged(appop, allow);
- }, Manifest.permission.MANAGE_TEST_NETWORKS);
- }
-
- private Ikev2VpnProfile buildIkev2VpnProfileCommon(
- Ikev2VpnProfile.Builder builder, boolean isRestrictedToTestNetworks) throws Exception {
- if (isRestrictedToTestNetworks) {
- builder.restrictToTestNetworks();
- }
-
- return builder.setBypassable(true)
- .setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS)
- .setProxy(TEST_PROXY_INFO)
- .setMaxMtu(TEST_MTU)
- .setMetered(false)
- .build();
- }
-
- private Ikev2VpnProfile buildIkev2VpnProfilePsk(boolean isRestrictedToTestNetworks)
- throws Exception {
- return buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V6, isRestrictedToTestNetworks);
- }
-
- private Ikev2VpnProfile buildIkev2VpnProfilePsk(
- String remote, boolean isRestrictedToTestNetworks) throws Exception {
- final Ikev2VpnProfile.Builder builder =
- new Ikev2VpnProfile.Builder(remote, TEST_IDENTITY).setAuthPsk(TEST_PSK);
-
- return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks);
- }
-
- private Ikev2VpnProfile buildIkev2VpnProfileUsernamePassword(boolean isRestrictedToTestNetworks)
- throws Exception {
- final Ikev2VpnProfile.Builder builder =
- new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
- .setAuthUsernamePassword(TEST_USER, TEST_PASSWORD, mServerRootCa);
-
- return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks);
- }
-
- private Ikev2VpnProfile buildIkev2VpnProfileDigitalSignature(boolean isRestrictedToTestNetworks)
- throws Exception {
- final Ikev2VpnProfile.Builder builder =
- new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
- .setAuthDigitalSignature(
- mUserCertKey.cert, mUserCertKey.key, mServerRootCa);
-
- return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks);
- }
-
- private void checkBasicIkev2VpnProfile(@NonNull Ikev2VpnProfile profile) throws Exception {
- assertEquals(TEST_SERVER_ADDR_V6, profile.getServerAddr());
- assertEquals(TEST_IDENTITY, profile.getUserIdentity());
- assertEquals(TEST_PROXY_INFO, profile.getProxyInfo());
- assertEquals(TEST_ALLOWED_ALGORITHMS, profile.getAllowedAlgorithms());
- assertTrue(profile.isBypassable());
- assertFalse(profile.isMetered());
- assertEquals(TEST_MTU, profile.getMaxMtu());
- assertFalse(profile.isRestrictedToTestNetworks());
- }
-
- @Test
- public void testBuildIkev2VpnProfilePsk() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- final Ikev2VpnProfile profile =
- buildIkev2VpnProfilePsk(false /* isRestrictedToTestNetworks */);
-
- checkBasicIkev2VpnProfile(profile);
- assertArrayEquals(TEST_PSK, profile.getPresharedKey());
-
- // Verify nothing else is set.
- assertNull(profile.getUsername());
- assertNull(profile.getPassword());
- assertNull(profile.getServerRootCaCert());
- assertNull(profile.getRsaPrivateKey());
- assertNull(profile.getUserCert());
- }
-
- @Test
- public void testBuildIkev2VpnProfileUsernamePassword() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- final Ikev2VpnProfile profile =
- buildIkev2VpnProfileUsernamePassword(false /* isRestrictedToTestNetworks */);
-
- checkBasicIkev2VpnProfile(profile);
- assertEquals(TEST_USER, profile.getUsername());
- assertEquals(TEST_PASSWORD, profile.getPassword());
- assertEquals(mServerRootCa, profile.getServerRootCaCert());
-
- // Verify nothing else is set.
- assertNull(profile.getPresharedKey());
- assertNull(profile.getRsaPrivateKey());
- assertNull(profile.getUserCert());
- }
-
- @Test
- public void testBuildIkev2VpnProfileDigitalSignature() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- final Ikev2VpnProfile profile =
- buildIkev2VpnProfileDigitalSignature(false /* isRestrictedToTestNetworks */);
-
- checkBasicIkev2VpnProfile(profile);
- assertEquals(mUserCertKey.cert, profile.getUserCert());
- assertEquals(mUserCertKey.key, profile.getRsaPrivateKey());
- assertEquals(mServerRootCa, profile.getServerRootCaCert());
-
- // Verify nothing else is set.
- assertNull(profile.getUsername());
- assertNull(profile.getPassword());
- assertNull(profile.getPresharedKey());
- }
-
- private void verifyProvisionVpnProfile(
- boolean hasActivateVpn, boolean hasActivatePlatformVpn, boolean expectIntent)
- throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- setAppop(AppOpsManager.OP_ACTIVATE_VPN, hasActivateVpn);
- setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, hasActivatePlatformVpn);
-
- final Ikev2VpnProfile profile =
- buildIkev2VpnProfilePsk(false /* isRestrictedToTestNetworks */);
- final Intent intent = sVpnMgr.provisionVpnProfile(profile);
- assertEquals(expectIntent, intent != null);
- }
-
- @Test
- public void testProvisionVpnProfileNoPreviousConsent() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- verifyProvisionVpnProfile(false /* hasActivateVpn */,
- false /* hasActivatePlatformVpn */, true /* expectIntent */);
- }
-
- @Test
- public void testProvisionVpnProfilePlatformVpnConsented() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- verifyProvisionVpnProfile(false /* hasActivateVpn */,
- true /* hasActivatePlatformVpn */, false /* expectIntent */);
- }
-
- @Test
- public void testProvisionVpnProfileVpnServiceConsented() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- verifyProvisionVpnProfile(true /* hasActivateVpn */,
- false /* hasActivatePlatformVpn */, false /* expectIntent */);
- }
-
- @Test
- public void testProvisionVpnProfileAllPreConsented() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- verifyProvisionVpnProfile(true /* hasActivateVpn */,
- true /* hasActivatePlatformVpn */, false /* expectIntent */);
- }
-
- @Test
- public void testDeleteVpnProfile() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true);
-
- final Ikev2VpnProfile profile =
- buildIkev2VpnProfilePsk(false /* isRestrictedToTestNetworks */);
- assertNull(sVpnMgr.provisionVpnProfile(profile));
-
- // Verify that deleting the profile works (even without the appop)
- setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false);
- sVpnMgr.deleteProvisionedVpnProfile();
-
- // Test that the profile was deleted - starting it should throw an IAE.
- try {
- setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true);
- sVpnMgr.startProvisionedVpnProfile();
- fail("Expected IllegalArgumentException due to missing profile");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testStartVpnProfileNoPreviousConsent() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- setAppop(AppOpsManager.OP_ACTIVATE_VPN, false);
- setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false);
-
- // Make sure the VpnProfile is not provisioned already.
- sVpnMgr.stopProvisionedVpnProfile();
-
- try {
- sVpnMgr.startProvisionedVpnProfile();
- fail("Expected SecurityException for missing consent");
- } catch (SecurityException expected) {
- }
- }
-
- private void checkStartStopVpnProfileBuildsNetworks(IkeTunUtils tunUtils, boolean testIpv6)
- throws Exception {
- String serverAddr = testIpv6 ? TEST_SERVER_ADDR_V6 : TEST_SERVER_ADDR_V4;
- String initResp = testIpv6 ? SUCCESSFUL_IKE_INIT_RESP_V6 : SUCCESSFUL_IKE_INIT_RESP_V4;
- String authResp = testIpv6 ? SUCCESSFUL_IKE_AUTH_RESP_V6 : SUCCESSFUL_IKE_AUTH_RESP_V4;
- boolean hasNat = !testIpv6;
-
- // Requires MANAGE_TEST_NETWORKS to provision a test-mode profile.
- mCtsNetUtils.setAppopPrivileged(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, true);
-
- final Ikev2VpnProfile profile =
- buildIkev2VpnProfilePsk(serverAddr, true /* isRestrictedToTestNetworks */);
- assertNull(sVpnMgr.provisionVpnProfile(profile));
-
- sVpnMgr.startProvisionedVpnProfile();
-
- // Inject IKE negotiation
- int expectedMsgId = 0;
- tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, false /* isEncap */,
- HexDump.hexStringToByteArray(initResp));
- tunUtils.awaitReqAndInjectResp(IKE_INITIATOR_SPI, expectedMsgId++, hasNat /* isEncap */,
- HexDump.hexStringToByteArray(authResp));
-
- // Verify the VPN network came up
- final NetworkRequest nr = new NetworkRequest.Builder()
- .clearCapabilities().addTransportType(TRANSPORT_VPN).build();
-
- final TestNetworkCallback cb = new TestNetworkCallback();
- sCM.requestNetwork(nr, cb);
- cb.waitForAvailable();
- final Network vpnNetwork = cb.currentNetwork;
- assertNotNull(vpnNetwork);
-
- final NetworkCapabilities caps = sCM.getNetworkCapabilities(vpnNetwork);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertTrue(caps.hasCapability(NET_CAPABILITY_INTERNET));
- assertEquals(Process.myUid(), caps.getOwnerUid());
-
- sVpnMgr.stopProvisionedVpnProfile();
- cb.waitForLost();
- assertEquals(vpnNetwork, cb.lastLostNetwork);
- }
-
- private void doTestStartStopVpnProfile(boolean testIpv6) throws Exception {
- // Non-final; these variables ensure we clean up properly after our test if we have
- // allocated test network resources
- final TestNetworkManager tnm = sContext.getSystemService(TestNetworkManager.class);
- TestNetworkInterface testIface = null;
- TestNetworkCallback tunNetworkCallback = null;
-
- try {
- // Build underlying test network
- testIface = tnm.createTunInterface(
- new LinkAddress[] {
- new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN),
- new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN)});
-
- // Hold on to this callback to ensure network does not get reaped.
- tunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork(
- testIface.getInterfaceName());
- final IkeTunUtils tunUtils = new IkeTunUtils(testIface.getFileDescriptor());
-
- checkStartStopVpnProfileBuildsNetworks(tunUtils, testIpv6);
- } finally {
- // Make sure to stop the VPN profile. This is safe to call multiple times.
- sVpnMgr.stopProvisionedVpnProfile();
-
- if (testIface != null) {
- testIface.getFileDescriptor().close();
- }
-
- if (tunNetworkCallback != null) {
- sCM.unregisterNetworkCallback(tunNetworkCallback);
- }
-
- final Network testNetwork = tunNetworkCallback.currentNetwork;
- if (testNetwork != null) {
- tnm.teardownTestNetwork(testNetwork);
- }
- }
- }
-
- @Test
- public void testStartStopVpnProfileV4() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- // Requires shell permission to update appops.
- runWithShellPermissionIdentity(() -> {
- doTestStartStopVpnProfile(false);
- });
- }
-
- @Test
- public void testStartStopVpnProfileV6() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- // Requires shell permission to update appops.
- runWithShellPermissionIdentity(() -> {
- doTestStartStopVpnProfile(true);
- });
- }
-
- private static class CertificateAndKey {
- public final X509Certificate cert;
- public final PrivateKey key;
-
- CertificateAndKey(X509Certificate cert, PrivateKey key) {
- this.cert = cert;
- this.key = key;
- }
- }
-
- private static CertificateAndKey generateRandomCertAndKeyPair() throws Exception {
- final Date validityBeginDate =
- new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L));
- final Date validityEndDate =
- new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1L));
-
- // Generate a keypair
- final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
- keyPairGenerator.initialize(512);
- final KeyPair keyPair = keyPairGenerator.generateKeyPair();
-
- final X500Principal dnName = new X500Principal("CN=test.android.com");
- final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
- certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
- certGen.setSubjectDN(dnName);
- certGen.setIssuerDN(dnName);
- certGen.setNotBefore(validityBeginDate);
- certGen.setNotAfter(validityEndDate);
- certGen.setPublicKey(keyPair.getPublic());
- certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
-
- final X509Certificate cert = certGen.generate(keyPair.getPrivate(), "AndroidOpenSSL");
- return new CertificateAndKey(cert, keyPair.getPrivate());
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/InetAddressesTest.java b/tests/tests/net/src/android/net/cts/InetAddressesTest.java
deleted file mode 100644
index 7837ce9..0000000
--- a/tests/tests/net/src/android/net/cts/InetAddressesTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.cts;
-
-import android.net.InetAddresses;
-import java.net.InetAddress;
-import junitparams.JUnitParamsRunner;
-import junitparams.Parameters;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(JUnitParamsRunner.class)
-public class InetAddressesTest {
-
- public static String[][] validNumericAddressesAndStringRepresentation() {
- return new String[][] {
- // Regular IPv4.
- { "1.2.3.4", "1.2.3.4" },
-
- // Regular IPv6.
- { "2001:4860:800d::68", "2001:4860:800d::68" },
- { "1234:5678::9ABC:DEF0", "1234:5678::9abc:def0" },
- { "2001:cdba:9abc:5678::", "2001:cdba:9abc:5678::" },
- { "::2001:cdba:9abc:5678", "::2001:cdba:9abc:5678" },
- { "64:ff9b::1.2.3.4", "64:ff9b::102:304" },
-
- { "::9abc:5678", "::154.188.86.120" },
-
- // Mapped IPv4
- { "::ffff:127.0.0.1", "127.0.0.1" },
-
- // Android does not recognize Octal (leading 0) cases: they are treated as decimal.
- { "0177.00.00.01", "177.0.0.1" },
-
- // Verify that examples from JavaDoc work correctly.
- { "192.0.2.1", "192.0.2.1" },
- { "2001:db8::1:2", "2001:db8::1:2" },
- };
- }
-
- public static String[] invalidNumericAddresses() {
- return new String[] {
- "",
- " ",
- "\t",
- "\n",
- "1.2.3.4.",
- "1.2.3",
- "1.2",
- "1",
- "1234",
- "0",
- "0x1.0x2.0x3.0x4",
- "0x7f.0x00.0x00.0x01",
- "0256.00.00.01",
- "fred",
- "www.google.com",
- // IPv6 encoded for use in URL as defined in RFC 2732
- "[fe80::6:2222]",
- };
- }
-
- @Parameters(method = "validNumericAddressesAndStringRepresentation")
- @Test
- public void parseNumericAddress(String address, String expectedString) {
- InetAddress inetAddress = InetAddresses.parseNumericAddress(address);
- assertEquals(expectedString, inetAddress.getHostAddress());
- }
-
- @Parameters(method = "invalidNumericAddresses")
- @Test
- public void test_parseNonNumericAddress(String address) {
- try {
- InetAddress inetAddress = InetAddresses.parseNumericAddress(address);
- fail(String.format(
- "Address %s is not numeric but was parsed as %s", address, inetAddress));
- } catch (IllegalArgumentException e) {
- assertThat(e.getMessage()).contains(address);
- }
- }
-
- @Test
- public void test_parseNumericAddress_null() {
- try {
- InetAddress inetAddress = InetAddresses.parseNumericAddress(null);
- fail(String.format("null is not numeric but was parsed as %s", inetAddress));
- } catch (NullPointerException e) {
- // expected
- }
- }
-
- @Parameters(method = "validNumericAddressesAndStringRepresentation")
- @Test
- public void test_isNumericAddress(String address, String unused) {
- assertTrue("expected '" + address + "' to be treated as numeric",
- InetAddresses.isNumericAddress(address));
- }
-
- @Parameters(method = "invalidNumericAddresses")
- @Test
- public void test_isNotNumericAddress(String address) {
- assertFalse("expected '" + address + "' to be treated as non-numeric",
- InetAddresses.isNumericAddress(address));
- }
-
- @Test
- public void test_isNumericAddress_null() {
- try {
- InetAddresses.isNumericAddress(null);
- fail("expected null to throw a NullPointerException");
- } catch (NullPointerException e) {
- // expected
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/IpConfigurationTest.java b/tests/tests/net/src/android/net/cts/IpConfigurationTest.java
deleted file mode 100644
index c6bc077..0000000
--- a/tests/tests/net/src/android/net/cts/IpConfigurationTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
-import android.net.IpConfiguration;
-import android.net.LinkAddress;
-import android.net.ProxyInfo;
-import android.net.StaticIpConfiguration;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.net.InetAddressUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.util.ArrayList;
-
-@RunWith(AndroidJUnit4.class)
-public final class IpConfigurationTest {
- private static final LinkAddress LINKADDR = new LinkAddress("192.0.2.2/25");
- private static final InetAddress GATEWAY = InetAddressUtils.parseNumericAddress("192.0.2.1");
- private static final InetAddress DNS1 = InetAddressUtils.parseNumericAddress("8.8.8.8");
- private static final InetAddress DNS2 = InetAddressUtils.parseNumericAddress("8.8.4.4");
- private static final String DOMAINS = "example.com";
-
- private static final ArrayList<InetAddress> dnsServers = new ArrayList<>();
-
- private StaticIpConfiguration mStaticIpConfig;
- private ProxyInfo mProxy;
-
- @Before
- public void setUp() {
- dnsServers.add(DNS1);
- dnsServers.add(DNS2);
- mStaticIpConfig = new StaticIpConfiguration.Builder()
- .setIpAddress(LINKADDR)
- .setGateway(GATEWAY)
- .setDnsServers(dnsServers)
- .setDomains(DOMAINS)
- .build();
-
- mProxy = ProxyInfo.buildDirectProxy("test", 8888);
- }
-
- @Test
- public void testConstructor() {
- IpConfiguration ipConfig = new IpConfiguration();
- checkEmpty(ipConfig);
- assertIpConfigurationEqual(ipConfig, new IpConfiguration());
- assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig));
-
- ipConfig.setStaticIpConfiguration(mStaticIpConfig);
- ipConfig.setHttpProxy(mProxy);
-
- ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC);
- ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC);
- assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig));
-
- ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC);
- ipConfig.setProxySettings(IpConfiguration.ProxySettings.STATIC);
- assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig));
-
- ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP);
- ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC);
- assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig));
-
- ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP);
- ipConfig.setProxySettings(IpConfiguration.ProxySettings.PAC);
- assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig));
-
- ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP);
- ipConfig.setProxySettings(IpConfiguration.ProxySettings.STATIC);
- assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig));
-
- ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP);
- ipConfig.setProxySettings(IpConfiguration.ProxySettings.NONE);
- assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig));
- }
-
- private void checkEmpty(IpConfiguration config) {
- assertEquals(IpConfiguration.IpAssignment.UNASSIGNED,
- config.getIpAssignment().UNASSIGNED);
- assertEquals(IpConfiguration.ProxySettings.UNASSIGNED,
- config.getProxySettings().UNASSIGNED);
- assertNull(config.getStaticIpConfiguration());
- assertNull(config.getHttpProxy());
- }
-
- private void assertIpConfigurationEqual(IpConfiguration source, IpConfiguration target) {
- assertEquals(source.getIpAssignment(), target.getIpAssignment());
- assertEquals(source.getProxySettings(), target.getProxySettings());
- assertEquals(source.getHttpProxy(), target.getHttpProxy());
- assertEquals(source.getStaticIpConfiguration(), target.getStaticIpConfiguration());
- }
-
- @Test
- public void testParcel() {
- final IpConfiguration config = new IpConfiguration();
- assertParcelSane(config, 4);
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/IpSecBaseTest.java b/tests/tests/net/src/android/net/cts/IpSecBaseTest.java
deleted file mode 100644
index 10e43e7..0000000
--- a/tests/tests/net/src/android/net/cts/IpSecBaseTest.java
+++ /dev/null
@@ -1,556 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static org.junit.Assert.assertArrayEquals;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.IpSecAlgorithm;
-import android.net.IpSecManager;
-import android.net.IpSecTransform;
-import android.platform.test.annotations.AppModeFull;
-import android.system.Os;
-import android.system.OsConstants;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class IpSecBaseTest {
-
- private static final String TAG = IpSecBaseTest.class.getSimpleName();
-
- protected static final String IPV4_LOOPBACK = "127.0.0.1";
- protected static final String IPV6_LOOPBACK = "::1";
- protected static final String[] LOOPBACK_ADDRS = new String[] {IPV4_LOOPBACK, IPV6_LOOPBACK};
- protected static final int[] DIRECTIONS =
- new int[] {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT};
-
- protected static final byte[] TEST_DATA = "Best test data ever!".getBytes();
- protected static final int DATA_BUFFER_LEN = 4096;
- protected static final int SOCK_TIMEOUT = 500;
-
- private static final byte[] KEY_DATA = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x20, 0x21, 0x22, 0x23
- };
-
- protected static final byte[] AUTH_KEY = getKey(256);
- protected static final byte[] CRYPT_KEY = getKey(256);
-
- protected ConnectivityManager mCM;
- protected IpSecManager mISM;
-
- @Before
- public void setUp() throws Exception {
- mISM =
- (IpSecManager)
- InstrumentationRegistry.getContext()
- .getSystemService(Context.IPSEC_SERVICE);
- mCM =
- (ConnectivityManager)
- InstrumentationRegistry.getContext()
- .getSystemService(Context.CONNECTIVITY_SERVICE);
- }
-
- protected static byte[] getKey(int bitLength) {
- return Arrays.copyOf(KEY_DATA, bitLength / 8);
- }
-
- protected static int getDomain(InetAddress address) {
- int domain;
- if (address instanceof Inet6Address) {
- domain = OsConstants.AF_INET6;
- } else {
- domain = OsConstants.AF_INET;
- }
- return domain;
- }
-
- protected static int getPort(FileDescriptor sock) throws Exception {
- return ((InetSocketAddress) Os.getsockname(sock)).getPort();
- }
-
- public static interface GenericSocket extends AutoCloseable {
- void send(byte[] data) throws Exception;
-
- byte[] receive() throws Exception;
-
- int getPort() throws Exception;
-
- void close() throws Exception;
-
- void applyTransportModeTransform(
- IpSecManager ism, int direction, IpSecTransform transform) throws Exception;
-
- void removeTransportModeTransforms(IpSecManager ism) throws Exception;
- }
-
- public static interface GenericTcpSocket extends GenericSocket {}
-
- public static interface GenericUdpSocket extends GenericSocket {
- void sendTo(byte[] data, InetAddress dstAddr, int port) throws Exception;
- }
-
- public abstract static class NativeSocket implements GenericSocket {
- public FileDescriptor mFd;
-
- public NativeSocket(FileDescriptor fd) {
- mFd = fd;
- }
-
- @Override
- public void send(byte[] data) throws Exception {
- Os.write(mFd, data, 0, data.length);
- }
-
- @Override
- public byte[] receive() throws Exception {
- byte[] in = new byte[DATA_BUFFER_LEN];
- AtomicInteger bytesRead = new AtomicInteger(-1);
-
- Thread readSockThread = new Thread(() -> {
- long startTime = System.currentTimeMillis();
- while (bytesRead.get() < 0 && System.currentTimeMillis() < startTime + SOCK_TIMEOUT) {
- try {
- bytesRead.set(Os.recvfrom(mFd, in, 0, DATA_BUFFER_LEN, 0, null));
- } catch (Exception e) {
- Log.e(TAG, "Error encountered reading from socket", e);
- }
- }
- });
-
- readSockThread.start();
- readSockThread.join(SOCK_TIMEOUT);
-
- if (bytesRead.get() < 0) {
- throw new IOException("No data received from socket");
- }
-
- return Arrays.copyOfRange(in, 0, bytesRead.get());
- }
-
- @Override
- public int getPort() throws Exception {
- return IpSecBaseTest.getPort(mFd);
- }
-
- @Override
- public void close() throws Exception {
- Os.close(mFd);
- }
-
- @Override
- public void applyTransportModeTransform(
- IpSecManager ism, int direction, IpSecTransform transform) throws Exception {
- ism.applyTransportModeTransform(mFd, direction, transform);
- }
-
- @Override
- public void removeTransportModeTransforms(IpSecManager ism) throws Exception {
- ism.removeTransportModeTransforms(mFd);
- }
- }
-
- public static class NativeTcpSocket extends NativeSocket implements GenericTcpSocket {
- public NativeTcpSocket(FileDescriptor fd) {
- super(fd);
- }
- }
-
- public static class NativeUdpSocket extends NativeSocket implements GenericUdpSocket {
- public NativeUdpSocket(FileDescriptor fd) {
- super(fd);
- }
-
- @Override
- public void sendTo(byte[] data, InetAddress dstAddr, int port) throws Exception {
- Os.sendto(mFd, data, 0, data.length, 0, dstAddr, port);
- }
- }
-
- public static class JavaUdpSocket implements GenericUdpSocket {
- public final DatagramSocket mSocket;
-
- public JavaUdpSocket(InetAddress localAddr, int port) {
- try {
- mSocket = new DatagramSocket(port, localAddr);
- mSocket.setSoTimeout(SOCK_TIMEOUT);
- } catch (SocketException e) {
- // Fail loudly if we can't set up sockets properly. And without the timeout, we
- // could easily end up in an endless wait.
- throw new RuntimeException(e);
- }
- }
-
- public JavaUdpSocket(InetAddress localAddr) {
- try {
- mSocket = new DatagramSocket(0, localAddr);
- mSocket.setSoTimeout(SOCK_TIMEOUT);
- } catch (SocketException e) {
- // Fail loudly if we can't set up sockets properly. And without the timeout, we
- // could easily end up in an endless wait.
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void send(byte[] data) throws Exception {
- mSocket.send(new DatagramPacket(data, data.length));
- }
-
- @Override
- public void sendTo(byte[] data, InetAddress dstAddr, int port) throws Exception {
- mSocket.send(new DatagramPacket(data, data.length, dstAddr, port));
- }
-
- @Override
- public int getPort() throws Exception {
- return mSocket.getLocalPort();
- }
-
- @Override
- public void close() throws Exception {
- mSocket.close();
- }
-
- @Override
- public byte[] receive() throws Exception {
- DatagramPacket data = new DatagramPacket(new byte[DATA_BUFFER_LEN], DATA_BUFFER_LEN);
- mSocket.receive(data);
- return Arrays.copyOfRange(data.getData(), 0, data.getLength());
- }
-
- @Override
- public void applyTransportModeTransform(
- IpSecManager ism, int direction, IpSecTransform transform) throws Exception {
- ism.applyTransportModeTransform(mSocket, direction, transform);
- }
-
- @Override
- public void removeTransportModeTransforms(IpSecManager ism) throws Exception {
- ism.removeTransportModeTransforms(mSocket);
- }
- }
-
- public static class JavaTcpSocket implements GenericTcpSocket {
- public final Socket mSocket;
-
- public JavaTcpSocket(Socket socket) {
- mSocket = socket;
- try {
- mSocket.setSoTimeout(SOCK_TIMEOUT);
- } catch (SocketException e) {
- // Fail loudly if we can't set up sockets properly. And without the timeout, we
- // could easily end up in an endless wait.
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void send(byte[] data) throws Exception {
- mSocket.getOutputStream().write(data);
- }
-
- @Override
- public byte[] receive() throws Exception {
- byte[] in = new byte[DATA_BUFFER_LEN];
- int bytesRead = mSocket.getInputStream().read(in);
- return Arrays.copyOfRange(in, 0, bytesRead);
- }
-
- @Override
- public int getPort() throws Exception {
- return mSocket.getLocalPort();
- }
-
- @Override
- public void close() throws Exception {
- mSocket.close();
- }
-
- @Override
- public void applyTransportModeTransform(
- IpSecManager ism, int direction, IpSecTransform transform) throws Exception {
- ism.applyTransportModeTransform(mSocket, direction, transform);
- }
-
- @Override
- public void removeTransportModeTransforms(IpSecManager ism) throws Exception {
- ism.removeTransportModeTransforms(mSocket);
- }
- }
-
- public static class SocketPair<T> {
- public final T mLeftSock;
- public final T mRightSock;
-
- public SocketPair(T leftSock, T rightSock) {
- mLeftSock = leftSock;
- mRightSock = rightSock;
- }
- }
-
- protected static void applyTransformBidirectionally(
- IpSecManager ism, IpSecTransform transform, GenericSocket socket) throws Exception {
- for (int direction : DIRECTIONS) {
- socket.applyTransportModeTransform(ism, direction, transform);
- }
- }
-
- public static SocketPair<NativeUdpSocket> getNativeUdpSocketPair(
- InetAddress localAddr, IpSecManager ism, IpSecTransform transform, boolean connected)
- throws Exception {
- int domain = getDomain(localAddr);
-
- NativeUdpSocket leftSock = new NativeUdpSocket(
- Os.socket(domain, OsConstants.SOCK_DGRAM, OsConstants.IPPROTO_UDP));
- NativeUdpSocket rightSock = new NativeUdpSocket(
- Os.socket(domain, OsConstants.SOCK_DGRAM, OsConstants.IPPROTO_UDP));
-
- for (NativeUdpSocket sock : new NativeUdpSocket[] {leftSock, rightSock}) {
- applyTransformBidirectionally(ism, transform, sock);
- Os.bind(sock.mFd, localAddr, 0);
- }
-
- if (connected) {
- Os.connect(leftSock.mFd, localAddr, rightSock.getPort());
- Os.connect(rightSock.mFd, localAddr, leftSock.getPort());
- }
-
- return new SocketPair<>(leftSock, rightSock);
- }
-
- public static SocketPair<NativeTcpSocket> getNativeTcpSocketPair(
- InetAddress localAddr, IpSecManager ism, IpSecTransform transform) throws Exception {
- int domain = getDomain(localAddr);
-
- NativeTcpSocket server = new NativeTcpSocket(
- Os.socket(domain, OsConstants.SOCK_STREAM, OsConstants.IPPROTO_TCP));
- NativeTcpSocket client = new NativeTcpSocket(
- Os.socket(domain, OsConstants.SOCK_STREAM, OsConstants.IPPROTO_TCP));
-
- Os.bind(server.mFd, localAddr, 0);
-
- applyTransformBidirectionally(ism, transform, server);
- applyTransformBidirectionally(ism, transform, client);
-
- Os.listen(server.mFd, 10);
- Os.connect(client.mFd, localAddr, server.getPort());
- NativeTcpSocket accepted = new NativeTcpSocket(Os.accept(server.mFd, null));
-
- applyTransformBidirectionally(ism, transform, accepted);
- server.close();
-
- return new SocketPair<>(client, accepted);
- }
-
- public static SocketPair<JavaUdpSocket> getJavaUdpSocketPair(
- InetAddress localAddr, IpSecManager ism, IpSecTransform transform, boolean connected)
- throws Exception {
- JavaUdpSocket leftSock = new JavaUdpSocket(localAddr);
- JavaUdpSocket rightSock = new JavaUdpSocket(localAddr);
-
- applyTransformBidirectionally(ism, transform, leftSock);
- applyTransformBidirectionally(ism, transform, rightSock);
-
- if (connected) {
- leftSock.mSocket.connect(localAddr, rightSock.mSocket.getLocalPort());
- rightSock.mSocket.connect(localAddr, leftSock.mSocket.getLocalPort());
- }
-
- return new SocketPair<>(leftSock, rightSock);
- }
-
- public static SocketPair<JavaTcpSocket> getJavaTcpSocketPair(
- InetAddress localAddr, IpSecManager ism, IpSecTransform transform) throws Exception {
- JavaTcpSocket clientSock = new JavaTcpSocket(new Socket());
- ServerSocket serverSocket = new ServerSocket();
- serverSocket.bind(new InetSocketAddress(localAddr, 0));
-
- // While technically the client socket does not need to be bound, the OpenJDK implementation
- // of Socket only allocates an FD when bind() or connect() or other similar methods are
- // called. So we call bind to force the FD creation, so that we can apply a transform to it
- // prior to socket connect.
- clientSock.mSocket.bind(new InetSocketAddress(localAddr, 0));
-
- // IpSecService doesn't support serverSockets at the moment; workaround using FD
- FileDescriptor serverFd = serverSocket.getImpl().getFD$();
-
- applyTransformBidirectionally(ism, transform, new NativeTcpSocket(serverFd));
- applyTransformBidirectionally(ism, transform, clientSock);
-
- clientSock.mSocket.connect(new InetSocketAddress(localAddr, serverSocket.getLocalPort()));
- JavaTcpSocket acceptedSock = new JavaTcpSocket(serverSocket.accept());
-
- applyTransformBidirectionally(ism, transform, acceptedSock);
- serverSocket.close();
-
- return new SocketPair<>(clientSock, acceptedSock);
- }
-
- private void checkSocketPair(GenericSocket left, GenericSocket right) throws Exception {
- left.send(TEST_DATA);
- assertArrayEquals(TEST_DATA, right.receive());
-
- right.send(TEST_DATA);
- assertArrayEquals(TEST_DATA, left.receive());
-
- left.close();
- right.close();
- }
-
- private void checkUnconnectedUdpSocketPair(
- GenericUdpSocket left, GenericUdpSocket right, InetAddress localAddr) throws Exception {
- left.sendTo(TEST_DATA, localAddr, right.getPort());
- assertArrayEquals(TEST_DATA, right.receive());
-
- right.sendTo(TEST_DATA, localAddr, left.getPort());
- assertArrayEquals(TEST_DATA, left.receive());
-
- left.close();
- right.close();
- }
-
- protected static IpSecTransform buildIpSecTransform(
- Context context,
- IpSecManager.SecurityParameterIndex spi,
- IpSecManager.UdpEncapsulationSocket encapSocket,
- InetAddress remoteAddr)
- throws Exception {
- IpSecTransform.Builder builder =
- new IpSecTransform.Builder(context)
- .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
- .setAuthentication(
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA256,
- AUTH_KEY,
- AUTH_KEY.length * 4));
-
- if (encapSocket != null) {
- builder.setIpv4Encapsulation(encapSocket, encapSocket.getPort());
- }
-
- return builder.buildTransportModeTransform(remoteAddr, spi);
- }
-
- private IpSecTransform buildDefaultTransform(InetAddress localAddr) throws Exception {
- try (IpSecManager.SecurityParameterIndex spi =
- mISM.allocateSecurityParameterIndex(localAddr)) {
- return buildIpSecTransform(InstrumentationRegistry.getContext(), spi, null, localAddr);
- }
- }
-
- @Test
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void testJavaTcpSocketPair() throws Exception {
- for (String addr : LOOPBACK_ADDRS) {
- InetAddress local = InetAddress.getByName(addr);
- try (IpSecTransform transform = buildDefaultTransform(local)) {
- SocketPair<JavaTcpSocket> sockets = getJavaTcpSocketPair(local, mISM, transform);
- checkSocketPair(sockets.mLeftSock, sockets.mRightSock);
- }
- }
- }
-
- @Test
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void testJavaUdpSocketPair() throws Exception {
- for (String addr : LOOPBACK_ADDRS) {
- InetAddress local = InetAddress.getByName(addr);
- try (IpSecTransform transform = buildDefaultTransform(local)) {
- SocketPair<JavaUdpSocket> sockets =
- getJavaUdpSocketPair(local, mISM, transform, true);
- checkSocketPair(sockets.mLeftSock, sockets.mRightSock);
- }
- }
- }
-
- @Test
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void testJavaUdpSocketPairUnconnected() throws Exception {
- for (String addr : LOOPBACK_ADDRS) {
- InetAddress local = InetAddress.getByName(addr);
- try (IpSecTransform transform = buildDefaultTransform(local)) {
- SocketPair<JavaUdpSocket> sockets =
- getJavaUdpSocketPair(local, mISM, transform, false);
- checkUnconnectedUdpSocketPair(sockets.mLeftSock, sockets.mRightSock, local);
- }
- }
- }
-
- @Test
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void testNativeTcpSocketPair() throws Exception {
- for (String addr : LOOPBACK_ADDRS) {
- InetAddress local = InetAddress.getByName(addr);
- try (IpSecTransform transform = buildDefaultTransform(local)) {
- SocketPair<NativeTcpSocket> sockets =
- getNativeTcpSocketPair(local, mISM, transform);
- checkSocketPair(sockets.mLeftSock, sockets.mRightSock);
- }
- }
- }
-
- @Test
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void testNativeUdpSocketPair() throws Exception {
- for (String addr : LOOPBACK_ADDRS) {
- InetAddress local = InetAddress.getByName(addr);
- try (IpSecTransform transform = buildDefaultTransform(local)) {
- SocketPair<NativeUdpSocket> sockets =
- getNativeUdpSocketPair(local, mISM, transform, true);
- checkSocketPair(sockets.mLeftSock, sockets.mRightSock);
- }
- }
- }
-
- @Test
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void testNativeUdpSocketPairUnconnected() throws Exception {
- for (String addr : LOOPBACK_ADDRS) {
- InetAddress local = InetAddress.getByName(addr);
- try (IpSecTransform transform = buildDefaultTransform(local)) {
- SocketPair<NativeUdpSocket> sockets =
- getNativeUdpSocketPair(local, mISM, transform, false);
- checkUnconnectedUdpSocketPair(sockets.mLeftSock, sockets.mRightSock, local);
- }
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/IpSecManagerTest.java b/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
deleted file mode 100644
index 355b496..0000000
--- a/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
+++ /dev/null
@@ -1,1189 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE;
-import static android.net.cts.PacketUtils.AES_CBC_IV_LEN;
-import static android.net.cts.PacketUtils.AES_GCM_BLK_SIZE;
-import static android.net.cts.PacketUtils.AES_GCM_IV_LEN;
-import static android.net.cts.PacketUtils.IP4_HDRLEN;
-import static android.net.cts.PacketUtils.IP6_HDRLEN;
-import static android.net.cts.PacketUtils.TCP_HDRLEN_WITH_TIMESTAMP_OPT;
-import static android.net.cts.PacketUtils.UDP_HDRLEN;
-import static android.system.OsConstants.IPPROTO_TCP;
-import static android.system.OsConstants.IPPROTO_UDP;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.IpSecAlgorithm;
-import android.net.IpSecManager;
-import android.net.IpSecTransform;
-import android.net.TrafficStats;
-import android.platform.test.annotations.AppModeFull;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.util.Arrays;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@AppModeFull(reason = "Socket cannot bind in instant app mode")
-public class IpSecManagerTest extends IpSecBaseTest {
-
- private static final String TAG = IpSecManagerTest.class.getSimpleName();
-
- private static final InetAddress GOOGLE_DNS_4 = InetAddress.parseNumericAddress("8.8.8.8");
- private static final InetAddress GOOGLE_DNS_6 =
- InetAddress.parseNumericAddress("2001:4860:4860::8888");
-
- private static final InetAddress[] GOOGLE_DNS_LIST =
- new InetAddress[] {GOOGLE_DNS_4, GOOGLE_DNS_6};
-
- private static final int DROID_SPI = 0xD1201D;
- private static final int MAX_PORT_BIND_ATTEMPTS = 10;
-
- private static final byte[] AEAD_KEY = getKey(288);
-
- /*
- * Allocate a random SPI
- * Allocate a specific SPI using previous randomly created SPI value
- * Realloc the same SPI that was specifically created (expect SpiUnavailable)
- * Close SPIs
- */
- @Test
- public void testAllocSpi() throws Exception {
- for (InetAddress addr : GOOGLE_DNS_LIST) {
- IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null;
- randomSpi = mISM.allocateSecurityParameterIndex(addr);
- assertTrue(
- "Failed to receive a valid SPI",
- randomSpi.getSpi() != IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
-
- droidSpi = mISM.allocateSecurityParameterIndex(addr, DROID_SPI);
- assertTrue("Failed to allocate specified SPI, " + DROID_SPI,
- droidSpi.getSpi() == DROID_SPI);
-
- try {
- mISM.allocateSecurityParameterIndex(addr, DROID_SPI);
- fail("Duplicate SPI was allowed to be created");
- } catch (IpSecManager.SpiUnavailableException expected) {
- // This is a success case because we expect a dupe SPI to throw
- }
-
- randomSpi.close();
- droidSpi.close();
- }
- }
-
- /** This function finds an available port */
- private static int findUnusedPort() throws Exception {
- // Get an available port.
- DatagramSocket s = new DatagramSocket();
- int port = s.getLocalPort();
- s.close();
- return port;
- }
-
- private static FileDescriptor getBoundUdpSocket(InetAddress address) throws Exception {
- FileDescriptor sock =
- Os.socket(getDomain(address), OsConstants.SOCK_DGRAM, OsConstants.IPPROTO_UDP);
-
- for (int i = 0; i < MAX_PORT_BIND_ATTEMPTS; i++) {
- try {
- int port = findUnusedPort();
- Os.bind(sock, address, port);
- break;
- } catch (ErrnoException e) {
- // Someone claimed the port since we called findUnusedPort.
- if (e.errno == OsConstants.EADDRINUSE) {
- if (i == MAX_PORT_BIND_ATTEMPTS - 1) {
-
- fail("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port");
- }
- continue;
- }
- throw e.rethrowAsIOException();
- }
- }
- return sock;
- }
-
- private void checkUnconnectedUdp(IpSecTransform transform, InetAddress local, int sendCount,
- boolean useJavaSockets) throws Exception {
- GenericUdpSocket sockLeft = null, sockRight = null;
- if (useJavaSockets) {
- SocketPair<JavaUdpSocket> sockets = getJavaUdpSocketPair(local, mISM, transform, false);
- sockLeft = sockets.mLeftSock;
- sockRight = sockets.mRightSock;
- } else {
- SocketPair<NativeUdpSocket> sockets =
- getNativeUdpSocketPair(local, mISM, transform, false);
- sockLeft = sockets.mLeftSock;
- sockRight = sockets.mRightSock;
- }
-
- for (int i = 0; i < sendCount; i++) {
- byte[] in;
-
- sockLeft.sendTo(TEST_DATA, local, sockRight.getPort());
- in = sockRight.receive();
- assertArrayEquals("Left-to-right encrypted data did not match.", TEST_DATA, in);
-
- sockRight.sendTo(TEST_DATA, local, sockLeft.getPort());
- in = sockLeft.receive();
- assertArrayEquals("Right-to-left encrypted data did not match.", TEST_DATA, in);
- }
-
- sockLeft.close();
- sockRight.close();
- }
-
- private void checkTcp(IpSecTransform transform, InetAddress local, int sendCount,
- boolean useJavaSockets) throws Exception {
- GenericTcpSocket client = null, accepted = null;
- if (useJavaSockets) {
- SocketPair<JavaTcpSocket> sockets = getJavaTcpSocketPair(local, mISM, transform);
- client = sockets.mLeftSock;
- accepted = sockets.mRightSock;
- } else {
- SocketPair<NativeTcpSocket> sockets = getNativeTcpSocketPair(local, mISM, transform);
- client = sockets.mLeftSock;
- accepted = sockets.mRightSock;
- }
-
- // Wait for TCP handshake packets to be counted
- StatsChecker.waitForNumPackets(3); // (SYN, SYN+ACK, ACK)
-
- // Reset StatsChecker, to ignore negotiation overhead.
- StatsChecker.initStatsChecker();
- for (int i = 0; i < sendCount; i++) {
- byte[] in;
-
- client.send(TEST_DATA);
- in = accepted.receive();
- assertArrayEquals("Client-to-server encrypted data did not match.", TEST_DATA, in);
-
- // Allow for newest data + ack packets to be returned before sending next packet
- // Also add the number of expected packets in each of the previous runs (4 per run)
- StatsChecker.waitForNumPackets(2 + (4 * i));
-
- accepted.send(TEST_DATA);
- in = client.receive();
- assertArrayEquals("Server-to-client encrypted data did not match.", TEST_DATA, in);
-
- // Allow for all data + ack packets to be returned before sending next packet
- // Also add the number of expected packets in each of the previous runs (4 per run)
- StatsChecker.waitForNumPackets(4 * (i + 1));
- }
-
- // Transforms should not be removed from the sockets, otherwise FIN packets will be sent
- // unencrypted.
- // This test also unfortunately happens to rely on a nuance of the cleanup order. By
- // keeping the policy on the socket, but removing the SA before lingering FIN packets
- // are sent (at an undetermined later time), the FIN packets are dropped. Without this,
- // we run into all kinds of headaches trying to test data accounting (unsolicited
- // packets mysteriously appearing and messing up our counters)
- // The right way to close sockets is to set SO_LINGER to ensure synchronous closure,
- // closing the sockets, and then closing the transforms. See documentation for the
- // Socket or FileDescriptor flavors of applyTransportModeTransform() in IpSecManager
- // for more details.
-
- client.close();
- accepted.close();
- }
-
- /*
- * Alloc outbound SPI
- * Alloc inbound SPI
- * Create transport mode transform
- * open socket
- * apply transform to socket
- * send data on socket
- * release transform
- * send data (expect exception)
- */
- @Test
- public void testCreateTransform() throws Exception {
- InetAddress localAddr = InetAddress.getByName(IPV4_LOOPBACK);
- IpSecManager.SecurityParameterIndex spi =
- mISM.allocateSecurityParameterIndex(localAddr);
-
- IpSecTransform transform =
- new IpSecTransform.Builder(InstrumentationRegistry.getContext())
- .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
- .setAuthentication(
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA256,
- AUTH_KEY,
- AUTH_KEY.length * 8))
- .buildTransportModeTransform(localAddr, spi);
-
- final boolean [][] applyInApplyOut = {
- {false, false}, {false, true}, {true, false}, {true,true}};
- final byte[] data = new String("Best test data ever!").getBytes("UTF-8");
- final DatagramPacket outPacket = new DatagramPacket(data, 0, data.length, localAddr, 0);
-
- byte[] in = new byte[data.length];
- DatagramPacket inPacket = new DatagramPacket(in, in.length);
- DatagramSocket localSocket;
- int localPort;
-
- for(boolean[] io : applyInApplyOut) {
- boolean applyIn = io[0];
- boolean applyOut = io[1];
- // Bind localSocket to a random available port.
- localSocket = new DatagramSocket(0);
- localPort = localSocket.getLocalPort();
- localSocket.setSoTimeout(200);
- outPacket.setPort(localPort);
- if (applyIn) {
- mISM.applyTransportModeTransform(
- localSocket, IpSecManager.DIRECTION_IN, transform);
- }
- if (applyOut) {
- mISM.applyTransportModeTransform(
- localSocket, IpSecManager.DIRECTION_OUT, transform);
- }
- if (applyIn == applyOut) {
- localSocket.send(outPacket);
- localSocket.receive(inPacket);
- assertTrue("Encapsulated data did not match.",
- Arrays.equals(outPacket.getData(), inPacket.getData()));
- mISM.removeTransportModeTransforms(localSocket);
- localSocket.close();
- } else {
- try {
- localSocket.send(outPacket);
- localSocket.receive(inPacket);
- } catch (IOException e) {
- continue;
- } finally {
- mISM.removeTransportModeTransforms(localSocket);
- localSocket.close();
- }
- // FIXME: This check is disabled because sockets currently receive data
- // if there is a valid SA for decryption, even when the input policy is
- // not applied to a socket.
- // fail("Data IO should fail on asymmetrical transforms! + Input="
- // + applyIn + " Output=" + applyOut);
- }
- }
- transform.close();
- }
-
- /** Snapshot of TrafficStats as of initStatsChecker call for later comparisons */
- private static class StatsChecker {
- private static final double ERROR_MARGIN_BYTES = 1.05;
- private static final double ERROR_MARGIN_PKTS = 1.05;
- private static final int MAX_WAIT_TIME_MILLIS = 1000;
-
- private static long uidTxBytes;
- private static long uidRxBytes;
- private static long uidTxPackets;
- private static long uidRxPackets;
-
- private static long ifaceTxBytes;
- private static long ifaceRxBytes;
- private static long ifaceTxPackets;
- private static long ifaceRxPackets;
-
- /**
- * This method counts the number of incoming packets, polling intermittently up to
- * MAX_WAIT_TIME_MILLIS.
- */
- private static void waitForNumPackets(int numPackets) throws Exception {
- long uidTxDelta = 0;
- long uidRxDelta = 0;
- for (int i = 0; i < 100; i++) {
- uidTxDelta = TrafficStats.getUidTxPackets(Os.getuid()) - uidTxPackets;
- uidRxDelta = TrafficStats.getUidRxPackets(Os.getuid()) - uidRxPackets;
-
- // TODO: Check Rx packets as well once kernel security policy bug is fixed.
- // (b/70635417)
- if (uidTxDelta >= numPackets) {
- return;
- }
- Thread.sleep(MAX_WAIT_TIME_MILLIS / 100);
- }
- fail(
- "Not enough traffic was recorded to satisfy the provided conditions: wanted "
- + numPackets
- + ", got "
- + uidTxDelta
- + " tx and "
- + uidRxDelta
- + " rx packets");
- }
-
- private static void assertUidStatsDelta(
- int expectedTxByteDelta,
- int expectedTxPacketDelta,
- int minRxByteDelta,
- int maxRxByteDelta,
- int expectedRxPacketDelta) {
- long newUidTxBytes = TrafficStats.getUidTxBytes(Os.getuid());
- long newUidRxBytes = TrafficStats.getUidRxBytes(Os.getuid());
- long newUidTxPackets = TrafficStats.getUidTxPackets(Os.getuid());
- long newUidRxPackets = TrafficStats.getUidRxPackets(Os.getuid());
-
- assertEquals(expectedTxByteDelta, newUidTxBytes - uidTxBytes);
- assertTrue(
- newUidRxBytes - uidRxBytes >= minRxByteDelta
- && newUidRxBytes - uidRxBytes <= maxRxByteDelta);
- assertEquals(expectedTxPacketDelta, newUidTxPackets - uidTxPackets);
- assertEquals(expectedRxPacketDelta, newUidRxPackets - uidRxPackets);
- }
-
- private static void assertIfaceStatsDelta(
- int expectedTxByteDelta,
- int expectedTxPacketDelta,
- int expectedRxByteDelta,
- int expectedRxPacketDelta)
- throws IOException {
- long newIfaceTxBytes = TrafficStats.getLoopbackTxBytes();
- long newIfaceRxBytes = TrafficStats.getLoopbackRxBytes();
- long newIfaceTxPackets = TrafficStats.getLoopbackTxPackets();
- long newIfaceRxPackets = TrafficStats.getLoopbackRxPackets();
-
- // Check that iface stats are within an acceptable range; data might be sent
- // on the local interface by other apps.
- assertApproxEquals(
- ifaceTxBytes, newIfaceTxBytes, expectedTxByteDelta, ERROR_MARGIN_BYTES);
- assertApproxEquals(
- ifaceRxBytes, newIfaceRxBytes, expectedRxByteDelta, ERROR_MARGIN_BYTES);
- assertApproxEquals(
- ifaceTxPackets, newIfaceTxPackets, expectedTxPacketDelta, ERROR_MARGIN_PKTS);
- assertApproxEquals(
- ifaceRxPackets, newIfaceRxPackets, expectedRxPacketDelta, ERROR_MARGIN_PKTS);
- }
-
- private static void assertApproxEquals(
- long oldStats, long newStats, int expectedDelta, double errorMargin) {
- assertTrue(expectedDelta <= newStats - oldStats);
- assertTrue((expectedDelta * errorMargin) > newStats - oldStats);
- }
-
- private static void initStatsChecker() throws Exception {
- uidTxBytes = TrafficStats.getUidTxBytes(Os.getuid());
- uidRxBytes = TrafficStats.getUidRxBytes(Os.getuid());
- uidTxPackets = TrafficStats.getUidTxPackets(Os.getuid());
- uidRxPackets = TrafficStats.getUidRxPackets(Os.getuid());
-
- ifaceTxBytes = TrafficStats.getLoopbackTxBytes();
- ifaceRxBytes = TrafficStats.getLoopbackRxBytes();
- ifaceTxPackets = TrafficStats.getLoopbackTxPackets();
- ifaceRxPackets = TrafficStats.getLoopbackRxPackets();
- }
- }
-
- private int getTruncLenBits(IpSecAlgorithm authOrAead) {
- return authOrAead == null ? 0 : authOrAead.getTruncationLengthBits();
- }
-
- private int getIvLen(IpSecAlgorithm cryptOrAead) {
- if (cryptOrAead == null) { return 0; }
-
- switch (cryptOrAead.getName()) {
- case IpSecAlgorithm.CRYPT_AES_CBC:
- return AES_CBC_IV_LEN;
- case IpSecAlgorithm.AUTH_CRYPT_AES_GCM:
- return AES_GCM_IV_LEN;
- default:
- throw new IllegalArgumentException(
- "IV length unknown for algorithm" + cryptOrAead.getName());
- }
- }
-
- private int getBlkSize(IpSecAlgorithm cryptOrAead) {
- // RFC 4303, section 2.4 states that ciphertext plus pad_len, next_header fields must
- // terminate on a 4-byte boundary. Thus, the minimum ciphertext block size is 4 bytes.
- if (cryptOrAead == null) { return 4; }
-
- switch (cryptOrAead.getName()) {
- case IpSecAlgorithm.CRYPT_AES_CBC:
- return AES_CBC_BLK_SIZE;
- case IpSecAlgorithm.AUTH_CRYPT_AES_GCM:
- return AES_GCM_BLK_SIZE;
- default:
- throw new IllegalArgumentException(
- "Blk size unknown for algorithm" + cryptOrAead.getName());
- }
- }
-
- public void checkTransform(
- int protocol,
- String localAddress,
- IpSecAlgorithm crypt,
- IpSecAlgorithm auth,
- IpSecAlgorithm aead,
- boolean doUdpEncap,
- int sendCount,
- boolean useJavaSockets)
- throws Exception {
- StatsChecker.initStatsChecker();
- InetAddress local = InetAddress.getByName(localAddress);
-
- try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket();
- IpSecManager.SecurityParameterIndex spi =
- mISM.allocateSecurityParameterIndex(local)) {
-
- IpSecTransform.Builder transformBuilder =
- new IpSecTransform.Builder(InstrumentationRegistry.getContext());
- if (crypt != null) {
- transformBuilder.setEncryption(crypt);
- }
- if (auth != null) {
- transformBuilder.setAuthentication(auth);
- }
- if (aead != null) {
- transformBuilder.setAuthenticatedEncryption(aead);
- }
-
- if (doUdpEncap) {
- transformBuilder =
- transformBuilder.setIpv4Encapsulation(encapSocket, encapSocket.getPort());
- }
-
- int ipHdrLen = local instanceof Inet6Address ? IP6_HDRLEN : IP4_HDRLEN;
- int transportHdrLen = 0;
- int udpEncapLen = doUdpEncap ? UDP_HDRLEN : 0;
-
- try (IpSecTransform transform =
- transformBuilder.buildTransportModeTransform(local, spi)) {
- if (protocol == IPPROTO_TCP) {
- transportHdrLen = TCP_HDRLEN_WITH_TIMESTAMP_OPT;
- checkTcp(transform, local, sendCount, useJavaSockets);
- } else if (protocol == IPPROTO_UDP) {
- transportHdrLen = UDP_HDRLEN;
-
- // TODO: Also check connected udp.
- checkUnconnectedUdp(transform, local, sendCount, useJavaSockets);
- } else {
- throw new IllegalArgumentException("Invalid protocol");
- }
- }
-
- checkStatsChecker(
- protocol,
- ipHdrLen,
- transportHdrLen,
- udpEncapLen,
- sendCount,
- getIvLen(crypt != null ? crypt : aead),
- getBlkSize(crypt != null ? crypt : aead),
- getTruncLenBits(auth != null ? auth : aead));
- }
- }
-
- private void checkStatsChecker(
- int protocol,
- int ipHdrLen,
- int transportHdrLen,
- int udpEncapLen,
- int sendCount,
- int ivLen,
- int blkSize,
- int truncLenBits)
- throws Exception {
-
- int innerPacketSize = TEST_DATA.length + transportHdrLen + ipHdrLen;
- int outerPacketSize =
- PacketUtils.calculateEspPacketSize(
- TEST_DATA.length + transportHdrLen, ivLen, blkSize, truncLenBits)
- + udpEncapLen
- + ipHdrLen;
-
- int expectedOuterBytes = outerPacketSize * sendCount;
- int expectedInnerBytes = innerPacketSize * sendCount;
- int expectedPackets = sendCount;
-
- // Each run sends two packets, one in each direction.
- sendCount *= 2;
- expectedOuterBytes *= 2;
- expectedInnerBytes *= 2;
- expectedPackets *= 2;
-
- // Add TCP ACKs for data packets
- if (protocol == IPPROTO_TCP) {
- int encryptedTcpPktSize =
- PacketUtils.calculateEspPacketSize(
- TCP_HDRLEN_WITH_TIMESTAMP_OPT, ivLen, blkSize, truncLenBits);
-
- // Add data packet ACKs
- expectedOuterBytes += (encryptedTcpPktSize + udpEncapLen + ipHdrLen) * (sendCount);
- expectedInnerBytes += (TCP_HDRLEN_WITH_TIMESTAMP_OPT + ipHdrLen) * (sendCount);
- expectedPackets += sendCount;
- }
-
- StatsChecker.waitForNumPackets(expectedPackets);
-
- // eBPF only counts inner packets, whereas xt_qtaguid counts outer packets. Allow both
- StatsChecker.assertUidStatsDelta(
- expectedOuterBytes,
- expectedPackets,
- expectedInnerBytes,
- expectedOuterBytes,
- expectedPackets);
-
- // Unreliable at low numbers due to potential interference from other processes.
- if (sendCount >= 1000) {
- StatsChecker.assertIfaceStatsDelta(
- expectedOuterBytes, expectedPackets, expectedOuterBytes, expectedPackets);
- }
- }
-
- private void checkIkePacket(
- NativeUdpSocket wrappedEncapSocket, InetAddress localAddr) throws Exception {
- StatsChecker.initStatsChecker();
-
- try (NativeUdpSocket remoteSocket = new NativeUdpSocket(getBoundUdpSocket(localAddr))) {
-
- // Append IKE/ESP header - 4 bytes of SPI, 4 bytes of seq number, all zeroed out
- // If the first four bytes are zero, assume non-ESP (IKE traffic)
- byte[] dataWithEspHeader = new byte[TEST_DATA.length + 8];
- System.arraycopy(TEST_DATA, 0, dataWithEspHeader, 8, TEST_DATA.length);
-
- // Send the IKE packet from remoteSocket to wrappedEncapSocket. Since IKE packets
- // are multiplexed over the socket, we expect them to appear on the encap socket
- // (as opposed to being decrypted and received on the non-encap socket)
- remoteSocket.sendTo(dataWithEspHeader, localAddr, wrappedEncapSocket.getPort());
- byte[] in = wrappedEncapSocket.receive();
- assertArrayEquals("Encapsulated data did not match.", dataWithEspHeader, in);
-
- // Also test that the IKE socket can send data out.
- wrappedEncapSocket.sendTo(dataWithEspHeader, localAddr, remoteSocket.getPort());
- in = remoteSocket.receive();
- assertArrayEquals("Encapsulated data did not match.", dataWithEspHeader, in);
-
- // Calculate expected packet sizes. Always use IPv4 header, since our kernels only
- // guarantee support of UDP encap on IPv4.
- int expectedNumPkts = 2;
- int expectedPacketSize =
- expectedNumPkts * (dataWithEspHeader.length + UDP_HDRLEN + IP4_HDRLEN);
-
- StatsChecker.waitForNumPackets(expectedNumPkts);
- StatsChecker.assertUidStatsDelta(
- expectedPacketSize,
- expectedNumPkts,
- expectedPacketSize,
- expectedPacketSize,
- expectedNumPkts);
- StatsChecker.assertIfaceStatsDelta(
- expectedPacketSize, expectedNumPkts, expectedPacketSize, expectedNumPkts);
- }
- }
-
- @Test
- public void testIkeOverUdpEncapSocket() throws Exception {
- // IPv6 not supported for UDP-encap-ESP
- InetAddress local = InetAddress.getByName(IPV4_LOOPBACK);
- try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) {
- NativeUdpSocket wrappedEncapSocket =
- new NativeUdpSocket(encapSocket.getFileDescriptor());
- checkIkePacket(wrappedEncapSocket, local);
-
- // Now try with a transform applied to a socket using this Encap socket
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
-
- try (IpSecManager.SecurityParameterIndex spi =
- mISM.allocateSecurityParameterIndex(local);
- IpSecTransform transform =
- new IpSecTransform.Builder(InstrumentationRegistry.getContext())
- .setEncryption(crypt)
- .setAuthentication(auth)
- .setIpv4Encapsulation(encapSocket, encapSocket.getPort())
- .buildTransportModeTransform(local, spi);
- JavaUdpSocket localSocket = new JavaUdpSocket(local)) {
- applyTransformBidirectionally(mISM, transform, localSocket);
-
- checkIkePacket(wrappedEncapSocket, local);
- }
- }
- }
-
- // TODO: Check IKE over ESP sockets (IPv4, IPv6) - does this need SOCK_RAW?
-
- /* TODO: Re-enable these when policy matcher works for reflected packets
- *
- * The issue here is that A sends to B, and everything is new; therefore PREROUTING counts
- * correctly. But it appears that the security path is not cleared afterwards, thus when A
- * sends an ACK back to B, the policy matcher flags it as a "IPSec" packet. See b/70635417
- */
-
- // public void testInterfaceCountersTcp4() throws Exception {
- // IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- // IpSecAlgorithm auth = new IpSecAlgorithm(
- // IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
- // checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1000);
- // }
-
- // public void testInterfaceCountersTcp6() throws Exception {
- // IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- // IpSecAlgorithm auth = new IpSecAlgorithm(
- // IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
- // checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1000);
- // }
-
- // public void testInterfaceCountersTcp4UdpEncap() throws Exception {
- // IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- // IpSecAlgorithm auth =
- // new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
- // checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, true, 1000);
- // }
-
- @Test
- public void testInterfaceCountersUdp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1000, false);
- }
-
- @Test
- public void testInterfaceCountersUdp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1000, false);
- }
-
- @Test
- public void testInterfaceCountersUdp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1000, false);
- }
-
- @Test
- public void testAesCbcHmacMd5Tcp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacMd5Tcp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacMd5Udp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacMd5Udp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha1Tcp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha1Tcp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha1Udp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha1Udp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha256Tcp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha256Tcp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha256Udp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha256Udp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha384Tcp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha384Tcp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha384Udp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha384Udp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha512Tcp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha512Tcp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha512Udp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha512Udp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
- }
-
- @Test
- public void testAesGcm64Tcp4() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
- }
-
- @Test
- public void testAesGcm64Tcp6() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
- }
-
- @Test
- public void testAesGcm64Udp4() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
- }
-
- @Test
- public void testAesGcm64Udp6() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
- }
-
- @Test
- public void testAesGcm96Tcp4() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
- }
-
- @Test
- public void testAesGcm96Tcp6() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
- }
-
- @Test
- public void testAesGcm96Udp4() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
- }
-
- @Test
- public void testAesGcm96Udp6() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
- }
-
- @Test
- public void testAesGcm128Tcp4() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
- }
-
- @Test
- public void testAesGcm128Tcp6() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
- }
-
- @Test
- public void testAesGcm128Udp4() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
- }
-
- @Test
- public void testAesGcm128Udp6() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
- }
-
- @Test
- public void testAesCbcHmacMd5Tcp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
- }
-
- @Test
- public void testAesCbcHmacMd5Udp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha1Tcp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha1Udp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha256Tcp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha256Udp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha384Tcp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha384Udp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha512Tcp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
- }
-
- @Test
- public void testAesCbcHmacSha512Udp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
- }
-
- @Test
- public void testAesGcm64Tcp4UdpEncap() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
- }
-
- @Test
- public void testAesGcm64Udp4UdpEncap() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
- }
-
- @Test
- public void testAesGcm96Tcp4UdpEncap() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
- }
-
- @Test
- public void testAesGcm96Udp4UdpEncap() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
- }
-
- @Test
- public void testAesGcm128Tcp4UdpEncap() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
- }
-
- @Test
- public void testAesGcm128Udp4UdpEncap() throws Exception {
- IpSecAlgorithm authCrypt =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
- }
-
- @Test
- public void testCryptUdp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, true);
- }
-
- @Test
- public void testAuthUdp4() throws Exception {
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, false, 1, true);
- }
-
- @Test
- public void testCryptUdp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, null, false, 1, true);
- }
-
- @Test
- public void testAuthUdp6() throws Exception {
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, null, false, 1, false);
- checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, null, false, 1, true);
- }
-
- @Test
- public void testCryptTcp4() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, false, 1, true);
- }
-
- @Test
- public void testAuthTcp4() throws Exception {
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, false, 1, true);
- }
-
- @Test
- public void testCryptTcp6() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, true);
- }
-
- @Test
- public void testAuthTcp6() throws Exception {
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, false);
- checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, true);
- }
-
- @Test
- public void testCryptUdp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, true, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, true, 1, true);
- }
-
- @Test
- public void testAuthUdp4UdpEncap() throws Exception {
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, true, 1, false);
- checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, true, 1, true);
- }
-
- @Test
- public void testCryptTcp4UdpEncap() throws Exception {
- IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, true, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, true, 1, true);
- }
-
- @Test
- public void testAuthTcp4UdpEncap() throws Exception {
- IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, true, 1, false);
- checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, true, 1, true);
- }
-
- @Test
- public void testOpenUdpEncapSocketSpecificPort() throws Exception {
- IpSecManager.UdpEncapsulationSocket encapSocket = null;
- int port = -1;
- for (int i = 0; i < MAX_PORT_BIND_ATTEMPTS; i++) {
- try {
- port = findUnusedPort();
- encapSocket = mISM.openUdpEncapsulationSocket(port);
- break;
- } catch (ErrnoException e) {
- if (e.errno == OsConstants.EADDRINUSE) {
- // Someone claimed the port since we called findUnusedPort.
- continue;
- }
- throw e;
- } finally {
- if (encapSocket != null) {
- encapSocket.close();
- }
- }
- }
-
- if (encapSocket == null) {
- fail("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port");
- }
-
- assertTrue("Returned invalid port", encapSocket.getPort() == port);
- }
-
- @Test
- public void testOpenUdpEncapSocketRandomPort() throws Exception {
- try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) {
- assertTrue("Returned invalid port", encapSocket.getPort() != 0);
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/tests/net/src/android/net/cts/IpSecManagerTunnelTest.java
deleted file mode 100644
index ae38faa..0000000
--- a/tests/tests/net/src/android/net/cts/IpSecManagerTunnelTest.java
+++ /dev/null
@@ -1,899 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS;
-import static android.net.IpSecManager.UdpEncapsulationSocket;
-import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE;
-import static android.net.cts.PacketUtils.AES_CBC_IV_LEN;
-import static android.net.cts.PacketUtils.BytePayload;
-import static android.net.cts.PacketUtils.EspHeader;
-import static android.net.cts.PacketUtils.IP4_HDRLEN;
-import static android.net.cts.PacketUtils.IP6_HDRLEN;
-import static android.net.cts.PacketUtils.IpHeader;
-import static android.net.cts.PacketUtils.UDP_HDRLEN;
-import static android.net.cts.PacketUtils.UdpHeader;
-import static android.net.cts.PacketUtils.getIpHeader;
-import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.IpSecAlgorithm;
-import android.net.IpSecManager;
-import android.net.IpSecTransform;
-import android.net.LinkAddress;
-import android.net.Network;
-import android.net.TestNetworkInterface;
-import android.net.TestNetworkManager;
-import android.net.cts.PacketUtils.Payload;
-import android.net.cts.util.CtsNetUtils;
-import android.os.ParcelFileDescriptor;
-import android.platform.test.annotations.AppModeFull;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps")
-public class IpSecManagerTunnelTest extends IpSecBaseTest {
- private static final String TAG = IpSecManagerTunnelTest.class.getSimpleName();
-
- private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1");
- private static final InetAddress REMOTE_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.2");
- private static final InetAddress LOCAL_OUTER_6 =
- InetAddress.parseNumericAddress("2001:db8:1::1");
- private static final InetAddress REMOTE_OUTER_6 =
- InetAddress.parseNumericAddress("2001:db8:1::2");
-
- private static final InetAddress LOCAL_INNER_4 =
- InetAddress.parseNumericAddress("198.51.100.1");
- private static final InetAddress REMOTE_INNER_4 =
- InetAddress.parseNumericAddress("198.51.100.2");
- private static final InetAddress LOCAL_INNER_6 =
- InetAddress.parseNumericAddress("2001:db8:2::1");
- private static final InetAddress REMOTE_INNER_6 =
- InetAddress.parseNumericAddress("2001:db8:2::2");
-
- private static final int IP4_PREFIX_LEN = 32;
- private static final int IP6_PREFIX_LEN = 128;
-
- private static final int TIMEOUT_MS = 500;
-
- // Static state to reduce setup/teardown
- private static ConnectivityManager sCM;
- private static TestNetworkManager sTNM;
- private static ParcelFileDescriptor sTunFd;
- private static TestNetworkCallback sTunNetworkCallback;
- private static Network sTunNetwork;
- private static TunUtils sTunUtils;
-
- private static Context sContext = InstrumentationRegistry.getContext();
- private static final CtsNetUtils mCtsNetUtils = new CtsNetUtils(sContext);
-
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- InstrumentationRegistry.getInstrumentation()
- .getUiAutomation()
- .adoptShellPermissionIdentity();
- sCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE);
-
- // 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
- // right appop permissions.
- mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, true);
-
- TestNetworkInterface testIface =
- sTNM.createTunInterface(
- new LinkAddress[] {
- new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN),
- new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN)
- });
-
- sTunFd = testIface.getFileDescriptor();
- sTunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork(testIface.getInterfaceName());
- sTunNetworkCallback.waitForAvailable();
- sTunNetwork = sTunNetworkCallback.currentNetwork;
-
- sTunUtils = new TunUtils(sTunFd);
- }
-
- @Before
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- // Set to true before every run; some tests flip this.
- mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, true);
-
- // Clear sTunUtils state
- sTunUtils.reset();
- }
-
- @AfterClass
- public static void tearDownAfterClass() throws Exception {
- mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, false);
-
- sCM.unregisterNetworkCallback(sTunNetworkCallback);
-
- sTNM.teardownTestNetwork(sTunNetwork);
- sTunFd.close();
-
- InstrumentationRegistry.getInstrumentation()
- .getUiAutomation()
- .dropShellPermissionIdentity();
- }
-
- @Test
- public void testSecurityExceptionCreateTunnelInterfaceWithoutAppop() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- // Ensure we don't have the appop. Permission is not requested in the Manifest
- mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, false);
-
- // Security exceptions are thrown regardless of IPv4/IPv6. Just test one
- try {
- mISM.createIpSecTunnelInterface(LOCAL_INNER_6, REMOTE_INNER_6, sTunNetwork);
- fail("Did not throw SecurityException for Tunnel creation without appop");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testSecurityExceptionBuildTunnelTransformWithoutAppop() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
-
- // Ensure we don't have the appop. Permission is not requested in the Manifest
- mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, false);
-
- // Security exceptions are thrown regardless of IPv4/IPv6. Just test one
- try (IpSecManager.SecurityParameterIndex spi =
- mISM.allocateSecurityParameterIndex(LOCAL_INNER_4);
- IpSecTransform transform =
- new IpSecTransform.Builder(sContext)
- .buildTunnelModeTransform(REMOTE_INNER_4, spi)) {
- fail("Did not throw SecurityException for Transform creation without appop");
- } catch (SecurityException expected) {
- }
- }
-
- /* Test runnables for callbacks after IPsec tunnels are set up. */
- private abstract class IpSecTunnelTestRunnable {
- /**
- * Runs the test code, and returns the inner socket port, if any.
- *
- * @param ipsecNetwork The IPsec Interface based Network for binding sockets on
- * @return the integer port of the inner socket if outbound, or 0 if inbound
- * IpSecTunnelTestRunnable
- * @throws Exception if any part of the test failed.
- */
- public abstract int run(Network ipsecNetwork) throws Exception;
- }
-
- private int getPacketSize(
- int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) {
- int expectedPacketSize = TEST_DATA.length + UDP_HDRLEN;
-
- // Inner Transport mode packet size
- if (transportInTunnelMode) {
- expectedPacketSize =
- PacketUtils.calculateEspPacketSize(
- expectedPacketSize,
- AES_CBC_IV_LEN,
- AES_CBC_BLK_SIZE,
- AUTH_KEY.length * 4);
- }
-
- // Inner IP Header
- expectedPacketSize += innerFamily == AF_INET ? IP4_HDRLEN : IP6_HDRLEN;
-
- // Tunnel mode transform size
- expectedPacketSize =
- PacketUtils.calculateEspPacketSize(
- expectedPacketSize, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, AUTH_KEY.length * 4);
-
- // UDP encap size
- expectedPacketSize += useEncap ? UDP_HDRLEN : 0;
-
- // Outer IP Header
- expectedPacketSize += outerFamily == AF_INET ? IP4_HDRLEN : IP6_HDRLEN;
-
- return expectedPacketSize;
- }
-
- private interface IpSecTunnelTestRunnableFactory {
- IpSecTunnelTestRunnable getIpSecTunnelTestRunnable(
- boolean transportInTunnelMode,
- int spi,
- InetAddress localInner,
- InetAddress remoteInner,
- InetAddress localOuter,
- InetAddress remoteOuter,
- IpSecTransform inTransportTransform,
- IpSecTransform outTransportTransform,
- int encapPort,
- int innerSocketPort,
- int expectedPacketSize)
- throws Exception;
- }
-
- private class OutputIpSecTunnelTestRunnableFactory implements IpSecTunnelTestRunnableFactory {
- public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable(
- boolean transportInTunnelMode,
- int spi,
- InetAddress localInner,
- InetAddress remoteInner,
- InetAddress localOuter,
- InetAddress remoteOuter,
- IpSecTransform inTransportTransform,
- IpSecTransform outTransportTransform,
- int encapPort,
- int unusedInnerSocketPort,
- int expectedPacketSize) {
- return new IpSecTunnelTestRunnable() {
- @Override
- public int run(Network ipsecNetwork) throws Exception {
- // Build a socket and send traffic
- JavaUdpSocket socket = new JavaUdpSocket(localInner);
- ipsecNetwork.bindSocket(socket.mSocket);
- int innerSocketPort = socket.getPort();
-
- // For Transport-In-Tunnel mode, apply transform to socket
- if (transportInTunnelMode) {
- mISM.applyTransportModeTransform(
- socket.mSocket, IpSecManager.DIRECTION_IN, inTransportTransform);
- mISM.applyTransportModeTransform(
- socket.mSocket, IpSecManager.DIRECTION_OUT, outTransportTransform);
- }
-
- socket.sendTo(TEST_DATA, remoteInner, socket.getPort());
-
- // Verify that an encrypted packet is sent. As of right now, checking encrypted
- // body is not possible, due to the test not knowing some of the fields of the
- // inner IP header (flow label, flags, etc)
- sTunUtils.awaitEspPacketNoPlaintext(
- spi, TEST_DATA, encapPort != 0, expectedPacketSize);
-
- socket.close();
-
- return innerSocketPort;
- }
- };
- }
- }
-
- private class InputReflectedIpSecTunnelTestRunnableFactory
- implements IpSecTunnelTestRunnableFactory {
- public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable(
- boolean transportInTunnelMode,
- int spi,
- InetAddress localInner,
- InetAddress remoteInner,
- InetAddress localOuter,
- InetAddress remoteOuter,
- IpSecTransform inTransportTransform,
- IpSecTransform outTransportTransform,
- int encapPort,
- int innerSocketPort,
- int expectedPacketSize)
- throws Exception {
- return new IpSecTunnelTestRunnable() {
- @Override
- public int run(Network ipsecNetwork) throws Exception {
- // Build a socket and receive traffic
- JavaUdpSocket socket = new JavaUdpSocket(localInner, innerSocketPort);
- ipsecNetwork.bindSocket(socket.mSocket);
-
- // For Transport-In-Tunnel mode, apply transform to socket
- if (transportInTunnelMode) {
- mISM.applyTransportModeTransform(
- socket.mSocket, IpSecManager.DIRECTION_IN, outTransportTransform);
- mISM.applyTransportModeTransform(
- socket.mSocket, IpSecManager.DIRECTION_OUT, inTransportTransform);
- }
-
- sTunUtils.reflectPackets();
-
- // Receive packet from socket, and validate that the payload is correct
- receiveAndValidatePacket(socket);
-
- socket.close();
-
- return 0;
- }
- };
- }
- }
-
- private class InputPacketGeneratorIpSecTunnelTestRunnableFactory
- implements IpSecTunnelTestRunnableFactory {
- public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable(
- boolean transportInTunnelMode,
- int spi,
- InetAddress localInner,
- InetAddress remoteInner,
- InetAddress localOuter,
- InetAddress remoteOuter,
- IpSecTransform inTransportTransform,
- IpSecTransform outTransportTransform,
- int encapPort,
- int innerSocketPort,
- int expectedPacketSize)
- throws Exception {
- return new IpSecTunnelTestRunnable() {
- @Override
- public int run(Network ipsecNetwork) throws Exception {
- // Build a socket and receive traffic
- JavaUdpSocket socket = new JavaUdpSocket(localInner);
- ipsecNetwork.bindSocket(socket.mSocket);
-
- // For Transport-In-Tunnel mode, apply transform to socket
- if (transportInTunnelMode) {
- mISM.applyTransportModeTransform(
- socket.mSocket, IpSecManager.DIRECTION_IN, outTransportTransform);
- mISM.applyTransportModeTransform(
- socket.mSocket, IpSecManager.DIRECTION_OUT, inTransportTransform);
- }
-
- byte[] pkt;
- if (transportInTunnelMode) {
- pkt =
- getTransportInTunnelModePacket(
- spi,
- spi,
- remoteInner,
- localInner,
- remoteOuter,
- localOuter,
- socket.getPort(),
- encapPort);
- } else {
- pkt =
- getTunnelModePacket(
- spi,
- remoteInner,
- localInner,
- remoteOuter,
- localOuter,
- socket.getPort(),
- encapPort);
- }
- sTunUtils.injectPacket(pkt);
-
- // Receive packet from socket, and validate
- receiveAndValidatePacket(socket);
-
- socket.close();
-
- return 0;
- }
- };
- }
- }
-
- private void checkTunnelOutput(
- int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode)
- throws Exception {
- checkTunnel(
- innerFamily,
- outerFamily,
- useEncap,
- transportInTunnelMode,
- new OutputIpSecTunnelTestRunnableFactory());
- }
-
- private void checkTunnelInput(
- int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode)
- throws Exception {
- checkTunnel(
- innerFamily,
- outerFamily,
- useEncap,
- transportInTunnelMode,
- new InputPacketGeneratorIpSecTunnelTestRunnableFactory());
- }
-
- /**
- * Validates that the kernel can talk to itself.
- *
- * <p>This test takes an outbound IPsec packet, reflects it (by flipping IP src/dst), and
- * injects it back into the TUN. This test then verifies that a packet with the correct payload
- * is found on the specified socket/port.
- */
- public void checkTunnelReflected(
- int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode)
- throws Exception {
- InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6;
- InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6;
-
- InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6;
- InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6;
-
- // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels.
- int spi = getRandomSpi(localOuter, remoteOuter);
- int expectedPacketSize =
- getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode);
-
- try (IpSecManager.SecurityParameterIndex inTransportSpi =
- mISM.allocateSecurityParameterIndex(localInner, spi);
- IpSecManager.SecurityParameterIndex outTransportSpi =
- mISM.allocateSecurityParameterIndex(remoteInner, spi);
- IpSecTransform inTransportTransform =
- buildIpSecTransform(sContext, inTransportSpi, null, remoteInner);
- IpSecTransform outTransportTransform =
- buildIpSecTransform(sContext, outTransportSpi, null, localInner);
- UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) {
-
- // Run output direction tests
- IpSecTunnelTestRunnable outputIpSecTunnelTestRunnable =
- new OutputIpSecTunnelTestRunnableFactory()
- .getIpSecTunnelTestRunnable(
- transportInTunnelMode,
- spi,
- localInner,
- remoteInner,
- localOuter,
- remoteOuter,
- inTransportTransform,
- outTransportTransform,
- useEncap ? encapSocket.getPort() : 0,
- 0,
- expectedPacketSize);
- int innerSocketPort =
- buildTunnelNetworkAndRunTests(
- localInner,
- remoteInner,
- localOuter,
- remoteOuter,
- spi,
- useEncap ? encapSocket : null,
- outputIpSecTunnelTestRunnable);
-
- // Input direction tests, with matching inner socket ports.
- IpSecTunnelTestRunnable inputIpSecTunnelTestRunnable =
- new InputReflectedIpSecTunnelTestRunnableFactory()
- .getIpSecTunnelTestRunnable(
- transportInTunnelMode,
- spi,
- remoteInner,
- localInner,
- localOuter,
- remoteOuter,
- inTransportTransform,
- outTransportTransform,
- useEncap ? encapSocket.getPort() : 0,
- innerSocketPort,
- expectedPacketSize);
- buildTunnelNetworkAndRunTests(
- remoteInner,
- localInner,
- localOuter,
- remoteOuter,
- spi,
- useEncap ? encapSocket : null,
- inputIpSecTunnelTestRunnable);
- }
- }
-
- public void checkTunnel(
- int innerFamily,
- int outerFamily,
- boolean useEncap,
- boolean transportInTunnelMode,
- IpSecTunnelTestRunnableFactory factory)
- throws Exception {
-
- InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6;
- InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6;
-
- InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6;
- InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6;
-
- // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels.
- // Re-uses the same SPI to ensure that even in cases of symmetric SPIs shared across tunnel
- // and transport mode, packets are encrypted/decrypted properly based on the src/dst.
- int spi = getRandomSpi(localOuter, remoteOuter);
- int expectedPacketSize =
- getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode);
-
- try (IpSecManager.SecurityParameterIndex inTransportSpi =
- mISM.allocateSecurityParameterIndex(localInner, spi);
- IpSecManager.SecurityParameterIndex outTransportSpi =
- mISM.allocateSecurityParameterIndex(remoteInner, spi);
- IpSecTransform inTransportTransform =
- buildIpSecTransform(sContext, inTransportSpi, null, remoteInner);
- IpSecTransform outTransportTransform =
- buildIpSecTransform(sContext, outTransportSpi, null, localInner);
- UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) {
-
- buildTunnelNetworkAndRunTests(
- localInner,
- remoteInner,
- localOuter,
- remoteOuter,
- spi,
- useEncap ? encapSocket : null,
- factory.getIpSecTunnelTestRunnable(
- transportInTunnelMode,
- spi,
- localInner,
- remoteInner,
- localOuter,
- remoteOuter,
- inTransportTransform,
- outTransportTransform,
- useEncap ? encapSocket.getPort() : 0,
- 0,
- expectedPacketSize));
- }
- }
-
- private int buildTunnelNetworkAndRunTests(
- InetAddress localInner,
- InetAddress remoteInner,
- InetAddress localOuter,
- InetAddress remoteOuter,
- int spi,
- UdpEncapsulationSocket encapSocket,
- IpSecTunnelTestRunnable test)
- throws Exception {
- int innerPrefixLen = localInner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN;
- TestNetworkCallback testNetworkCb = null;
- int innerSocketPort;
-
- try (IpSecManager.SecurityParameterIndex inSpi =
- mISM.allocateSecurityParameterIndex(localOuter, spi);
- IpSecManager.SecurityParameterIndex outSpi =
- mISM.allocateSecurityParameterIndex(remoteOuter, spi);
- IpSecManager.IpSecTunnelInterface tunnelIface =
- mISM.createIpSecTunnelInterface(localOuter, remoteOuter, sTunNetwork)) {
- // Build the test network
- tunnelIface.addAddress(localInner, innerPrefixLen);
- testNetworkCb = mCtsNetUtils.setupAndGetTestNetwork(tunnelIface.getInterfaceName());
- testNetworkCb.waitForAvailable();
- Network testNetwork = testNetworkCb.currentNetwork;
-
- // Check interface was created
- assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName()));
-
- // Verify address was added
- final NetworkInterface netIface = NetworkInterface.getByInetAddress(localInner);
- assertNotNull(netIface);
- assertEquals(tunnelIface.getInterfaceName(), netIface.getDisplayName());
-
- // Configure Transform parameters
- IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext);
- transformBuilder.setEncryption(
- new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY));
- transformBuilder.setAuthentication(
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4));
-
- if (encapSocket != null) {
- transformBuilder.setIpv4Encapsulation(encapSocket, encapSocket.getPort());
- }
-
- // Apply transform and check that traffic is properly encrypted
- try (IpSecTransform inTransform =
- transformBuilder.buildTunnelModeTransform(remoteOuter, inSpi);
- IpSecTransform outTransform =
- transformBuilder.buildTunnelModeTransform(localOuter, outSpi)) {
- mISM.applyTunnelModeTransform(tunnelIface, IpSecManager.DIRECTION_IN, inTransform);
- mISM.applyTunnelModeTransform(
- tunnelIface, IpSecManager.DIRECTION_OUT, outTransform);
-
- innerSocketPort = test.run(testNetwork);
- }
-
- // Teardown the test network
- sTNM.teardownTestNetwork(testNetwork);
-
- // Remove addresses and check that interface is still present, but fails lookup-by-addr
- tunnelIface.removeAddress(localInner, innerPrefixLen);
- assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName()));
- assertNull(NetworkInterface.getByInetAddress(localInner));
-
- // Check interface was cleaned up
- tunnelIface.close();
- assertNull(NetworkInterface.getByName(tunnelIface.getInterfaceName()));
- } finally {
- if (testNetworkCb != null) {
- sCM.unregisterNetworkCallback(testNetworkCb);
- }
- }
-
- return innerSocketPort;
- }
-
- private static void receiveAndValidatePacket(JavaUdpSocket socket) throws Exception {
- byte[] socketResponseBytes = socket.receive();
- assertArrayEquals(TEST_DATA, socketResponseBytes);
- }
-
- private int getRandomSpi(InetAddress localOuter, InetAddress remoteOuter) throws Exception {
- // Try to allocate both in and out SPIs using the same requested SPI value.
- try (IpSecManager.SecurityParameterIndex inSpi =
- mISM.allocateSecurityParameterIndex(localOuter);
- IpSecManager.SecurityParameterIndex outSpi =
- mISM.allocateSecurityParameterIndex(remoteOuter, inSpi.getSpi()); ) {
- return inSpi.getSpi();
- }
- }
-
- private EspHeader buildTransportModeEspPacket(
- int spi, InetAddress src, InetAddress dst, int port, Payload payload) throws Exception {
- IpHeader preEspIpHeader = getIpHeader(payload.getProtocolId(), src, dst, payload);
-
- return new EspHeader(
- payload.getProtocolId(),
- spi,
- 1, // sequence number
- CRYPT_KEY, // Same key for auth and crypt
- payload.getPacketBytes(preEspIpHeader));
- }
-
- private EspHeader buildTunnelModeEspPacket(
- int spi,
- InetAddress srcInner,
- InetAddress dstInner,
- InetAddress srcOuter,
- InetAddress dstOuter,
- int port,
- int encapPort,
- Payload payload)
- throws Exception {
- IpHeader innerIp = getIpHeader(payload.getProtocolId(), srcInner, dstInner, payload);
- return new EspHeader(
- innerIp.getProtocolId(),
- spi,
- 1, // sequence number
- CRYPT_KEY, // Same key for auth and crypt
- innerIp.getPacketBytes());
- }
-
- private IpHeader maybeEncapPacket(
- InetAddress src, InetAddress dst, int encapPort, EspHeader espPayload)
- throws Exception {
-
- Payload payload = espPayload;
- if (encapPort != 0) {
- payload = new UdpHeader(encapPort, encapPort, espPayload);
- }
-
- return getIpHeader(payload.getProtocolId(), src, dst, payload);
- }
-
- private byte[] getTunnelModePacket(
- int spi,
- InetAddress srcInner,
- InetAddress dstInner,
- InetAddress srcOuter,
- InetAddress dstOuter,
- int port,
- int encapPort)
- throws Exception {
- UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA));
-
- EspHeader espPayload =
- buildTunnelModeEspPacket(
- spi, srcInner, dstInner, srcOuter, dstOuter, port, encapPort, udp);
- return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes();
- }
-
- private byte[] getTransportInTunnelModePacket(
- int spiInner,
- int spiOuter,
- InetAddress srcInner,
- InetAddress dstInner,
- InetAddress srcOuter,
- InetAddress dstOuter,
- int port,
- int encapPort)
- throws Exception {
- UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA));
-
- EspHeader espPayload = buildTransportModeEspPacket(spiInner, srcInner, dstInner, port, udp);
- espPayload =
- buildTunnelModeEspPacket(
- spiOuter,
- srcInner,
- dstInner,
- srcOuter,
- dstOuter,
- port,
- encapPort,
- espPayload);
- return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes();
- }
-
- // Transport-in-Tunnel mode tests
- @Test
- public void testTransportInTunnelModeV4InV4() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelOutput(AF_INET, AF_INET, false, true);
- checkTunnelInput(AF_INET, AF_INET, false, true);
- }
-
- @Test
- public void testTransportInTunnelModeV4InV4Reflected() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelReflected(AF_INET, AF_INET, false, true);
- }
-
- @Test
- public void testTransportInTunnelModeV4InV4UdpEncap() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelOutput(AF_INET, AF_INET, true, true);
- checkTunnelInput(AF_INET, AF_INET, true, true);
- }
-
- @Test
- public void testTransportInTunnelModeV4InV4UdpEncapReflected() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelReflected(AF_INET, AF_INET, false, true);
- }
-
- @Test
- public void testTransportInTunnelModeV4InV6() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelOutput(AF_INET, AF_INET6, false, true);
- checkTunnelInput(AF_INET, AF_INET6, false, true);
- }
-
- @Test
- public void testTransportInTunnelModeV4InV6Reflected() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelReflected(AF_INET, AF_INET, false, true);
- }
-
- @Test
- public void testTransportInTunnelModeV6InV4() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelOutput(AF_INET6, AF_INET, false, true);
- checkTunnelInput(AF_INET6, AF_INET, false, true);
- }
-
- @Test
- public void testTransportInTunnelModeV6InV4Reflected() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelReflected(AF_INET, AF_INET, false, true);
- }
-
- @Test
- public void testTransportInTunnelModeV6InV4UdpEncap() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelOutput(AF_INET6, AF_INET, true, true);
- checkTunnelInput(AF_INET6, AF_INET, true, true);
- }
-
- @Test
- public void testTransportInTunnelModeV6InV4UdpEncapReflected() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelReflected(AF_INET, AF_INET, false, true);
- }
-
- @Test
- public void testTransportInTunnelModeV6InV6() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelOutput(AF_INET, AF_INET6, false, true);
- checkTunnelInput(AF_INET, AF_INET6, false, true);
- }
-
- @Test
- public void testTransportInTunnelModeV6InV6Reflected() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelReflected(AF_INET, AF_INET, false, true);
- }
-
- // Tunnel mode tests
- @Test
- public void testTunnelV4InV4() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelOutput(AF_INET, AF_INET, false, false);
- checkTunnelInput(AF_INET, AF_INET, false, false);
- }
-
- @Test
- public void testTunnelV4InV4Reflected() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelReflected(AF_INET, AF_INET, false, false);
- }
-
- @Test
- public void testTunnelV4InV4UdpEncap() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelOutput(AF_INET, AF_INET, true, false);
- checkTunnelInput(AF_INET, AF_INET, true, false);
- }
-
- @Test
- public void testTunnelV4InV4UdpEncapReflected() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelReflected(AF_INET, AF_INET, true, false);
- }
-
- @Test
- public void testTunnelV4InV6() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelOutput(AF_INET, AF_INET6, false, false);
- checkTunnelInput(AF_INET, AF_INET6, false, false);
- }
-
- @Test
- public void testTunnelV4InV6Reflected() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelReflected(AF_INET, AF_INET6, false, false);
- }
-
- @Test
- public void testTunnelV6InV4() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelOutput(AF_INET6, AF_INET, false, false);
- checkTunnelInput(AF_INET6, AF_INET, false, false);
- }
-
- @Test
- public void testTunnelV6InV4Reflected() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelReflected(AF_INET6, AF_INET, false, false);
- }
-
- @Test
- public void testTunnelV6InV4UdpEncap() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelOutput(AF_INET6, AF_INET, true, false);
- checkTunnelInput(AF_INET6, AF_INET, true, false);
- }
-
- @Test
- public void testTunnelV6InV4UdpEncapReflected() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelReflected(AF_INET6, AF_INET, true, false);
- }
-
- @Test
- public void testTunnelV6InV6() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelOutput(AF_INET6, AF_INET6, false, false);
- checkTunnelInput(AF_INET6, AF_INET6, false, false);
- }
-
- @Test
- public void testTunnelV6InV6Reflected() throws Exception {
- assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- checkTunnelReflected(AF_INET6, AF_INET6, false, false);
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/LocalServerSocketTest.java b/tests/tests/net/src/android/net/cts/LocalServerSocketTest.java
deleted file mode 100644
index 7c5a1b3..0000000
--- a/tests/tests/net/src/android/net/cts/LocalServerSocketTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.cts;
-
-import junit.framework.TestCase;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-
-public class LocalServerSocketTest extends TestCase {
-
- public void testLocalServerSocket() throws IOException {
- String address = "com.android.net.LocalServerSocketTest_testLocalServerSocket";
- LocalServerSocket localServerSocket = new LocalServerSocket(address);
- assertNotNull(localServerSocket.getLocalSocketAddress());
-
- // create client socket
- LocalSocket clientSocket = new LocalSocket();
-
- // establish connection between client and server
- clientSocket.connect(new LocalSocketAddress(address));
- LocalSocket serverSocket = localServerSocket.accept();
-
- assertTrue(serverSocket.isConnected());
- assertTrue(serverSocket.isBound());
-
- // send data from client to server
- OutputStream clientOutStream = clientSocket.getOutputStream();
- clientOutStream.write(12);
- InputStream serverInStream = serverSocket.getInputStream();
- assertEquals(12, serverInStream.read());
-
- // send data from server to client
- OutputStream serverOutStream = serverSocket.getOutputStream();
- serverOutStream.write(3);
- InputStream clientInStream = clientSocket.getInputStream();
- assertEquals(3, clientInStream.read());
-
- // close server socket
- assertNotNull(localServerSocket.getFileDescriptor());
- localServerSocket.close();
- assertNull(localServerSocket.getFileDescriptor());
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/LocalSocketAddressTest.java b/tests/tests/net/src/android/net/cts/LocalSocketAddressTest.java
deleted file mode 100644
index 6ef003b..0000000
--- a/tests/tests/net/src/android/net/cts/LocalSocketAddressTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.net.LocalSocketAddress;
-import android.net.LocalSocketAddress.Namespace;
-import android.test.AndroidTestCase;
-
-public class LocalSocketAddressTest extends AndroidTestCase {
-
- public void testNewLocalSocketAddressWithDefaultNamespace() {
- // default namespace
- LocalSocketAddress localSocketAddress = new LocalSocketAddress("name");
- assertEquals("name", localSocketAddress.getName());
- assertEquals(Namespace.ABSTRACT, localSocketAddress.getNamespace());
-
- // specify the namespace
- LocalSocketAddress localSocketAddress2 =
- new LocalSocketAddress("name2", Namespace.ABSTRACT);
- assertEquals("name2", localSocketAddress2.getName());
- assertEquals(Namespace.ABSTRACT, localSocketAddress2.getNamespace());
-
- LocalSocketAddress localSocketAddress3 =
- new LocalSocketAddress("name3", Namespace.FILESYSTEM);
- assertEquals("name3", localSocketAddress3.getName());
- assertEquals(Namespace.FILESYSTEM, localSocketAddress3.getNamespace());
-
- LocalSocketAddress localSocketAddress4 =
- new LocalSocketAddress("name4", Namespace.RESERVED);
- assertEquals("name4", localSocketAddress4.getName());
- assertEquals(Namespace.RESERVED, localSocketAddress4.getNamespace());
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java b/tests/tests/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java
deleted file mode 100644
index 97dfa43..0000000
--- a/tests/tests/net/src/android/net/cts/LocalSocketAddress_NamespaceTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.net.LocalSocketAddress.Namespace;
-import android.test.AndroidTestCase;
-
-public class LocalSocketAddress_NamespaceTest extends AndroidTestCase {
-
- public void testValueOf() {
- assertEquals(Namespace.ABSTRACT, Namespace.valueOf("ABSTRACT"));
- assertEquals(Namespace.RESERVED, Namespace.valueOf("RESERVED"));
- assertEquals(Namespace.FILESYSTEM, Namespace.valueOf("FILESYSTEM"));
- }
-
- public void testValues() {
- Namespace[] expected = Namespace.values();
- assertEquals(Namespace.ABSTRACT, expected[0]);
- assertEquals(Namespace.RESERVED, expected[1]);
- assertEquals(Namespace.FILESYSTEM, expected[2]);
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/LocalSocketTest.java b/tests/tests/net/src/android/net/cts/LocalSocketTest.java
deleted file mode 100644
index 6e61705..0000000
--- a/tests/tests/net/src/android/net/cts/LocalSocketTest.java
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import junit.framework.TestCase;
-
-import android.net.Credentials;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-import android.system.Os;
-import android.system.OsConstants;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-public class LocalSocketTest extends TestCase {
- private final static String ADDRESS_PREFIX = "com.android.net.LocalSocketTest";
-
- public void testLocalConnections() throws IOException {
- String address = ADDRESS_PREFIX + "_testLocalConnections";
- // create client and server socket
- LocalServerSocket localServerSocket = new LocalServerSocket(address);
- LocalSocket clientSocket = new LocalSocket();
-
- // establish connection between client and server
- LocalSocketAddress locSockAddr = new LocalSocketAddress(address);
- assertFalse(clientSocket.isConnected());
- clientSocket.connect(locSockAddr);
- assertTrue(clientSocket.isConnected());
-
- LocalSocket serverSocket = localServerSocket.accept();
- assertTrue(serverSocket.isConnected());
- assertTrue(serverSocket.isBound());
- try {
- serverSocket.bind(localServerSocket.getLocalSocketAddress());
- fail("Cannot bind a LocalSocket from accept()");
- } catch (IOException expected) {
- }
- try {
- serverSocket.connect(locSockAddr);
- fail("Cannot connect a LocalSocket from accept()");
- } catch (IOException expected) {
- }
-
- Credentials credent = clientSocket.getPeerCredentials();
- assertTrue(0 != credent.getPid());
-
- // send data from client to server
- OutputStream clientOutStream = clientSocket.getOutputStream();
- clientOutStream.write(12);
- InputStream serverInStream = serverSocket.getInputStream();
- assertEquals(12, serverInStream.read());
-
- //send data from server to client
- OutputStream serverOutStream = serverSocket.getOutputStream();
- serverOutStream.write(3);
- InputStream clientInStream = clientSocket.getInputStream();
- assertEquals(3, clientInStream.read());
-
- // Test sending and receiving file descriptors
- clientSocket.setFileDescriptorsForSend(new FileDescriptor[]{FileDescriptor.in});
- clientOutStream.write(32);
- assertEquals(32, serverInStream.read());
-
- FileDescriptor[] out = serverSocket.getAncillaryFileDescriptors();
- assertEquals(1, out.length);
- FileDescriptor fd = clientSocket.getFileDescriptor();
- assertTrue(fd.valid());
-
- //shutdown input stream of client
- clientSocket.shutdownInput();
- assertEquals(-1, clientInStream.read());
-
- //shutdown output stream of client
- clientSocket.shutdownOutput();
- try {
- clientOutStream.write(10);
- fail("testLocalSocket shouldn't come to here");
- } catch (IOException e) {
- // expected
- }
-
- //shutdown input stream of server
- serverSocket.shutdownInput();
- assertEquals(-1, serverInStream.read());
-
- //shutdown output stream of server
- serverSocket.shutdownOutput();
- try {
- serverOutStream.write(10);
- fail("testLocalSocket shouldn't come to here");
- } catch (IOException e) {
- // expected
- }
-
- //close client socket
- clientSocket.close();
- try {
- clientInStream.read();
- fail("testLocalSocket shouldn't come to here");
- } catch (IOException e) {
- // expected
- }
-
- //close server socket
- serverSocket.close();
- try {
- serverInStream.read();
- fail("testLocalSocket shouldn't come to here");
- } catch (IOException e) {
- // expected
- }
- }
-
- public void testAccessors() throws IOException {
- String address = ADDRESS_PREFIX + "_testAccessors";
- LocalSocket socket = new LocalSocket();
- LocalSocketAddress addr = new LocalSocketAddress(address);
-
- assertFalse(socket.isBound());
- socket.bind(addr);
- assertTrue(socket.isBound());
- assertEquals(addr, socket.getLocalSocketAddress());
-
- String str = socket.toString();
- assertTrue(str.contains("impl:android.net.LocalSocketImpl"));
-
- socket.setReceiveBufferSize(1999);
- assertEquals(1999 << 1, socket.getReceiveBufferSize());
-
- socket.setSendBufferSize(3998);
- assertEquals(3998 << 1, socket.getSendBufferSize());
-
- assertEquals(0, socket.getSoTimeout());
- socket.setSoTimeout(1996);
- assertTrue(socket.getSoTimeout() > 0);
-
- try {
- socket.getRemoteSocketAddress();
- fail("testLocalSocketSecondary shouldn't come to here");
- } catch (UnsupportedOperationException e) {
- // expected
- }
-
- try {
- socket.isClosed();
- fail("testLocalSocketSecondary shouldn't come to here");
- } catch (UnsupportedOperationException e) {
- // expected
- }
-
- try {
- socket.isInputShutdown();
- fail("testLocalSocketSecondary shouldn't come to here");
- } catch (UnsupportedOperationException e) {
- // expected
- }
-
- try {
- socket.isOutputShutdown();
- fail("testLocalSocketSecondary shouldn't come to here");
- } catch (UnsupportedOperationException e) {
- // expected
- }
-
- try {
- socket.connect(addr, 2005);
- fail("testLocalSocketSecondary shouldn't come to here");
- } catch (UnsupportedOperationException e) {
- // expected
- }
-
- socket.close();
- }
-
- // http://b/31205169
- public void testSetSoTimeout_readTimeout() throws Exception {
- String address = ADDRESS_PREFIX + "_testSetSoTimeout_readTimeout";
-
- try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
- final LocalSocket clientSocket = socketPair.clientSocket;
-
- // Set the timeout in millis.
- int timeoutMillis = 1000;
- clientSocket.setSoTimeout(timeoutMillis);
-
- // Avoid blocking the test run if timeout doesn't happen by using a separate thread.
- Callable<Result> reader = () -> {
- try {
- clientSocket.getInputStream().read();
- return Result.noException("Did not block");
- } catch (IOException e) {
- return Result.exception(e);
- }
- };
- // Allow the configured timeout, plus some slop.
- int allowedTime = timeoutMillis + 2000;
- Result result = runInSeparateThread(allowedTime, reader);
-
- // Check the message was a timeout, it's all we have to go on.
- String expectedMessage = Os.strerror(OsConstants.EAGAIN);
- result.assertThrewIOException(expectedMessage);
- }
- }
-
- // http://b/31205169
- public void testSetSoTimeout_writeTimeout() throws Exception {
- String address = ADDRESS_PREFIX + "_testSetSoTimeout_writeTimeout";
-
- try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
- final LocalSocket clientSocket = socketPair.clientSocket;
-
- // Set the timeout in millis.
- int timeoutMillis = 1000;
- clientSocket.setSoTimeout(timeoutMillis);
-
- // Set a small buffer size so we know we can flood it.
- clientSocket.setSendBufferSize(100);
- final int bufferSize = clientSocket.getSendBufferSize();
-
- // Avoid blocking the test run if timeout doesn't happen by using a separate thread.
- Callable<Result> writer = () -> {
- try {
- byte[] toWrite = new byte[bufferSize * 2];
- clientSocket.getOutputStream().write(toWrite);
- return Result.noException("Did not block");
- } catch (IOException e) {
- return Result.exception(e);
- }
- };
- // Allow the configured timeout, plus some slop.
- int allowedTime = timeoutMillis + 2000;
-
- Result result = runInSeparateThread(allowedTime, writer);
-
- // Check the message was a timeout, it's all we have to go on.
- String expectedMessage = Os.strerror(OsConstants.EAGAIN);
- result.assertThrewIOException(expectedMessage);
- }
- }
-
- public void testAvailable() throws Exception {
- String address = ADDRESS_PREFIX + "_testAvailable";
-
- try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
- LocalSocket clientSocket = socketPair.clientSocket;
- LocalSocket serverSocket = socketPair.serverSocket.accept();
-
- OutputStream clientOutputStream = clientSocket.getOutputStream();
- InputStream serverInputStream = serverSocket.getInputStream();
- assertEquals(0, serverInputStream.available());
-
- byte[] buffer = new byte[50];
- clientOutputStream.write(buffer);
- assertEquals(50, serverInputStream.available());
-
- InputStream clientInputStream = clientSocket.getInputStream();
- OutputStream serverOutputStream = serverSocket.getOutputStream();
- assertEquals(0, clientInputStream.available());
- serverOutputStream.write(buffer);
- assertEquals(50, serverInputStream.available());
-
- serverSocket.close();
- }
- }
-
- // http://b/34095140
- public void testLocalSocketCreatedFromFileDescriptor() throws Exception {
- String address = ADDRESS_PREFIX + "_testLocalSocketCreatedFromFileDescriptor";
-
- // Establish connection between a local client and server to get a valid client socket file
- // descriptor.
- try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
- // Extract the client FileDescriptor we can use.
- FileDescriptor fileDescriptor = socketPair.clientSocket.getFileDescriptor();
- assertTrue(fileDescriptor.valid());
-
- // Create the LocalSocket we want to test.
- LocalSocket clientSocketCreatedFromFileDescriptor =
- LocalSocket.createConnectedLocalSocket(fileDescriptor);
- assertTrue(clientSocketCreatedFromFileDescriptor.isConnected());
- assertTrue(clientSocketCreatedFromFileDescriptor.isBound());
-
- // Test the LocalSocket can be used for communication.
- LocalSocket serverSocket = socketPair.serverSocket.accept();
- OutputStream clientOutputStream =
- clientSocketCreatedFromFileDescriptor.getOutputStream();
- InputStream serverInputStream = serverSocket.getInputStream();
-
- clientOutputStream.write(12);
- assertEquals(12, serverInputStream.read());
-
- // Closing clientSocketCreatedFromFileDescriptor does not close the file descriptor.
- clientSocketCreatedFromFileDescriptor.close();
- assertTrue(fileDescriptor.valid());
-
- // .. while closing the LocalSocket that owned the file descriptor does.
- socketPair.clientSocket.close();
- assertFalse(fileDescriptor.valid());
- }
- }
-
- public void testFlush() throws Exception {
- String address = ADDRESS_PREFIX + "_testFlush";
-
- try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
- LocalSocket clientSocket = socketPair.clientSocket;
- LocalSocket serverSocket = socketPair.serverSocket.accept();
-
- OutputStream clientOutputStream = clientSocket.getOutputStream();
- InputStream serverInputStream = serverSocket.getInputStream();
- testFlushWorks(clientOutputStream, serverInputStream);
-
- OutputStream serverOutputStream = serverSocket.getOutputStream();
- InputStream clientInputStream = clientSocket.getInputStream();
- testFlushWorks(serverOutputStream, clientInputStream);
-
- serverSocket.close();
- }
- }
-
- private void testFlushWorks(OutputStream outputStream, InputStream inputStream)
- throws Exception {
- final int bytesToTransfer = 50;
- StreamReader inputStreamReader = new StreamReader(inputStream, bytesToTransfer);
-
- byte[] buffer = new byte[bytesToTransfer];
- outputStream.write(buffer);
- assertEquals(bytesToTransfer, inputStream.available());
-
- // Start consuming the data.
- inputStreamReader.start();
-
- // This doesn't actually flush any buffers, it just polls until the reader has read all the
- // bytes.
- outputStream.flush();
-
- inputStreamReader.waitForCompletion(5000);
- inputStreamReader.assertBytesRead(bytesToTransfer);
- assertEquals(0, inputStream.available());
- }
-
- private static class StreamReader extends Thread {
- private final InputStream is;
- private final int expectedByteCount;
- private final CountDownLatch completeLatch = new CountDownLatch(1);
-
- private volatile Exception exception;
- private int bytesRead;
-
- private StreamReader(InputStream is, int expectedByteCount) {
- this.is = is;
- this.expectedByteCount = expectedByteCount;
- }
-
- @Override
- public void run() {
- try {
- byte[] buffer = new byte[10];
- int readCount;
- while ((readCount = is.read(buffer)) >= 0) {
- bytesRead += readCount;
- if (bytesRead >= expectedByteCount) {
- break;
- }
- }
- } catch (IOException e) {
- exception = e;
- } finally {
- completeLatch.countDown();
- }
- }
-
- public void waitForCompletion(long waitMillis) throws Exception {
- if (!completeLatch.await(waitMillis, TimeUnit.MILLISECONDS)) {
- fail("Timeout waiting for completion");
- }
- if (exception != null) {
- throw new Exception("Read failed", exception);
- }
- }
-
- public void assertBytesRead(int expected) {
- assertEquals(expected, bytesRead);
- }
- }
-
- private static class Result {
- private final String type;
- private final Exception e;
-
- private Result(String type, Exception e) {
- this.type = type;
- this.e = e;
- }
-
- static Result noException(String description) {
- return new Result(description, null);
- }
-
- static Result exception(Exception e) {
- return new Result(e.getClass().getName(), e);
- }
-
- void assertThrewIOException(String expectedMessage) {
- assertEquals("Unexpected result type", IOException.class.getName(), type);
- assertEquals("Unexpected exception message", expectedMessage, e.getMessage());
- }
- }
-
- private static Result runInSeparateThread(int allowedTime, final Callable<Result> callable)
- throws Exception {
- ExecutorService service = Executors.newSingleThreadScheduledExecutor();
- Future<Result> future = service.submit(callable);
- Result result = future.get(allowedTime, TimeUnit.MILLISECONDS);
- if (!future.isDone()) {
- fail("Worker thread appears blocked");
- }
- return result;
- }
-
- private static class LocalSocketPair implements AutoCloseable {
- static LocalSocketPair createConnectedSocketPair(String address) throws Exception {
- LocalServerSocket localServerSocket = new LocalServerSocket(address);
- final LocalSocket clientSocket = new LocalSocket();
-
- // Establish connection between client and server
- LocalSocketAddress locSockAddr = new LocalSocketAddress(address);
- clientSocket.connect(locSockAddr);
- assertTrue(clientSocket.isConnected());
- return new LocalSocketPair(localServerSocket, clientSocket);
- }
-
- final LocalServerSocket serverSocket;
- final LocalSocket clientSocket;
-
- LocalSocketPair(LocalServerSocket serverSocket, LocalSocket clientSocket) {
- this.serverSocket = serverSocket;
- this.clientSocket = clientSocket;
- }
-
- public void close() throws Exception {
- serverSocket.close();
- clientSocket.close();
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/MacAddressTest.java b/tests/tests/net/src/android/net/cts/MacAddressTest.java
deleted file mode 100644
index 4d25e62..0000000
--- a/tests/tests/net/src/android/net/cts/MacAddressTest.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static android.net.MacAddress.TYPE_BROADCAST;
-import static android.net.MacAddress.TYPE_MULTICAST;
-import static android.net.MacAddress.TYPE_UNICAST;
-
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.MacAddress;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet6Address;
-import java.util.Arrays;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class MacAddressTest {
-
- static class TestCase {
- final String macAddress;
- final String ouiString;
- final int addressType;
- final boolean isLocallyAssigned;
-
- TestCase(String macAddress, String ouiString, int addressType, boolean isLocallyAssigned) {
- this.macAddress = macAddress;
- this.ouiString = ouiString;
- this.addressType = addressType;
- this.isLocallyAssigned = isLocallyAssigned;
- }
- }
-
- static final boolean LOCALLY_ASSIGNED = true;
- static final boolean GLOBALLY_UNIQUE = false;
-
- static String typeToString(int addressType) {
- switch (addressType) {
- case TYPE_UNICAST:
- return "TYPE_UNICAST";
- case TYPE_BROADCAST:
- return "TYPE_BROADCAST";
- case TYPE_MULTICAST:
- return "TYPE_MULTICAST";
- default:
- return "UNKNOWN";
- }
- }
-
- static String localAssignedToString(boolean isLocallyAssigned) {
- return isLocallyAssigned ? "LOCALLY_ASSIGNED" : "GLOBALLY_UNIQUE";
- }
-
- @Test
- public void testMacAddress() {
- TestCase[] tests = {
- new TestCase("ff:ff:ff:ff:ff:ff", "ff:ff:ff", TYPE_BROADCAST, LOCALLY_ASSIGNED),
- new TestCase("d2:c4:22:4d:32:a8", "d2:c4:22", TYPE_UNICAST, LOCALLY_ASSIGNED),
- new TestCase("33:33:aa:bb:cc:dd", "33:33:aa", TYPE_MULTICAST, LOCALLY_ASSIGNED),
- new TestCase("06:00:00:00:00:00", "06:00:00", TYPE_UNICAST, LOCALLY_ASSIGNED),
- new TestCase("07:00:d3:56:8a:c4", "07:00:d3", TYPE_MULTICAST, LOCALLY_ASSIGNED),
- new TestCase("00:01:44:55:66:77", "00:01:44", TYPE_UNICAST, GLOBALLY_UNIQUE),
- new TestCase("08:00:22:33:44:55", "08:00:22", TYPE_UNICAST, GLOBALLY_UNIQUE),
- };
-
- for (TestCase tc : tests) {
- MacAddress mac = MacAddress.fromString(tc.macAddress);
-
- if (!tc.ouiString.equals(mac.toOuiString())) {
- fail(String.format("expected OUI string %s, got %s",
- tc.ouiString, mac.toOuiString()));
- }
-
- if (tc.isLocallyAssigned != mac.isLocallyAssigned()) {
- fail(String.format("expected %s to be %s, got %s", mac,
- localAssignedToString(tc.isLocallyAssigned),
- localAssignedToString(mac.isLocallyAssigned())));
- }
-
- if (tc.addressType != mac.getAddressType()) {
- fail(String.format("expected %s address type to be %s, got %s", mac,
- typeToString(tc.addressType), typeToString(mac.getAddressType())));
- }
-
- if (!tc.macAddress.equals(mac.toString())) {
- fail(String.format("expected toString() to return %s, got %s",
- tc.macAddress, mac.toString()));
- }
-
- if (!mac.equals(MacAddress.fromBytes(mac.toByteArray()))) {
- byte[] bytes = mac.toByteArray();
- fail(String.format("expected mac address from bytes %s to be %s, got %s",
- Arrays.toString(bytes),
- MacAddress.fromBytes(bytes),
- mac));
- }
- }
- }
-
- @Test
- public void testConstructorInputValidation() {
- String[] invalidStringAddresses = {
- "",
- "abcd",
- "1:2:3:4:5",
- "1:2:3:4:5:6:7",
- "10000:2:3:4:5:6",
- };
-
- for (String s : invalidStringAddresses) {
- try {
- MacAddress mac = MacAddress.fromString(s);
- fail("MacAddress.fromString(" + s + ") should have failed, but returned " + mac);
- } catch (IllegalArgumentException excepted) {
- }
- }
-
- try {
- MacAddress mac = MacAddress.fromString(null);
- fail("MacAddress.fromString(null) should have failed, but returned " + mac);
- } catch (NullPointerException excepted) {
- }
-
- byte[][] invalidBytesAddresses = {
- {},
- {1,2,3,4,5},
- {1,2,3,4,5,6,7},
- };
-
- for (byte[] b : invalidBytesAddresses) {
- try {
- MacAddress mac = MacAddress.fromBytes(b);
- fail("MacAddress.fromBytes(" + Arrays.toString(b)
- + ") should have failed, but returned " + mac);
- } catch (IllegalArgumentException excepted) {
- }
- }
-
- try {
- MacAddress mac = MacAddress.fromBytes(null);
- fail("MacAddress.fromBytes(null) should have failed, but returned " + mac);
- } catch (NullPointerException excepted) {
- }
- }
-
- @Test
- public void testMatches() {
- // match 4 bytes prefix
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:dd:00:00"),
- MacAddress.fromString("ff:ff:ff:ff:00:00")));
-
- // match bytes 0,1,2 and 5
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:00:00:11"),
- MacAddress.fromString("ff:ff:ff:00:00:ff")));
-
- // match 34 bit prefix
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:dd:c0:00"),
- MacAddress.fromString("ff:ff:ff:ff:c0:00")));
-
- // fail to match 36 bit prefix
- assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:dd:40:00"),
- MacAddress.fromString("ff:ff:ff:ff:f0:00")));
-
- // match all 6 bytes
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:dd:ee:11"),
- MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
-
- // match none of 6 bytes
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("00:00:00:00:00:00"),
- MacAddress.fromString("00:00:00:00:00:00")));
- }
-
- /**
- * Tests that link-local address generation from MAC is valid.
- */
- @Test
- public void testLinkLocalFromMacGeneration() {
- final MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
- final byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
- 0x74, (byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f};
- final Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac();
- assertTrue(llv6.isLinkLocalAddress());
- assertArrayEquals(inet6ll, llv6.getAddress());
- }
-
- @Test
- public void testParcelMacAddress() {
- final MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
-
- assertParcelSane(mac, 1);
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/MailToTest.java b/tests/tests/net/src/android/net/cts/MailToTest.java
deleted file mode 100644
index e454d20..0000000
--- a/tests/tests/net/src/android/net/cts/MailToTest.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.net.MailTo;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-public class MailToTest extends AndroidTestCase {
- private static final String MAILTOURI_1 = "mailto:chris@example.com";
- private static final String MAILTOURI_2 = "mailto:infobot@example.com?subject=current-issue";
- private static final String MAILTOURI_3 =
- "mailto:infobot@example.com?body=send%20current-issue";
- private static final String MAILTOURI_4 = "mailto:infobot@example.com?body=send%20current-" +
- "issue%0D%0Asend%20index";
- private static final String MAILTOURI_5 = "mailto:joe@example.com?" +
- "cc=bob@example.com&body=hello";
- private static final String MAILTOURI_6 = "mailto:?to=joe@example.com&" +
- "cc=bob@example.com&body=hello";
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- }
-
- public void testParseMailToURI() {
- assertFalse(MailTo.isMailTo(null));
- assertFalse(MailTo.isMailTo(""));
- assertFalse(MailTo.isMailTo("http://www.google.com"));
-
- assertTrue(MailTo.isMailTo(MAILTOURI_1));
- MailTo mailTo_1 = MailTo.parse(MAILTOURI_1);
- Log.d("Trace", mailTo_1.toString());
- assertEquals("chris@example.com", mailTo_1.getTo());
- assertEquals(1, mailTo_1.getHeaders().size());
- assertNull(mailTo_1.getBody());
- assertNull(mailTo_1.getCc());
- assertNull(mailTo_1.getSubject());
- assertEquals("mailto:?to=chris%40example.com&", mailTo_1.toString());
-
- assertTrue(MailTo.isMailTo(MAILTOURI_2));
- MailTo mailTo_2 = MailTo.parse(MAILTOURI_2);
- Log.d("Trace", mailTo_2.toString());
- assertEquals(2, mailTo_2.getHeaders().size());
- assertEquals("infobot@example.com", mailTo_2.getTo());
- assertEquals("current-issue", mailTo_2.getSubject());
- assertNull(mailTo_2.getBody());
- assertNull(mailTo_2.getCc());
- String stringUrl = mailTo_2.toString();
- assertTrue(stringUrl.startsWith("mailto:?"));
- assertTrue(stringUrl.contains("to=infobot%40example.com&"));
- assertTrue(stringUrl.contains("subject=current-issue&"));
-
- assertTrue(MailTo.isMailTo(MAILTOURI_3));
- MailTo mailTo_3 = MailTo.parse(MAILTOURI_3);
- Log.d("Trace", mailTo_3.toString());
- assertEquals(2, mailTo_3.getHeaders().size());
- assertEquals("infobot@example.com", mailTo_3.getTo());
- assertEquals("send current-issue", mailTo_3.getBody());
- assertNull(mailTo_3.getCc());
- assertNull(mailTo_3.getSubject());
- stringUrl = mailTo_3.toString();
- assertTrue(stringUrl.startsWith("mailto:?"));
- assertTrue(stringUrl.contains("to=infobot%40example.com&"));
- assertTrue(stringUrl.contains("body=send%20current-issue&"));
-
- assertTrue(MailTo.isMailTo(MAILTOURI_4));
- MailTo mailTo_4 = MailTo.parse(MAILTOURI_4);
- Log.d("Trace", mailTo_4.toString() + " " + mailTo_4.getBody());
- assertEquals(2, mailTo_4.getHeaders().size());
- assertEquals("infobot@example.com", mailTo_4.getTo());
- assertEquals("send current-issue\r\nsend index", mailTo_4.getBody());
- assertNull(mailTo_4.getCc());
- assertNull(mailTo_4.getSubject());
- stringUrl = mailTo_4.toString();
- assertTrue(stringUrl.startsWith("mailto:?"));
- assertTrue(stringUrl.contains("to=infobot%40example.com&"));
- assertTrue(stringUrl.contains("body=send%20current-issue%0D%0Asend%20index&"));
-
-
- assertTrue(MailTo.isMailTo(MAILTOURI_5));
- MailTo mailTo_5 = MailTo.parse(MAILTOURI_5);
- Log.d("Trace", mailTo_5.toString() + mailTo_5.getHeaders().toString()
- + mailTo_5.getHeaders().size());
- assertEquals(3, mailTo_5.getHeaders().size());
- assertEquals("joe@example.com", mailTo_5.getTo());
- assertEquals("bob@example.com", mailTo_5.getCc());
- assertEquals("hello", mailTo_5.getBody());
- assertNull(mailTo_5.getSubject());
- stringUrl = mailTo_5.toString();
- assertTrue(stringUrl.startsWith("mailto:?"));
- assertTrue(stringUrl.contains("cc=bob%40example.com&"));
- assertTrue(stringUrl.contains("body=hello&"));
- assertTrue(stringUrl.contains("to=joe%40example.com&"));
-
- assertTrue(MailTo.isMailTo(MAILTOURI_6));
- MailTo mailTo_6 = MailTo.parse(MAILTOURI_6);
- Log.d("Trace", mailTo_6.toString() + mailTo_6.getHeaders().toString()
- + mailTo_6.getHeaders().size());
- assertEquals(3, mailTo_6.getHeaders().size());
- assertEquals(", joe@example.com", mailTo_6.getTo());
- assertEquals("bob@example.com", mailTo_6.getCc());
- assertEquals("hello", mailTo_6.getBody());
- assertNull(mailTo_6.getSubject());
- stringUrl = mailTo_6.toString();
- assertTrue(stringUrl.startsWith("mailto:?"));
- assertTrue(stringUrl.contains("cc=bob%40example.com&"));
- assertTrue(stringUrl.contains("body=hello&"));
- assertTrue(stringUrl.contains("to=%2C%20joe%40example.com&"));
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
deleted file mode 100644
index 6d3db89..0000000
--- a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-
-import android.content.Context;
-import android.content.ContentResolver;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkUtils;
-import android.net.cts.util.CtsNetUtils;
-import android.platform.test.annotations.AppModeFull;
-import android.provider.Settings;
-import android.system.ErrnoException;
-import android.system.OsConstants;
-import android.test.AndroidTestCase;
-
-import java.util.ArrayList;
-
-public class MultinetworkApiTest extends AndroidTestCase {
-
- static {
- System.loadLibrary("nativemultinetwork_jni");
- }
-
- private static final String TAG = "MultinetworkNativeApiTest";
- static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google";
-
- /**
- * @return 0 on success
- */
- private static native int runGetaddrinfoCheck(long networkHandle);
- private static native int runSetprocnetwork(long networkHandle);
- private static native int runSetsocknetwork(long networkHandle);
- private static native int runDatagramCheck(long networkHandle);
- private static native void runResNapiMalformedCheck(long networkHandle);
- private static native void runResNcancelCheck(long networkHandle);
- private static native void runResNqueryCheck(long networkHandle);
- private static native void runResNsendCheck(long networkHandle);
- private static native void runResNnxDomainCheck(long networkHandle);
-
-
- private ContentResolver mCR;
- private ConnectivityManager mCM;
- private CtsNetUtils mCtsNetUtils;
- private String mOldMode;
- private String mOldDnsSpecifier;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
- mCR = getContext().getContentResolver();
- mCtsNetUtils = new CtsNetUtils(getContext());
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
- private Network[] getTestableNetworks() {
- final ArrayList<Network> testableNetworks = new ArrayList<Network>();
- for (Network network : mCM.getAllNetworks()) {
- final NetworkCapabilities nc = mCM.getNetworkCapabilities(network);
- if (nc != null
- && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
- testableNetworks.add(network);
- }
- }
-
- assertTrue(
- "This test requires that at least one network be connected. " +
- "Please ensure that the device is connected to a network.",
- testableNetworks.size() >= 1);
- return testableNetworks.toArray(new Network[0]);
- }
-
- public void testGetaddrinfo() throws ErrnoException {
- for (Network network : getTestableNetworks()) {
- int errno = runGetaddrinfoCheck(network.getNetworkHandle());
- if (errno != 0) {
- throw new ErrnoException(
- "getaddrinfo on " + mCM.getNetworkInfo(network), -errno);
- }
- }
- }
-
- public void testSetprocnetwork() throws ErrnoException {
- // Hopefully no prior test in this process space has set a default network.
- assertNull(mCM.getProcessDefaultNetwork());
- assertEquals(0, NetworkUtils.getBoundNetworkForProcess());
-
- for (Network network : getTestableNetworks()) {
- mCM.setProcessDefaultNetwork(null);
- assertNull(mCM.getProcessDefaultNetwork());
-
- int errno = runSetprocnetwork(network.getNetworkHandle());
- if (errno != 0) {
- throw new ErrnoException(
- "setprocnetwork on " + mCM.getNetworkInfo(network), -errno);
- }
- Network processDefault = mCM.getProcessDefaultNetwork();
- assertNotNull(processDefault);
- assertEquals(network, processDefault);
- // TODO: open DatagramSockets, connect them to 192.0.2.1 and 2001:db8::,
- // and ensure that the source address is in fact on this network as
- // determined by mCM.getLinkProperties(network).
-
- mCM.setProcessDefaultNetwork(null);
- }
-
- for (Network network : getTestableNetworks()) {
- NetworkUtils.bindProcessToNetwork(0);
- assertNull(mCM.getBoundNetworkForProcess());
-
- int errno = runSetprocnetwork(network.getNetworkHandle());
- if (errno != 0) {
- throw new ErrnoException(
- "setprocnetwork on " + mCM.getNetworkInfo(network), -errno);
- }
- assertEquals(network, new Network(mCM.getBoundNetworkForProcess()));
- // TODO: open DatagramSockets, connect them to 192.0.2.1 and 2001:db8::,
- // and ensure that the source address is in fact on this network as
- // determined by mCM.getLinkProperties(network).
-
- NetworkUtils.bindProcessToNetwork(0);
- }
- }
-
- public void testSetsocknetwork() throws ErrnoException {
- for (Network network : getTestableNetworks()) {
- int errno = runSetsocknetwork(network.getNetworkHandle());
- if (errno != 0) {
- throw new ErrnoException(
- "setsocknetwork on " + mCM.getNetworkInfo(network), -errno);
- }
- }
- }
-
- public void testNativeDatagramTransmission() throws ErrnoException {
- for (Network network : getTestableNetworks()) {
- int errno = runDatagramCheck(network.getNetworkHandle());
- if (errno != 0) {
- throw new ErrnoException(
- "DatagramCheck on " + mCM.getNetworkInfo(network), -errno);
- }
- }
- }
-
- public void testNoSuchNetwork() {
- final Network eNoNet = new Network(54321);
- assertNull(mCM.getNetworkInfo(eNoNet));
-
- final long eNoNetHandle = eNoNet.getNetworkHandle();
- assertEquals(-OsConstants.ENONET, runSetsocknetwork(eNoNetHandle));
- assertEquals(-OsConstants.ENONET, runSetprocnetwork(eNoNetHandle));
- // TODO: correct test permissions so this call is not silently re-mapped
- // to query on the default network.
- // assertEquals(-OsConstants.ENONET, runGetaddrinfoCheck(eNoNetHandle));
- }
-
- public void testNetworkHandle() {
- // Test Network -> NetworkHandle -> Network results in the same Network.
- for (Network network : getTestableNetworks()) {
- long networkHandle = network.getNetworkHandle();
- Network newNetwork = Network.fromNetworkHandle(networkHandle);
- assertEquals(newNetwork, network);
- }
-
- // Test that only obfuscated handles are allowed.
- try {
- Network.fromNetworkHandle(100);
- fail();
- } catch (IllegalArgumentException e) {}
- try {
- Network.fromNetworkHandle(-1);
- fail();
- } catch (IllegalArgumentException e) {}
- try {
- Network.fromNetworkHandle(0);
- fail();
- } catch (IllegalArgumentException e) {}
- }
-
- public void testResNApi() throws Exception {
- final Network[] testNetworks = getTestableNetworks();
-
- for (Network network : testNetworks) {
- // Throws AssertionError directly in jni function if test fail.
- runResNqueryCheck(network.getNetworkHandle());
- runResNsendCheck(network.getNetworkHandle());
- runResNcancelCheck(network.getNetworkHandle());
- runResNapiMalformedCheck(network.getNetworkHandle());
-
- final NetworkCapabilities nc = mCM.getNetworkCapabilities(network);
- // Some cellular networks configure their DNS servers never to return NXDOMAIN, so don't
- // test NXDOMAIN on these DNS servers.
- // b/144521720
- if (nc != null && !nc.hasTransport(TRANSPORT_CELLULAR)) {
- runResNnxDomainCheck(network.getNetworkHandle());
- }
- }
- }
-
- @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
- public void testResNApiNXDomainPrivateDns() throws InterruptedException {
- mCtsNetUtils.storePrivateDnsSetting();
- // Enable private DNS strict mode and set server to dns.google before doing NxDomain test.
- // b/144521720
- try {
- 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, true);
- runResNnxDomainCheck(network.getNetworkHandle());
- }
- } finally {
- mCtsNetUtils.restorePrivateDnsSetting();
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/NetworkAgentTest.kt b/tests/tests/net/src/android/net/cts/NetworkAgentTest.kt
deleted file mode 100644
index c8e1fc3..0000000
--- a/tests/tests/net/src/android/net/cts/NetworkAgentTest.kt
+++ /dev/null
@@ -1,641 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.cts
-
-import android.app.Instrumentation
-import android.content.Context
-import android.net.ConnectivityManager
-import android.net.KeepalivePacketData
-import android.net.LinkAddress
-import android.net.LinkProperties
-import android.net.Network
-import android.net.NetworkAgent
-import android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER
-import android.net.NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT
-import android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER
-import android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS
-import android.net.NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED
-import android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE
-import android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE
-import android.net.NetworkAgent.INVALID_NETWORK
-import android.net.NetworkAgent.VALID_NETWORK
-import android.net.NetworkAgentConfig
-import android.net.NetworkCapabilities
-import android.net.NetworkProvider
-import android.net.NetworkRequest
-import android.net.SocketKeepalive
-import android.net.StringNetworkSpecifier
-import android.net.Uri
-import android.os.Build
-import android.os.Bundle
-import android.os.Handler
-import android.os.HandlerThread
-import android.os.Looper
-import android.os.Message
-import android.os.Messenger
-import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAddKeepalivePacketFilter
-import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAutomaticReconnectDisabled
-import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested
-import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted
-import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnRemoveKeepalivePacketFilter
-import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSaveAcceptUnvalidated
-import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnSignalStrengthThresholdsUpdated
-import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive
-import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive
-import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus
-import androidx.test.InstrumentationRegistry
-import androidx.test.runner.AndroidJUnit4
-import com.android.internal.util.AsyncChannel
-import com.android.testutils.ArrayTrackRecord
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.RecorderCallback.CallbackEntry.Available
-import com.android.testutils.RecorderCallback.CallbackEntry.Lost
-import com.android.testutils.TestableNetworkCallback
-import java.util.UUID
-import org.junit.After
-import org.junit.Assert.assertArrayEquals
-import org.junit.Assert.fail
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import java.net.InetAddress
-import java.time.Duration
-import kotlin.test.assertEquals
-import kotlin.test.assertFalse
-import kotlin.test.assertFailsWith
-import kotlin.test.assertNotNull
-import kotlin.test.assertNull
-import kotlin.test.assertTrue
-
-// This test doesn't really have a constraint on how fast the methods should return. If it's
-// going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio
-// without affecting the run time of successful runs. Thus, set a very high timeout.
-private const val DEFAULT_TIMEOUT_MS = 5000L
-// When waiting for a NetworkCallback to determine there was no timeout, waiting is the
-// only possible thing (the relevant handler is the one in the real ConnectivityService,
-// and then there is the Binder call), so have a short timeout for this as it will be
-// exhausted every time.
-private const val NO_CALLBACK_TIMEOUT = 200L
-// Any legal score (0~99) for the test network would do, as it is going to be kept up by the
-// requests filed by the test and should never match normal internet requests. 70 is the default
-// score of Ethernet networks, it's as good a value as any other.
-private const val TEST_NETWORK_SCORE = 70
-private const val BETTER_NETWORK_SCORE = 75
-private const val FAKE_NET_ID = 1098
-private val instrumentation: Instrumentation
- get() = InstrumentationRegistry.getInstrumentation()
-private val context: Context
- get() = InstrumentationRegistry.getContext()
-private fun Message(what: Int, arg1: Int, arg2: Int, obj: Any?) = Message.obtain().also {
- it.what = what
- it.arg1 = arg1
- it.arg2 = arg2
- it.obj = obj
-}
-
-@RunWith(AndroidJUnit4::class)
-class NetworkAgentTest {
- @Rule @JvmField
- val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q)
-
- private val LOCAL_IPV4_ADDRESS = InetAddress.parseNumericAddress("192.0.2.1")
- private val REMOTE_IPV4_ADDRESS = InetAddress.parseNumericAddress("192.0.2.2")
-
- private val mCM = context.getSystemService(ConnectivityManager::class.java)
- private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread")
- private val mFakeConnectivityService by lazy { FakeConnectivityService(mHandlerThread.looper) }
-
- private class Provider(context: Context, looper: Looper) :
- NetworkProvider(context, looper, "NetworkAgentTest NetworkProvider")
-
- private val agentsToCleanUp = mutableListOf<NetworkAgent>()
- private val callbacksToCleanUp = mutableListOf<TestableNetworkCallback>()
-
- @Before
- fun setUp() {
- instrumentation.getUiAutomation().adoptShellPermissionIdentity()
- mHandlerThread.start()
- }
-
- @After
- fun tearDown() {
- agentsToCleanUp.forEach { it.unregister() }
- callbacksToCleanUp.forEach { mCM.unregisterNetworkCallback(it) }
- mHandlerThread.quitSafely()
- instrumentation.getUiAutomation().dropShellPermissionIdentity()
- }
-
- /**
- * A fake that helps simulating ConnectivityService talking to a harnessed agent.
- * This fake only supports speaking to one harnessed agent at a time because it
- * only keeps track of one async channel.
- */
- private class FakeConnectivityService(looper: Looper) {
- private val CMD_EXPECT_DISCONNECT = 1
- private var disconnectExpected = false
- private val msgHistory = ArrayTrackRecord<Message>().newReadHead()
- private val asyncChannel = AsyncChannel()
- private val handler = object : Handler(looper) {
- override fun handleMessage(msg: Message) {
- msgHistory.add(Message.obtain(msg)) // make a copy as the original will be recycled
- when (msg.what) {
- CMD_EXPECT_DISCONNECT -> disconnectExpected = true
- AsyncChannel.CMD_CHANNEL_HALF_CONNECTED ->
- asyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION)
- AsyncChannel.CMD_CHANNEL_DISCONNECTED ->
- if (!disconnectExpected) {
- fail("Agent unexpectedly disconnected")
- } else {
- disconnectExpected = false
- }
- }
- }
- }
-
- fun connect(agentMsngr: Messenger) = asyncChannel.connect(context, handler, agentMsngr)
-
- fun disconnect() = asyncChannel.disconnect()
-
- fun sendMessage(what: Int, arg1: Int = 0, arg2: Int = 0, obj: Any? = null) =
- asyncChannel.sendMessage(Message(what, arg1, arg2, obj))
-
- fun expectMessage(what: Int) =
- assertNotNull(msgHistory.poll(DEFAULT_TIMEOUT_MS) { it.what == what })
-
- fun willExpectDisconnectOnce() = handler.sendEmptyMessage(CMD_EXPECT_DISCONNECT)
- }
-
- private open class TestableNetworkAgent(
- looper: Looper,
- val nc: NetworkCapabilities,
- val lp: LinkProperties,
- conf: NetworkAgentConfig
- ) : NetworkAgent(context, looper, TestableNetworkAgent::class.java.simpleName /* tag */,
- nc, lp, TEST_NETWORK_SCORE, conf, Provider(context, looper)) {
- private val history = ArrayTrackRecord<CallbackEntry>().newReadHead()
-
- sealed class CallbackEntry {
- object OnBandwidthUpdateRequested : CallbackEntry()
- object OnNetworkUnwanted : CallbackEntry()
- data class OnAddKeepalivePacketFilter(
- val slot: Int,
- val packet: KeepalivePacketData
- ) : CallbackEntry()
- data class OnRemoveKeepalivePacketFilter(val slot: Int) : CallbackEntry()
- data class OnStartSocketKeepalive(
- val slot: Int,
- val interval: Int,
- val packet: KeepalivePacketData
- ) : CallbackEntry()
- data class OnStopSocketKeepalive(val slot: Int) : CallbackEntry()
- data class OnSaveAcceptUnvalidated(val accept: Boolean) : CallbackEntry()
- object OnAutomaticReconnectDisabled : CallbackEntry()
- data class OnValidationStatus(val status: Int, val uri: Uri?) : CallbackEntry()
- data class OnSignalStrengthThresholdsUpdated(val thresholds: IntArray) : CallbackEntry()
- }
-
- fun getName(): String? = (nc.getNetworkSpecifier() as? StringNetworkSpecifier)?.specifier
-
- override fun onBandwidthUpdateRequested() {
- history.add(OnBandwidthUpdateRequested)
- }
-
- override fun onNetworkUnwanted() {
- history.add(OnNetworkUnwanted)
- }
-
- override fun onAddKeepalivePacketFilter(slot: Int, packet: KeepalivePacketData) {
- history.add(OnAddKeepalivePacketFilter(slot, packet))
- }
-
- override fun onRemoveKeepalivePacketFilter(slot: Int) {
- history.add(OnRemoveKeepalivePacketFilter(slot))
- }
-
- override fun onStartSocketKeepalive(
- slot: Int,
- interval: Duration,
- packet: KeepalivePacketData
- ) {
- history.add(OnStartSocketKeepalive(slot, interval.seconds.toInt(), packet))
- }
-
- override fun onStopSocketKeepalive(slot: Int) {
- history.add(OnStopSocketKeepalive(slot))
- }
-
- override fun onSaveAcceptUnvalidated(accept: Boolean) {
- history.add(OnSaveAcceptUnvalidated(accept))
- }
-
- override fun onAutomaticReconnectDisabled() {
- history.add(OnAutomaticReconnectDisabled)
- }
-
- override fun onSignalStrengthThresholdsUpdated(thresholds: IntArray) {
- history.add(OnSignalStrengthThresholdsUpdated(thresholds))
- }
-
- fun expectEmptySignalStrengths() {
- expectCallback<OnSignalStrengthThresholdsUpdated>().let {
- // intArrayOf() without arguments makes an empty array
- assertArrayEquals(intArrayOf(), it.thresholds)
- }
- }
-
- override fun onValidationStatus(status: Int, uri: Uri?) {
- history.add(OnValidationStatus(status, uri))
- }
-
- // Expects the initial validation event that always occurs immediately after registering
- // a NetworkAgent whose network does not require validation (which test networks do
- // not, since they lack the INTERNET capability). It always contains the default argument
- // for the URI.
- fun expectNoInternetValidationStatus() = expectCallback<OnValidationStatus>().let {
- assertEquals(it.status, VALID_NETWORK)
- // The returned Uri is parsed from the empty string, which means it's an
- // instance of the (private) Uri.StringUri. There are no real good ways
- // to check this, the least bad is to just convert it to a string and
- // make sure it's empty.
- assertEquals("", it.uri.toString())
- }
-
- inline fun <reified T : CallbackEntry> expectCallback(): T {
- val foundCallback = history.poll(DEFAULT_TIMEOUT_MS)
- assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback")
- return foundCallback
- }
-
- fun assertNoCallback() {
- assertTrue(waitForIdle(DEFAULT_TIMEOUT_MS),
- "Handler didn't became idle after ${DEFAULT_TIMEOUT_MS}ms")
- assertNull(history.peek())
- }
- }
-
- private fun requestNetwork(request: NetworkRequest, callback: TestableNetworkCallback) {
- mCM.requestNetwork(request, callback)
- callbacksToCleanUp.add(callback)
- }
-
- private fun registerNetworkCallback(
- request: NetworkRequest,
- callback: TestableNetworkCallback
- ) {
- mCM.registerNetworkCallback(request, callback)
- callbacksToCleanUp.add(callback)
- }
-
- private fun createNetworkAgent(name: String? = null): TestableNetworkAgent {
- val nc = NetworkCapabilities().apply {
- addTransportType(NetworkCapabilities.TRANSPORT_TEST)
- removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
- removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
- addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
- addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- if (null != name) {
- setNetworkSpecifier(StringNetworkSpecifier(name))
- }
- }
- val lp = LinkProperties().apply {
- addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 0))
- }
- val config = NetworkAgentConfig.Builder().build()
- return TestableNetworkAgent(mHandlerThread.looper, nc, lp, config).also {
- agentsToCleanUp.add(it)
- }
- }
-
- private fun createConnectedNetworkAgent(name: String? = null):
- Pair<TestableNetworkAgent, TestableNetworkCallback> {
- val request: NetworkRequest = NetworkRequest.Builder()
- .clearCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
- .build()
- val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
- requestNetwork(request, callback)
- val agent = createNetworkAgent(name)
- agent.register()
- agent.markConnected()
- return agent to callback
- }
-
- private fun createNetworkAgentWithFakeCS() = createNetworkAgent().also {
- mFakeConnectivityService.connect(it.registerForTest(Network(FAKE_NET_ID)))
- }
-
- @Test
- fun testConnectAndUnregister() {
- val (agent, callback) = createConnectedNetworkAgent()
- callback.expectAvailableThenValidatedCallbacks(agent.network)
- agent.expectEmptySignalStrengths()
- agent.expectNoInternetValidationStatus()
- agent.unregister()
- callback.expectCallback<Lost>(agent.network)
- agent.expectCallback<OnNetworkUnwanted>()
- assertFailsWith<IllegalStateException>("Must not be able to register an agent twice") {
- agent.register()
- }
- }
-
- @Test
- fun testOnBandwidthUpdateRequested() {
- val (agent, callback) = createConnectedNetworkAgent()
- callback.expectAvailableThenValidatedCallbacks(agent.network)
- agent.expectEmptySignalStrengths()
- agent.expectNoInternetValidationStatus()
- mCM.requestBandwidthUpdate(agent.network)
- agent.expectCallback<OnBandwidthUpdateRequested>()
- agent.unregister()
- }
-
- @Test
- fun testSignalStrengthThresholds() {
- val thresholds = intArrayOf(30, 50, 65)
- val callbacks = thresholds.map { strength ->
- val request = NetworkRequest.Builder()
- .clearCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
- .setSignalStrength(strength)
- .build()
- TestableNetworkCallback(DEFAULT_TIMEOUT_MS).also {
- registerNetworkCallback(request, it)
- }
- }
- createConnectedNetworkAgent().let { (agent, callback) ->
- callback.expectAvailableThenValidatedCallbacks(agent.network)
- agent.expectCallback<OnSignalStrengthThresholdsUpdated>().let {
- assertArrayEquals(it.thresholds, thresholds)
- }
- agent.expectNoInternetValidationStatus()
-
- // Send signal strength and check that the callbacks are called appropriately.
- val nc = NetworkCapabilities(agent.nc)
- nc.setSignalStrength(20)
- agent.sendNetworkCapabilities(nc)
- callbacks.forEach { it.assertNoCallback(NO_CALLBACK_TIMEOUT) }
-
- nc.setSignalStrength(40)
- agent.sendNetworkCapabilities(nc)
- callbacks[0].expectAvailableCallbacks(agent.network)
- callbacks[1].assertNoCallback(NO_CALLBACK_TIMEOUT)
- callbacks[2].assertNoCallback(NO_CALLBACK_TIMEOUT)
-
- nc.setSignalStrength(80)
- agent.sendNetworkCapabilities(nc)
- callbacks[0].expectCapabilitiesThat(agent.network) { it.signalStrength == 80 }
- callbacks[1].expectAvailableCallbacks(agent.network)
- callbacks[2].expectAvailableCallbacks(agent.network)
-
- nc.setSignalStrength(55)
- agent.sendNetworkCapabilities(nc)
- callbacks[0].expectCapabilitiesThat(agent.network) { it.signalStrength == 55 }
- callbacks[1].expectCapabilitiesThat(agent.network) { it.signalStrength == 55 }
- callbacks[2].expectCallback<Lost>(agent.network)
- }
- callbacks.forEach {
- mCM.unregisterNetworkCallback(it)
- }
- }
-
- @Test
- fun testSocketKeepalive(): Unit = createNetworkAgentWithFakeCS().let { agent ->
- val packet = object : KeepalivePacketData(
- LOCAL_IPV4_ADDRESS /* srcAddress */, 1234 /* srcPort */,
- REMOTE_IPV4_ADDRESS /* dstAddress */, 4567 /* dstPort */,
- ByteArray(100 /* size */) { it.toByte() /* init */ }) {}
- val slot = 4
- val interval = 37
-
- mFakeConnectivityService.sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER,
- arg1 = slot, obj = packet)
- mFakeConnectivityService.sendMessage(CMD_START_SOCKET_KEEPALIVE,
- arg1 = slot, arg2 = interval, obj = packet)
-
- agent.expectCallback<OnAddKeepalivePacketFilter>().let {
- assertEquals(it.slot, slot)
- assertEquals(it.packet, packet)
- }
- agent.expectCallback<OnStartSocketKeepalive>().let {
- assertEquals(it.slot, slot)
- assertEquals(it.interval, interval)
- assertEquals(it.packet, packet)
- }
-
- agent.assertNoCallback()
-
- // Check that when the agent sends a keepalive event, ConnectivityService receives the
- // expected message.
- agent.sendSocketKeepaliveEvent(slot, SocketKeepalive.ERROR_UNSUPPORTED)
- mFakeConnectivityService.expectMessage(NetworkAgent.EVENT_SOCKET_KEEPALIVE).let() {
- assertEquals(slot, it.arg1)
- assertEquals(SocketKeepalive.ERROR_UNSUPPORTED, it.arg2)
- }
-
- mFakeConnectivityService.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, arg1 = slot)
- mFakeConnectivityService.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, arg1 = slot)
- agent.expectCallback<OnStopSocketKeepalive>().let {
- assertEquals(it.slot, slot)
- }
- agent.expectCallback<OnRemoveKeepalivePacketFilter>().let {
- assertEquals(it.slot, slot)
- }
- }
-
- @Test
- fun testSendUpdates(): Unit = createConnectedNetworkAgent().let { (agent, callback) ->
- callback.expectAvailableThenValidatedCallbacks(agent.network)
- agent.expectEmptySignalStrengths()
- agent.expectNoInternetValidationStatus()
- val ifaceName = "adhocIface"
- val lp = LinkProperties(agent.lp)
- lp.setInterfaceName(ifaceName)
- agent.sendLinkProperties(lp)
- callback.expectLinkPropertiesThat(agent.network) {
- it.getInterfaceName() == ifaceName
- }
- val nc = NetworkCapabilities(agent.nc)
- nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
- agent.sendNetworkCapabilities(nc)
- callback.expectCapabilitiesThat(agent.network) {
- it.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
- }
- }
-
- @Test
- fun testSendScore() {
- // This test will create two networks and check that the one with the stronger
- // score wins out for a request that matches them both.
- // First create requests to make sure both networks are kept up, using the
- // specifier so they are specific to each network
- val name1 = UUID.randomUUID().toString()
- val name2 = UUID.randomUUID().toString()
- val request1 = NetworkRequest.Builder()
- .clearCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
- .setNetworkSpecifier(StringNetworkSpecifier(name1))
- .build()
- val request2 = NetworkRequest.Builder()
- .clearCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
- .setNetworkSpecifier(StringNetworkSpecifier(name2))
- .build()
- val callback1 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
- val callback2 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
- requestNetwork(request1, callback1)
- requestNetwork(request2, callback2)
-
- // Then file the interesting request
- val request = NetworkRequest.Builder()
- .clearCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
- .build()
- val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
- requestNetwork(request, callback)
-
- // Connect the first Network
- createConnectedNetworkAgent(name1).let { (agent1, _) ->
- callback.expectAvailableThenValidatedCallbacks(agent1.network)
- // Upgrade agent1 to a better score so that there is no ambiguity when
- // agent2 connects that agent1 is still better
- agent1.sendNetworkScore(BETTER_NETWORK_SCORE - 1)
- // Connect the second agent
- createConnectedNetworkAgent(name2).let { (agent2, _) ->
- agent2.markConnected()
- // The callback should not see anything yet
- callback.assertNoCallback(NO_CALLBACK_TIMEOUT)
- // Now update the score and expect the callback now prefers agent2
- agent2.sendNetworkScore(BETTER_NETWORK_SCORE)
- callback.expectCallback<Available>(agent2.network)
- }
- }
-
- // tearDown() will unregister the requests and agents
- }
-
- @Test
- fun testSetAcceptUnvalidated() {
- createNetworkAgentWithFakeCS().let { agent ->
- mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 1)
- agent.expectCallback<OnSaveAcceptUnvalidated>().let {
- assertTrue(it.accept)
- }
- agent.assertNoCallback()
- }
- }
-
- @Test
- fun testSetAcceptUnvalidatedPreventAutomaticReconnect() {
- createNetworkAgentWithFakeCS().let { agent ->
- mFakeConnectivityService.sendMessage(CMD_SAVE_ACCEPT_UNVALIDATED, 0)
- mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT)
- agent.expectCallback<OnSaveAcceptUnvalidated>().let {
- assertFalse(it.accept)
- }
- agent.expectCallback<OnAutomaticReconnectDisabled>()
- agent.assertNoCallback()
- // When automatic reconnect is turned off, the network is torn down and
- // ConnectivityService sends a disconnect. This in turn causes the agent
- // to send a DISCONNECTED message to CS.
- mFakeConnectivityService.willExpectDisconnectOnce()
- mFakeConnectivityService.disconnect()
- mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED)
- agent.expectCallback<OnNetworkUnwanted>()
- }
- }
-
- @Test
- fun testPreventAutomaticReconnect() {
- createNetworkAgentWithFakeCS().let { agent ->
- mFakeConnectivityService.sendMessage(CMD_PREVENT_AUTOMATIC_RECONNECT)
- agent.expectCallback<OnAutomaticReconnectDisabled>()
- agent.assertNoCallback()
- mFakeConnectivityService.willExpectDisconnectOnce()
- mFakeConnectivityService.disconnect()
- mFakeConnectivityService.expectMessage(AsyncChannel.CMD_CHANNEL_DISCONNECTED)
- agent.expectCallback<OnNetworkUnwanted>()
- }
- }
-
- @Test
- fun testValidationStatus() = createNetworkAgentWithFakeCS().let { agent ->
- val uri = Uri.parse("http://www.google.com")
- val bundle = Bundle().apply {
- putString(NetworkAgent.REDIRECT_URL_KEY, uri.toString())
- }
- mFakeConnectivityService.sendMessage(CMD_REPORT_NETWORK_STATUS,
- arg1 = VALID_NETWORK, obj = bundle)
- agent.expectCallback<OnValidationStatus>().let {
- assertEquals(it.status, VALID_NETWORK)
- assertEquals(it.uri, uri)
- }
-
- mFakeConnectivityService.sendMessage(CMD_REPORT_NETWORK_STATUS,
- arg1 = INVALID_NETWORK, obj = Bundle())
- agent.expectCallback<OnValidationStatus>().let {
- assertEquals(it.status, INVALID_NETWORK)
- assertNull(it.uri)
- }
- }
-
- @Test
- fun testTemporarilyUnmeteredCapability() {
- // This test will create a networks with/without NET_CAPABILITY_TEMPORARILY_NOT_METERED
- // and check that the callback reflects the capability changes.
- // First create a request to make sure the network is kept up
- val request1 = NetworkRequest.Builder()
- .clearCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
- .build()
- val callback1 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS).also {
- registerNetworkCallback(request1, it)
- }
- requestNetwork(request1, callback1)
-
- // Then file the interesting request
- val request = NetworkRequest.Builder()
- .clearCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
- .build()
- val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
- requestNetwork(request, callback)
-
- // Connect the network
- createConnectedNetworkAgent().let { (agent, _) ->
- callback.expectAvailableThenValidatedCallbacks(agent.network)
-
- // Send TEMP_NOT_METERED and check that the callback is called appropriately.
- val nc1 = NetworkCapabilities(agent.nc)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)
- agent.sendNetworkCapabilities(nc1)
- callback.expectCapabilitiesThat(agent.network) {
- it.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)
- }
-
- // Remove TEMP_NOT_METERED and check that the callback is called appropriately.
- val nc2 = NetworkCapabilities(agent.nc)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)
- agent.sendNetworkCapabilities(nc2)
- callback.expectCapabilitiesThat(agent.network) {
- !it.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)
- }
- }
-
- // tearDown() will unregister the requests and agents
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/NetworkInfoTest.kt b/tests/tests/net/src/android/net/cts/NetworkInfoTest.kt
deleted file mode 100644
index fa15e8f..0000000
--- a/tests/tests/net/src/android/net/cts/NetworkInfoTest.kt
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts
-
-import android.os.Build
-import android.content.Context
-import android.net.ConnectivityManager
-import android.net.NetworkInfo
-import android.net.NetworkInfo.DetailedState
-import android.net.NetworkInfo.State
-import android.telephony.TelephonyManager
-import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotNull
-import org.junit.Assert.assertNull
-import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
-import org.junit.Rule
-import org.junit.runner.RunWith
-import org.junit.Test
-
-const val TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE
-const val TYPE_WIFI = ConnectivityManager.TYPE_WIFI
-const val MOBILE_TYPE_NAME = "mobile"
-const val WIFI_TYPE_NAME = "WIFI"
-const val LTE_SUBTYPE_NAME = "LTE"
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class NetworkInfoTest {
- @Rule @JvmField
- val ignoreRule = DevSdkIgnoreRule()
-
- @Test
- fun testAccessNetworkInfoProperties() {
- val cm = InstrumentationRegistry.getInstrumentation().context
- .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
- val ni = cm.getAllNetworkInfo()
- assertTrue(ni.isNotEmpty())
-
- for (netInfo in ni) {
- when (netInfo.getType()) {
- TYPE_MOBILE -> assertNetworkInfo(netInfo, MOBILE_TYPE_NAME)
- TYPE_WIFI -> assertNetworkInfo(netInfo, WIFI_TYPE_NAME)
- // TODO: Add BLUETOOTH_TETHER testing
- }
- }
- }
-
- private fun assertNetworkInfo(netInfo: NetworkInfo, expectedTypeName: String) {
- assertTrue(expectedTypeName.equals(netInfo.getTypeName(), ignoreCase = true))
- assertNotNull(netInfo.toString())
-
- if (!netInfo.isConnectedOrConnecting()) return
-
- assertTrue(netInfo.isAvailable())
- if (State.CONNECTED == netInfo.getState()) {
- assertTrue(netInfo.isConnected())
- }
- assertTrue(State.CONNECTING == netInfo.getState() ||
- State.CONNECTED == netInfo.getState())
- assertTrue(DetailedState.SCANNING == netInfo.getDetailedState() ||
- DetailedState.CONNECTING == netInfo.getDetailedState() ||
- DetailedState.AUTHENTICATING == netInfo.getDetailedState() ||
- DetailedState.CONNECTED == netInfo.getDetailedState())
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testConstructor() {
- val networkInfo = NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE,
- MOBILE_TYPE_NAME, LTE_SUBTYPE_NAME)
-
- assertEquals(TYPE_MOBILE, networkInfo.type)
- assertEquals(TelephonyManager.NETWORK_TYPE_LTE, networkInfo.subtype)
- assertEquals(MOBILE_TYPE_NAME, networkInfo.typeName)
- assertEquals(LTE_SUBTYPE_NAME, networkInfo.subtypeName)
- assertEquals(DetailedState.IDLE, networkInfo.detailedState)
- assertEquals(State.UNKNOWN, networkInfo.state)
- assertNull(networkInfo.reason)
- assertNull(networkInfo.extraInfo)
-
- try {
- NetworkInfo(ConnectivityManager.MAX_NETWORK_TYPE + 1,
- TelephonyManager.NETWORK_TYPE_LTE, MOBILE_TYPE_NAME, LTE_SUBTYPE_NAME)
- fail("Unexpected behavior. Network type is invalid.")
- } catch (e: IllegalArgumentException) {
- // Expected behavior.
- }
- }
-
- @Test
- fun testSetDetailedState() {
- val networkInfo = NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE,
- MOBILE_TYPE_NAME, LTE_SUBTYPE_NAME)
- val reason = "TestNetworkInfo"
- val extraReason = "setDetailedState test"
-
- networkInfo.setDetailedState(DetailedState.CONNECTED, reason, extraReason)
- assertEquals(DetailedState.CONNECTED, networkInfo.detailedState)
- assertEquals(State.CONNECTED, networkInfo.state)
- assertEquals(reason, networkInfo.reason)
- assertEquals(extraReason, networkInfo.extraInfo)
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java b/tests/tests/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java
deleted file mode 100644
index 590ce89..0000000
--- a/tests/tests/net/src/android/net/cts/NetworkInfo_DetailedStateTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-
-import android.net.NetworkInfo.DetailedState;
-import android.test.AndroidTestCase;
-
-public class NetworkInfo_DetailedStateTest extends AndroidTestCase {
-
- public void testValueOf() {
- assertEquals(DetailedState.AUTHENTICATING, DetailedState.valueOf("AUTHENTICATING"));
- assertEquals(DetailedState.CONNECTED, DetailedState.valueOf("CONNECTED"));
- assertEquals(DetailedState.CONNECTING, DetailedState.valueOf("CONNECTING"));
- assertEquals(DetailedState.DISCONNECTED, DetailedState.valueOf("DISCONNECTED"));
- assertEquals(DetailedState.DISCONNECTING, DetailedState.valueOf("DISCONNECTING"));
- assertEquals(DetailedState.FAILED, DetailedState.valueOf("FAILED"));
- assertEquals(DetailedState.IDLE, DetailedState.valueOf("IDLE"));
- assertEquals(DetailedState.OBTAINING_IPADDR, DetailedState.valueOf("OBTAINING_IPADDR"));
- assertEquals(DetailedState.SCANNING, DetailedState.valueOf("SCANNING"));
- assertEquals(DetailedState.SUSPENDED, DetailedState.valueOf("SUSPENDED"));
- }
-
- public void testValues() {
- DetailedState[] expected = DetailedState.values();
- assertEquals(13, expected.length);
- assertEquals(DetailedState.IDLE, expected[0]);
- assertEquals(DetailedState.SCANNING, expected[1]);
- assertEquals(DetailedState.CONNECTING, expected[2]);
- assertEquals(DetailedState.AUTHENTICATING, expected[3]);
- assertEquals(DetailedState.OBTAINING_IPADDR, expected[4]);
- assertEquals(DetailedState.CONNECTED, expected[5]);
- assertEquals(DetailedState.SUSPENDED, expected[6]);
- assertEquals(DetailedState.DISCONNECTING, expected[7]);
- assertEquals(DetailedState.DISCONNECTED, expected[8]);
- assertEquals(DetailedState.FAILED, expected[9]);
- assertEquals(DetailedState.BLOCKED, expected[10]);
- assertEquals(DetailedState.VERIFYING_POOR_LINK, expected[11]);
- assertEquals(DetailedState.CAPTIVE_PORTAL_CHECK, expected[12]);
- }
-
-}
diff --git a/tests/tests/net/src/android/net/cts/NetworkInfo_StateTest.java b/tests/tests/net/src/android/net/cts/NetworkInfo_StateTest.java
deleted file mode 100644
index 5303ef1..0000000
--- a/tests/tests/net/src/android/net/cts/NetworkInfo_StateTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.net.NetworkInfo.State;
-import android.test.AndroidTestCase;
-
-public class NetworkInfo_StateTest extends AndroidTestCase {
-
- public void testValueOf() {
- assertEquals(State.CONNECTED, State.valueOf("CONNECTED"));
- assertEquals(State.CONNECTING, State.valueOf("CONNECTING"));
- assertEquals(State.DISCONNECTED, State.valueOf("DISCONNECTED"));
- assertEquals(State.DISCONNECTING, State.valueOf("DISCONNECTING"));
- assertEquals(State.SUSPENDED, State.valueOf("SUSPENDED"));
- assertEquals(State.UNKNOWN, State.valueOf("UNKNOWN"));
- }
-
- public void testValues() {
- State[] expected = State.values();
- assertEquals(6, expected.length);
- assertEquals(State.CONNECTING, expected[0]);
- assertEquals(State.CONNECTED, expected[1]);
- assertEquals(State.SUSPENDED, expected[2]);
- assertEquals(State.DISCONNECTING, expected[3]);
- assertEquals(State.DISCONNECTED, expected[4]);
- assertEquals(State.UNKNOWN, expected[5]);
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/NetworkRequestTest.java b/tests/tests/net/src/android/net/cts/NetworkRequestTest.java
deleted file mode 100644
index d118c8a..0000000
--- a/tests/tests/net/src/android/net/cts/NetworkRequestTest.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-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;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.MacAddress;
-import android.net.MatchAllNetworkSpecifier;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.net.NetworkSpecifier;
-import android.net.UidRange;
-import android.net.wifi.WifiNetworkSpecifier;
-import android.os.Build;
-import android.os.PatternMatcher;
-import android.os.Process;
-import android.util.ArraySet;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class NetworkRequestTest {
- @Rule
- public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
-
- private static final String TEST_SSID = "TestSSID";
- private static final String OTHER_SSID = "OtherSSID";
- private static final int TEST_UID = 2097;
- private static final String TEST_PACKAGE_NAME = "test.package.name";
- private static final MacAddress ARBITRARY_ADDRESS = MacAddress.fromString("3:5:8:12:9:2");
-
- private class LocalNetworkSpecifier extends NetworkSpecifier {
- private final int mId;
-
- LocalNetworkSpecifier(int id) {
- mId = id;
- }
-
- @Override
- public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- return other instanceof LocalNetworkSpecifier
- && mId == ((LocalNetworkSpecifier) other).mId;
- }
- }
-
- @Test
- public void testCapabilities() {
- assertTrue(new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build()
- .hasCapability(NET_CAPABILITY_MMS));
- assertFalse(new NetworkRequest.Builder().removeCapability(NET_CAPABILITY_MMS).build()
- .hasCapability(NET_CAPABILITY_MMS));
-
- final NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build();
- // Verify request has no capabilities
- 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;
- for(int bit = 0; bit < MAX_POSSIBLE_CAPABILITY; bit++) {
- assertFalse(nr.hasCapability(bit));
- }
- }
-
- @Test
- public void testTransports() {
- assertTrue(new NetworkRequest.Builder().addTransportType(TRANSPORT_BLUETOOTH).build()
- .hasTransport(TRANSPORT_BLUETOOTH));
- assertFalse(new NetworkRequest.Builder().removeTransportType(TRANSPORT_BLUETOOTH).build()
- .hasTransport(TRANSPORT_BLUETOOTH));
- }
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testSpecifier() {
- assertNull(new NetworkRequest.Builder().build().getNetworkSpecifier());
- final WifiNetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
- .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL))
- .setBssidPattern(ARBITRARY_ADDRESS, ARBITRARY_ADDRESS)
- .build();
- final NetworkSpecifier obtainedSpecifier = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(specifier)
- .build()
- .getNetworkSpecifier();
- assertEquals(obtainedSpecifier, specifier);
-
- assertNull(new NetworkRequest.Builder()
- .clearCapabilities()
- .build()
- .getNetworkSpecifier());
- }
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testRequestorPackageName() {
- assertNull(new NetworkRequest.Builder().build().getRequestorPackageName());
- final String pkgName = "android.net.test";
- final NetworkCapabilities nc = new NetworkCapabilities.Builder()
- .setRequestorPackageName(pkgName)
- .build();
- final NetworkRequest nr = new NetworkRequest.Builder()
- .setCapabilities(nc)
- .build();
- assertEquals(pkgName, nr.getRequestorPackageName());
- assertNull(new NetworkRequest.Builder()
- .clearCapabilities()
- .build()
- .getRequestorPackageName());
- }
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testCanBeSatisfiedBy() {
- final LocalNetworkSpecifier specifier1 = new LocalNetworkSpecifier(1234 /* id */);
- final LocalNetworkSpecifier specifier2 = new LocalNetworkSpecifier(5678 /* id */);
-
- final NetworkCapabilities capCellularMmsInternet = new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_MMS)
- .addCapability(NET_CAPABILITY_INTERNET);
- final NetworkCapabilities capCellularVpnMmsInternet =
- new NetworkCapabilities(capCellularMmsInternet).addTransportType(TRANSPORT_VPN);
- final NetworkCapabilities capCellularMmsInternetSpecifier1 =
- new NetworkCapabilities(capCellularMmsInternet).setNetworkSpecifier(specifier1);
- final NetworkCapabilities capVpnInternetSpecifier1 = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addTransportType(TRANSPORT_VPN)
- .setNetworkSpecifier(specifier1);
- final NetworkCapabilities capCellularMmsInternetMatchallspecifier =
- new NetworkCapabilities(capCellularMmsInternet)
- .setNetworkSpecifier(new MatchAllNetworkSpecifier());
- final NetworkCapabilities capCellularMmsInternetSpecifier2 =
- new NetworkCapabilities(capCellularMmsInternet).setNetworkSpecifier(specifier2);
-
- final NetworkRequest requestCellularInternetSpecifier1 = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .setNetworkSpecifier(specifier1)
- .build();
- assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(null));
- assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(new NetworkCapabilities()));
- assertTrue(requestCellularInternetSpecifier1.canBeSatisfiedBy(
- capCellularMmsInternetMatchallspecifier));
- assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(capCellularMmsInternet));
- assertTrue(requestCellularInternetSpecifier1.canBeSatisfiedBy(
- capCellularMmsInternetSpecifier1));
- assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(capCellularVpnMmsInternet));
- assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(
- capCellularMmsInternetSpecifier2));
-
- final NetworkRequest requestCellularInternet = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- assertTrue(requestCellularInternet.canBeSatisfiedBy(capCellularMmsInternet));
- assertTrue(requestCellularInternet.canBeSatisfiedBy(capCellularMmsInternetSpecifier1));
- assertTrue(requestCellularInternet.canBeSatisfiedBy(capCellularMmsInternetSpecifier2));
- assertFalse(requestCellularInternet.canBeSatisfiedBy(capVpnInternetSpecifier1));
- assertTrue(requestCellularInternet.canBeSatisfiedBy(capCellularVpnMmsInternet));
- }
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testInvariantInCanBeSatisfiedBy() {
- // Test invariant that result of NetworkRequest.canBeSatisfiedBy() should be the same with
- // NetworkCapabilities.satisfiedByNetworkCapabilities().
- final LocalNetworkSpecifier specifier1 = new LocalNetworkSpecifier(1234 /* id */);
- final int uid = Process.myUid();
- final ArraySet<UidRange> ranges = new ArraySet<>();
- ranges.add(new UidRange(uid, uid));
- final NetworkRequest requestCombination = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .setLinkUpstreamBandwidthKbps(1000)
- .setNetworkSpecifier(specifier1)
- .setSignalStrength(-123)
- .setUids(ranges).build();
- final NetworkCapabilities capCell = new NetworkCapabilities.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- assertCorrectlySatisfies(false, requestCombination, capCell);
-
- final NetworkCapabilities capCellInternet = new NetworkCapabilities.Builder(capCell)
- .addCapability(NET_CAPABILITY_INTERNET).build();
- assertCorrectlySatisfies(false, requestCombination, capCellInternet);
-
- final NetworkCapabilities capCellInternetBW =
- new NetworkCapabilities.Builder(capCellInternet)
- .setLinkUpstreamBandwidthKbps(1024).build();
- assertCorrectlySatisfies(false, requestCombination, capCellInternetBW);
-
- final NetworkCapabilities capCellInternetBWSpecifier1 =
- new NetworkCapabilities.Builder(capCellInternetBW)
- .setNetworkSpecifier(specifier1).build();
- assertCorrectlySatisfies(false, requestCombination, capCellInternetBWSpecifier1);
-
- final NetworkCapabilities capCellInternetBWSpecifier1Signal =
- new NetworkCapabilities.Builder(capCellInternetBWSpecifier1)
- .setSignalStrength(-123).build();
- assertCorrectlySatisfies(true, requestCombination,
- capCellInternetBWSpecifier1Signal);
-
- final NetworkCapabilities capCellInternetBWSpecifier1SignalUid =
- new NetworkCapabilities.Builder(capCellInternetBWSpecifier1Signal)
- .setOwnerUid(uid)
- .setAdministratorUids(new int [] {uid}).build();
- assertCorrectlySatisfies(true, requestCombination,
- capCellInternetBWSpecifier1SignalUid);
- }
-
- private void assertCorrectlySatisfies(boolean expect, NetworkRequest request,
- NetworkCapabilities nc) {
- assertEquals(expect, request.canBeSatisfiedBy(nc));
- assertEquals(
- request.canBeSatisfiedBy(nc),
- request.networkCapabilities.satisfiedByNetworkCapabilities(nc));
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testRequestorUid() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- // Verify default value is INVALID_UID
- assertEquals(Process.INVALID_UID, new NetworkRequest.Builder()
- .setCapabilities(nc).build().getRequestorUid());
-
- nc.setRequestorUid(1314);
- final NetworkRequest nr = new NetworkRequest.Builder().setCapabilities(nc).build();
- assertEquals(1314, nr.getRequestorUid());
-
- assertEquals(Process.INVALID_UID, new NetworkRequest.Builder()
- .clearCapabilities().build().getRequestorUid());
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/NetworkStatsBinderTest.java b/tests/tests/net/src/android/net/cts/NetworkStatsBinderTest.java
deleted file mode 100644
index 1a48983..0000000
--- a/tests/tests/net/src/android/net/cts/NetworkStatsBinderTest.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static android.os.Process.INVALID_UID;
-
-import static org.junit.Assert.assertEquals;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.net.INetworkStatsService;
-import android.net.TrafficStats;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.test.AndroidTestCase;
-import android.util.SparseArray;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.CollectionUtils;
-import com.android.testutils.DevSdkIgnoreRule;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Function;
-import java.util.function.Predicate;
-
-@RunWith(AndroidJUnit4.class)
-public class NetworkStatsBinderTest {
- // NOTE: These are shamelessly copied from TrafficStats.
- private static final int TYPE_RX_BYTES = 0;
- private static final int TYPE_RX_PACKETS = 1;
- private static final int TYPE_TX_BYTES = 2;
- private static final int TYPE_TX_PACKETS = 3;
-
- @Rule
- public DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(
- Build.VERSION_CODES.Q /* ignoreClassUpTo */);
-
- private final SparseArray<Function<Integer, Long>> mUidStatsQueryOpArray = new SparseArray<>();
-
- @Before
- public void setUp() throws Exception {
- mUidStatsQueryOpArray.put(TYPE_RX_BYTES, uid -> TrafficStats.getUidRxBytes(uid));
- mUidStatsQueryOpArray.put(TYPE_RX_PACKETS, uid -> TrafficStats.getUidRxPackets(uid));
- mUidStatsQueryOpArray.put(TYPE_TX_BYTES, uid -> TrafficStats.getUidTxBytes(uid));
- mUidStatsQueryOpArray.put(TYPE_TX_PACKETS, uid -> TrafficStats.getUidTxPackets(uid));
- }
-
- private long getUidStatsFromBinder(int uid, int type) throws Exception {
- Method getServiceMethod = Class.forName("android.os.ServiceManager")
- .getDeclaredMethod("getService", new Class[]{String.class});
- IBinder binder = (IBinder) getServiceMethod.invoke(null, Context.NETWORK_STATS_SERVICE);
- INetworkStatsService nss = INetworkStatsService.Stub.asInterface(binder);
- return nss.getUidStats(uid, type);
- }
-
- private int getFirstAppUidThat(@NonNull Predicate<Integer> predicate) {
- PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
- List<PackageInfo> apps = pm.getInstalledPackages(0 /* flags */);
- final PackageInfo match = CollectionUtils.find(apps,
- it -> it.applicationInfo != null && predicate.test(it.applicationInfo.uid));
- if (match != null) return match.applicationInfo.uid;
- return INVALID_UID;
- }
-
- @Test
- public void testAccessUidStatsFromBinder() throws Exception {
- final int myUid = Process.myUid();
- final List<Integer> testUidList = new ArrayList<>();
-
- // Prepare uid list for testing.
- testUidList.add(INVALID_UID);
- testUidList.add(Process.ROOT_UID);
- testUidList.add(Process.SYSTEM_UID);
- testUidList.add(myUid);
- testUidList.add(Process.LAST_APPLICATION_UID);
- testUidList.add(Process.LAST_APPLICATION_UID + 1);
- // If available, pick another existing uid for testing that is not already contained
- // in the list above.
- final int notMyUid = getFirstAppUidThat(uid -> uid >= 0 && !testUidList.contains(uid));
- if (notMyUid != INVALID_UID) testUidList.add(notMyUid);
-
- for (final int uid : testUidList) {
- for (int i = 0; i < mUidStatsQueryOpArray.size(); i++) {
- final int type = mUidStatsQueryOpArray.keyAt(i);
- try {
- final long uidStatsFromBinder = getUidStatsFromBinder(uid, type);
- final long uidTrafficStats = mUidStatsQueryOpArray.get(type).apply(uid);
-
- // Verify that UNSUPPORTED is returned if the uid is not current app uid.
- if (uid != myUid) {
- assertEquals(uidStatsFromBinder, TrafficStats.UNSUPPORTED);
- }
- // Verify that returned result is the same with the result get from
- // TrafficStats.
- // TODO: If the test is flaky then it should instead assert that the values
- // are approximately similar.
- assertEquals("uidStats is not matched for query type " + type
- + ", uid=" + uid + ", myUid=" + myUid, uidTrafficStats,
- uidStatsFromBinder);
- } catch (IllegalAccessException e) {
- /* Java language access prevents exploitation. */
- return;
- } catch (InvocationTargetException e) {
- /* Underlying method has been changed. */
- return;
- } catch (ClassNotFoundException e) {
- /* not vulnerable if hidden API no longer available */
- return;
- } catch (NoSuchMethodException e) {
- /* not vulnerable if hidden API no longer available */
- return;
- } catch (RemoteException e) {
- return;
- }
- }
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java b/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java
deleted file mode 100644
index 81a9e30..0000000
--- a/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.platform.test.annotations.AppModeFull;
-import android.os.FileUtils;
-import android.os.ParcelFileDescriptor;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.compatibility.common.util.ApiLevelUtil;
-import com.android.compatibility.common.util.SystemUtil;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Formatter;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class NetworkWatchlistTest {
-
- private static final String TEST_WATCHLIST_XML = "assets/network_watchlist_config_for_test.xml";
- private static final String TEST_EMPTY_WATCHLIST_XML =
- "assets/network_watchlist_config_empty_for_test.xml";
- private static final String TMP_CONFIG_PATH =
- "/data/local/tmp/network_watchlist_config_for_test.xml";
- // Generated from sha256sum network_watchlist_config_for_test.xml
- private static final String TEST_WATCHLIST_CONFIG_HASH =
- "B5FC4636994180D54E1E912F78178AB1D8BD2BE71D90CA9F5BBC3284E4D04ED4";
-
- private ConnectivityManager mConnectivityManager;
- private boolean mHasFeature;
-
- @Before
- public void setUp() throws Exception {
- mHasFeature = isAtLeastP();
- mConnectivityManager =
- (ConnectivityManager) InstrumentationRegistry.getContext().getSystemService(
- Context.CONNECTIVITY_SERVICE);
- assumeTrue(mHasFeature);
- // Set empty watchlist test config before testing
- setWatchlistConfig(TEST_EMPTY_WATCHLIST_XML);
- // Verify test watchlist config is not set before testing
- byte[] result = mConnectivityManager.getNetworkWatchlistConfigHash();
- assertNotNull("Watchlist config does not exist", result);
- assertNotEquals(TEST_WATCHLIST_CONFIG_HASH, byteArrayToHexString(result));
- }
-
- @After
- public void tearDown() throws Exception {
- if (mHasFeature) {
- // Set empty watchlist test config after testing
- setWatchlistConfig(TEST_EMPTY_WATCHLIST_XML);
- }
- }
-
- private void cleanup() throws IOException {
- runCommand("rm " + TMP_CONFIG_PATH);
- }
-
- private boolean isAtLeastP() throws Exception {
- // TODO: replace with ApiLevelUtil.isAtLeast(Build.VERSION_CODES.P) when the P API level
- // constant is defined.
- return ApiLevelUtil.getCodename().compareToIgnoreCase("P") >= 0;
- }
-
- /**
- * Test if ConnectivityManager.getNetworkWatchlistConfigHash() correctly
- * returns the hash of config we set.
- */
- @Test
- @AppModeFull(reason = "Cannot access resource file in instant app mode")
- public void testGetWatchlistConfigHash() throws Exception {
- // Set watchlist config file for test
- setWatchlistConfig(TEST_WATCHLIST_XML);
- // Test if watchlist config hash value is correct
- byte[] result = mConnectivityManager.getNetworkWatchlistConfigHash();
- Assert.assertEquals(TEST_WATCHLIST_CONFIG_HASH, byteArrayToHexString(result));
- }
-
- private static String byteArrayToHexString(byte[] bytes) {
- Formatter formatter = new Formatter();
- for (byte b : bytes) {
- formatter.format("%02X", b);
- }
- return formatter.toString();
- }
-
- private void saveResourceToFile(String res, String filePath) throws IOException {
- // App can't access /data/local/tmp directly, so we pipe resource to file through stdin.
- ParcelFileDescriptor stdin = pipeFromStdin(filePath);
- pipeResourceToFileDescriptor(res, stdin);
- }
-
- /* Pipe stdin to a file in filePath. Returns PFD for stdin. */
- private ParcelFileDescriptor pipeFromStdin(String filePath) {
- // Not all devices have symlink for /dev/stdin, so use /proc/self/fd/0 directly.
- // /dev/stdin maps to /proc/self/fd/0.
- return runRwCommand("cp /proc/self/fd/0 " + filePath)[1];
- }
-
- private void pipeResourceToFileDescriptor(String res, ParcelFileDescriptor pfd)
- throws IOException {
- InputStream resStream = getClass().getClassLoader().getResourceAsStream(res);
- FileOutputStream fdStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd);
-
- FileUtils.copy(resStream, fdStream);
-
- try {
- fdStream.close();
- } catch (IOException e) {
- }
- }
-
- private static String runCommand(String command) throws IOException {
- return SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command);
- }
-
- private static ParcelFileDescriptor[] runRwCommand(String command) {
- return InstrumentationRegistry.getInstrumentation()
- .getUiAutomation().executeShellCommandRw(command);
- }
-
- private void setWatchlistConfig(String watchlistConfigFile) throws Exception {
- cleanup();
- saveResourceToFile(watchlistConfigFile, TMP_CONFIG_PATH);
- final String cmdResult = runCommand(
- "cmd network_watchlist set-test-config " + TMP_CONFIG_PATH).trim();
- assertThat(cmdResult).contains("Success");
- cleanup();
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/PacketUtils.java b/tests/tests/net/src/android/net/cts/PacketUtils.java
deleted file mode 100644
index 0aedecb..0000000
--- a/tests/tests/net/src/android/net/cts/PacketUtils.java
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static android.system.OsConstants.IPPROTO_IPV6;
-import static android.system.OsConstants.IPPROTO_UDP;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ShortBuffer;
-import java.security.GeneralSecurityException;
-import java.security.SecureRandom;
-import java.util.Arrays;
-
-import javax.crypto.Cipher;
-import javax.crypto.Mac;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-public class PacketUtils {
- private static final String TAG = PacketUtils.class.getSimpleName();
-
- private static final int DATA_BUFFER_LEN = 4096;
-
- static final int IP4_HDRLEN = 20;
- static final int IP6_HDRLEN = 40;
- static final int UDP_HDRLEN = 8;
- static final int TCP_HDRLEN = 20;
- static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12;
-
- // Not defined in OsConstants
- static final int IPPROTO_IPV4 = 4;
- static final int IPPROTO_ESP = 50;
-
- // Encryption parameters
- static final int AES_GCM_IV_LEN = 8;
- static final int AES_CBC_IV_LEN = 16;
- static final int AES_GCM_BLK_SIZE = 4;
- static final int AES_CBC_BLK_SIZE = 16;
-
- // Encryption algorithms
- static final String AES = "AES";
- static final String AES_CBC = "AES/CBC/NoPadding";
- static final String HMAC_SHA_256 = "HmacSHA256";
-
- public interface Payload {
- byte[] getPacketBytes(IpHeader header) throws Exception;
-
- void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception;
-
- short length();
-
- int getProtocolId();
- }
-
- public abstract static class IpHeader {
-
- public final byte proto;
- public final InetAddress srcAddr;
- public final InetAddress dstAddr;
- public final Payload payload;
-
- public IpHeader(int proto, InetAddress src, InetAddress dst, Payload payload) {
- this.proto = (byte) proto;
- this.srcAddr = src;
- this.dstAddr = dst;
- this.payload = payload;
- }
-
- public abstract byte[] getPacketBytes() throws Exception;
-
- public abstract int getProtocolId();
- }
-
- public static class Ip4Header extends IpHeader {
- private short checksum;
-
- public Ip4Header(int proto, Inet4Address src, Inet4Address dst, Payload payload) {
- super(proto, src, dst, payload);
- }
-
- public byte[] getPacketBytes() throws Exception {
- ByteBuffer resultBuffer = buildHeader();
- payload.addPacketBytes(this, resultBuffer);
-
- return getByteArrayFromBuffer(resultBuffer);
- }
-
- public ByteBuffer buildHeader() {
- ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
-
- // Version, IHL
- bb.put((byte) (0x45));
-
- // DCSP, ECN
- bb.put((byte) 0);
-
- // Total Length
- bb.putShort((short) (IP4_HDRLEN + payload.length()));
-
- // Empty for Identification, Flags and Fragment Offset
- bb.putShort((short) 0);
- bb.put((byte) 0x40);
- bb.put((byte) 0x00);
-
- // TTL
- bb.put((byte) 64);
-
- // Protocol
- bb.put(proto);
-
- // Header Checksum
- final int ipChecksumOffset = bb.position();
- bb.putShort((short) 0);
-
- // Src/Dst addresses
- bb.put(srcAddr.getAddress());
- bb.put(dstAddr.getAddress());
-
- bb.putShort(ipChecksumOffset, calculateChecksum(bb));
-
- return bb;
- }
-
- private short calculateChecksum(ByteBuffer bb) {
- int checksum = 0;
-
- // Calculate sum of 16-bit values, excluding checksum. IPv4 headers are always 32-bit
- // aligned, so no special cases needed for unaligned values.
- ShortBuffer shortBuffer = ByteBuffer.wrap(getByteArrayFromBuffer(bb)).asShortBuffer();
- while (shortBuffer.hasRemaining()) {
- short val = shortBuffer.get();
-
- // Wrap as needed
- checksum = addAndWrapForChecksum(checksum, val);
- }
-
- return onesComplement(checksum);
- }
-
- public int getProtocolId() {
- return IPPROTO_IPV4;
- }
- }
-
- public static class Ip6Header extends IpHeader {
- public Ip6Header(int nextHeader, Inet6Address src, Inet6Address dst, Payload payload) {
- super(nextHeader, src, dst, payload);
- }
-
- public byte[] getPacketBytes() throws Exception {
- ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
-
- // Version | Traffic Class (First 4 bits)
- bb.put((byte) 0x60);
-
- // Traffic class (Last 4 bits), Flow Label
- bb.put((byte) 0);
- bb.put((byte) 0);
- bb.put((byte) 0);
-
- // Payload Length
- bb.putShort((short) payload.length());
-
- // Next Header
- bb.put(proto);
-
- // Hop Limit
- bb.put((byte) 64);
-
- // Src/Dst addresses
- bb.put(srcAddr.getAddress());
- bb.put(dstAddr.getAddress());
-
- // Payload
- payload.addPacketBytes(this, bb);
-
- return getByteArrayFromBuffer(bb);
- }
-
- public int getProtocolId() {
- return IPPROTO_IPV6;
- }
- }
-
- public static class BytePayload implements Payload {
- public final byte[] payload;
-
- public BytePayload(byte[] payload) {
- this.payload = payload;
- }
-
- public int getProtocolId() {
- return -1;
- }
-
- public byte[] getPacketBytes(IpHeader header) {
- ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
-
- addPacketBytes(header, bb);
- return getByteArrayFromBuffer(bb);
- }
-
- public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) {
- resultBuffer.put(payload);
- }
-
- public short length() {
- return (short) payload.length;
- }
- }
-
- public static class UdpHeader implements Payload {
-
- public final short srcPort;
- public final short dstPort;
- public final Payload payload;
-
- public UdpHeader(int srcPort, int dstPort, Payload payload) {
- this.srcPort = (short) srcPort;
- this.dstPort = (short) dstPort;
- this.payload = payload;
- }
-
- public int getProtocolId() {
- return IPPROTO_UDP;
- }
-
- public short length() {
- return (short) (payload.length() + 8);
- }
-
- public byte[] getPacketBytes(IpHeader header) throws Exception {
- ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
-
- addPacketBytes(header, bb);
- return getByteArrayFromBuffer(bb);
- }
-
- public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception {
- // Source, Destination port
- resultBuffer.putShort(srcPort);
- resultBuffer.putShort(dstPort);
-
- // Payload Length
- resultBuffer.putShort(length());
-
- // Get payload bytes for checksum + payload
- ByteBuffer payloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN);
- payload.addPacketBytes(header, payloadBuffer);
- byte[] payloadBytes = getByteArrayFromBuffer(payloadBuffer);
-
- // Checksum
- resultBuffer.putShort(calculateChecksum(header, payloadBytes));
-
- // Payload
- resultBuffer.put(payloadBytes);
- }
-
- private short calculateChecksum(IpHeader header, byte[] payloadBytes) throws Exception {
- int newChecksum = 0;
- ShortBuffer srcBuffer = ByteBuffer.wrap(header.srcAddr.getAddress()).asShortBuffer();
- ShortBuffer dstBuffer = ByteBuffer.wrap(header.dstAddr.getAddress()).asShortBuffer();
-
- while (srcBuffer.hasRemaining() || dstBuffer.hasRemaining()) {
- short val = srcBuffer.hasRemaining() ? srcBuffer.get() : dstBuffer.get();
-
- // Wrap as needed
- newChecksum = addAndWrapForChecksum(newChecksum, val);
- }
-
- // Add pseudo-header values. Proto is 0-padded, so just use the byte.
- newChecksum = addAndWrapForChecksum(newChecksum, header.proto);
- newChecksum = addAndWrapForChecksum(newChecksum, length());
- newChecksum = addAndWrapForChecksum(newChecksum, srcPort);
- newChecksum = addAndWrapForChecksum(newChecksum, dstPort);
- newChecksum = addAndWrapForChecksum(newChecksum, length());
-
- ShortBuffer payloadShortBuffer = ByteBuffer.wrap(payloadBytes).asShortBuffer();
- while (payloadShortBuffer.hasRemaining()) {
- newChecksum = addAndWrapForChecksum(newChecksum, payloadShortBuffer.get());
- }
- if (payload.length() % 2 != 0) {
- newChecksum =
- addAndWrapForChecksum(
- newChecksum, (payloadBytes[payloadBytes.length - 1] << 8));
- }
-
- return onesComplement(newChecksum);
- }
- }
-
- public static class EspHeader implements Payload {
- public final int nextHeader;
- public final int spi;
- public final int seqNum;
- public final byte[] key;
- public final byte[] payload;
-
- /**
- * Generic constructor for ESP headers.
- *
- * <p>For Tunnel mode, payload will be a full IP header + attached payloads
- *
- * <p>For Transport mode, payload will be only the attached payloads, but with the checksum
- * calculated using the pre-encryption IP header
- */
- public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) {
- this.nextHeader = nextHeader;
- this.spi = spi;
- this.seqNum = seqNum;
- this.key = key;
- this.payload = payload;
- }
-
- public int getProtocolId() {
- return IPPROTO_ESP;
- }
-
- public short length() {
- // ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len)
- return (short)
- calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128);
- }
-
- public byte[] getPacketBytes(IpHeader header) throws Exception {
- ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN);
-
- addPacketBytes(header, bb);
- return getByteArrayFromBuffer(bb);
- }
-
- public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception {
- ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN);
- espPayloadBuffer.putInt(spi);
- espPayloadBuffer.putInt(seqNum);
- espPayloadBuffer.put(getCiphertext(key));
-
- espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16);
- resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer));
- }
-
- private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException {
- Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256);
- SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256);
- sha256HMAC.init(authKey);
-
- return sha256HMAC.doFinal(authenticatedSection);
- }
-
- /**
- * Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks
- *
- * <p>The ciphertext does NOT include the SPI/Sequence numbers, or the ICV.
- */
- private byte[] getCiphertext(byte[] key) throws GeneralSecurityException {
- int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE);
- ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen);
- paddedPayload.put(payload);
-
- // Add padding - consecutive integers from 0x01
- int pad = 1;
- while (paddedPayload.position() < paddedPayload.limit()) {
- paddedPayload.put((byte) pad++);
- }
-
- paddedPayload.position(paddedPayload.limit() - 2);
- paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length
- paddedPayload.put((byte) nextHeader);
-
- // Generate Initialization Vector
- byte[] iv = new byte[AES_CBC_IV_LEN];
- new SecureRandom().nextBytes(iv);
- IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
- SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES);
-
- // Encrypt payload
- Cipher cipher = Cipher.getInstance(AES_CBC);
- cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
- byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload));
-
- // Build ciphertext
- ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length);
- cipherText.put(iv);
- cipherText.put(encrypted);
-
- return getByteArrayFromBuffer(cipherText);
- }
- }
-
- private static int addAndWrapForChecksum(int currentChecksum, int value) {
- currentChecksum += value & 0x0000ffff;
-
- // Wrap anything beyond the first 16 bits, and add to lower order bits
- return (currentChecksum >>> 16) + (currentChecksum & 0x0000ffff);
- }
-
- private static short onesComplement(int val) {
- val = (val >>> 16) + (val & 0xffff);
-
- if (val == 0) return 0;
- return (short) ((~val) & 0xffff);
- }
-
- public static int calculateEspPacketSize(
- int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) {
- final int ESP_HDRLEN = 4 + 4; // SPI + Seq#
- final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length
- payloadLen += cryptIvLength; // Initialization Vector
-
- // Align to block size of encryption algorithm
- payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize);
- return payloadLen + ESP_HDRLEN + ICV_LEN;
- }
-
- private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) {
- payloadLen += 2; // ESP trailer
-
- // Align to block size of encryption algorithm
- return payloadLen + calculateEspPadLen(payloadLen, cryptBlockSize);
- }
-
- private static int calculateEspPadLen(int payloadLen, int cryptBlockSize) {
- return (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize;
- }
-
- private static byte[] getByteArrayFromBuffer(ByteBuffer buffer) {
- return Arrays.copyOfRange(buffer.array(), 0, buffer.position());
- }
-
- public static IpHeader getIpHeader(
- int protocol, InetAddress src, InetAddress dst, Payload payload) {
- if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) {
- throw new IllegalArgumentException("Invalid src/dst address combination");
- }
-
- if (src instanceof Inet6Address) {
- return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload);
- } else {
- return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload);
- }
- }
-
- /*
- * Debug printing
- */
- private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
-
- public static String bytesToHex(byte[] bytes) {
- StringBuilder sb = new StringBuilder();
- for (byte b : bytes) {
- sb.append(hexArray[b >>> 4]);
- sb.append(hexArray[b & 0x0F]);
- sb.append(' ');
- }
- return sb.toString();
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/ProxyInfoTest.java b/tests/tests/net/src/android/net/cts/ProxyInfoTest.java
deleted file mode 100644
index 1c5624c..0000000
--- a/tests/tests/net/src/android/net/cts/ProxyInfoTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.ProxyInfo;
-import android.net.Uri;
-import android.os.Build;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-@RunWith(AndroidJUnit4.class)
-public final class ProxyInfoTest {
- private static final String TEST_HOST = "test.example.com";
- private static final int TEST_PORT = 5566;
- private static final Uri TEST_URI = Uri.parse("https://test.example.com");
- // This matches android.net.ProxyInfo#LOCAL_EXCL_LIST
- private static final String LOCAL_EXCL_LIST = "";
- // This matches android.net.ProxyInfo#LOCAL_HOST
- private static final String LOCAL_HOST = "localhost";
- // This matches android.net.ProxyInfo#LOCAL_PORT
- private static final int LOCAL_PORT = -1;
-
- @Rule
- public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
-
- @Test
- public void testConstructor() {
- final ProxyInfo proxy = new ProxyInfo((ProxyInfo) null);
- checkEmpty(proxy);
-
- assertEquals(proxy, new ProxyInfo(proxy));
- }
-
- @Test
- public void testBuildDirectProxy() {
- final ProxyInfo proxy1 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT);
-
- assertEquals(TEST_HOST, proxy1.getHost());
- assertEquals(TEST_PORT, proxy1.getPort());
- assertArrayEquals(new String[0], proxy1.getExclusionList());
- assertEquals(Uri.EMPTY, proxy1.getPacFileUrl());
-
- final List<String> exclList = new ArrayList<>();
- exclList.add("localhost");
- exclList.add("*.exclusion.com");
- final ProxyInfo proxy2 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT, exclList);
-
- assertEquals(TEST_HOST, proxy2.getHost());
- assertEquals(TEST_PORT, proxy2.getPort());
- assertArrayEquals(exclList.toArray(new String[0]), proxy2.getExclusionList());
- assertEquals(Uri.EMPTY, proxy2.getPacFileUrl());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testBuildPacProxy() {
- final ProxyInfo proxy1 = ProxyInfo.buildPacProxy(TEST_URI);
-
- assertEquals(LOCAL_HOST, proxy1.getHost());
- assertEquals(LOCAL_PORT, proxy1.getPort());
- assertArrayEquals(LOCAL_EXCL_LIST.toLowerCase(Locale.ROOT).split(","),
- proxy1.getExclusionList());
- assertEquals(TEST_URI, proxy1.getPacFileUrl());
-
- final ProxyInfo proxy2 = ProxyInfo.buildPacProxy(TEST_URI, TEST_PORT);
-
- assertEquals(LOCAL_HOST, proxy2.getHost());
- assertEquals(TEST_PORT, proxy2.getPort());
- assertArrayEquals(LOCAL_EXCL_LIST.toLowerCase(Locale.ROOT).split(","),
- proxy2.getExclusionList());
- assertEquals(TEST_URI, proxy2.getPacFileUrl());
- }
-
- @Test
- public void testIsValid() {
- final ProxyInfo proxy1 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT);
- assertTrue(proxy1.isValid());
-
- // Given empty host
- final ProxyInfo proxy2 = ProxyInfo.buildDirectProxy("", TEST_PORT);
- assertFalse(proxy2.isValid());
- // Given invalid host
- final ProxyInfo proxy3 = ProxyInfo.buildDirectProxy(".invalid.com", TEST_PORT);
- assertFalse(proxy3.isValid());
- // Given invalid port.
- final ProxyInfo proxy4 = ProxyInfo.buildDirectProxy(TEST_HOST, 0);
- assertFalse(proxy4.isValid());
- // Given another invalid port
- final ProxyInfo proxy5 = ProxyInfo.buildDirectProxy(TEST_HOST, 65536);
- assertFalse(proxy5.isValid());
- // Given invalid exclusion list
- final List<String> exclList = new ArrayList<>();
- exclList.add(".invalid.com");
- exclList.add("%.test.net");
- final ProxyInfo proxy6 = ProxyInfo.buildDirectProxy(TEST_HOST, TEST_PORT, exclList);
- assertFalse(proxy6.isValid());
- }
-
- private void checkEmpty(ProxyInfo proxy) {
- assertNull(proxy.getHost());
- assertEquals(0, proxy.getPort());
- assertNull(proxy.getExclusionList());
- assertEquals(Uri.EMPTY, proxy.getPacFileUrl());
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/ProxyTest.java b/tests/tests/net/src/android/net/cts/ProxyTest.java
deleted file mode 100644
index 467d12f..0000000
--- a/tests/tests/net/src/android/net/cts/ProxyTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-
-import android.net.Proxy;
-import android.test.AndroidTestCase;
-
-public class ProxyTest extends AndroidTestCase {
-
- public void testConstructor() {
- new Proxy();
- }
-
- public void testAccessProperties() {
- final int minValidPort = 0;
- final int maxValidPort = 65535;
- int defaultPort = Proxy.getDefaultPort();
- if(null == Proxy.getDefaultHost()) {
- assertEquals(-1, defaultPort);
- } else {
- assertTrue(defaultPort >= minValidPort && defaultPort <= maxValidPort);
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/RssiCurveTest.java b/tests/tests/net/src/android/net/cts/RssiCurveTest.java
deleted file mode 100644
index d651b71..0000000
--- a/tests/tests/net/src/android/net/cts/RssiCurveTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.net.RssiCurve;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** CTS tests for {@link RssiCurve}. */
-@RunWith(AndroidJUnit4.class)
-public class RssiCurveTest {
-
- @Test
- public void lookupScore_constantCurve() {
- // One bucket from rssi=-100 to 100 with score 10.
- RssiCurve curve = new RssiCurve(-100, 200, new byte[] { 10 });
- assertThat(curve.lookupScore(-200)).isEqualTo(10);
- assertThat(curve.lookupScore(-100)).isEqualTo(10);
- assertThat(curve.lookupScore(0)).isEqualTo(10);
- assertThat(curve.lookupScore(100)).isEqualTo(10);
- assertThat(curve.lookupScore(200)).isEqualTo(10);
- }
-
- @Test
- public void lookupScore_changingCurve() {
- // One bucket from -100 to 0 with score -10, and one bucket from 0 to 100 with score 10.
- RssiCurve curve = new RssiCurve(-100, 100, new byte[] { -10, 10 });
- assertThat(curve.lookupScore(-200)).isEqualTo(-10);
- assertThat(curve.lookupScore(-100)).isEqualTo(-10);
- assertThat(curve.lookupScore(-50)).isEqualTo(-10);
- assertThat(curve.lookupScore(0)).isEqualTo(10);
- assertThat(curve.lookupScore(50)).isEqualTo(10);
- assertThat(curve.lookupScore(100)).isEqualTo(10);
- assertThat(curve.lookupScore(200)).isEqualTo(10);
- }
-
- @Test
- public void lookupScore_linearCurve() {
- // Curve starting at -110, with 15 buckets of width 10 whose scores increases by 10 with
- // each bucket. The current active network gets a boost of 15 to its RSSI.
- RssiCurve curve = new RssiCurve(
- -110,
- 10,
- new byte[] { -20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120 },
- 15);
-
- assertThat(curve.lookupScore(-120)).isEqualTo(-20);
- assertThat(curve.lookupScore(-120, false)).isEqualTo(-20);
- assertThat(curve.lookupScore(-120, true)).isEqualTo(-20);
-
- assertThat(curve.lookupScore(-111)).isEqualTo(-20);
- assertThat(curve.lookupScore(-111, false)).isEqualTo(-20);
- assertThat(curve.lookupScore(-111, true)).isEqualTo(-10);
-
- assertThat(curve.lookupScore(-110)).isEqualTo(-20);
- assertThat(curve.lookupScore(-110, false)).isEqualTo(-20);
- assertThat(curve.lookupScore(-110, true)).isEqualTo(-10);
-
- assertThat(curve.lookupScore(-105)).isEqualTo(-20);
- assertThat(curve.lookupScore(-105, false)).isEqualTo(-20);
- assertThat(curve.lookupScore(-105, true)).isEqualTo(0);
-
- assertThat(curve.lookupScore(-100)).isEqualTo(-10);
- assertThat(curve.lookupScore(-100, false)).isEqualTo(-10);
- assertThat(curve.lookupScore(-100, true)).isEqualTo(0);
-
- assertThat(curve.lookupScore(-50)).isEqualTo(40);
- assertThat(curve.lookupScore(-50, false)).isEqualTo(40);
- assertThat(curve.lookupScore(-50, true)).isEqualTo(50);
-
- assertThat(curve.lookupScore(0)).isEqualTo(90);
- assertThat(curve.lookupScore(0, false)).isEqualTo(90);
- assertThat(curve.lookupScore(0, true)).isEqualTo(100);
-
- assertThat(curve.lookupScore(30)).isEqualTo(120);
- assertThat(curve.lookupScore(30, false)).isEqualTo(120);
- assertThat(curve.lookupScore(30, true)).isEqualTo(120);
-
- assertThat(curve.lookupScore(40)).isEqualTo(120);
- assertThat(curve.lookupScore(40, false)).isEqualTo(120);
- assertThat(curve.lookupScore(40, true)).isEqualTo(120);
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/tests/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java
deleted file mode 100644
index cbe54f8..0000000
--- a/tests/tests/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.SSLCertificateSocketFactory;
-import android.platform.test.annotations.AppModeFull;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-import libcore.javax.net.ssl.SSLConfigurationAsserts;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class SSLCertificateSocketFactoryTest {
- // TEST_HOST should point to a web server with a valid TLS certificate.
- private static final String TEST_HOST = "www.google.com";
- private static final int HTTPS_PORT = 443;
- private HostnameVerifier mDefaultVerifier;
- private SSLCertificateSocketFactory mSocketFactory;
- private InetAddress mLocalAddress;
- // InetAddress obtained by resolving TEST_HOST.
- private InetAddress mTestHostAddress;
- // SocketAddress combining mTestHostAddress and HTTPS_PORT.
- private List<SocketAddress> mTestSocketAddresses;
-
- @Before
- public void setUp() {
- // Expected state before each test method is that
- // HttpsURLConnection.getDefaultHostnameVerifier() will return the system default.
- mDefaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
- mSocketFactory = (SSLCertificateSocketFactory)
- SSLCertificateSocketFactory.getDefault(1000 /* handshakeTimeoutMillis */);
- assertNotNull(mSocketFactory);
- InetAddress[] addresses;
- try {
- addresses = InetAddress.getAllByName(TEST_HOST);
- mTestHostAddress = addresses[0];
- } catch (UnknownHostException uhe) {
- throw new AssertionError(
- "Unable to test SSLCertificateSocketFactory: cannot resolve " + TEST_HOST, uhe);
- }
-
- mTestSocketAddresses = Arrays.stream(addresses)
- .map(addr -> new InetSocketAddress(addr, HTTPS_PORT))
- .collect(Collectors.toList());
-
- // Find the local IP address which will be used to connect to TEST_HOST.
- try {
- Socket testSocket = new Socket(TEST_HOST, HTTPS_PORT);
- mLocalAddress = testSocket.getLocalAddress();
- testSocket.close();
- } catch (IOException ioe) {
- throw new AssertionError(""
- + "Unable to test SSLCertificateSocketFactory: cannot connect to "
- + TEST_HOST, ioe);
- }
- }
-
- // Restore the system default hostname verifier after each test.
- @After
- public void restoreDefaultHostnameVerifier() {
- HttpsURLConnection.setDefaultHostnameVerifier(mDefaultVerifier);
- }
-
- @Test
- public void testDefaultConfiguration() throws Exception {
- SSLConfigurationAsserts.assertSSLSocketFactoryDefaultConfiguration(mSocketFactory);
- }
-
- @Test
- public void testAccessProperties() {
- mSocketFactory.getSupportedCipherSuites();
- mSocketFactory.getDefaultCipherSuites();
- }
-
- /**
- * Tests the {@code createSocket()} cases which are expected to fail with {@code IOException}.
- */
- @Test
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void createSocket_io_error_expected() {
- // Connect to the localhost HTTPS port. Should result in connection refused IOException
- // because no service should be listening on that port.
- InetAddress localhostAddress = InetAddress.getLoopbackAddress();
- try {
- mSocketFactory.createSocket(localhostAddress, HTTPS_PORT);
- fail();
- } catch (IOException e) {
- // expected
- }
-
- // Same, but also binding to a local address.
- try {
- mSocketFactory.createSocket(localhostAddress, HTTPS_PORT, localhostAddress, 0);
- fail();
- } catch (IOException e) {
- // expected
- }
-
- // Same, wrapping an existing plain socket which is in an unconnected state.
- try {
- Socket socket = new Socket();
- mSocketFactory.createSocket(socket, "localhost", HTTPS_PORT, true);
- fail();
- } catch (IOException e) {
- // expected
- }
- }
-
- /**
- * Tests hostname verification for
- * {@link SSLCertificateSocketFactory#createSocket(String, int)}.
- *
- * <p>This method should return a socket which is fully connected (i.e. TLS handshake complete)
- * and whose peer TLS certificate has been verified to have the correct hostname.
- *
- * <p>{@link SSLCertificateSocketFactory} is documented to verify hostnames using
- * the {@link HostnameVerifier} returned by
- * {@link HttpsURLConnection#getDefaultHostnameVerifier}, so this test connects twice,
- * once with the system default {@link HostnameVerifier} which is expected to succeed,
- * and once after installing a {@link NegativeHostnameVerifier} which will cause
- * {@link SSLCertificateSocketFactory#verifyHostname} to throw a
- * {@link SSLPeerUnverifiedException}.
- *
- * <p>These tests only test the hostname verification logic in SSLCertificateSocketFactory,
- * other TLS failure modes and the default HostnameVerifier are tested elsewhere, see
- * {@link com.squareup.okhttp.internal.tls.HostnameVerifierTest} and
- * https://android.googlesource.com/platform/external/boringssl/+/refs/heads/master/src/ssl/test
- *
- * <p>Tests the following behaviour:-
- * <ul>
- * <li>TEST_SERVER is available and has a valid TLS certificate
- * <li>{@code createSocket()} verifies the remote hostname is correct using
- * {@link HttpsURLConnection#getDefaultHostnameVerifier}
- * <li>{@link SSLPeerUnverifiedException} is thrown when the remote hostname is invalid
- * </ul>
- *
- * <p>See also http://b/2807618.
- */
- @Test
- public void createSocket_simple_with_hostname_verification() throws Exception {
- Socket socket = mSocketFactory.createSocket(TEST_HOST, HTTPS_PORT);
- assertConnectedSocket(socket);
- socket.close();
-
- HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier());
- try {
- mSocketFactory.createSocket(TEST_HOST, HTTPS_PORT);
- fail();
- } catch (SSLPeerUnverifiedException expected) {
- // expected
- }
- }
-
- /**
- * Tests hostname verification for
- * {@link SSLCertificateSocketFactory#createSocket(Socket, String, int, boolean)}.
- *
- * <p>This method should return a socket which is fully connected (i.e. TLS handshake complete)
- * and whose peer TLS certificate has been verified to have the correct hostname.
- *
- * <p>The TLS socket returned is wrapped around the plain socket passed into
- * {@code createSocket()}.
- *
- * <p>See {@link #createSocket_simple_with_hostname_verification()} for test methodology.
- */
- @Test
- public void createSocket_wrapped_with_hostname_verification() throws Exception {
- Socket underlying = new Socket(TEST_HOST, HTTPS_PORT);
- Socket socket = mSocketFactory.createSocket(underlying, TEST_HOST, HTTPS_PORT, true);
- assertConnectedSocket(socket);
- socket.close();
-
- HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier());
- try {
- underlying = new Socket(TEST_HOST, HTTPS_PORT);
- mSocketFactory.createSocket(underlying, TEST_HOST, HTTPS_PORT, true);
- fail();
- } catch (SSLPeerUnverifiedException expected) {
- // expected
- }
- }
-
- /**
- * Tests hostname verification for
- * {@link SSLCertificateSocketFactory#createSocket(String, int, InetAddress, int)}.
- *
- * <p>This method should return a socket which is fully connected (i.e. TLS handshake complete)
- * and whose peer TLS certificate has been verified to have the correct hostname.
- *
- * <p>The TLS socket returned is also bound to the local address determined in {@link #setUp} to
- * be used for connections to TEST_HOST, and a wildcard port.
- *
- * <p>See {@link #createSocket_simple_with_hostname_verification()} for test methodology.
- */
- @Test
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void createSocket_bound_with_hostname_verification() throws Exception {
- Socket socket = mSocketFactory.createSocket(TEST_HOST, HTTPS_PORT, mLocalAddress, 0);
- assertConnectedSocket(socket);
- socket.close();
-
- HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier());
- try {
- mSocketFactory.createSocket(TEST_HOST, HTTPS_PORT, mLocalAddress, 0);
- fail();
- } catch (SSLPeerUnverifiedException expected) {
- // expected
- }
- }
-
- /**
- * Tests hostname verification for
- * {@link SSLCertificateSocketFactory#createSocket(InetAddress, int)}.
- *
- * <p>This method should return a socket which the documentation describes as "unconnected",
- * which actually means that the socket is fully connected at the TCP layer but TLS handshaking
- * and hostname verification have not yet taken place.
- *
- * <p>Behaviour is tested by installing a {@link NegativeHostnameVerifier} and by calling
- * {@link #assertConnectedSocket} to ensure TLS handshaking but no hostname verification takes
- * place. Next, {@link SSLCertificateSocketFactory#verifyHostname} is called to ensure
- * that hostname verification is using the {@link HostnameVerifier} returned by
- * {@link HttpsURLConnection#getDefaultHostnameVerifier} as documented.
- *
- * <p>Tests the following behaviour:-
- * <ul>
- * <li>TEST_SERVER is available and has a valid TLS certificate
- * <li>{@code createSocket()} does not verify the remote hostname
- * <li>Calling {@link SSLCertificateSocketFactory#verifyHostname} on the returned socket
- * throws {@link SSLPeerUnverifiedException} if the remote hostname is invalid
- * </ul>
- */
- @Test
- public void createSocket_simple_no_hostname_verification() throws Exception{
- HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier());
- Socket socket = mSocketFactory.createSocket(mTestHostAddress, HTTPS_PORT);
- // Need to provide the expected hostname here or the TLS handshake will
- // be unable to supply SNI to the remote host.
- mSocketFactory.setHostname(socket, TEST_HOST);
- assertConnectedSocket(socket);
- try {
- SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST);
- fail();
- } catch (SSLPeerUnverifiedException expected) {
- // expected
- }
- HttpsURLConnection.setDefaultHostnameVerifier(mDefaultVerifier);
- SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST);
- socket.close();
- }
-
- /**
- * Tests hostname verification for
- * {@link SSLCertificateSocketFactory#createSocket(InetAddress, int, InetAddress, int)}.
- *
- * <p>This method should return a socket which the documentation describes as "unconnected",
- * which actually means that the socket is fully connected at the TCP layer but TLS handshaking
- * and hostname verification have not yet taken place.
- *
- * <p>The TLS socket returned is also bound to the local address determined in {@link #setUp} to
- * be used for connections to TEST_HOST, and a wildcard port.
- *
- * <p>See {@link #createSocket_simple_no_hostname_verification()} for test methodology.
- */
- @Test
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void createSocket_bound_no_hostname_verification() throws Exception{
- HttpsURLConnection.setDefaultHostnameVerifier(new NegativeHostnameVerifier());
- Socket socket =
- mSocketFactory.createSocket(mTestHostAddress, HTTPS_PORT, mLocalAddress, 0);
- // Need to provide the expected hostname here or the TLS handshake will
- // be unable to supply SNI to the peer.
- mSocketFactory.setHostname(socket, TEST_HOST);
- assertConnectedSocket(socket);
- try {
- SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST);
- fail();
- } catch (SSLPeerUnverifiedException expected) {
- // expected
- }
- HttpsURLConnection.setDefaultHostnameVerifier(mDefaultVerifier);
- SSLCertificateSocketFactory.verifyHostname(socket, TEST_HOST);
- socket.close();
- }
-
- /**
- * Asserts a socket is fully connected to the expected peer.
- *
- * <p>For the variants of createSocket which verify the remote hostname,
- * {@code socket} should already be fully connected.
- *
- * <p>For the non-verifying variants, retrieving the input stream will trigger a TLS handshake
- * and so may throw an exception, for example if the peer's certificate is invalid.
- *
- * <p>Does no hostname verification.
- */
- private void assertConnectedSocket(Socket socket) throws Exception {
- assertNotNull(socket);
- assertTrue(socket.isConnected());
- assertNotNull(socket.getInputStream());
- assertNotNull(socket.getOutputStream());
- assertTrue(mTestSocketAddresses.contains(socket.getRemoteSocketAddress()));
- }
-
- /**
- * A HostnameVerifier which always returns false to simulate a server returning a
- * certificate which does not match the expected hostname.
- */
- private static class NegativeHostnameVerifier implements HostnameVerifier {
- @Override
- public boolean verify(String hostname, SSLSession sslSession) {
- return false;
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/TheaterModeTest.java b/tests/tests/net/src/android/net/cts/TheaterModeTest.java
deleted file mode 100644
index d1ddeaa..0000000
--- a/tests/tests/net/src/android/net/cts/TheaterModeTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.platform.test.annotations.AppModeFull;
-import android.provider.Settings;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-public class TheaterModeTest extends AndroidTestCase {
- private static final String TAG = "TheaterModeTest";
- private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
- private static final String FEATURE_WIFI = "android.hardware.wifi";
- private static final int TIMEOUT_MS = 10 * 1000;
- private boolean mHasFeature;
- private Context mContext;
- private ContentResolver resolver;
-
- public void setup() {
- mContext= getContext();
- resolver = mContext.getContentResolver();
- mHasFeature = (mContext.getPackageManager().hasSystemFeature(FEATURE_BLUETOOTH)
- || mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI));
- }
-
- @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
- public void testTheaterMode() {
- setup();
- if (!mHasFeature) {
- Log.i(TAG, "The device doesn't support network bluetooth or wifi feature");
- return;
- }
-
- for (int testCount = 0; testCount < 2; testCount++) {
- if (!doOneTest()) {
- fail("Theater mode failed to change in " + TIMEOUT_MS + "msec");
- return;
- }
- }
- }
-
- private boolean doOneTest() {
- boolean theaterModeOn = isTheaterModeOn();
-
- setTheaterModeOn(!theaterModeOn);
- try {
- Thread.sleep(TIMEOUT_MS);
- } catch (InterruptedException e) {
- Log.e(TAG, "Sleep time interrupted.", e);
- }
-
- if (theaterModeOn == isTheaterModeOn()) {
- return false;
- }
- return true;
- }
-
- private void setTheaterModeOn(boolean enabling) {
- // Change the system setting for theater mode
- Settings.Global.putInt(resolver, Settings.Global.THEATER_MODE_ON, enabling ? 1 : 0);
- }
-
- private boolean isTheaterModeOn() {
- // Read the system setting for theater mode
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.THEATER_MODE_ON, 0) != 0;
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/TrafficStatsTest.java b/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
deleted file mode 100755
index 37bdd44..0000000
--- a/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.net.NetworkStats;
-import android.net.TrafficStats;
-import android.os.Process;
-import android.platform.test.annotations.AppModeFull;
-import android.test.AndroidTestCase;
-import android.util.Log;
-import android.util.Range;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public class TrafficStatsTest extends AndroidTestCase {
- private static final String LOG_TAG = "TrafficStatsTest";
-
- /** Verify the given value is in range [lower, upper] */
- private void assertInRange(String tag, long value, long lower, long upper) {
- final Range range = new Range(lower, upper);
- assertTrue(tag + ": " + value + " is not within range [" + lower + ", " + upper + "]",
- range.contains(value));
- }
-
- public void testValidMobileStats() {
- // We can't assume a mobile network is even present in this test, so
- // we simply assert that a valid value is returned.
-
- assertTrue(TrafficStats.getMobileTxPackets() >= 0);
- assertTrue(TrafficStats.getMobileRxPackets() >= 0);
- assertTrue(TrafficStats.getMobileTxBytes() >= 0);
- assertTrue(TrafficStats.getMobileRxBytes() >= 0);
- }
-
- public void testValidTotalStats() {
- assertTrue(TrafficStats.getTotalTxPackets() >= 0);
- assertTrue(TrafficStats.getTotalRxPackets() >= 0);
- assertTrue(TrafficStats.getTotalTxBytes() >= 0);
- assertTrue(TrafficStats.getTotalRxBytes() >= 0);
- }
-
- public void testValidPacketStats() {
- assertTrue(TrafficStats.getTxPackets("lo") >= 0);
- assertTrue(TrafficStats.getRxPackets("lo") >= 0);
- }
-
- public void testThreadStatsTag() throws Exception {
- TrafficStats.setThreadStatsTag(0xf00d);
- assertTrue("Tag didn't stick", TrafficStats.getThreadStatsTag() == 0xf00d);
-
- final CountDownLatch latch = new CountDownLatch(1);
-
- new Thread("TrafficStatsTest.testThreadStatsTag") {
- @Override
- public void run() {
- assertTrue("Tag leaked", TrafficStats.getThreadStatsTag() != 0xf00d);
- TrafficStats.setThreadStatsTag(0xcafe);
- assertTrue("Tag didn't stick", TrafficStats.getThreadStatsTag() == 0xcafe);
- latch.countDown();
- }
- }.start();
-
- latch.await(5, TimeUnit.SECONDS);
- assertTrue("Tag lost", TrafficStats.getThreadStatsTag() == 0xf00d);
-
- TrafficStats.clearThreadStatsTag();
- assertTrue("Tag not cleared", TrafficStats.getThreadStatsTag() != 0xf00d);
- }
-
- long tcpPacketToIpBytes(long packetCount, long bytes) {
- // ip header + tcp header + data.
- // Tcp header is mostly 32. Syn has different tcp options -> 40. Don't care.
- return packetCount * (20 + 32 + bytes);
- }
-
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void testTrafficStatsForLocalhost() throws IOException {
- final long mobileTxPacketsBefore = TrafficStats.getMobileTxPackets();
- final long mobileRxPacketsBefore = TrafficStats.getMobileRxPackets();
- final long mobileTxBytesBefore = TrafficStats.getMobileTxBytes();
- final long mobileRxBytesBefore = TrafficStats.getMobileRxBytes();
- final long totalTxPacketsBefore = TrafficStats.getTotalTxPackets();
- final long totalRxPacketsBefore = TrafficStats.getTotalRxPackets();
- final long totalTxBytesBefore = TrafficStats.getTotalTxBytes();
- final long totalRxBytesBefore = TrafficStats.getTotalRxBytes();
- final long uidTxBytesBefore = TrafficStats.getUidTxBytes(Process.myUid());
- final long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid());
- final long uidTxPacketsBefore = TrafficStats.getUidTxPackets(Process.myUid());
- final long uidRxPacketsBefore = TrafficStats.getUidRxPackets(Process.myUid());
- final long ifaceTxPacketsBefore = TrafficStats.getTxPackets("lo");
- final long ifaceRxPacketsBefore = TrafficStats.getRxPackets("lo");
-
- // Transfer 1MB of data across an explicitly localhost socket.
- final int byteCount = 1024;
- final int packetCount = 1024;
-
- TrafficStats.startDataProfiling(null);
- final ServerSocket server = new ServerSocket(0);
- new Thread("TrafficStatsTest.testTrafficStatsForLocalhost") {
- @Override
- public void run() {
- try {
- final Socket socket = new Socket("localhost", server.getLocalPort());
- // Make sure that each write()+flush() turns into a packet:
- // disable Nagle.
- socket.setTcpNoDelay(true);
- final OutputStream out = socket.getOutputStream();
- final byte[] buf = new byte[byteCount];
- TrafficStats.setThreadStatsTag(0x42);
- TrafficStats.tagSocket(socket);
- for (int i = 0; i < packetCount; i++) {
- out.write(buf);
- out.flush();
- try {
- // Bug: 10668088, Even with Nagle disabled, and flushing the 1024 bytes
- // the kernel still regroups data into a larger packet.
- Thread.sleep(5);
- } catch (InterruptedException e) {
- }
- }
- out.close();
- socket.close();
- } catch (IOException e) {
- Log.i(LOG_TAG, "Badness during writes to socket: " + e);
- }
- }
- }.start();
-
- int read = 0;
- try {
- final Socket socket = server.accept();
- socket.setTcpNoDelay(true);
- TrafficStats.setThreadStatsTag(0x43);
- TrafficStats.tagSocket(socket);
- final InputStream in = socket.getInputStream();
- final byte[] buf = new byte[byteCount];
- while (read < byteCount * packetCount) {
- int n = in.read(buf);
- assertTrue("Unexpected EOF", n > 0);
- read += n;
- }
- } finally {
- server.close();
- }
- assertTrue("Not all data read back", read >= byteCount * packetCount);
-
- // It's too fast to call getUidTxBytes function.
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- }
- final NetworkStats testStats = TrafficStats.stopDataProfiling(null);
-
- final long mobileTxPacketsAfter = TrafficStats.getMobileTxPackets();
- final long mobileRxPacketsAfter = TrafficStats.getMobileRxPackets();
- final long mobileTxBytesAfter = TrafficStats.getMobileTxBytes();
- final long mobileRxBytesAfter = TrafficStats.getMobileRxBytes();
- final long totalTxPacketsAfter = TrafficStats.getTotalTxPackets();
- final long totalRxPacketsAfter = TrafficStats.getTotalRxPackets();
- final long totalTxBytesAfter = TrafficStats.getTotalTxBytes();
- final long totalRxBytesAfter = TrafficStats.getTotalRxBytes();
- final long uidTxBytesAfter = TrafficStats.getUidTxBytes(Process.myUid());
- final long uidRxBytesAfter = TrafficStats.getUidRxBytes(Process.myUid());
- final long uidTxPacketsAfter = TrafficStats.getUidTxPackets(Process.myUid());
- final long uidRxPacketsAfter = TrafficStats.getUidRxPackets(Process.myUid());
- final long uidTxDeltaBytes = uidTxBytesAfter - uidTxBytesBefore;
- final long uidTxDeltaPackets = uidTxPacketsAfter - uidTxPacketsBefore;
- final long uidRxDeltaBytes = uidRxBytesAfter - uidRxBytesBefore;
- final long uidRxDeltaPackets = uidRxPacketsAfter - uidRxPacketsBefore;
- final long ifaceTxPacketsAfter = TrafficStats.getTxPackets("lo");
- final long ifaceRxPacketsAfter = TrafficStats.getRxPackets("lo");
- final long ifaceTxDeltaPackets = ifaceTxPacketsAfter - ifaceTxPacketsBefore;
- final long ifaceRxDeltaPackets = ifaceRxPacketsAfter - ifaceRxPacketsBefore;
-
- // Localhost traffic *does* count against per-UID stats.
- /*
- * Calculations:
- * - bytes
- * bytes is approx: packets * data + packets * acks;
- * but sometimes there are less acks than packets, so we set a lower
- * limit of 1 ack.
- * - setup/teardown
- * + 7 approx.: syn, syn-ack, ack, fin-ack, ack, fin-ack, ack;
- * but sometimes the last find-acks just vanish, so we set a lower limit of +5.
- */
- final int maxExpectedExtraPackets = 7;
- final int minExpectedExtraPackets = 5;
-
- // Some other tests don't cleanup connections correctly.
- // They have the same UID, so we discount their lingering traffic
- // which happens only on non-localhost, such as TCP FIN retranmission packets
- final long deltaTxOtherPackets = (totalTxPacketsAfter - totalTxPacketsBefore)
- - uidTxDeltaPackets;
- final long deltaRxOtherPackets = (totalRxPacketsAfter - totalRxPacketsBefore)
- - uidRxDeltaPackets;
- if (deltaTxOtherPackets > 0 || deltaRxOtherPackets > 0) {
- Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/"
- + deltaRxOtherPackets);
- }
-
- // Check that the per-uid stats obtained from data profiling contain the expected values.
- // The data profiling snapshot is generated from the readNetworkStatsDetail() method in
- // networkStatsService, so it's possible to verify that the detailed stats for a given
- // uid are correct.
- final NetworkStats.Entry entry = testStats.getTotal(null, Process.myUid());
- final long pktBytes = tcpPacketToIpBytes(packetCount, byteCount);
- final long pktWithNoDataBytes = tcpPacketToIpBytes(packetCount, 0);
- final long minExpExtraPktBytes = tcpPacketToIpBytes(minExpectedExtraPackets, 0);
- final long maxExpExtraPktBytes = tcpPacketToIpBytes(maxExpectedExtraPackets, 0);
- final long deltaTxOtherPktBytes = tcpPacketToIpBytes(deltaTxOtherPackets, 0);
- final long deltaRxOtherPktBytes = tcpPacketToIpBytes(deltaRxOtherPackets, 0);
- assertInRange("txPackets detail", entry.txPackets, packetCount + minExpectedExtraPackets,
- uidTxDeltaPackets);
- assertInRange("rxPackets detail", entry.rxPackets, packetCount + minExpectedExtraPackets,
- uidRxDeltaPackets);
- assertInRange("txBytes detail", entry.txBytes, pktBytes + minExpExtraPktBytes,
- uidTxDeltaBytes);
- assertInRange("rxBytes detail", entry.rxBytes, pktBytes + minExpExtraPktBytes,
- uidRxDeltaBytes);
- assertInRange("uidtxp", uidTxDeltaPackets, packetCount + minExpectedExtraPackets,
- packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets);
- assertInRange("uidrxp", uidRxDeltaPackets, packetCount + minExpectedExtraPackets,
- packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets);
- assertInRange("uidtxb", uidTxDeltaBytes, pktBytes + minExpExtraPktBytes,
- pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaTxOtherPktBytes);
- assertInRange("uidrxb", uidRxDeltaBytes, pktBytes + minExpExtraPktBytes,
- pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaRxOtherPktBytes);
- assertInRange("iftxp", ifaceTxDeltaPackets, packetCount + minExpectedExtraPackets,
- packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets);
- assertInRange("ifrxp", ifaceRxDeltaPackets, packetCount + minExpectedExtraPackets,
- packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets);
-
- // Localhost traffic *does* count against total stats.
- // Check the total stats increased after test data transfer over localhost has been made.
- assertTrue("ttxp: " + totalTxPacketsBefore + " -> " + totalTxPacketsAfter,
- totalTxPacketsAfter >= totalTxPacketsBefore + uidTxDeltaPackets);
- assertTrue("trxp: " + totalRxPacketsBefore + " -> " + totalRxPacketsAfter,
- totalRxPacketsAfter >= totalRxPacketsBefore + uidRxDeltaPackets);
- assertTrue("ttxb: " + totalTxBytesBefore + " -> " + totalTxBytesAfter,
- totalTxBytesAfter >= totalTxBytesBefore + uidTxDeltaBytes);
- assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter,
- totalRxBytesAfter >= totalRxBytesBefore + uidRxDeltaBytes);
- assertTrue("iftxp: " + ifaceTxPacketsBefore + " -> " + ifaceTxPacketsAfter,
- totalTxPacketsAfter >= totalTxPacketsBefore + ifaceTxDeltaPackets);
- assertTrue("ifrxp: " + ifaceRxPacketsBefore + " -> " + ifaceRxPacketsAfter,
- totalRxPacketsAfter >= totalRxPacketsBefore + ifaceRxDeltaPackets);
-
- // Localhost traffic should *not* count against mobile stats,
- // There might be some other traffic, but nowhere near 1MB.
- assertInRange("mtxp", mobileTxPacketsAfter, mobileTxPacketsBefore,
- mobileTxPacketsBefore + 500);
- assertInRange("mrxp", mobileRxPacketsAfter, mobileRxPacketsBefore,
- mobileRxPacketsBefore + 500);
- assertInRange("mtxb", mobileTxBytesAfter, mobileTxBytesBefore,
- mobileTxBytesBefore + 200000);
- assertInRange("mrxb", mobileRxBytesAfter, mobileRxBytesBefore,
- mobileRxBytesBefore + 200000);
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/TunUtils.java b/tests/tests/net/src/android/net/cts/TunUtils.java
deleted file mode 100644
index adaba9d..0000000
--- a/tests/tests/net/src/android/net/cts/TunUtils.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import static android.net.cts.PacketUtils.IP4_HDRLEN;
-import static android.net.cts.PacketUtils.IP6_HDRLEN;
-import static android.net.cts.PacketUtils.IPPROTO_ESP;
-import static android.net.cts.PacketUtils.UDP_HDRLEN;
-import static android.system.OsConstants.IPPROTO_UDP;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.os.ParcelFileDescriptor;
-
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.function.Predicate;
-
-public class TunUtils {
- private static final String TAG = TunUtils.class.getSimpleName();
-
- protected static final int IP4_ADDR_OFFSET = 12;
- protected static final int IP4_ADDR_LEN = 4;
- protected static final int IP6_ADDR_OFFSET = 8;
- protected static final int IP6_ADDR_LEN = 16;
- protected static final int IP4_PROTO_OFFSET = 9;
- protected static final int IP6_PROTO_OFFSET = 6;
-
- private static final int DATA_BUFFER_LEN = 4096;
- private static final int TIMEOUT = 1000;
-
- private final List<byte[]> mPackets = new ArrayList<>();
- private final ParcelFileDescriptor mTunFd;
- private final Thread mReaderThread;
-
- public TunUtils(ParcelFileDescriptor tunFd) {
- mTunFd = tunFd;
-
- // Start background reader thread
- mReaderThread =
- new Thread(
- () -> {
- try {
- // Loop will exit and thread will quit when tunFd is closed.
- // Receiving either EOF or an exception will exit this reader loop.
- // FileInputStream in uninterruptable, so there's no good way to
- // ensure that this thread shuts down except upon FD closure.
- while (true) {
- byte[] intercepted = receiveFromTun();
- if (intercepted == null) {
- // Exit once we've hit EOF
- return;
- } else if (intercepted.length > 0) {
- // Only save packet if we've received any bytes.
- synchronized (mPackets) {
- mPackets.add(intercepted);
- mPackets.notifyAll();
- }
- }
- }
- } catch (IOException ignored) {
- // Simply exit this reader thread
- return;
- }
- });
- mReaderThread.start();
- }
-
- private byte[] receiveFromTun() throws IOException {
- FileInputStream in = new FileInputStream(mTunFd.getFileDescriptor());
- byte[] inBytes = new byte[DATA_BUFFER_LEN];
- int bytesRead = in.read(inBytes);
-
- if (bytesRead < 0) {
- return null; // return null for EOF
- } else if (bytesRead >= DATA_BUFFER_LEN) {
- throw new IllegalStateException("Too big packet. Fragmentation unsupported");
- }
- return Arrays.copyOf(inBytes, bytesRead);
- }
-
- private byte[] getFirstMatchingPacket(Predicate<byte[]> verifier, int startIndex) {
- synchronized (mPackets) {
- for (int i = startIndex; i < mPackets.size(); i++) {
- byte[] pkt = mPackets.get(i);
- if (verifier.test(pkt)) {
- return pkt;
- }
- }
- }
- return null;
- }
-
- protected byte[] awaitPacket(Predicate<byte[]> verifier) throws Exception {
- long endTime = System.currentTimeMillis() + TIMEOUT;
- int startIndex = 0;
-
- synchronized (mPackets) {
- while (System.currentTimeMillis() < endTime) {
- final byte[] pkt = getFirstMatchingPacket(verifier, startIndex);
- if (pkt != null) {
- return pkt; // We've found the packet we're looking for.
- }
-
- startIndex = mPackets.size();
-
- // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout
- long waitTimeout = endTime - System.currentTimeMillis();
- if (waitTimeout > 0) {
- mPackets.wait(waitTimeout);
- }
- }
- }
-
- fail("No packet found matching verifier");
- throw new IllegalStateException("Impossible condition; should have thrown in fail()");
- }
-
- public byte[] awaitEspPacketNoPlaintext(
- int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception {
- final byte[] espPkt = awaitPacket(
- (pkt) -> isEspFailIfSpecifiedPlaintextFound(pkt, spi, useEncap, plaintext));
-
- // Validate packet size
- assertEquals(expectedPacketSize, espPkt.length);
-
- return espPkt; // We've found the packet we're looking for.
- }
-
- private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) {
- // Check SPI byte by byte.
- return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff)
- && pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff)
- && pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff)
- && pkt[espOffset + 3] == (byte) (spi & 0xff);
- }
-
- /**
- * Variant of isEsp that also fails the test if the provided plaintext is found
- *
- * @param pkt the packet bytes to verify
- * @param spi the expected SPI to look for
- * @param encap whether encap was enabled, and the packet has a UDP header
- * @param plaintext the plaintext packet before outbound encryption, which MUST not appear in
- * the provided packet.
- */
- private static boolean isEspFailIfSpecifiedPlaintextFound(
- byte[] pkt, int spi, boolean encap, byte[] plaintext) {
- if (Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) != -1) {
- fail("Banned plaintext packet found");
- }
-
- return isEsp(pkt, spi, encap);
- }
-
- private static boolean isEsp(byte[] pkt, int spi, boolean encap) {
- if (isIpv6(pkt)) {
- // IPv6 UDP encap not supported by kernels; assume non-encap.
- return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi);
- } else {
- // Use default IPv4 header length (assuming no options)
- if (encap) {
- return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP
- && isSpiEqual(pkt, IP4_HDRLEN + UDP_HDRLEN, spi);
- } else {
- return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP4_HDRLEN, spi);
- }
- }
- }
-
- public static boolean isIpv6(byte[] pkt) {
- // First nibble shows IP version. 0x60 for IPv6
- return (pkt[0] & (byte) 0xF0) == (byte) 0x60;
- }
-
- private static byte[] getReflectedPacket(byte[] pkt) {
- byte[] reflected = Arrays.copyOf(pkt, pkt.length);
-
- if (isIpv6(pkt)) {
- // Set reflected packet's dst to that of the original's src
- System.arraycopy(
- pkt, // src
- IP6_ADDR_OFFSET + IP6_ADDR_LEN, // src offset
- reflected, // dst
- IP6_ADDR_OFFSET, // dst offset
- IP6_ADDR_LEN); // len
- // Set reflected packet's src IP to that of the original's dst IP
- System.arraycopy(
- pkt, // src
- IP6_ADDR_OFFSET, // src offset
- reflected, // dst
- IP6_ADDR_OFFSET + IP6_ADDR_LEN, // dst offset
- IP6_ADDR_LEN); // len
- } else {
- // Set reflected packet's dst to that of the original's src
- System.arraycopy(
- pkt, // src
- IP4_ADDR_OFFSET + IP4_ADDR_LEN, // src offset
- reflected, // dst
- IP4_ADDR_OFFSET, // dst offset
- IP4_ADDR_LEN); // len
- // Set reflected packet's src IP to that of the original's dst IP
- System.arraycopy(
- pkt, // src
- IP4_ADDR_OFFSET, // src offset
- reflected, // dst
- IP4_ADDR_OFFSET + IP4_ADDR_LEN, // dst offset
- IP4_ADDR_LEN); // len
- }
- return reflected;
- }
-
- /** Takes all captured packets, flips the src/dst, and re-injects them. */
- public void reflectPackets() throws IOException {
- synchronized (mPackets) {
- for (byte[] pkt : mPackets) {
- injectPacket(getReflectedPacket(pkt));
- }
- }
- }
-
- public void injectPacket(byte[] pkt) throws IOException {
- FileOutputStream out = new FileOutputStream(mTunFd.getFileDescriptor());
- out.write(pkt);
- out.flush();
- }
-
- /** Resets the intercepted packets. */
- public void reset() throws IOException {
- synchronized (mPackets) {
- mPackets.clear();
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/UriTest.java b/tests/tests/net/src/android/net/cts/UriTest.java
deleted file mode 100644
index 40b8fb7..0000000
--- a/tests/tests/net/src/android/net/cts/UriTest.java
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.content.ContentUris;
-import android.net.Uri;
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-import java.io.File;
-import java.util.Arrays;
-import java.util.ArrayList;
-
-public class UriTest extends AndroidTestCase {
- public void testParcelling() {
- parcelAndUnparcel(Uri.parse("foo:bob%20lee"));
- parcelAndUnparcel(Uri.fromParts("foo", "bob lee", "fragment"));
- parcelAndUnparcel(new Uri.Builder()
- .scheme("http")
- .authority("crazybob.org")
- .path("/rss/")
- .encodedQuery("a=b")
- .fragment("foo")
- .build());
- }
-
- private void parcelAndUnparcel(Uri u) {
- Parcel p = Parcel.obtain();
- Uri.writeToParcel(p, u);
- p.setDataPosition(0);
- assertEquals(u, Uri.CREATOR.createFromParcel(p));
-
- p.setDataPosition(0);
- u = u.buildUpon().build();
- Uri.writeToParcel(p, u);
- p.setDataPosition(0);
- assertEquals(u, Uri.CREATOR.createFromParcel(p));
- }
-
- public void testBuildUpon() {
- Uri u = Uri.parse("bob:lee").buildUpon().scheme("robert").build();
- assertEquals("robert", u.getScheme());
- assertEquals("lee", u.getEncodedSchemeSpecificPart());
- assertEquals("lee", u.getSchemeSpecificPart());
- assertNull(u.getQuery());
- assertNull(u.getPath());
- assertNull(u.getAuthority());
- assertNull(u.getHost());
-
- Uri a = Uri.fromParts("foo", "bar", "tee");
- Uri b = a.buildUpon().fragment("new").build();
- assertEquals("new", b.getFragment());
- assertEquals("bar", b.getSchemeSpecificPart());
- assertEquals("foo", b.getScheme());
- a = new Uri.Builder()
- .scheme("foo")
- .encodedOpaquePart("bar")
- .fragment("tee")
- .build();
- b = a.buildUpon().fragment("new").build();
- assertEquals("new", b.getFragment());
- assertEquals("bar", b.getSchemeSpecificPart());
- assertEquals("foo", b.getScheme());
-
- a = Uri.fromParts("scheme", "[2001:db8::dead:e1f]/foo", "bar");
- b = a.buildUpon().fragment("qux").build();
- assertEquals("qux", b.getFragment());
- assertEquals("[2001:db8::dead:e1f]/foo", b.getSchemeSpecificPart());
- assertEquals("scheme", b.getScheme());
- }
-
- public void testStringUri() {
- assertEquals("bob lee",
- Uri.parse("foo:bob%20lee").getSchemeSpecificPart());
- assertEquals("bob%20lee",
- Uri.parse("foo:bob%20lee").getEncodedSchemeSpecificPart());
-
- assertEquals("/bob%20lee",
- Uri.parse("foo:/bob%20lee").getEncodedPath());
- assertNull(Uri.parse("foo:bob%20lee").getPath());
-
- assertEquals("bob%20lee",
- Uri.parse("foo:?bob%20lee").getEncodedQuery());
- assertNull(Uri.parse("foo:bob%20lee").getEncodedQuery());
- assertNull(Uri.parse("foo:bar#?bob%20lee").getQuery());
-
- assertEquals("bob%20lee",
- Uri.parse("foo:#bob%20lee").getEncodedFragment());
-
- Uri uri = Uri.parse("http://localhost:42");
- assertEquals("localhost", uri.getHost());
- assertEquals(42, uri.getPort());
-
- uri = Uri.parse("http://bob@localhost:42");
- assertEquals("bob", uri.getUserInfo());
- assertEquals("localhost", uri.getHost());
- assertEquals(42, uri.getPort());
-
- uri = Uri.parse("http://bob%20lee@localhost:42");
- assertEquals("bob lee", uri.getUserInfo());
- assertEquals("bob%20lee", uri.getEncodedUserInfo());
-
- uri = Uri.parse("http://localhost");
- assertEquals("localhost", uri.getHost());
- assertEquals(-1, uri.getPort());
-
- uri = Uri.parse("http://a:a@example.com:a@example2.com/path");
- assertEquals("a:a@example.com:a@example2.com", uri.getAuthority());
- assertEquals("example2.com", uri.getHost());
- assertEquals(-1, uri.getPort());
- assertEquals("/path", uri.getPath());
-
- uri = Uri.parse("http://a.foo.com\\.example.com/path");
- assertEquals("a.foo.com", uri.getHost());
- assertEquals(-1, uri.getPort());
- assertEquals("\\.example.com/path", uri.getPath());
-
- uri = Uri.parse("https://[2001:db8::dead:e1f]/foo");
- assertEquals("[2001:db8::dead:e1f]", uri.getAuthority());
- assertNull(uri.getUserInfo());
- assertEquals("[2001:db8::dead:e1f]", uri.getHost());
- assertEquals(-1, uri.getPort());
- assertEquals("/foo", uri.getPath());
- assertEquals(null, uri.getFragment());
- assertEquals("//[2001:db8::dead:e1f]/foo", uri.getSchemeSpecificPart());
-
- uri = Uri.parse("https://[2001:db8::dead:e1f]/#foo");
- assertEquals("[2001:db8::dead:e1f]", uri.getAuthority());
- assertNull(uri.getUserInfo());
- assertEquals("[2001:db8::dead:e1f]", uri.getHost());
- assertEquals(-1, uri.getPort());
- assertEquals("/", uri.getPath());
- assertEquals("foo", uri.getFragment());
- assertEquals("//[2001:db8::dead:e1f]/", uri.getSchemeSpecificPart());
-
- uri = Uri.parse(
- "https://some:user@[2001:db8::dead:e1f]:1234/foo?corge=thud&corge=garp#bar");
- assertEquals("some:user@[2001:db8::dead:e1f]:1234", uri.getAuthority());
- assertEquals("some:user", uri.getUserInfo());
- assertEquals("[2001:db8::dead:e1f]", uri.getHost());
- assertEquals(1234, uri.getPort());
- assertEquals("/foo", uri.getPath());
- assertEquals("bar", uri.getFragment());
- assertEquals("//some:user@[2001:db8::dead:e1f]:1234/foo?corge=thud&corge=garp",
- uri.getSchemeSpecificPart());
- assertEquals("corge=thud&corge=garp", uri.getQuery());
- assertEquals("thud", uri.getQueryParameter("corge"));
- assertEquals(Arrays.asList("thud", "garp"), uri.getQueryParameters("corge"));
- }
-
- public void testCompareTo() {
- Uri a = Uri.parse("foo:a");
- Uri b = Uri.parse("foo:b");
- Uri b2 = Uri.parse("foo:b");
-
- assertTrue(a.compareTo(b) < 0);
- assertTrue(b.compareTo(a) > 0);
- assertEquals(0, b.compareTo(b2));
- }
-
- public void testEqualsAndHashCode() {
- Uri a = Uri.parse("http://crazybob.org/test/?foo=bar#tee");
-
- Uri b = new Uri.Builder()
- .scheme("http")
- .authority("crazybob.org")
- .path("/test/")
- .encodedQuery("foo=bar")
- .fragment("tee")
- .build();
-
- // Try alternate builder methods.
- Uri c = new Uri.Builder()
- .scheme("http")
- .encodedAuthority("crazybob.org")
- .encodedPath("/test/")
- .encodedQuery("foo=bar")
- .encodedFragment("tee")
- .build();
-
- assertFalse(Uri.EMPTY.equals(null));
- assertEquals(a, b);
- assertEquals(b, c);
- assertEquals(c, a);
- assertEquals(a.hashCode(), b.hashCode());
- assertEquals(b.hashCode(), c.hashCode());
- }
-
- public void testEncodeAndDecode() {
- String encoded = Uri.encode("Bob:/", "/");
- assertEquals(-1, encoded.indexOf(':'));
- assertTrue(encoded.indexOf('/') > -1);
- assertEncodeDecodeRoundtripExact(null);
- assertEncodeDecodeRoundtripExact("");
- assertEncodeDecodeRoundtripExact("Bob");
- assertEncodeDecodeRoundtripExact(":Bob");
- assertEncodeDecodeRoundtripExact("::Bob");
- assertEncodeDecodeRoundtripExact("Bob::Lee");
- assertEncodeDecodeRoundtripExact("Bob:Lee");
- assertEncodeDecodeRoundtripExact("Bob::");
- assertEncodeDecodeRoundtripExact("Bob:");
- assertEncodeDecodeRoundtripExact("::Bob::");
- assertEncodeDecodeRoundtripExact("https:/some:user@[2001:db8::dead:e1f]:1234/foo#bar");
- }
-
- private static void assertEncodeDecodeRoundtripExact(String s) {
- assertEquals(s, Uri.decode(Uri.encode(s, null)));
- }
-
- public void testDecode_emptyString_returnsEmptyString() {
- assertEquals("", Uri.decode(""));
- }
-
- public void testDecode_null_returnsNull() {
- assertNull(Uri.decode(null));
- }
-
- public void testDecode_wrongHexDigit() {
- // %p in the end.
- assertEquals("ab/$\u0102%\u0840\uFFFD\u0000", Uri.decode("ab%2f$%C4%82%25%e0%a1%80%p"));
- }
-
- public void testDecode_secondHexDigitWrong() {
- // %1p in the end.
- assertEquals("ab/$\u0102%\u0840\uFFFD\u0001", Uri.decode("ab%2f$%c4%82%25%e0%a1%80%1p"));
- }
-
- public void testDecode_endsWithPercent_appendsUnknownCharacter() {
- // % in the end.
- assertEquals("ab/$\u0102%\u0840\uFFFD", Uri.decode("ab%2f$%c4%82%25%e0%a1%80%"));
- }
-
- public void testDecode_plusNotConverted() {
- assertEquals("ab/$\u0102%+\u0840", Uri.decode("ab%2f$%c4%82%25+%e0%a1%80"));
- }
-
- // Last character needs decoding (make sure we are flushing the buffer with chars to decode).
- public void testDecode_lastCharacter() {
- assertEquals("ab/$\u0102%\u0840", Uri.decode("ab%2f$%c4%82%25%e0%a1%80"));
- }
-
- // Check that a second row of encoded characters is decoded properly (internal buffers are
- // reset properly).
- public void testDecode_secondRowOfEncoded() {
- assertEquals("ab/$\u0102%\u0840aa\u0840",
- Uri.decode("ab%2f$%c4%82%25%e0%a1%80aa%e0%a1%80"));
- }
-
- public void testFromFile() {
- File f = new File("/tmp/bob");
- Uri uri = Uri.fromFile(f);
- assertEquals("file:///tmp/bob", uri.toString());
- try {
- Uri.fromFile(null);
- fail("testFile fail");
- } catch (NullPointerException e) {}
- }
-
- public void testQueryParameters() {
- Uri uri = Uri.parse("content://user");
- assertEquals(null, uri.getQueryParameter("a"));
-
- uri = uri.buildUpon().appendQueryParameter("a", "b").build();
- assertEquals("b", uri.getQueryParameter("a"));
-
- uri = uri.buildUpon().appendQueryParameter("a", "b2").build();
- assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a"));
-
- uri = uri.buildUpon().appendQueryParameter("c", "d").build();
- assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a"));
- assertEquals("d", uri.getQueryParameter("c"));
- }
-
- public void testPathOperations() {
- Uri uri = Uri.parse("content://user/a/b");
-
- assertEquals(2, uri.getPathSegments().size());
- assertEquals("a", uri.getPathSegments().get(0));
- assertEquals("b", uri.getPathSegments().get(1));
- assertEquals("b", uri.getLastPathSegment());
-
- Uri first = uri;
- uri = uri.buildUpon().appendPath("c").build();
- assertEquals(3, uri.getPathSegments().size());
- assertEquals("c", uri.getPathSegments().get(2));
- assertEquals("c", uri.getLastPathSegment());
- assertEquals("content://user/a/b/c", uri.toString());
-
- uri = ContentUris.withAppendedId(uri, 100);
- assertEquals(4, uri.getPathSegments().size());
- assertEquals("100", uri.getPathSegments().get(3));
- assertEquals("100", uri.getLastPathSegment());
- assertEquals(100, ContentUris.parseId(uri));
- assertEquals("content://user/a/b/c/100", uri.toString());
-
- // Make sure the original URI is still intact.
- assertEquals(2, first.getPathSegments().size());
- assertEquals("b", first.getLastPathSegment());
-
- try {
- first.getPathSegments().get(2);
- fail("test path operations");
- } catch (IndexOutOfBoundsException e) {}
-
- assertEquals(null, Uri.EMPTY.getLastPathSegment());
-
- Uri withC = Uri.parse("foo:/a/b/").buildUpon().appendPath("c").build();
- assertEquals("/a/b/c", withC.getPath());
- }
-
- public void testOpaqueUri() {
- Uri uri = Uri.parse("mailto:nobody");
- testOpaqueUri(uri);
-
- uri = uri.buildUpon().build();
- testOpaqueUri(uri);
-
- uri = Uri.fromParts("mailto", "nobody", null);
- testOpaqueUri(uri);
-
- uri = uri.buildUpon().build();
- testOpaqueUri(uri);
-
- uri = new Uri.Builder()
- .scheme("mailto")
- .opaquePart("nobody")
- .build();
- testOpaqueUri(uri);
-
- uri = uri.buildUpon().build();
- testOpaqueUri(uri);
- }
-
- private void testOpaqueUri(Uri uri) {
- assertEquals("mailto", uri.getScheme());
- assertEquals("nobody", uri.getSchemeSpecificPart());
- assertEquals("nobody", uri.getEncodedSchemeSpecificPart());
-
- assertNull(uri.getFragment());
- assertTrue(uri.isAbsolute());
- assertTrue(uri.isOpaque());
- assertFalse(uri.isRelative());
- assertFalse(uri.isHierarchical());
-
- assertNull(uri.getAuthority());
- assertNull(uri.getEncodedAuthority());
- assertNull(uri.getPath());
- assertNull(uri.getEncodedPath());
- assertNull(uri.getUserInfo());
- assertNull(uri.getEncodedUserInfo());
- assertNull(uri.getQuery());
- assertNull(uri.getEncodedQuery());
- assertNull(uri.getHost());
- assertEquals(-1, uri.getPort());
-
- assertTrue(uri.getPathSegments().isEmpty());
- assertNull(uri.getLastPathSegment());
-
- assertEquals("mailto:nobody", uri.toString());
-
- Uri withFragment = uri.buildUpon().fragment("top").build();
- assertEquals("mailto:nobody#top", withFragment.toString());
- }
-
- public void testHierarchicalUris() {
- testHierarchical("http", "google.com", "/p1/p2", "query", "fragment");
- testHierarchical("file", null, "/p1/p2", null, null);
- testHierarchical("content", "contact", "/p1/p2", null, null);
- testHierarchical("http", "google.com", "/p1/p2", null, "fragment");
- testHierarchical("http", "google.com", "", null, "fragment");
- testHierarchical("http", "google.com", "", "query", "fragment");
- testHierarchical("http", "google.com", "", "query", null);
- testHierarchical("http", null, "/", "query", null);
- }
-
- private static void testHierarchical(String scheme, String authority,
- String path, String query, String fragment) {
- StringBuilder sb = new StringBuilder();
-
- if (authority != null) {
- sb.append("//").append(authority);
- }
- if (path != null) {
- sb.append(path);
- }
- if (query != null) {
- sb.append('?').append(query);
- }
-
- String ssp = sb.toString();
-
- if (scheme != null) {
- sb.insert(0, scheme + ":");
- }
- if (fragment != null) {
- sb.append('#').append(fragment);
- }
-
- String uriString = sb.toString();
-
- Uri uri = Uri.parse(uriString);
-
- // Run these twice to test caching.
- compareHierarchical(
- uriString, ssp, uri, scheme, authority, path, query, fragment);
- compareHierarchical(
- uriString, ssp, uri, scheme, authority, path, query, fragment);
-
- // Test rebuilt version.
- uri = uri.buildUpon().build();
-
- // Run these twice to test caching.
- compareHierarchical(
- uriString, ssp, uri, scheme, authority, path, query, fragment);
- compareHierarchical(
- uriString, ssp, uri, scheme, authority, path, query, fragment);
-
- // The decoded and encoded versions of the inputs are all the same.
- // We'll test the actual encoding decoding separately.
-
- // Test building with encoded versions.
- Uri built = new Uri.Builder()
- .scheme(scheme)
- .encodedAuthority(authority)
- .encodedPath(path)
- .encodedQuery(query)
- .encodedFragment(fragment)
- .build();
-
- compareHierarchical(
- uriString, ssp, built, scheme, authority, path, query, fragment);
- compareHierarchical(
- uriString, ssp, built, scheme, authority, path, query, fragment);
-
- // Test building with decoded versions.
- built = new Uri.Builder()
- .scheme(scheme)
- .authority(authority)
- .path(path)
- .query(query)
- .fragment(fragment)
- .build();
-
- compareHierarchical(
- uriString, ssp, built, scheme, authority, path, query, fragment);
- compareHierarchical(
- uriString, ssp, built, scheme, authority, path, query, fragment);
-
- // Rebuild.
- built = built.buildUpon().build();
-
- compareHierarchical(
- uriString, ssp, built, scheme, authority, path, query, fragment);
- compareHierarchical(
- uriString, ssp, built, scheme, authority, path, query, fragment);
- }
-
- private static void compareHierarchical(String uriString, String ssp,
- Uri uri,
- String scheme, String authority, String path, String query,
- String fragment) {
- assertEquals(scheme, uri.getScheme());
- assertEquals(authority, uri.getAuthority());
- assertEquals(authority, uri.getEncodedAuthority());
- assertEquals(path, uri.getPath());
- assertEquals(path, uri.getEncodedPath());
- assertEquals(query, uri.getQuery());
- assertEquals(query, uri.getEncodedQuery());
- assertEquals(fragment, uri.getFragment());
- assertEquals(fragment, uri.getEncodedFragment());
- assertEquals(ssp, uri.getSchemeSpecificPart());
-
- if (scheme != null) {
- assertTrue(uri.isAbsolute());
- assertFalse(uri.isRelative());
- } else {
- assertFalse(uri.isAbsolute());
- assertTrue(uri.isRelative());
- }
-
- assertFalse(uri.isOpaque());
- assertTrue(uri.isHierarchical());
- assertEquals(uriString, uri.toString());
- }
-
- public void testNormalizeScheme() {
- assertEquals(Uri.parse(""), Uri.parse("").normalizeScheme());
- assertEquals(Uri.parse("http://www.android.com"),
- Uri.parse("http://www.android.com").normalizeScheme());
- assertEquals(Uri.parse("http://USER@WWW.ANDROID.COM:100/ABOUT?foo=blah@bar=bleh#c"),
- Uri.parse("HTTP://USER@WWW.ANDROID.COM:100/ABOUT?foo=blah@bar=bleh#c")
- .normalizeScheme());
- }
-
- public void testToSafeString_tel() {
- checkToSafeString("tel:xxxxxx", "tel:Google");
- checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");
- checkToSafeString("tEl:xxx.xxx-xxxx", "tEl:123.456-7890");
- }
-
- public void testToSafeString_sip() {
- checkToSafeString("sip:xxxxxxx@xxxxxxx.xxxxxxxx", "sip:android@android.com:1234");
- checkToSafeString("sIp:xxxxxxx@xxxxxxx.xxx", "sIp:android@android.com");
- }
-
- public void testToSafeString_sms() {
- checkToSafeString("sms:xxxxxx", "sms:123abc");
- checkToSafeString("smS:xxx.xxx-xxxx", "smS:123.456-7890");
- }
-
- public void testToSafeString_smsto() {
- checkToSafeString("smsto:xxxxxx", "smsto:123abc");
- checkToSafeString("SMSTo:xxx.xxx-xxxx", "SMSTo:123.456-7890");
- }
-
- public void testToSafeString_mailto() {
- checkToSafeString("mailto:xxxxxxx@xxxxxxx.xxx", "mailto:android@android.com");
- checkToSafeString("Mailto:xxxxxxx@xxxxxxx.xxxxxxxxxx",
- "Mailto:android@android.com/secret");
- }
-
- public void testToSafeString_nfc() {
- checkToSafeString("nfc:xxxxxx", "nfc:123abc");
- checkToSafeString("nfc:xxx.xxx-xxxx", "nfc:123.456-7890");
- checkToSafeString("nfc:xxxxxxx@xxxxxxx.xxx", "nfc:android@android.com");
- }
-
- public void testToSafeString_http() {
- checkToSafeString("http://www.android.com/...", "http://www.android.com");
- checkToSafeString("HTTP://www.android.com/...", "HTTP://www.android.com");
- checkToSafeString("http://www.android.com/...", "http://www.android.com/");
- checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param");
- checkToSafeString("http://www.android.com/...",
- "http://user:pwd@www.android.com/secretUrl?param");
- checkToSafeString("http://www.android.com/...",
- "http://user@www.android.com/secretUrl?param");
- checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param");
- checkToSafeString("http:///...", "http:///path?param");
- checkToSafeString("http:///...", "http://");
- checkToSafeString("http://:12345/...", "http://:12345/");
- }
-
- public void testToSafeString_https() {
- checkToSafeString("https://www.android.com/...", "https://www.android.com/secretUrl?param");
- checkToSafeString("https://www.android.com:8443/...",
- "https://user:pwd@www.android.com:8443/secretUrl?param");
- checkToSafeString("https://www.android.com/...", "https://user:pwd@www.android.com");
- checkToSafeString("Https://www.android.com/...", "Https://user:pwd@www.android.com");
- }
-
- public void testToSafeString_ftp() {
- checkToSafeString("ftp://ftp.android.com/...", "ftp://ftp.android.com/");
- checkToSafeString("ftP://ftp.android.com/...", "ftP://anonymous@ftp.android.com/");
- checkToSafeString("ftp://ftp.android.com:2121/...",
- "ftp://root:love@ftp.android.com:2121/");
- }
-
- public void testToSafeString_rtsp() {
- checkToSafeString("rtsp://rtsp.android.com/...", "rtsp://rtsp.android.com/");
- checkToSafeString("rtsp://rtsp.android.com/...", "rtsp://rtsp.android.com/video.mov");
- checkToSafeString("rtsp://rtsp.android.com/...", "rtsp://rtsp.android.com/video.mov?param");
- checkToSafeString("RtsP://rtsp.android.com/...", "RtsP://anonymous@rtsp.android.com/");
- checkToSafeString("rtsp://rtsp.android.com:2121/...",
- "rtsp://username:password@rtsp.android.com:2121/");
- }
-
- public void testToSafeString_notSupport() {
- checkToSafeString("unsupported://ajkakjah/askdha/secret?secret",
- "unsupported://ajkakjah/askdha/secret?secret");
- checkToSafeString("unsupported:ajkakjah/askdha/secret?secret",
- "unsupported:ajkakjah/askdha/secret?secret");
- }
-
- private void checkToSafeString(String expectedSafeString, String original) {
- assertEquals(expectedSafeString, Uri.parse(original).toSafeString());
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/Uri_BuilderTest.java b/tests/tests/net/src/android/net/cts/Uri_BuilderTest.java
deleted file mode 100644
index 4088d82..0000000
--- a/tests/tests/net/src/android/net/cts/Uri_BuilderTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import junit.framework.TestCase;
-import android.net.Uri.Builder;
-import android.net.Uri;
-
-public class Uri_BuilderTest extends TestCase {
- public void testBuilderOperations() {
- Uri uri = Uri.parse("http://google.com/p1?query#fragment");
- Builder builder = uri.buildUpon();
- uri = builder.appendPath("p2").build();
- assertEquals("http", uri.getScheme());
- assertEquals("google.com", uri.getAuthority());
- assertEquals("/p1/p2", uri.getPath());
- assertEquals("query", uri.getQuery());
- assertEquals("fragment", uri.getFragment());
- assertEquals(uri.toString(), builder.toString());
-
- uri = Uri.parse("mailto:nobody");
- builder = uri.buildUpon();
- uri = builder.build();
- assertEquals("mailto", uri.getScheme());
- assertEquals("nobody", uri.getSchemeSpecificPart());
- assertEquals(uri.toString(), builder.toString());
-
- uri = new Uri.Builder()
- .scheme("http")
- .encodedAuthority("google.com")
- .encodedPath("/p1")
- .appendEncodedPath("p2")
- .encodedQuery("query")
- .appendQueryParameter("query2", null)
- .encodedFragment("fragment")
- .build();
- assertEquals("http", uri.getScheme());
- assertEquals("google.com", uri.getEncodedAuthority());
- assertEquals("/p1/p2", uri.getEncodedPath());
- assertEquals("query&query2=null", uri.getEncodedQuery());
- assertEquals("fragment", uri.getEncodedFragment());
-
- uri = new Uri.Builder()
- .scheme("mailto")
- .encodedOpaquePart("nobody")
- .build();
- assertEquals("mailto", uri.getScheme());
- assertEquals("nobody", uri.getEncodedSchemeSpecificPart());
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/UrlQuerySanitizerTest.java b/tests/tests/net/src/android/net/cts/UrlQuerySanitizerTest.java
deleted file mode 100644
index 5a70928..0000000
--- a/tests/tests/net/src/android/net/cts/UrlQuerySanitizerTest.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-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 android.net.UrlQuerySanitizer;
-import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer;
-import android.net.UrlQuerySanitizer.ParameterValuePair;
-import android.net.UrlQuerySanitizer.ValueSanitizer;
-import android.os.Build;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-import java.util.Set;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class UrlQuerySanitizerTest {
- @Rule
- public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
-
- private static final int ALL_OK = IllegalCharacterValueSanitizer.ALL_OK;
-
- // URL for test.
- private static final String TEST_URL = "http://example.com/?name=Joe+User&age=20&height=175";
-
- // Default sanitizer's change when "+".
- private static final String EXPECTED_UNDERLINE_NAME = "Joe_User";
-
- // IllegalCharacterValueSanitizer sanitizer's change when "+".
- private static final String EXPECTED_SPACE_NAME = "Joe User";
- private static final String EXPECTED_AGE = "20";
- private static final String EXPECTED_HEIGHT = "175";
- private static final String NAME = "name";
- private static final String AGE = "age";
- private static final String HEIGHT = "height";
-
- @Test
- public void testUrlQuerySanitizer() {
- MockUrlQuerySanitizer uqs = new MockUrlQuerySanitizer();
- assertFalse(uqs.getAllowUnregisteredParamaters());
-
- final String query = "book=thinking in java&price=108";
- final String book = "book";
- final String bookName = "thinking in java";
- final String price = "price";
- final String bookPrice = "108";
- final String notExistPar = "notExistParameter";
- uqs.registerParameters(new String[]{book, price}, UrlQuerySanitizer.getSpaceLegal());
- uqs.parseQuery(query);
- assertTrue(uqs.hasParameter(book));
- assertTrue(uqs.hasParameter(price));
- assertFalse(uqs.hasParameter(notExistPar));
- assertEquals(bookName, uqs.getValue(book));
- assertEquals(bookPrice, uqs.getValue(price));
- assertNull(uqs.getValue(notExistPar));
- uqs.clear();
- assertFalse(uqs.hasParameter(book));
- assertFalse(uqs.hasParameter(price));
-
- uqs.parseEntry(book, bookName);
- assertTrue(uqs.hasParameter(book));
- assertEquals(bookName, uqs.getValue(book));
- uqs.parseEntry(price, bookPrice);
- assertTrue(uqs.hasParameter(price));
- assertEquals(bookPrice, uqs.getValue(price));
- assertFalse(uqs.hasParameter(notExistPar));
- assertNull(uqs.getValue(notExistPar));
-
- uqs = new MockUrlQuerySanitizer(TEST_URL);
- assertTrue(uqs.getAllowUnregisteredParamaters());
-
- assertTrue(uqs.hasParameter(NAME));
- assertTrue(uqs.hasParameter(AGE));
- assertTrue(uqs.hasParameter(HEIGHT));
- assertFalse(uqs.hasParameter(notExistPar));
-
- assertEquals(EXPECTED_UNDERLINE_NAME, uqs.getValue(NAME));
- assertEquals(EXPECTED_AGE, uqs.getValue(AGE));
- assertEquals(EXPECTED_HEIGHT, uqs.getValue(HEIGHT));
- assertNull(uqs.getValue(notExistPar));
-
- final int ContainerLen = 3;
- Set<String> urlSet = uqs.getParameterSet();
- assertEquals(ContainerLen, urlSet.size());
- assertTrue(urlSet.contains(NAME));
- assertTrue(urlSet.contains(AGE));
- assertTrue(urlSet.contains(HEIGHT));
- assertFalse(urlSet.contains(notExistPar));
-
- List<ParameterValuePair> urlList = uqs.getParameterList();
- assertEquals(ContainerLen, urlList.size());
- ParameterValuePair pvp = urlList.get(0);
- assertEquals(NAME, pvp.mParameter);
- assertEquals(EXPECTED_UNDERLINE_NAME, pvp.mValue);
- pvp = urlList.get(1);
- assertEquals(AGE, pvp.mParameter);
- assertEquals(EXPECTED_AGE, pvp.mValue);
- pvp = urlList.get(2);
- assertEquals(HEIGHT, pvp.mParameter);
- assertEquals(EXPECTED_HEIGHT, pvp.mValue);
-
- assertFalse(uqs.getPreferFirstRepeatedParameter());
- uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT + 1);
- assertEquals(ContainerLen, urlSet.size());
- assertEquals(ContainerLen + 1, urlList.size());
- assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT));
-
- uqs.setPreferFirstRepeatedParameter(true);
- assertTrue(uqs.getPreferFirstRepeatedParameter());
- uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT);
- assertEquals(ContainerLen, urlSet.size());
- assertEquals(ContainerLen + 2, urlList.size());
- assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT));
-
- uqs.registerParameter(NAME, null);
- assertNull(uqs.getValueSanitizer(NAME));
- assertNotNull(uqs.getEffectiveValueSanitizer(NAME));
-
- uqs.setAllowUnregisteredParamaters(false);
- assertFalse(uqs.getAllowUnregisteredParamaters());
- uqs.registerParameter(NAME, null);
- assertNull(uqs.getEffectiveValueSanitizer(NAME));
-
- ValueSanitizer vs = new IllegalCharacterValueSanitizer(ALL_OK);
- uqs.registerParameter(NAME, vs);
- uqs.parseUrl(TEST_URL);
- assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME));
- assertNotSame(EXPECTED_AGE, uqs.getValue(AGE));
-
- String[] register = {NAME, AGE};
- uqs.registerParameters(register, vs);
- uqs.parseUrl(TEST_URL);
- assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME));
- assertEquals(EXPECTED_AGE, uqs.getValue(AGE));
- assertNotSame(EXPECTED_HEIGHT, uqs.getValue(HEIGHT));
-
- uqs.setUnregisteredParameterValueSanitizer(vs);
- assertEquals(vs, uqs.getUnregisteredParameterValueSanitizer());
-
- vs = UrlQuerySanitizer.getAllIllegal();
- assertEquals("Joe_User", vs.sanitize("Joe<User"));
- vs = UrlQuerySanitizer.getAllButNulAndAngleBracketsLegal();
- assertEquals("Joe User", vs.sanitize("Joe<>\0User"));
- vs = UrlQuerySanitizer.getAllButNulLegal();
- assertEquals("Joe User", vs.sanitize("Joe\0User"));
- vs = UrlQuerySanitizer.getAllButWhitespaceLegal();
- assertEquals("Joe_User", vs.sanitize("Joe User"));
- vs = UrlQuerySanitizer.getAmpAndSpaceLegal();
- assertEquals("Joe User&", vs.sanitize("Joe User&"));
- vs = UrlQuerySanitizer.getAmpLegal();
- assertEquals("Joe_User&", vs.sanitize("Joe User&"));
- vs = UrlQuerySanitizer.getSpaceLegal();
- assertEquals("Joe User ", vs.sanitize("Joe User&"));
- vs = UrlQuerySanitizer.getUrlAndSpaceLegal();
- assertEquals("Joe User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'"));
- vs = UrlQuerySanitizer.getUrlLegal();
- assertEquals("Joe_User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'"));
-
- String escape = "Joe";
- assertEquals(escape, uqs.unescape(escape));
- String expectedPlus = "Joe User";
- String expectedPercentSignHex = "title=" + Character.toString((char)181);
- String initialPlus = "Joe+User";
- String initialPercentSign = "title=%B5";
- assertEquals(expectedPlus, uqs.unescape(initialPlus));
- assertEquals(expectedPercentSignHex, uqs.unescape(initialPercentSign));
- String expectedPlusThenPercentSign = "Joe Random, User";
- String plusThenPercentSign = "Joe+Random%2C%20User";
- assertEquals(expectedPlusThenPercentSign, uqs.unescape(plusThenPercentSign));
- String expectedPercentSignThenPlus = "Joe, Random User";
- String percentSignThenPlus = "Joe%2C+Random+User";
- assertEquals(expectedPercentSignThenPlus, uqs.unescape(percentSignThenPlus));
-
- assertTrue(uqs.decodeHexDigit('0') >= 0);
- assertTrue(uqs.decodeHexDigit('b') >= 0);
- assertTrue(uqs.decodeHexDigit('F') >= 0);
- assertTrue(uqs.decodeHexDigit('$') < 0);
-
- assertTrue(uqs.isHexDigit('0'));
- assertTrue(uqs.isHexDigit('b'));
- assertTrue(uqs.isHexDigit('F'));
- assertFalse(uqs.isHexDigit('$'));
-
- uqs.clear();
- assertEquals(0, urlSet.size());
- assertEquals(0, urlList.size());
-
- uqs.setPreferFirstRepeatedParameter(true);
- assertTrue(uqs.getPreferFirstRepeatedParameter());
- uqs.setPreferFirstRepeatedParameter(false);
- assertFalse(uqs.getPreferFirstRepeatedParameter());
-
- UrlQuerySanitizer uq = new UrlQuerySanitizer();
- uq.setPreferFirstRepeatedParameter(true);
- final String PARA_ANSWER = "answer";
- uq.registerParameter(PARA_ANSWER, new MockValueSanitizer());
- uq.parseUrl("http://www.google.com/question?answer=13&answer=42");
- assertEquals("13", uq.getValue(PARA_ANSWER));
-
- uq.setPreferFirstRepeatedParameter(false);
- uq.parseQuery("http://www.google.com/question?answer=13&answer=42");
- assertEquals("42", uq.getValue(PARA_ANSWER));
-
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q) // Only fixed in R
- public void testScriptUrlOk_73822755() {
- ValueSanitizer sanitizer = new UrlQuerySanitizer.IllegalCharacterValueSanitizer(
- UrlQuerySanitizer.IllegalCharacterValueSanitizer.SCRIPT_URL_OK);
- assertEquals("javascript:alert()", sanitizer.sanitize("javascript:alert()"));
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q) // Only fixed in R
- public void testScriptUrlBlocked_73822755() {
- ValueSanitizer sanitizer = UrlQuerySanitizer.getUrlAndSpaceLegal();
- assertEquals("", sanitizer.sanitize("javascript:alert()"));
- }
-
- private static class MockValueSanitizer implements ValueSanitizer{
-
- public String sanitize(String value) {
- return value;
- }
- }
-
- class MockUrlQuerySanitizer extends UrlQuerySanitizer {
- public MockUrlQuerySanitizer() {
- super();
- }
-
- public MockUrlQuerySanitizer(String url) {
- super(url);
- }
-
- @Override
- protected void addSanitizedEntry(String parameter, String value) {
- super.addSanitizedEntry(parameter, value);
- }
-
- @Override
- protected void clear() {
- super.clear();
- }
-
- @Override
- protected int decodeHexDigit(char c) {
- return super.decodeHexDigit(c);
- }
-
- @Override
- protected boolean isHexDigit(char c) {
- return super.isHexDigit(c);
- }
-
- @Override
- protected void parseEntry(String parameter, String value) {
- super.parseEntry(parameter, value);
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java b/tests/tests/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java
deleted file mode 100644
index f86af31..0000000
--- a/tests/tests/net/src/android/net/cts/UrlQuerySanitizer_IllegalCharacterValueSanitizerTest.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.net.UrlQuerySanitizer;
-import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer;
-import android.test.AndroidTestCase;
-
-public class UrlQuerySanitizer_IllegalCharacterValueSanitizerTest extends AndroidTestCase {
- static final int SPACE_OK = IllegalCharacterValueSanitizer.SPACE_OK;
- public void testSanitize() {
- IllegalCharacterValueSanitizer sanitizer = new IllegalCharacterValueSanitizer(SPACE_OK);
- assertEquals("Joe User", sanitizer.sanitize("Joe<User"));
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/UrlQuerySanitizer_ParameterValuePairTest.java b/tests/tests/net/src/android/net/cts/UrlQuerySanitizer_ParameterValuePairTest.java
deleted file mode 100644
index 077cdaf..0000000
--- a/tests/tests/net/src/android/net/cts/UrlQuerySanitizer_ParameterValuePairTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.net.UrlQuerySanitizer;
-import android.net.UrlQuerySanitizer.ParameterValuePair;
-import android.test.AndroidTestCase;
-
-public class UrlQuerySanitizer_ParameterValuePairTest extends AndroidTestCase {
- public void testConstructor() {
- final String parameter = "name";
- final String vaule = "Joe_user";
-
- UrlQuerySanitizer uqs = new UrlQuerySanitizer();
- ParameterValuePair parameterValuePair = uqs.new ParameterValuePair(parameter, vaule);
- assertEquals(parameter, parameterValuePair.mParameter);
- assertEquals(vaule, parameterValuePair.mValue);
- }
-}
diff --git a/tests/tests/net/src/android/net/cts/VpnServiceTest.java b/tests/tests/net/src/android/net/cts/VpnServiceTest.java
deleted file mode 100644
index 15af23c..0000000
--- a/tests/tests/net/src/android/net/cts/VpnServiceTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.cts;
-
-import android.content.Intent;
-import android.net.VpnService;
-import android.os.ParcelFileDescriptor;
-import android.platform.test.annotations.AppModeFull;
-import android.test.AndroidTestCase;
-
-import java.io.File;
-import java.net.DatagramSocket;
-import java.net.Socket;
-
-/**
- * VpnService API is built with security in mind. However, its security also
- * blocks us from writing tests for positive cases. For now we only test for
- * negative cases, and we will try to cover the rest in the future.
- */
-public class VpnServiceTest extends AndroidTestCase {
-
- private static final String TAG = VpnServiceTest.class.getSimpleName();
-
- private VpnService mVpnService = new VpnService();
-
- @AppModeFull(reason = "PackageManager#queryIntentActivities cannot access in instant app mode")
- public void testPrepare() throws Exception {
- // Should never return null since we are not prepared.
- Intent intent = VpnService.prepare(mContext);
- assertNotNull(intent);
-
- // Should be always resolved by only one activity.
- int count = mContext.getPackageManager().queryIntentActivities(intent, 0).size();
- assertEquals(1, count);
- }
-
- public void testEstablish() throws Exception {
- ParcelFileDescriptor descriptor = null;
- try {
- // Should always return null since we are not prepared.
- descriptor = mVpnService.new Builder().addAddress("8.8.8.8", 30).establish();
- assertNull(descriptor);
- } finally {
- try {
- descriptor.close();
- } catch (Exception e) {
- // ignore
- }
- }
- }
-
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void testProtect_DatagramSocket() throws Exception {
- DatagramSocket socket = new DatagramSocket();
- try {
- // Should always return false since we are not prepared.
- assertFalse(mVpnService.protect(socket));
- } finally {
- try {
- socket.close();
- } catch (Exception e) {
- // ignore
- }
- }
- }
-
- public void testProtect_Socket() throws Exception {
- Socket socket = new Socket();
- try {
- // Should always return false since we are not prepared.
- assertFalse(mVpnService.protect(socket));
- } finally {
- try {
- socket.close();
- } catch (Exception e) {
- // ignore
- }
- }
- }
-
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void testProtect_int() throws Exception {
- DatagramSocket socket = new DatagramSocket();
- ParcelFileDescriptor descriptor = ParcelFileDescriptor.fromDatagramSocket(socket);
- try {
- // Should always return false since we are not prepared.
- assertFalse(mVpnService.protect(descriptor.getFd()));
- } finally {
- try {
- descriptor.close();
- } catch (Exception e) {
- // ignore
- }
- try {
- socket.close();
- } catch (Exception e) {
- // ignore
- }
- }
- }
-
- public void testTunDevice() throws Exception {
- File file = new File("/dev/tun");
- assertTrue(file.exists());
- assertFalse(file.isFile());
- assertFalse(file.isDirectory());
- assertFalse(file.canExecute());
- assertFalse(file.canRead());
- assertFalse(file.canWrite());
- }
-}
diff --git a/tests/tests/net/src/android/net/ipv6/cts/PingTest.java b/tests/tests/net/src/android/net/ipv6/cts/PingTest.java
deleted file mode 100644
index 146fd83..0000000
--- a/tests/tests/net/src/android/net/ipv6/cts/PingTest.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipv6.cts;
-
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.StructTimeval;
-import static android.system.OsConstants.*;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.Inet6Address;
-import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Random;
-
-/**
- * Checks that the device has kernel support for the IPv6 ping socket. This allows ping6 to work
- * without root privileges. The necessary kernel code is in Linux 3.11 or above, or the
- * <code>common/android-3.x</code> kernel trees. If you are not running one of these kernels, the
- * functionality can be obtained by cherry-picking the following patches from David Miller's
- * <code>net-next</code> tree:
- * <ul>
- * <li>6d0bfe2 net: ipv6: Add IPv6 support to the ping socket.
- * <li>c26d6b4 ping: always initialize ->sin6_scope_id and ->sin6_flowinfo
- * <li>fbfe80c net: ipv6: fix wrong ping_v6_sendmsg return value
- * <li>a1bdc45 net: ipv6: add missing lock in ping_v6_sendmsg
- * <li>cf970c0 ping: prevent NULL pointer dereference on write to msg_name
- * </ul>
- * or the equivalent backports to the <code>common/android-3.x</code> trees.
- */
-public class PingTest extends AndroidTestCase {
- /** Maximum size of the packets we're using to test. */
- private static final int MAX_SIZE = 4096;
-
- /** Size of the ICMPv6 header. */
- private static final int ICMP_HEADER_SIZE = 8;
-
- /** Number of packets to test. */
- private static final int NUM_PACKETS = 10;
-
- /** The beginning of an ICMPv6 echo request: type, code, and uninitialized checksum. */
- private static final byte[] PING_HEADER = new byte[] {
- (byte) ICMP6_ECHO_REQUEST, (byte) 0x00, (byte) 0x00, (byte) 0x00
- };
-
- /**
- * Returns a byte array containing an ICMPv6 echo request with the specified payload length.
- */
- private byte[] pingPacket(int payloadLength) {
- byte[] packet = new byte[payloadLength + ICMP_HEADER_SIZE];
- new Random().nextBytes(packet);
- System.arraycopy(PING_HEADER, 0, packet, 0, PING_HEADER.length);
- return packet;
- }
-
- /**
- * Checks that the first length bytes of two byte arrays are equal.
- */
- private void assertArrayBytesEqual(byte[] expected, byte[] actual, int length) {
- for (int i = 0; i < length; i++) {
- assertEquals("Arrays differ at index " + i + ":", expected[i], actual[i]);
- }
- }
-
- /**
- * Creates an IPv6 ping socket and sets a receive timeout of 100ms.
- */
- private FileDescriptor createPingSocket() throws ErrnoException {
- FileDescriptor s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
- Os.setsockoptTimeval(s, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(100));
- return s;
- }
-
- /**
- * Sends a ping packet to a random port on the specified address on the specified socket.
- */
- private void sendPing(FileDescriptor s,
- InetAddress address, byte[] packet) throws ErrnoException, IOException {
- // Pick a random port. Choose a range that gives a reasonable chance of picking a low port.
- int port = (int) (Math.random() * 2048);
-
- // Send the packet.
- int ret = Os.sendto(s, ByteBuffer.wrap(packet), 0, address, port);
- assertEquals(packet.length, ret);
- }
-
- /**
- * Checks that a socket has received a response appropriate to the specified packet.
- */
- private void checkResponse(FileDescriptor s, InetAddress dest,
- byte[] sent, boolean useRecvfrom) throws ErrnoException, IOException {
- ByteBuffer responseBuffer = ByteBuffer.allocate(MAX_SIZE);
- int bytesRead;
-
- // Receive the response.
- if (useRecvfrom) {
- InetSocketAddress from = new InetSocketAddress();
- bytesRead = Os.recvfrom(s, responseBuffer, 0, from);
-
- // Check the source address and scope ID.
- assertTrue(from.getAddress() instanceof Inet6Address);
- Inet6Address fromAddress = (Inet6Address) from.getAddress();
- assertEquals(0, fromAddress.getScopeId());
- assertNull(fromAddress.getScopedInterface());
- assertEquals(dest.getHostAddress(), fromAddress.getHostAddress());
- } else {
- bytesRead = Os.read(s, responseBuffer);
- }
-
- // Check the packet length.
- assertEquals(sent.length, bytesRead);
-
- // Check the response is an echo reply.
- byte[] response = new byte[bytesRead];
- responseBuffer.flip();
- responseBuffer.get(response, 0, bytesRead);
- assertEquals((byte) ICMP6_ECHO_REPLY, response[0]);
-
- // Find out what ICMP ID was used in the packet that was sent.
- int id = ((InetSocketAddress) Os.getsockname(s)).getPort();
- sent[4] = (byte) (id / 256);
- sent[5] = (byte) (id % 256);
-
- // Ensure the response is the same as the packet, except for the type (which is 0x81)
- // and the ID and checksum, which are set by the kernel.
- response[0] = (byte) 0x80; // Type.
- response[2] = response[3] = (byte) 0x00; // Checksum.
- assertArrayBytesEqual(response, sent, bytesRead);
- }
-
- /**
- * Sends NUM_PACKETS random ping packets to ::1 and checks the replies.
- */
- public void testLoopbackPing() throws ErrnoException, IOException {
- // Generate a random ping packet and send it to localhost.
- InetAddress ipv6Loopback = InetAddress.getByName(null);
- assertEquals("::1", ipv6Loopback.getHostAddress());
-
- for (int i = 0; i < NUM_PACKETS; i++) {
- byte[] packet = pingPacket((int) (Math.random() * (MAX_SIZE - ICMP_HEADER_SIZE)));
- FileDescriptor s = createPingSocket();
- // Use both recvfrom and read().
- sendPing(s, ipv6Loopback, packet);
- checkResponse(s, ipv6Loopback, packet, true);
- sendPing(s, ipv6Loopback, packet);
- checkResponse(s, ipv6Loopback, packet, false);
- // Check closing the socket doesn't raise an exception.
- Os.close(s);
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/rtp/cts/AudioCodecTest.java b/tests/tests/net/src/android/net/rtp/cts/AudioCodecTest.java
deleted file mode 100644
index 412498c..0000000
--- a/tests/tests/net/src/android/net/rtp/cts/AudioCodecTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.rtp.cts;
-
-import android.net.rtp.AudioCodec;
-import android.test.AndroidTestCase;
-
-public class AudioCodecTest extends AndroidTestCase {
-
- private void assertEquals(AudioCodec codec, int type, String rtpmap, String fmtp) {
- if (type >= 0) {
- assertEquals(codec.type, type);
- } else {
- assertTrue(codec.type >= 96 && codec.type <= 127);
- }
- assertEquals(codec.rtpmap.compareToIgnoreCase(rtpmap), 0);
- assertEquals(codec.fmtp, fmtp);
- }
-
- public void testConstants() throws Exception {
- assertEquals(AudioCodec.PCMU, 0, "PCMU/8000", null);
- assertEquals(AudioCodec.PCMA, 8, "PCMA/8000", null);
- assertEquals(AudioCodec.GSM, 3, "GSM/8000", null);
- assertEquals(AudioCodec.GSM_EFR, -1, "GSM-EFR/8000", null);
- assertEquals(AudioCodec.AMR, -1, "AMR/8000", null);
-
- assertFalse(AudioCodec.AMR.type == AudioCodec.GSM_EFR.type);
- }
-
- public void testGetCodec() throws Exception {
- // Bad types.
- assertNull(AudioCodec.getCodec(128, "PCMU/8000", null));
- assertNull(AudioCodec.getCodec(-1, "PCMU/8000", null));
- assertNull(AudioCodec.getCodec(96, null, null));
-
- // Fixed types.
- assertEquals(AudioCodec.getCodec(0, null, null), 0, "PCMU/8000", null);
- assertEquals(AudioCodec.getCodec(8, null, null), 8, "PCMA/8000", null);
- assertEquals(AudioCodec.getCodec(3, null, null), 3, "GSM/8000", null);
-
- // Dynamic types.
- assertEquals(AudioCodec.getCodec(96, "pcmu/8000", null), 96, "PCMU/8000", null);
- assertEquals(AudioCodec.getCodec(97, "pcma/8000", null), 97, "PCMA/8000", null);
- assertEquals(AudioCodec.getCodec(98, "gsm/8000", null), 98, "GSM/8000", null);
- assertEquals(AudioCodec.getCodec(99, "gsm-efr/8000", null), 99, "GSM-EFR/8000", null);
- assertEquals(AudioCodec.getCodec(100, "amr/8000", null), 100, "AMR/8000", null);
- }
-
- public void testGetCodecs() throws Exception {
- AudioCodec[] codecs = AudioCodec.getCodecs();
- assertTrue(codecs.length >= 5);
-
- // The types of the codecs should be different.
- boolean[] types = new boolean[128];
- for (AudioCodec codec : codecs) {
- assertFalse(types[codec.type]);
- types[codec.type] = true;
- }
- }
-}
diff --git a/tests/tests/net/src/android/net/rtp/cts/AudioGroupTest.java b/tests/tests/net/src/android/net/rtp/cts/AudioGroupTest.java
deleted file mode 100644
index fc78e96..0000000
--- a/tests/tests/net/src/android/net/rtp/cts/AudioGroupTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.rtp.cts;
-
-import android.content.Context;
-import android.media.AudioManager;
-import android.net.rtp.AudioCodec;
-import android.net.rtp.AudioGroup;
-import android.net.rtp.AudioStream;
-import android.net.rtp.RtpStream;
-import android.os.Build;
-import android.platform.test.annotations.AppModeFull;
-import android.test.AndroidTestCase;
-
-import androidx.core.os.BuildCompat;
-
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-
-@AppModeFull(reason = "RtpStream cannot create in instant app mode")
-public class AudioGroupTest extends AndroidTestCase {
-
- private static final String TAG = AudioGroupTest.class.getSimpleName();
-
- private AudioManager mAudioManager;
-
- private AudioStream mStreamA;
- private DatagramSocket mSocketA;
- private AudioStream mStreamB;
- private DatagramSocket mSocketB;
- private AudioGroup mGroup;
-
- @Override
- public void setUp() throws Exception {
- mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
-
- InetAddress local = InetAddress.getByName("::1");
-
- mStreamA = new AudioStream(local);
- mStreamA.setMode(RtpStream.MODE_NORMAL);
- mStreamA.setCodec(AudioCodec.PCMU);
- mSocketA = new DatagramSocket();
- mSocketA.connect(mStreamA.getLocalAddress(), mStreamA.getLocalPort());
- mStreamA.associate(mSocketA.getLocalAddress(), mSocketA.getLocalPort());
-
- mStreamB = new AudioStream(local);
- mStreamB.setMode(RtpStream.MODE_NORMAL);
- mStreamB.setCodec(AudioCodec.PCMU);
- mSocketB = new DatagramSocket();
- mSocketB.connect(mStreamB.getLocalAddress(), mStreamB.getLocalPort());
- mStreamB.associate(mSocketB.getLocalAddress(), mSocketB.getLocalPort());
-
- // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
- mGroup = Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR()
- ? new AudioGroup(mContext)
- : new AudioGroup(); // Constructor with context argument was introduced in R
- }
-
- @Override
- public void tearDown() throws Exception {
- mGroup.clear();
- mStreamA.release();
- mSocketA.close();
- mStreamB.release();
- mSocketB.close();
- mAudioManager.setMode(AudioManager.MODE_NORMAL);
- }
-
- private void assertPacket(DatagramSocket socket, int length) throws Exception {
- DatagramPacket packet = new DatagramPacket(new byte[length + 1], length + 1);
- socket.setSoTimeout(3000);
- socket.receive(packet);
- assertEquals(packet.getLength(), length);
- }
-
- private void drain(DatagramSocket socket) throws Exception {
- DatagramPacket packet = new DatagramPacket(new byte[1], 1);
- socket.setSoTimeout(1);
- try {
- // Drain the socket by retrieving all the packets queued on it.
- // A SocketTimeoutException will be thrown when it becomes empty.
- while (true) {
- socket.receive(packet);
- }
- } catch (Exception e) {
- // ignore.
- }
- }
-
- public void testTraffic() throws Exception {
- mStreamA.join(mGroup);
- assertPacket(mSocketA, 12 + 160);
-
- mStreamB.join(mGroup);
- assertPacket(mSocketB, 12 + 160);
-
- mStreamA.join(null);
- drain(mSocketA);
-
- drain(mSocketB);
- assertPacket(mSocketB, 12 + 160);
-
- mStreamA.join(mGroup);
- assertPacket(mSocketA, 12 + 160);
- }
-
- public void testSetMode() throws Exception {
- mGroup.setMode(AudioGroup.MODE_NORMAL);
- assertEquals(mGroup.getMode(), AudioGroup.MODE_NORMAL);
-
- mGroup.setMode(AudioGroup.MODE_MUTED);
- assertEquals(mGroup.getMode(), AudioGroup.MODE_MUTED);
-
- mStreamA.join(mGroup);
- mStreamB.join(mGroup);
-
- mGroup.setMode(AudioGroup.MODE_NORMAL);
- assertEquals(mGroup.getMode(), AudioGroup.MODE_NORMAL);
-
- mGroup.setMode(AudioGroup.MODE_MUTED);
- assertEquals(mGroup.getMode(), AudioGroup.MODE_MUTED);
- }
-
- public void testAdd() throws Exception {
- mStreamA.join(mGroup);
- assertEquals(mGroup.getStreams().length, 1);
-
- mStreamB.join(mGroup);
- assertEquals(mGroup.getStreams().length, 2);
-
- mStreamA.join(mGroup);
- assertEquals(mGroup.getStreams().length, 2);
- }
-
- public void testRemove() throws Exception {
- mStreamA.join(mGroup);
- assertEquals(mGroup.getStreams().length, 1);
-
- mStreamA.join(null);
- assertEquals(mGroup.getStreams().length, 0);
-
- mStreamA.join(mGroup);
- assertEquals(mGroup.getStreams().length, 1);
- }
-
- public void testClear() throws Exception {
- mStreamA.join(mGroup);
- mStreamB.join(mGroup);
- mGroup.clear();
-
- assertEquals(mGroup.getStreams().length, 0);
- assertFalse(mStreamA.isBusy());
- assertFalse(mStreamB.isBusy());
- }
-
- public void testDoubleClear() throws Exception {
- mStreamA.join(mGroup);
- mStreamB.join(mGroup);
- mGroup.clear();
- mGroup.clear();
- }
-}
diff --git a/tests/tests/net/src/android/net/rtp/cts/AudioStreamTest.java b/tests/tests/net/src/android/net/rtp/cts/AudioStreamTest.java
deleted file mode 100644
index f2db6ee..0000000
--- a/tests/tests/net/src/android/net/rtp/cts/AudioStreamTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net.rtp.cts;
-
-import android.net.rtp.AudioCodec;
-import android.net.rtp.AudioStream;
-import android.platform.test.annotations.AppModeFull;
-import android.test.AndroidTestCase;
-
-import java.net.InetAddress;
-
-@AppModeFull(reason = "RtpStream cannot create in instant app mode")
-public class AudioStreamTest extends AndroidTestCase {
-
- private void testRtpStream(InetAddress address) throws Exception {
- AudioStream stream = new AudioStream(address);
- assertEquals(stream.getLocalAddress(), address);
- assertEquals(stream.getLocalPort() % 2, 0);
-
- assertNull(stream.getRemoteAddress());
- assertEquals(stream.getRemotePort(), -1);
- stream.associate(address, 1000);
- assertEquals(stream.getRemoteAddress(), address);
- assertEquals(stream.getRemotePort(), 1000);
-
- assertFalse(stream.isBusy());
- stream.release();
- }
-
- public void testV4Stream() throws Exception {
- testRtpStream(InetAddress.getByName("127.0.0.1"));
- }
-
- public void testV6Stream() throws Exception {
- testRtpStream(InetAddress.getByName("::1"));
- }
-
- public void testSetDtmfType() throws Exception {
- AudioStream stream = new AudioStream(InetAddress.getByName("::1"));
-
- assertEquals(stream.getDtmfType(), -1);
- try {
- stream.setDtmfType(0);
- fail("Expecting IllegalArgumentException");
- } catch (IllegalArgumentException e) {
- // ignore
- }
- stream.setDtmfType(96);
- assertEquals(stream.getDtmfType(), 96);
-
- stream.setCodec(AudioCodec.getCodec(97, "PCMU/8000", null));
- try {
- stream.setDtmfType(97);
- fail("Expecting IllegalArgumentException");
- } catch (IllegalArgumentException e) {
- // ignore
- }
- stream.release();
- }
-
- public void testSetCodec() throws Exception {
- AudioStream stream = new AudioStream(InetAddress.getByName("::1"));
-
- assertNull(stream.getCodec());
- stream.setCodec(AudioCodec.getCodec(97, "PCMU/8000", null));
- assertNotNull(stream.getCodec());
-
- stream.setDtmfType(96);
- try {
- stream.setCodec(AudioCodec.getCodec(96, "PCMU/8000", null));
- fail("Expecting IllegalArgumentException");
- } catch (IllegalArgumentException e) {
- // ignore
- }
- stream.release();
- }
-
- public void testDoubleRelease() throws Exception {
- AudioStream stream = new AudioStream(InetAddress.getByName("::1"));
- stream.release();
- stream.release();
- }
-}
diff --git a/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
deleted file mode 100644
index f1bc130..0000000
--- a/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-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;
-import static android.net.NetworkCapabilities.TRANSPORT_TEST;
-import static android.net.wifi.WifiManager.SCAN_RESULTS_AVAILABLE_ACTION;
-
-import static com.android.compatibility.common.util.ShellIdentityUtils.invokeWithShellPermissions;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.annotation.NonNull;
-import android.app.AppOpsManager;
-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.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.State;
-import android.net.NetworkRequest;
-import android.net.TestNetworkManager;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Binder;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.SystemProperties;
-import android.provider.Settings;
-import android.system.Os;
-import android.system.OsConstants;
-import android.util.Log;
-
-import com.android.compatibility.common.util.SystemUtil;
-
-import junit.framework.AssertionFailedError;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-public final class CtsNetUtils {
- private static final String TAG = CtsNetUtils.class.getSimpleName();
- private static final int DURATION = 10000;
- private static final int SOCKET_TIMEOUT_MS = 2000;
- private static final int PRIVATE_DNS_PROBE_MS = 1_000;
-
- private static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000;
- private static final int CONNECTIVITY_CHANGE_TIMEOUT_SECS = 30;
- public static final int HTTP_PORT = 80;
- public static final String TEST_HOST = "connectivitycheck.gstatic.com";
- public static final String HTTP_REQUEST =
- "GET /generate_204 HTTP/1.0\r\n" +
- "Host: " + TEST_HOST + "\r\n" +
- "Connection: keep-alive\r\n\r\n";
- // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
- public static final String NETWORK_CALLBACK_ACTION =
- "ConnectivityManagerTest.NetworkCallbackAction";
-
- private final IBinder mBinder = new Binder();
- 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();
- }
-
- /** Checks if FEATURE_IPSEC_TUNNELS is enabled on the device */
- public boolean hasIpsecTunnelsFeature() {
- return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
- || SystemProperties.getInt("ro.product.first_api_level", 0)
- >= Build.VERSION_CODES.Q;
- }
-
- /**
- * Sets the given appop using shell commands
- *
- * <p>Expects caller to hold the shell permission identity.
- */
- public void setAppopPrivileged(int appop, boolean allow) {
- final String opName = AppOpsManager.opToName(appop);
- for (final String pkg : new String[] {"com.android.shell", mContext.getPackageName()}) {
- final String cmd =
- String.format(
- "appops set %s %s %s",
- pkg, // Package name
- opName, // Appop
- (allow ? "allow" : "deny")); // Action
- SystemUtil.runShellCommand(cmd);
- }
- }
-
- /** Sets up a test network using the provided interface name */
- public TestNetworkCallback setupAndGetTestNetwork(String ifname) throws Exception {
- // Build a network request
- final NetworkRequest nr =
- new NetworkRequest.Builder()
- .clearCapabilities()
- .addTransportType(TRANSPORT_TEST)
- .setNetworkSpecifier(ifname)
- .build();
-
- final TestNetworkCallback cb = new TestNetworkCallback();
- mCm.requestNetwork(nr, cb);
-
- // Setup the test network after network request is filed to prevent Network from being
- // reaped due to no requests matching it.
- mContext.getSystemService(TestNetworkManager.class).setupTestNetwork(ifname, mBinder);
-
- return cb;
- }
-
- // Toggle WiFi twice, leaving it in the state it started in
- public void toggleWifi() {
- if (mWifiManager.isWifiEnabled()) {
- Network wifiNetwork = getWifiNetwork();
- disconnectFromWifi(wifiNetwork);
- connectToWifi();
- } else {
- connectToWifi();
- Network wifiNetwork = getWifiNetwork();
- disconnectFromWifi(wifiNetwork);
- }
- }
-
- /**
- * Enable WiFi and wait for it to become connected to a network.
- *
- * This method expects to receive a legacy broadcast on connect, which may not be sent if the
- * network does not become default or if it is not the first network.
- */
- public Network connectToWifi() {
- return connectToWifi(true /* expectLegacyBroadcast */);
- }
-
- /**
- * Enable WiFi and wait for it to become connected to a network.
- *
- * A network is considered connected when a {@link NetworkRequest} with TRANSPORT_WIFI
- * receives a {@link NetworkCallback#onAvailable(Network)} callback.
- */
- public Network ensureWifiConnected() {
- return connectToWifi(false /* expectLegacyBroadcast */);
- }
-
- /**
- * Enable WiFi and wait for it to become connected to a network.
- *
- * @param expectLegacyBroadcast Whether to check for a legacy CONNECTIVITY_ACTION connected
- * broadcast. The broadcast is typically not sent if the network
- * does not become the default network, and is not the first
- * network to appear.
- * @return The network that was newly connected.
- */
- private Network connectToWifi(boolean expectLegacyBroadcast) {
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
- Network wifiNetwork = null;
-
- ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
- mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
- IntentFilter filter = new IntentFilter();
- filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- mContext.registerReceiver(receiver, filter);
-
- boolean connected = false;
- final String err = "Wifi must be configured to connect to an access point for this test.";
- try {
- clearWifiBlacklist();
- SystemUtil.runShellCommand("svc wifi enable");
- final WifiConfiguration config = maybeAddVirtualWifiConfiguration();
- if (config == null) {
- // TODO: this may not clear the BSSID blacklist, as opposed to
- // mWifiManager.connect(config)
- SystemUtil.runWithShellPermissionIdentity(() -> mWifiManager.reconnect(),
- NETWORK_SETTINGS);
- } else {
- // When running CTS, devices are expected to have wifi networks pre-configured.
- // This condition is only hit on virtual devices.
- SystemUtil.runWithShellPermissionIdentity(
- () -> mWifiManager.connect(config, null /* listener */), NETWORK_SETTINGS);
- }
- // Ensure we get an onAvailable callback and possibly a CONNECTIVITY_ACTION.
- wifiNetwork = callback.waitForAvailable();
- assertNotNull(err, wifiNetwork);
- connected = !expectLegacyBroadcast || receiver.waitForState();
- } catch (InterruptedException ex) {
- fail("connectToWifi was interrupted");
- } finally {
- mCm.unregisterNetworkCallback(callback);
- mContext.unregisterReceiver(receiver);
- }
-
- assertTrue(err, connected);
- return wifiNetwork;
- }
-
- private WifiConfiguration maybeAddVirtualWifiConfiguration() {
- final List<WifiConfiguration> configs = invokeWithShellPermissions(
- mWifiManager::getConfiguredNetworks);
- // If no network is configured, add a config for virtual access points if applicable
- if (configs.size() == 0) {
- final List<ScanResult> scanResults = getWifiScanResults();
- final WifiConfiguration virtualConfig = maybeConfigureVirtualNetwork(scanResults);
- assertNotNull("The device has no configured wifi network", virtualConfig);
-
- return virtualConfig;
- }
- // No need to add a configuration: there is already one
- return null;
- }
-
- private List<ScanResult> getWifiScanResults() {
- final CompletableFuture<List<ScanResult>> scanResultsFuture = new CompletableFuture<>();
- SystemUtil.runWithShellPermissionIdentity(() -> {
- final BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- scanResultsFuture.complete(mWifiManager.getScanResults());
- }
- };
- mContext.registerReceiver(receiver, new IntentFilter(SCAN_RESULTS_AVAILABLE_ACTION));
- mWifiManager.startScan();
- });
-
- try {
- return scanResultsFuture.get(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS);
- } catch (ExecutionException | InterruptedException | TimeoutException e) {
- throw new AssertionFailedError("Wifi scan results not received within timeout");
- }
- }
-
- /**
- * If a virtual wifi network is detected, add a configuration for that network.
- * TODO(b/158150376): have the test infrastructure add virtual wifi networks when appropriate.
- */
- private WifiConfiguration maybeConfigureVirtualNetwork(List<ScanResult> scanResults) {
- // Virtual wifi networks used on the emulator and cloud testing infrastructure
- final List<String> virtualSsids = Arrays.asList("VirtWifi", "AndroidWifi");
- Log.d(TAG, "Wifi scan results: " + scanResults);
- final ScanResult virtualScanResult = scanResults.stream().filter(
- s -> virtualSsids.contains(s.SSID)).findFirst().orElse(null);
-
- // Only add the virtual configuration if the virtual AP is detected in scans
- if (virtualScanResult == null) return null;
-
- final WifiConfiguration virtualConfig = new WifiConfiguration();
- // ASCII SSIDs need to be surrounded by double quotes
- virtualConfig.SSID = "\"" + virtualScanResult.SSID + "\"";
- virtualConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
-
- SystemUtil.runWithShellPermissionIdentity(() -> {
- final int networkId = mWifiManager.addNetwork(virtualConfig);
- assertTrue(networkId >= 0);
- assertTrue(mWifiManager.enableNetwork(networkId, false /* attemptConnect */));
- });
- return virtualConfig;
- }
-
- /**
- * Re-enable wifi networks that were blacklisted, typically because no internet connection was
- * detected the last time they were connected. This is necessary to make sure wifi can reconnect
- * to them.
- */
- private void clearWifiBlacklist() {
- SystemUtil.runWithShellPermissionIdentity(() -> {
- for (WifiConfiguration cfg : mWifiManager.getConfiguredNetworks()) {
- assertTrue(mWifiManager.enableNetwork(cfg.networkId, false /* attemptConnect */));
- }
- });
- }
-
- /**
- * Disable WiFi and wait for it to become disconnected from the network.
- *
- * This method expects to receive a legacy broadcast on disconnect, which may not be sent if the
- * network was not default, or was not the first network.
- *
- * @param wifiNetworkToCheck If non-null, a network that should be disconnected. This network
- * is expected to be able to establish a TCP connection to a remote
- * server before disconnecting, and to have that connection closed in
- * the process.
- */
- public void disconnectFromWifi(Network wifiNetworkToCheck) {
- disconnectFromWifi(wifiNetworkToCheck, true /* expectLegacyBroadcast */);
- }
-
- /**
- * Disable WiFi and wait for it to become disconnected from the network.
- *
- * @param wifiNetworkToCheck If non-null, a network that should be disconnected. This network
- * is expected to be able to establish a TCP connection to a remote
- * server before disconnecting, and to have that connection closed in
- * the process.
- */
- public void ensureWifiDisconnected(Network wifiNetworkToCheck) {
- disconnectFromWifi(wifiNetworkToCheck, false /* expectLegacyBroadcast */);
- }
-
- /**
- * Disable WiFi and wait for it to become disconnected from the network.
- *
- * @param wifiNetworkToCheck If non-null, a network that should be disconnected. This network
- * is expected to be able to establish a TCP connection to a remote
- * server before disconnecting, and to have that connection closed in
- * the process.
- * @param expectLegacyBroadcast Whether to check for a legacy CONNECTIVITY_ACTION disconnected
- * broadcast. The broadcast is typically not sent if the network
- * was not the default network and not the first network to appear.
- * The check will always be skipped if the device was not connected
- * to wifi in the first place.
- */
- private void disconnectFromWifi(Network wifiNetworkToCheck, boolean expectLegacyBroadcast) {
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
-
- ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
- mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED);
- IntentFilter filter = new IntentFilter();
- filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- mContext.registerReceiver(receiver, filter);
-
- final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
- final boolean wasWifiConnected = wifiInfo != null && wifiInfo.getNetworkId() != -1;
- // Assert that we can establish a TCP connection on wifi.
- Socket wifiBoundSocket = null;
- if (wifiNetworkToCheck != null) {
- assertTrue("Cannot check network " + wifiNetworkToCheck + ": wifi is not connected",
- wasWifiConnected);
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(wifiNetworkToCheck);
- assertNotNull("Network " + wifiNetworkToCheck + " is not connected", nc);
- try {
- wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT);
- testHttpRequest(wifiBoundSocket);
- } catch (IOException e) {
- fail("HTTP request before wifi disconnected failed with: " + e);
- }
- }
-
- try {
- SystemUtil.runShellCommand("svc wifi disable");
- if (wasWifiConnected) {
- // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION.
- assertNotNull("Did not receive onLost callback after disabling wifi",
- callback.waitForLost());
- }
- if (wasWifiConnected && expectLegacyBroadcast) {
- assertTrue("Wifi failed to reach DISCONNECTED state.", receiver.waitForState());
- }
- } catch (InterruptedException ex) {
- fail("disconnectFromWifi was interrupted");
- } finally {
- mCm.unregisterNetworkCallback(callback);
- mContext.unregisterReceiver(receiver);
- }
-
- // Check that the socket is closed when wifi disconnects.
- if (wifiBoundSocket != null) {
- try {
- testHttpRequest(wifiBoundSocket);
- fail("HTTP request should not succeed after wifi disconnects");
- } catch (IOException expected) {
- assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage());
- }
- }
- }
-
- public Network getWifiNetwork() {
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
- Network network = null;
- try {
- network = callback.waitForAvailable();
- } catch (InterruptedException e) {
- fail("NetworkCallback wait was interrupted.");
- } finally {
- mCm.unregisterNetworkCallback(callback);
- }
- assertNotNull("Cannot find Network for wifi. Is wifi connected?", network);
- return network;
- }
-
- public Network connectToCell() throws InterruptedException {
- if (cellConnectAttempted()) {
- throw new IllegalStateException("Already connected");
- }
- NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- mCellNetworkCallback = new TestNetworkCallback();
- mCm.requestNetwork(cellRequest, mCellNetworkCallback);
- final Network cellNetwork = mCellNetworkCallback.waitForAvailable();
- assertNotNull("Cell network not available. " +
- "Please ensure the device has working mobile data.", cellNetwork);
- return cellNetwork;
- }
-
- public void disconnectFromCell() {
- if (!cellConnectAttempted()) {
- throw new IllegalStateException("Cell connection not attempted");
- }
- mCm.unregisterNetworkCallback(mCellNetworkCallback);
- mCellNetworkCallback = null;
- }
-
- public boolean cellConnectAttempted() {
- return mCellNetworkCallback != null;
- }
-
- private NetworkRequest makeWifiNetworkRequest() {
- return new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
- }
-
- private void testHttpRequest(Socket s) throws IOException {
- OutputStream out = s.getOutputStream();
- InputStream in = s.getInputStream();
-
- final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8");
- byte[] responseBytes = new byte[4096];
- out.write(requestBytes);
- in.read(responseBytes);
- assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n"));
- }
-
- private Socket getBoundSocket(Network network, String host, int port) throws IOException {
- InetSocketAddress addr = new InetSocketAddress(host, port);
- Socket s = network.getSocketFactory().createSocket();
- try {
- s.setSoTimeout(SOCKET_TIMEOUT_MS);
- s.connect(addr, SOCKET_TIMEOUT_MS);
- } catch (IOException e) {
- s.close();
- throw e;
- }
- 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, boolean requiresValidatedServers) throws InterruptedException {
- CountDownLatch latch = new CountDownLatch(1);
- NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
- NetworkCallback callback = new NetworkCallback() {
- @Override
- public void onLinkPropertiesChanged(Network n, LinkProperties lp) {
- if (requiresValidatedServers && lp.getValidatedPrivateDnsServers().isEmpty()) {
- return;
- }
- if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) {
- latch.countDown();
- }
- }
- };
- mCm.registerNetworkCallback(request, callback);
- 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
- // completes. This would result in tearDown disabling private DNS, and the NetworkMonitor
- // private DNS probe getting stuck because there are no longer any private DNS servers to
- // query. This then results in the next test not being able to change the private DNS
- // setting within the timeout, because the NetworkMonitor thread is blocked in the
- // private DNS probe. There is no way to know when the probe has completed: because the
- // network is likely already validated, there is no callback that we can listen to, so
- // just sleep.
- if (requiresValidatedServers) {
- Thread.sleep(PRIVATE_DNS_PROBE_MS);
- }
- }
-
- /**
- * Receiver that captures the last connectivity change's network type and state. Recognizes
- * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents.
- */
- public static class ConnectivityActionReceiver extends BroadcastReceiver {
-
- private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
-
- private final int mNetworkType;
- private final NetworkInfo.State mNetState;
- private final ConnectivityManager mCm;
-
- public ConnectivityActionReceiver(ConnectivityManager cm, int networkType,
- NetworkInfo.State netState) {
- this.mCm = cm;
- mNetworkType = networkType;
- mNetState = netState;
- }
-
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- NetworkInfo networkInfo = null;
-
- // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable
- // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is
- // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo.
- if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
- networkInfo = intent.getExtras()
- .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO);
- assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO",
- networkInfo);
- } else if (NETWORK_CALLBACK_ACTION.equals(action)) {
- Network network = intent.getExtras()
- .getParcelable(ConnectivityManager.EXTRA_NETWORK);
- assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network);
- networkInfo = this.mCm.getNetworkInfo(network);
- if (networkInfo == null) {
- // When disconnecting, it seems like we get an intent sent with an invalid
- // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(),
- // it is invalid. Ignore these.
- Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring "
- + "invalid network");
- return;
- }
- } else {
- fail("ConnectivityActionReceiver received unxpected intent action: " + action);
- }
-
- assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo);
- int networkType = networkInfo.getType();
- State networkState = networkInfo.getState();
- Log.i(TAG, "Network type: " + networkType + " state: " + networkState);
- if (networkType == mNetworkType && networkInfo.getState() == mNetState) {
- mReceiveLatch.countDown();
- }
- }
-
- public boolean waitForState() throws InterruptedException {
- return mReceiveLatch.await(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS);
- }
- }
-
- /**
- * Callback used in testRegisterNetworkCallback that allows caller to block on
- * {@code onAvailable}.
- */
- public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
- private final CountDownLatch mAvailableLatch = new CountDownLatch(1);
- private final CountDownLatch mLostLatch = new CountDownLatch(1);
- private final CountDownLatch mUnavailableLatch = new CountDownLatch(1);
-
- public Network currentNetwork;
- public Network lastLostNetwork;
-
- public Network waitForAvailable() throws InterruptedException {
- return mAvailableLatch.await(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS)
- ? currentNetwork : null;
- }
-
- public Network waitForLost() throws InterruptedException {
- return mLostLatch.await(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS)
- ? lastLostNetwork : null;
- }
-
- public boolean waitForUnavailable() throws InterruptedException {
- return mUnavailableLatch.await(2, TimeUnit.SECONDS);
- }
-
-
- @Override
- public void onAvailable(Network network) {
- currentNetwork = network;
- mAvailableLatch.countDown();
- }
-
- @Override
- public void onLost(Network network) {
- lastLostNetwork = network;
- if (network.equals(currentNetwork)) {
- currentNetwork = null;
- }
- mLostLatch.countDown();
- }
-
- @Override
- public void onUnavailable() {
- mUnavailableLatch.countDown();
- }
- }
-}
diff --git a/tests/tests/os/Android.bp b/tests/tests/os/Android.bp
index e04630b..7597768 100644
--- a/tests/tests/os/Android.bp
+++ b/tests/tests/os/Android.bp
@@ -51,6 +51,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
sdk_version: "test_current",
libs: [
@@ -59,4 +60,5 @@
],
// Do not compress minijail policy files.
aaptflags: ["-0 .policy"],
+ min_sdk_version : "29"
}
diff --git a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index 44a5444..da07dcb 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -16,6 +16,7 @@
package android.os.cts
+import android.app.ActivityManager
import android.app.Instrumentation
import android.content.Context
import android.content.Intent
@@ -26,6 +27,7 @@
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.content.res.Resources
import android.net.Uri
+import android.os.Build
import android.platform.test.annotations.AppModeFull
import android.provider.DeviceConfig
import android.support.test.uiautomator.By
@@ -54,6 +56,7 @@
import org.junit.Assert.assertFalse
import org.junit.Assert.assertThat
import org.junit.Assert.assertTrue
+import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -86,11 +89,7 @@
@Before
fun setup() {
- // Kill Permission Controller
- assertThat(
- runShellCommand("killall " +
- context.packageManager.permissionControllerPackageName),
- equalTo(""))
+ assumeTrue(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
// Collapse notifications
assertThat(
@@ -293,8 +292,12 @@
}
private fun runAutoRevoke() {
- runShellCommand("cmd jobscheduler run -u 0 " +
- "-f ${context.packageManager.permissionControllerPackageName} 2")
+ // Sometimes first run observes stale package data
+ // so run twice to prevent that
+ repeat(2) {
+ runShellCommand("cmd jobscheduler run -u 0 " +
+ "-f ${context.packageManager.permissionControllerPackageName} 2")
+ }
}
private inline fun <T> withDeviceConfig(
diff --git a/tests/tests/permission/Android.bp b/tests/tests/permission/Android.bp
index 6c42051..c8459cf 100644
--- a/tests/tests/permission/Android.bp
+++ b/tests/tests/permission/Android.bp
@@ -22,6 +22,7 @@
"vts10",
"general-tests",
"sts",
+ "mts",
],
// Include both the 32 and 64 bit versions
compile_multilib: "both",
diff --git a/tests/tests/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/Android.bp b/tests/tests/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/Android.bp
index 331551f..0b1c436 100644
--- a/tests/tests/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/Android.bp
+++ b/tests/tests/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/Android.bp
@@ -23,5 +23,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppThatAccessesLocationOnCommand/Android.bp b/tests/tests/permission/AppThatAccessesLocationOnCommand/Android.bp
index 6d56a9a..7a8d3e9 100644
--- a/tests/tests/permission/AppThatAccessesLocationOnCommand/Android.bp
+++ b/tests/tests/permission/AppThatAccessesLocationOnCommand/Android.bp
@@ -24,6 +24,7 @@
"vts10",
"general-tests",
"sts",
+ "mts",
],
srcs: [
"src/**/*.java",
diff --git a/tests/tests/permission/AppThatDefinesUndefinedPermissionGroupElement/Android.bp b/tests/tests/permission/AppThatDefinesUndefinedPermissionGroupElement/Android.bp
index c8fd250..8fd122f 100644
--- a/tests/tests/permission/AppThatDefinesUndefinedPermissionGroupElement/Android.bp
+++ b/tests/tests/permission/AppThatDefinesUndefinedPermissionGroupElement/Android.bp
@@ -23,6 +23,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
srcs: ["src/**/*.kt"],
}
diff --git a/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp b/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp
index dc04e1c..5289a03 100644
--- a/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp
+++ b/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp
@@ -24,5 +24,6 @@
"vts10",
"general-tests",
"sts",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppThatRequestContactsAndCallLogPermission16/Android.bp b/tests/tests/permission/AppThatRequestContactsAndCallLogPermission16/Android.bp
index 2e3a777..a773751 100644
--- a/tests/tests/permission/AppThatRequestContactsAndCallLogPermission16/Android.bp
+++ b/tests/tests/permission/AppThatRequestContactsAndCallLogPermission16/Android.bp
@@ -23,5 +23,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppThatRequestContactsPermission15/Android.bp b/tests/tests/permission/AppThatRequestContactsPermission15/Android.bp
index 3e1af1d..4aafcf0 100644
--- a/tests/tests/permission/AppThatRequestContactsPermission15/Android.bp
+++ b/tests/tests/permission/AppThatRequestContactsPermission15/Android.bp
@@ -23,5 +23,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppThatRequestContactsPermission16/Android.bp b/tests/tests/permission/AppThatRequestContactsPermission16/Android.bp
index 17dd3ba..ce315fc 100644
--- a/tests/tests/permission/AppThatRequestContactsPermission16/Android.bp
+++ b/tests/tests/permission/AppThatRequestContactsPermission16/Android.bp
@@ -23,5 +23,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppThatRequestLocationAndBackgroundPermission29/Android.bp b/tests/tests/permission/AppThatRequestLocationAndBackgroundPermission29/Android.bp
index 0146b6c..5558cd0 100644
--- a/tests/tests/permission/AppThatRequestLocationAndBackgroundPermission29/Android.bp
+++ b/tests/tests/permission/AppThatRequestLocationAndBackgroundPermission29/Android.bp
@@ -23,5 +23,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppThatRequestLocationPermission22/Android.bp b/tests/tests/permission/AppThatRequestLocationPermission22/Android.bp
index 1383819..5675d7c 100644
--- a/tests/tests/permission/AppThatRequestLocationPermission22/Android.bp
+++ b/tests/tests/permission/AppThatRequestLocationPermission22/Android.bp
@@ -23,5 +23,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppThatRequestLocationPermission28/Android.bp b/tests/tests/permission/AppThatRequestLocationPermission28/Android.bp
index 5ed80ec..8d37688 100644
--- a/tests/tests/permission/AppThatRequestLocationPermission28/Android.bp
+++ b/tests/tests/permission/AppThatRequestLocationPermission28/Android.bp
@@ -23,5 +23,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppThatRequestLocationPermission29/Android.bp b/tests/tests/permission/AppThatRequestLocationPermission29/Android.bp
index 9546523..3bf0f8a 100644
--- a/tests/tests/permission/AppThatRequestLocationPermission29/Android.bp
+++ b/tests/tests/permission/AppThatRequestLocationPermission29/Android.bp
@@ -23,5 +23,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppThatRequestLocationPermission29v4/Android.bp b/tests/tests/permission/AppThatRequestLocationPermission29v4/Android.bp
index 10d2a66..4115428 100644
--- a/tests/tests/permission/AppThatRequestLocationPermission29v4/Android.bp
+++ b/tests/tests/permission/AppThatRequestLocationPermission29v4/Android.bp
@@ -23,5 +23,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppThatRequestPermissionAandB/Android.bp b/tests/tests/permission/AppThatRequestPermissionAandB/Android.bp
index 498ba83..d735739 100644
--- a/tests/tests/permission/AppThatRequestPermissionAandB/Android.bp
+++ b/tests/tests/permission/AppThatRequestPermissionAandB/Android.bp
@@ -24,6 +24,7 @@
"vts10",
"general-tests",
"sts",
+ "mts",
],
srcs: ["src/**/*.java"],
}
diff --git a/tests/tests/permission/AppThatRequestPermissionAandC/Android.bp b/tests/tests/permission/AppThatRequestPermissionAandC/Android.bp
index d38273c..9b0963b 100644
--- a/tests/tests/permission/AppThatRequestPermissionAandC/Android.bp
+++ b/tests/tests/permission/AppThatRequestPermissionAandC/Android.bp
@@ -24,6 +24,7 @@
"vts10",
"general-tests",
"sts",
+ "mts",
],
srcs: ["src/**/*.java"],
}
diff --git a/tests/tests/permission/AppThatRequestStoragePermission28/Android.bp b/tests/tests/permission/AppThatRequestStoragePermission28/Android.bp
index cdc8bb0..29fe7a2 100644
--- a/tests/tests/permission/AppThatRequestStoragePermission28/Android.bp
+++ b/tests/tests/permission/AppThatRequestStoragePermission28/Android.bp
@@ -23,5 +23,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppThatRequestStoragePermission29/Android.bp b/tests/tests/permission/AppThatRequestStoragePermission29/Android.bp
index d2a4897..412b2d7 100644
--- a/tests/tests/permission/AppThatRequestStoragePermission29/Android.bp
+++ b/tests/tests/permission/AppThatRequestStoragePermission29/Android.bp
@@ -23,5 +23,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppThatRunsRationaleTests/Android.bp b/tests/tests/permission/AppThatRunsRationaleTests/Android.bp
index 9555499..f2c7fa5 100644
--- a/tests/tests/permission/AppThatRunsRationaleTests/Android.bp
+++ b/tests/tests/permission/AppThatRunsRationaleTests/Android.bp
@@ -25,6 +25,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
srcs: ["src/**/*.java"],
diff --git a/tests/tests/permission/AppWithSharedUidThatRequestLocationPermission28/Android.bp b/tests/tests/permission/AppWithSharedUidThatRequestLocationPermission28/Android.bp
index 688651e..e82f753 100644
--- a/tests/tests/permission/AppWithSharedUidThatRequestLocationPermission28/Android.bp
+++ b/tests/tests/permission/AppWithSharedUidThatRequestLocationPermission28/Android.bp
@@ -25,5 +25,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppWithSharedUidThatRequestLocationPermission29/Android.bp b/tests/tests/permission/AppWithSharedUidThatRequestLocationPermission29/Android.bp
index b8b258e..46f0fb9 100644
--- a/tests/tests/permission/AppWithSharedUidThatRequestLocationPermission29/Android.bp
+++ b/tests/tests/permission/AppWithSharedUidThatRequestLocationPermission29/Android.bp
@@ -25,5 +25,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppWithSharedUidThatRequestsNoPermissions/Android.bp b/tests/tests/permission/AppWithSharedUidThatRequestsNoPermissions/Android.bp
index c9a4b93..9f7c3d1 100644
--- a/tests/tests/permission/AppWithSharedUidThatRequestsNoPermissions/Android.bp
+++ b/tests/tests/permission/AppWithSharedUidThatRequestsNoPermissions/Android.bp
@@ -22,5 +22,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/AppWithSharedUidThatRequestsPermissions/Android.bp b/tests/tests/permission/AppWithSharedUidThatRequestsPermissions/Android.bp
index fc8d9ee..43cd875 100644
--- a/tests/tests/permission/AppWithSharedUidThatRequestsPermissions/Android.bp
+++ b/tests/tests/permission/AppWithSharedUidThatRequestsPermissions/Android.bp
@@ -22,5 +22,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/sdk28/Android.bp b/tests/tests/permission/sdk28/Android.bp
index 856bbd1..e7ec37f 100644
--- a/tests/tests/permission/sdk28/Android.bp
+++ b/tests/tests/permission/sdk28/Android.bp
@@ -25,5 +25,6 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/permission/src/android/permission/cts/PermissionManagerTest.java b/tests/tests/permission/src/android/permission/cts/PermissionManagerTest.java
new file mode 100644
index 0000000..6fa940a
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/PermissionManagerTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.permission.PermissionManager;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link PermissionManager}
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Instant apps cannot talk to permission manager")
+public class PermissionManagerTest {
+ private final Context mContext = InstrumentationRegistry.getTargetContext();
+
+ @Test
+ public void testRuntimePermissionsVersion() throws Exception {
+ final PermissionManager permissionManager =
+ mContext.getSystemService(PermissionManager.class);
+ final int version = callWithShellPermissionIdentity(() ->
+ permissionManager.getRuntimePermissionsVersion());
+ assertThat(version).isAtLeast(0);
+ runWithShellPermissionIdentity(() ->
+ permissionManager.setRuntimePermissionsVersion(version));
+ }
+}
diff --git a/tests/tests/permission/telephony/Android.bp b/tests/tests/permission/telephony/Android.bp
index c5388ea..74e2b5a 100644
--- a/tests/tests/permission/telephony/Android.bp
+++ b/tests/tests/permission/telephony/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
// Include both the 32 and 64 bit versions
compile_multilib: "both",
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp
index d0f09e3..92ebffa 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp
@@ -23,6 +23,7 @@
"vts10",
"general-tests",
"sts",
+ "mts",
],
certificate: ":cts-testkey1",
}
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp
index 0eeccc7..54c0f8e 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp
@@ -23,6 +23,7 @@
"vts10",
"general-tests",
"sts",
+ "mts",
],
certificate: ":cts-testkey2",
}
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp
index a335bda..8281a57 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
"sts",
],
certificate: ":cts-testkey1",
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp
index 5fd0445..ab825ba 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
"sts",
],
certificate: ":cts-testkey1",
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp
index 22d0110..666c143 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
"sts",
],
certificate: ":cts-testkey2",
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp
index 2000dd1..c7f8491 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
"sts",
],
certificate: ":cts-testkey1",
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp
index c98ec85..942691b 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
"sts",
],
certificate: ":cts-testkey2",
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp
index 4f2b93c..516527c 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp
@@ -23,6 +23,7 @@
"vts10",
"general-tests",
"sts",
+ "mts",
],
certificate: ":cts-testkey1",
}
diff --git a/tests/tests/provider/Android.bp b/tests/tests/provider/Android.bp
index 4c797d0..07ccbc0 100644
--- a/tests/tests/provider/Android.bp
+++ b/tests/tests/provider/Android.bp
@@ -9,6 +9,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
libs: [
@@ -19,6 +20,7 @@
],
static_libs: [
+ "androidx.test.core",
"androidx.slice_slice-core",
"androidx.slice_slice-view",
"compatibility-device-util-axt",
diff --git a/tests/tests/provider/OWNERS b/tests/tests/provider/OWNERS
index ed13f6f..090071a 100644
--- a/tests/tests/provider/OWNERS
+++ b/tests/tests/provider/OWNERS
@@ -7,3 +7,4 @@
nona@google.com
nandana@google.com
zezeozue@google.com
+corinac@google.com
diff --git a/tests/tests/provider/app/GalleryTestApp/Android.bp b/tests/tests/provider/app/GalleryTestApp/Android.bp
index 9f2359c..5da74ce 100644
--- a/tests/tests/provider/app/GalleryTestApp/Android.bp
+++ b/tests/tests/provider/app/GalleryTestApp/Android.bp
@@ -25,4 +25,5 @@
optimize: {
enabled: false,
},
+ min_sdk_version : "29",
}
diff --git a/tests/tests/provider/preconditions/Android.bp b/tests/tests/provider/preconditions/Android.bp
index 31247b0..da65d11 100644
--- a/tests/tests/provider/preconditions/Android.bp
+++ b/tests/tests/provider/preconditions/Android.bp
@@ -11,6 +11,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
host_supported: true,
device_supported: false,
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStoreAudioTestHelper.java b/tests/tests/provider/src/android/provider/cts/media/MediaStoreAudioTestHelper.java
index 471f85a..b7b9033 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStoreAudioTestHelper.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStoreAudioTestHelper.java
@@ -19,10 +19,12 @@
import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
+import android.os.Build;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio.Media;
import android.provider.cts.ProviderTestUtils;
+import androidx.test.filters.SdkSuppress;
import androidx.test.runner.AndroidJUnit4;
import junit.framework.Assert;
@@ -53,6 +55,7 @@
* @see MediaStore_Audio_Artists_AlbumsTest
* @see MediaStore_Audio_AlbumsTest
*/
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(AndroidJUnit4.class)
public class MediaStoreAudioTestHelper {
public static abstract class MockAudioMediaInfo {
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStoreIntentsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStoreIntentsTest.java
index d5442e0..451b1bf 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStoreIntentsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStoreIntentsTest.java
@@ -24,11 +24,13 @@
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.net.Uri;
+import android.os.Build;
import android.provider.MediaStore;
import android.provider.cts.ProviderTestUtils;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Test;
@@ -43,6 +45,7 @@
* Tests to verify that common actions on {@link MediaStore} content are
* available.
*/
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStoreIntentsTest {
private Uri mExternalAudio;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStoreMatchTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStoreMatchTest.java
index 49e6150..73f42c2 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStoreMatchTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStoreMatchTest.java
@@ -27,6 +27,7 @@
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
@@ -35,6 +36,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Test;
@@ -43,6 +45,7 @@
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStoreMatchTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStoreNotificationTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStoreNotificationTest.java
index 3bb3ca3..8774091 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStoreNotificationTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStoreNotificationTest.java
@@ -25,12 +25,14 @@
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.provider.MediaStore;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Ignore;
@@ -43,6 +45,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStoreNotificationTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStorePendingTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStorePendingTest.java
index 92c98b9..b77a8e5 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStorePendingTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStorePendingTest.java
@@ -35,6 +35,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.os.Environment;
import android.os.FileUtils;
import android.provider.MediaStore;
@@ -46,6 +47,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import com.google.common.base.Objects;
@@ -65,6 +67,7 @@
import java.util.HashSet;
import java.util.Set;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStorePendingTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStorePlacementTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStorePlacementTest.java
index 5b4d484..aed220d 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStorePlacementTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStorePlacementTest.java
@@ -26,6 +26,7 @@
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
@@ -35,6 +36,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Assume;
import org.junit.Before;
@@ -48,6 +50,7 @@
import java.io.OutputStream;
import java.util.Optional;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStorePlacementTest {
static final String TAG = "MediaStorePlacementTest";
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java
index 0dae752..0aa1026 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java
@@ -40,6 +40,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.After;
import org.junit.Before;
@@ -51,6 +52,7 @@
import java.util.Set;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStoreTest {
static final String TAG = "MediaStoreTest";
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStoreTrashedTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStoreTrashedTest.java
index 2ed9aff..7778e8a 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStoreTrashedTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStoreTrashedTest.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
@@ -34,6 +35,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Assume;
import org.junit.Before;
@@ -45,6 +47,7 @@
import java.io.File;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStoreTrashedTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStoreUtils.java b/tests/tests/provider/src/android/provider/cts/media/MediaStoreUtils.java
index 0120afb..49a33ad 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStoreUtils.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStoreUtils.java
@@ -19,6 +19,7 @@
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
+import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.provider.MediaStore.DownloadColumns;
@@ -34,7 +35,9 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.test.filters.SdkSuppress;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
public class MediaStoreUtils {
@Test
public void testStub() {
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_AudioTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_AudioTest.java
index 5cdfa54..39b58ce 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_AudioTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_AudioTest.java
@@ -19,14 +19,17 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.os.Build;
import android.provider.MediaStore.Audio;
import androidx.test.runner.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(AndroidJUnit4.class)
public class MediaStore_AudioTest {
private String mKeyForBeatles;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_AlbumsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_AlbumsTest.java
index 2621949..7f1f9b4 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_AlbumsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_AlbumsTest.java
@@ -32,6 +32,7 @@
import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.net.Uri;
+import android.os.Build;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio.Albums;
import android.provider.MediaStore.Audio.Media;
@@ -43,6 +44,7 @@
import android.util.Size;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Test;
@@ -54,6 +56,7 @@
import java.io.File;
import java.io.IOException;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Audio_AlbumsTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_ArtistsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_ArtistsTest.java
index 6ab7c28..39ad280 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_ArtistsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_ArtistsTest.java
@@ -28,6 +28,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.provider.MediaStore.Audio.Artists;
import android.provider.cts.ProviderTestUtils;
import android.provider.cts.media.MediaStoreAudioTestHelper.Audio1;
@@ -35,6 +36,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Test;
@@ -43,6 +45,7 @@
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Audio_ArtistsTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_Artists_AlbumsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_Artists_AlbumsTest.java
index a3bd099..5aed01f 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_Artists_AlbumsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_Artists_AlbumsTest.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio.Artists.Albums;
import android.provider.MediaStore.Audio.Media;
@@ -38,6 +39,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Test;
@@ -46,6 +48,7 @@
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Audio_Artists_AlbumsTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_GenresTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_GenresTest.java
index dee863f..83d1ba2 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_GenresTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_GenresTest.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.provider.MediaStore.Audio.Genres;
import android.provider.MediaStore.Audio.Genres.Members;
import android.provider.cts.ProviderTestUtils;
@@ -36,6 +37,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Ignore;
@@ -45,6 +47,7 @@
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Audio_GenresTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_Genres_MembersTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_Genres_MembersTest.java
index b9dc9c9..2a45fdc 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_Genres_MembersTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_Genres_MembersTest.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio.Genres;
import android.provider.MediaStore.Audio.Genres.Members;
@@ -39,6 +40,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.After;
import org.junit.Before;
@@ -49,6 +51,7 @@
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Audio_Genres_MembersTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_MediaTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_MediaTest.java
index 00aabc2..bc4925c 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_MediaTest.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
@@ -44,6 +45,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Test;
@@ -55,6 +57,7 @@
import java.io.File;
import java.io.OutputStream;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Audio_MediaTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_PlaylistsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_PlaylistsTest.java
index 0d0ec25..46c59e7 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_PlaylistsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_PlaylistsTest.java
@@ -28,6 +28,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio.Playlists;
import android.provider.MediaStore.MediaColumns;
@@ -35,6 +36,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Test;
@@ -43,6 +45,7 @@
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Audio_PlaylistsTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_Playlists_MembersTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_Playlists_MembersTest.java
index 76f7470..be57b56 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_Playlists_MembersTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_Playlists_MembersTest.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio.Media;
import android.provider.MediaStore.Audio.Playlists;
@@ -43,6 +44,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.After;
import org.junit.Before;
@@ -52,6 +54,7 @@
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Audio_Playlists_MembersTest {
private String[] mAudioProjection = {
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_DownloadsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_DownloadsTest.java
index a0fc55c..963e61e 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_DownloadsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_DownloadsTest.java
@@ -30,6 +30,7 @@
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.os.Environment;
import android.os.FileUtils;
import android.provider.MediaStore;
@@ -44,6 +45,7 @@
import android.util.Size;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Assume;
import org.junit.Before;
@@ -64,6 +66,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_DownloadsTest {
private static final String TAG = MediaStore_DownloadsTest.class.getSimpleName();
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_FilesTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_FilesTest.java
index aa5b1be..95cb076 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_FilesTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_FilesTest.java
@@ -35,6 +35,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
@@ -45,6 +46,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Test;
@@ -58,6 +60,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_FilesTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
index 1d18a8a..bacc7b9 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
@@ -34,6 +34,7 @@
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
@@ -51,6 +52,7 @@
import android.util.Size;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Assume;
import org.junit.Before;
@@ -69,6 +71,7 @@
import java.util.Arrays;
import java.util.HashSet;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Images_MediaTest {
private static final String MIME_TYPE_JPEG = "image/jpeg";
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
index 479c3ab..ad543be 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
@@ -42,6 +42,7 @@
import android.graphics.Color;
import android.graphics.ImageDecoder;
import android.net.Uri;
+import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.Images.Media;
@@ -56,6 +57,7 @@
import android.util.Size;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import junit.framework.AssertionFailedError;
@@ -72,6 +74,7 @@
import java.io.OutputStream;
import java.util.ArrayList;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Images_ThumbnailsTest {
private ArrayList<Uri> mRowsAdded;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_MetadataKeysTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_MetadataKeysTest.java
index e70df20..3bb44eb 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_MetadataKeysTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_MetadataKeysTest.java
@@ -29,12 +29,14 @@
import android.content.pm.ComponentInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.apps.cts.gallerytestapp.ReviewActivity;
import android.provider.apps.cts.gallerytestapp.ReviewPrewarmService;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.ArrayUtils;
@@ -44,6 +46,7 @@
import java.util.List;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(AndroidJUnit4.class)
public class MediaStore_MetadataKeysTest {
private static final String TEST_PACKAGE_NAME = "android.provider.apps.cts.gallerytestapp";
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_VideoTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_VideoTest.java
index 202c3ea..1caa7ed 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_VideoTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_VideoTest.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.provider.MediaStore;
import android.provider.MediaStore.Video;
import android.provider.MediaStore.Video.VideoColumns;
@@ -34,6 +35,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Test;
@@ -44,6 +46,7 @@
import java.io.File;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_VideoTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_MediaTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_MediaTest.java
index 5026c0ed..6f50176 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_MediaTest.java
@@ -34,6 +34,7 @@
import android.database.Cursor;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
+import android.os.Build;
import android.os.Environment;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
@@ -49,6 +50,7 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.Assume;
import org.junit.Before;
@@ -65,6 +67,7 @@
import java.io.OutputStream;
import java.util.Arrays;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Video_MediaTest {
private Context mContext;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_ThumbnailsTest.java
index a2859b7..b04d1dd 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_ThumbnailsTest.java
@@ -36,6 +36,7 @@
import android.graphics.Bitmap;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
+import android.os.Build;
import android.os.FileUtils;
import android.provider.MediaStore;
import android.provider.MediaStore.Files;
@@ -48,6 +49,7 @@
import android.util.Size;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import com.android.compatibility.common.util.MediaUtils;
@@ -64,6 +66,7 @@
import java.io.InputStream;
import java.io.OutputStream;
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Video_ThumbnailsTest {
private static final String TAG = "MediaStore_Video_ThumbnailsTest";
diff --git a/tests/tests/sdkextensions/Android.bp b/tests/tests/sdkextensions/Android.bp
deleted file mode 100644
index 89b241b..0000000
--- a/tests/tests/sdkextensions/Android.bp
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-android_test {
- name: "CtsSdkExtensionsTestCases",
- defaults: ["cts_defaults"],
- static_libs: [
- "androidx.test.rules",
- "ctstestrunner-axt",
- ],
- srcs: [ "src/**/*.java" ],
- test_config: "CtsSdkExtensionsTestCases.xml",
- test_suites: [
- "cts",
- "mts",
- "general-tests",
- ],
- sdk_version: "system_current",
-}
diff --git a/tests/tests/sdkextensions/AndroidManifest.xml b/tests/tests/sdkextensions/AndroidManifest.xml
deleted file mode 100644
index a6391b5..0000000
--- a/tests/tests/sdkextensions/AndroidManifest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.os.ext.cts">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.os.ext.cts"
- android:label="CTS tests of android.os.ext">
- <meta-data android:name="listener"
- android:value="com.android.cts.runner.CtsTestRunListener" />
- </instrumentation>
-
-</manifest>
diff --git a/tests/tests/sdkextensions/CtsSdkExtensionsTestCases.xml b/tests/tests/sdkextensions/CtsSdkExtensionsTestCases.xml
deleted file mode 100644
index a0b2055..0000000
--- a/tests/tests/sdkextensions/CtsSdkExtensionsTestCases.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Configuration for SdkExtension Tests">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="framework" />
- <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsSdkExtensionsTestCases.apk" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.os.ext.cts" />
- </test>
-
- <!-- Run CtsSdkExtensionsTestCases when "com.google.android.sdkext" is on device.
- Otherwise skip. The logic only applies to situations when CtsSdkExtensionsTestCasesdoes
- is triggered via mts-tradefed. It is disabled for all other *TS.
- -->
- <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
- <option name="mainline-module-package-name" value="com.google.android.sdkext" />
- </object>
-</configuration>
diff --git a/tests/tests/sdkextensions/OWNERS b/tests/tests/sdkextensions/OWNERS
deleted file mode 100644
index 8e32df8..0000000
--- a/tests/tests/sdkextensions/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include platform/frameworks/base:/apex/sdkextensions/OWNERS
diff --git a/tests/tests/sdkextensions/TEST_MAPPING b/tests/tests/sdkextensions/TEST_MAPPING
deleted file mode 100644
index 7783bda..0000000
--- a/tests/tests/sdkextensions/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit": [
- {
- "name": "CtsSdkExtensionsTestCases"
- }
- ]
-}
diff --git a/tests/tests/sdkextensions/src/android/os/ext/cts/SdkExtensionsTest.java b/tests/tests/sdkextensions/src/android/os/ext/cts/SdkExtensionsTest.java
deleted file mode 100644
index 884f5ef..0000000
--- a/tests/tests/sdkextensions/src/android/os/ext/cts/SdkExtensionsTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os.ext.cts;
-
-import android.os.Build;
-import android.os.ext.SdkExtensions;
-import junit.framework.TestCase;
-
-public class SdkExtensionsTest extends TestCase {
-
- /** Verify that getExtensionVersion only accepts valid extension SDKs */
- public void testBadArgument() throws Exception {
- // R is the first SDK version with extensions.
- for (int sdk = -1_000_000; sdk < Build.VERSION_CODES.R; sdk++) {
- try {
- SdkExtensions.getExtensionVersion(sdk);
- fail("expected IllegalArgumentException");
- } catch (IllegalArgumentException expected) { }
- }
- }
-
- /** Verifies that getExtensionVersion only return existing versions */
- public void testValidValues() throws Exception {
- for (int sdk = Build.VERSION_CODES.R; sdk <= 1_000_000; sdk++) {
- // No extension SDKs versions yet.
- assertEquals(0, SdkExtensions.getExtensionVersion(sdk));
- }
- }
-}
diff --git a/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java b/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java
index 4665644..e6e06d6 100644
--- a/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java
+++ b/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java
@@ -48,28 +48,42 @@
public StubTextToSpeechService() {
supportedLanguages.add(new Locale("eng"));
- supportedCountries.add(new Locale("eng", "USA"));
- supportedCountries.add(new Locale("eng", "GBR"));
- GBFallbacks.add(new Locale("eng", "NZL"));
+ supportedCountries.add(new Locale("eng", "US"));
+ supportedCountries.add(new Locale("eng", "GB"));
+ GBFallbacks.add(new Locale("eng", "NZ"));
}
@Override
protected String[] onGetLanguage() {
- return new String[] { "eng", "USA", "" };
+ return new String[] { "eng", "US", "" };
}
@Override
protected int onIsLanguageAvailable(String lang, String country, String variant) {
+ country = convertISO3CountryToISO2(country);
if (supportedCountries.contains(new Locale(lang, country))) {
return TextToSpeech.LANG_COUNTRY_AVAILABLE;
}
if (supportedLanguages.contains(new Locale(lang))) {
return TextToSpeech.LANG_AVAILABLE;
}
-
+
return TextToSpeech.LANG_NOT_SUPPORTED;
}
+ private String convertISO3CountryToISO2(String iso3Country) {
+ switch (iso3Country.toUpperCase()) {
+ case "USA":
+ return "US";
+ case "GBR":
+ return "GB";
+ case "NZL":
+ return "NZ";
+ default:
+ return iso3Country;
+ }
+ }
+
@Override
protected int onLoadLanguage(String lang, String country, String variant) {
return onIsLanguageAvailable(lang, country, variant);
diff --git a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java
index addd14e..7921d94 100644
--- a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java
+++ b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java
@@ -15,6 +15,7 @@
*/
package android.speech.tts.cts;
+import android.media.AudioAttributes;
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.Environment;
@@ -27,6 +28,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.List;
+import java.util.Locale;
/**
* Tests for {@link android.speech.tts.TextToSpeechService} using StubTextToSpeechService.
@@ -206,6 +208,24 @@
}
}
+ public void testSetLanguage() {
+ TextToSpeech tts = getTts();
+
+ assertEquals(tts.setLanguage(null), TextToSpeech.LANG_NOT_SUPPORTED);
+ assertEquals(tts.setLanguage(new Locale("en", "US")), TextToSpeech.LANG_COUNTRY_AVAILABLE);
+ assertEquals(tts.setLanguage(new Locale("en")), TextToSpeech.LANG_AVAILABLE);
+ assertEquals(tts.setLanguage(new Locale("es", "US")), TextToSpeech.LANG_NOT_SUPPORTED);
+ }
+
+ public void testAddAudioAttributes() {
+ TextToSpeech tts = getTts();
+ AudioAttributes attr =
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
+
+ assertEquals(tts.setAudioAttributes(null), TextToSpeech.ERROR);
+ assertEquals(tts.setAudioAttributes(attr), TextToSpeech.SUCCESS);
+ }
+
private HashMap<String, String> createParams(String utteranceId) {
HashMap<String, String> params = new HashMap<>();
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, utteranceId);
diff --git a/tests/tests/telecom/AndroidTest.xml b/tests/tests/telecom/AndroidTest.xml
index 741a897..6979af2 100644
--- a/tests/tests/telecom/AndroidTest.xml
+++ b/tests/tests/telecom/AndroidTest.xml
@@ -20,9 +20,6 @@
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="hidden-api-checks" value="false" />
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.TokenRequirement">
- <option name="token" value="sim-card" />
- </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CallRedirectionServiceTestApp.apk" />
diff --git a/tests/tests/tethering/Android.bp b/tests/tests/tethering/Android.bp
deleted file mode 100644
index 85bb0e0..0000000
--- a/tests/tests/tethering/Android.bp
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-android_test {
- name: "CtsTetheringTest",
- defaults: ["cts_defaults"],
-
- libs: [
- "android.test.base.stubs",
- ],
-
- srcs: [
- "src/**/*.java",
- ],
-
- static_libs: [
- "TetheringCommonTests",
- "TetheringIntegrationTestsLib",
- "compatibility-device-util-axt",
- "cts-net-utils",
- "net-tests-utils",
- "ctstestrunner-axt",
- "junit",
- "junit-params",
- ],
-
- jni_libs: [
- // For mockito extended
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- ],
-
- // Change to system current when TetheringManager move to bootclass path.
- platform_apis: true,
-
- // Tag this module as a cts test artifact
- test_suites: [
- "cts",
- "general-tests",
- "mts",
- ],
-
- // Include both the 32 and 64 bit versions
- compile_multilib: "both",
-}
diff --git a/tests/tests/tethering/AndroidManifest.xml b/tests/tests/tethering/AndroidManifest.xml
deleted file mode 100644
index 665002e..0000000
--- a/tests/tests/tethering/AndroidManifest.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.tethering.cts">
-
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-
- <application android:debuggable="true">
- <uses-library android:name="android.test.runner" />
- </application>
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.tethering.cts"
- android:label="CTS tests of android.tethering">
- <meta-data android:name="listener"
- android:value="com.android.cts.runner.CtsTestRunListener" />
- </instrumentation>
-
-</manifest>
diff --git a/tests/tests/tethering/AndroidTest.xml b/tests/tests/tethering/AndroidTest.xml
deleted file mode 100644
index e752e3a..0000000
--- a/tests/tests/tethering/AndroidTest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for CTS Tethering test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="networking" />
- <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <option name="not-shardable" value="true" />
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsTetheringTest.apk" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.tethering.cts" />
- </test>
-
- <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
- <option name="mainline-module-package-name" value="com.google.android.tethering" />
- </object>
-</configuration>
diff --git a/tests/tests/tethering/OWNERS b/tests/tests/tethering/OWNERS
deleted file mode 100644
index cd6abeb..0000000
--- a/tests/tests/tethering/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 31808
-lorenzo@google.com
-satk@google.com
-
diff --git a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
deleted file mode 100644
index f47f454..0000000
--- a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
+++ /dev/null
@@ -1,800 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.tethering.test;
-
-import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.TetheringManager.TETHERING_USB;
-import static android.net.TetheringManager.TETHERING_WIFI;
-import static android.net.TetheringManager.TETHERING_WIFI_P2P;
-import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
-import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
-import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
-import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
-import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
-import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
-
-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;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
-
-import android.app.UiAutomation;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.LinkAddress;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.TetheredClient;
-import android.net.TetheringManager;
-import android.net.TetheringManager.OnTetheringEntitlementResultListener;
-import android.net.TetheringManager.TetheringEventCallback;
-import android.net.TetheringManager.TetheringInterfaceRegexps;
-import android.net.TetheringManager.TetheringRequest;
-import android.net.cts.util.CtsNetUtils;
-import android.net.cts.util.CtsNetUtils.TestNetworkCallback;
-import android.net.wifi.WifiClient;
-import android.net.wifi.WifiManager;
-import android.net.wifi.WifiManager.SoftApCallback;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.PersistableBundle;
-import android.os.ResultReceiver;
-import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-
-import androidx.annotation.NonNull;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.ArrayTrackRecord;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-
-@RunWith(AndroidJUnit4.class)
-public class TetheringManagerTest {
-
- private Context mContext;
-
- private ConnectivityManager mCm;
- private TetheringManager mTM;
- private WifiManager mWm;
- private PackageManager mPm;
-
- private TetherChangeReceiver mTetherChangeReceiver;
- private CtsNetUtils mCtsNetUtils;
-
- private static final int DEFAULT_TIMEOUT_MS = 60_000;
-
- private void adoptShellPermissionIdentity() {
- final UiAutomation uiAutomation =
- InstrumentationRegistry.getInstrumentation().getUiAutomation();
- uiAutomation.adoptShellPermissionIdentity();
- }
-
- private void dropShellPermissionIdentity() {
- final UiAutomation uiAutomation =
- InstrumentationRegistry.getInstrumentation().getUiAutomation();
- uiAutomation.dropShellPermissionIdentity();
- }
-
- @Before
- public void setUp() throws Exception {
- adoptShellPermissionIdentity();
- mContext = InstrumentationRegistry.getContext();
- mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- mTM = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE);
- mWm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- mPm = mContext.getPackageManager();
- mCtsNetUtils = new CtsNetUtils(mContext);
- mTetherChangeReceiver = new TetherChangeReceiver();
- final IntentFilter filter = new IntentFilter(
- TetheringManager.ACTION_TETHER_STATE_CHANGED);
- final Intent intent = mContext.registerReceiver(mTetherChangeReceiver, filter);
- if (intent != null) mTetherChangeReceiver.onReceive(null, intent);
- }
-
- @After
- public void tearDown() throws Exception {
- mTM.stopAllTethering();
- mContext.unregisterReceiver(mTetherChangeReceiver);
- dropShellPermissionIdentity();
- }
-
- private static class StopSoftApCallback implements SoftApCallback {
- private final ConditionVariable mWaiting = new ConditionVariable();
- @Override
- public void onStateChanged(int state, int failureReason) {
- if (state == WifiManager.WIFI_AP_STATE_DISABLED) mWaiting.open();
- }
-
- @Override
- public void onConnectedClientsChanged(List<WifiClient> clients) { }
-
- public void waitForSoftApStopped() {
- if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) {
- fail("stopSoftAp Timeout");
- }
- }
- }
-
- // Wait for softAp to be disabled. This is necessary on devices where stopping softAp
- // deletes the interface. On these devices, tethering immediately stops when the softAp
- // interface is removed, but softAp is not yet fully disabled. Wait for softAp to be
- // fully disabled, because otherwise the next test might fail because it attempts to
- // start softAp before it's fully stopped.
- private void expectSoftApDisabled() {
- final StopSoftApCallback callback = new StopSoftApCallback();
- try {
- mWm.registerSoftApCallback(c -> c.run(), callback);
- // registerSoftApCallback will immediately call the callback with the current state, so
- // this callback will fire even if softAp is already disabled.
- callback.waitForSoftApStopped();
- } finally {
- mWm.unregisterSoftApCallback(callback);
- }
- }
-
- private class TetherChangeReceiver extends BroadcastReceiver {
- private class TetherState {
- final ArrayList<String> mAvailable;
- final ArrayList<String> mActive;
- final ArrayList<String> mErrored;
-
- TetherState(Intent intent) {
- mAvailable = intent.getStringArrayListExtra(
- TetheringManager.EXTRA_AVAILABLE_TETHER);
- mActive = intent.getStringArrayListExtra(
- TetheringManager.EXTRA_ACTIVE_TETHER);
- mErrored = intent.getStringArrayListExtra(
- TetheringManager.EXTRA_ERRORED_TETHER);
- }
- }
-
- @Override
- public void onReceive(Context content, Intent intent) {
- String action = intent.getAction();
- if (action.equals(TetheringManager.ACTION_TETHER_STATE_CHANGED)) {
- mResult.add(new TetherState(intent));
- }
- }
-
- public final LinkedBlockingQueue<TetherState> mResult = new LinkedBlockingQueue<>();
-
- // Expects that tethering reaches the desired state.
- // - If active is true, expects that tethering is enabled on at least one interface
- // matching ifaceRegexs.
- // - If active is false, expects that tethering is disabled on all the interfaces matching
- // ifaceRegexs.
- // Fails if any interface matching ifaceRegexs becomes errored.
- public void expectTethering(final boolean active, final String[] ifaceRegexs) {
- while (true) {
- final TetherState state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS, ifaceRegexs);
- assertNotNull("Did not receive expected state change, active: " + active, state);
-
- if (isIfaceActive(ifaceRegexs, state) == active) return;
- }
- }
-
- private TetherState pollAndAssertNoError(final int timeout, final String[] ifaceRegexs) {
- final TetherState state = pollTetherState(timeout);
- assertNoErroredIfaces(state, ifaceRegexs);
- return state;
- }
-
- private TetherState pollTetherState(final int timeout) {
- try {
- return mResult.poll(timeout, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- fail("No result after " + timeout + " ms");
- return null;
- }
- }
-
- private boolean isIfaceActive(final String[] ifaceRegexs, final TetherState state) {
- return isIfaceMatch(ifaceRegexs, state.mActive);
- }
-
- private void assertNoErroredIfaces(final TetherState state, final String[] ifaceRegexs) {
- if (state == null || state.mErrored == null) return;
-
- if (isIfaceMatch(ifaceRegexs, state.mErrored)) {
- fail("Found failed tethering interfaces: " + Arrays.toString(state.mErrored.toArray()));
- }
- }
- }
-
- private static class StartTetheringCallback implements TetheringManager.StartTetheringCallback {
- private static int TIMEOUT_MS = 30_000;
- public static class CallbackValue {
- public final int error;
-
- private CallbackValue(final int e) {
- error = e;
- }
-
- public static class OnTetheringStarted extends CallbackValue {
- OnTetheringStarted() { super(TETHER_ERROR_NO_ERROR); }
- }
-
- public static class OnTetheringFailed extends CallbackValue {
- OnTetheringFailed(final int error) { super(error); }
- }
-
- @Override
- public String toString() {
- return String.format("%s(%d)", getClass().getSimpleName(), error);
- }
- }
-
- private final ArrayTrackRecord<CallbackValue>.ReadHead mHistory =
- new ArrayTrackRecord<CallbackValue>().newReadHead();
-
- @Override
- public void onTetheringStarted() {
- mHistory.add(new CallbackValue.OnTetheringStarted());
- }
-
- @Override
- public void onTetheringFailed(final int error) {
- mHistory.add(new CallbackValue.OnTetheringFailed(error));
- }
-
- public void verifyTetheringStarted() {
- final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true);
- assertNotNull("No onTetheringStarted after " + TIMEOUT_MS + " ms", cv);
- assertTrue("Fail start tethering:" + cv,
- cv instanceof CallbackValue.OnTetheringStarted);
- }
-
- public void expectTetheringFailed(final int expected) throws InterruptedException {
- final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true);
- assertNotNull("No onTetheringFailed after " + TIMEOUT_MS + " ms", cv);
- assertTrue("Expect fail with error code " + expected + ", but received: " + cv,
- (cv instanceof CallbackValue.OnTetheringFailed) && (cv.error == expected));
- }
- }
-
- private static boolean isIfaceMatch(final List<String> ifaceRegexs,
- final List<String> ifaces) {
- return isIfaceMatch(ifaceRegexs.toArray(new String[0]), ifaces);
- }
-
- private static boolean isIfaceMatch(final String[] ifaceRegexs, final List<String> ifaces) {
- if (ifaceRegexs == null) fail("ifaceRegexs should not be null");
-
- if (ifaces == null) return false;
-
- for (String s : ifaces) {
- for (String regex : ifaceRegexs) {
- if (s.matches(regex)) {
- return true;
- }
- }
- }
- return false;
- }
-
- @Test
- public void testStartTetheringWithStateChangeBroadcast() throws Exception {
- if (!mTM.isTetheringSupported()) return;
-
- final String[] wifiRegexs = mTM.getTetherableWifiRegexs();
- if (wifiRegexs.length == 0) return;
-
- final String[] tetheredIfaces = mTM.getTetheredIfaces();
- assertTrue(tetheredIfaces.length == 0);
-
- final StartTetheringCallback startTetheringCallback = new StartTetheringCallback();
- final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
- .setShouldShowEntitlementUi(false).build();
- mTM.startTethering(request, c -> c.run() /* executor */, startTetheringCallback);
- startTetheringCallback.verifyTetheringStarted();
-
- mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs);
-
- mTM.stopTethering(TETHERING_WIFI);
- expectSoftApDisabled();
- mTetherChangeReceiver.expectTethering(false /* active */, wifiRegexs);
- }
-
- @Test
- public void testTetheringRequest() {
- final TetheringRequest tr = new TetheringRequest.Builder(TETHERING_WIFI).build();
- assertEquals(TETHERING_WIFI, tr.getTetheringType());
- assertNull(tr.getLocalIpv4Address());
- assertNull(tr.getClientStaticIpv4Address());
- assertFalse(tr.isExemptFromEntitlementCheck());
- assertTrue(tr.getShouldShowEntitlementUi());
-
- final LinkAddress localAddr = new LinkAddress("192.168.24.5/24");
- final LinkAddress clientAddr = new LinkAddress("192.168.24.100/24");
- final TetheringRequest tr2 = new TetheringRequest.Builder(TETHERING_USB)
- .setStaticIpv4Addresses(localAddr, clientAddr)
- .setExemptFromEntitlementCheck(true)
- .setShouldShowEntitlementUi(false).build();
-
- assertEquals(localAddr, tr2.getLocalIpv4Address());
- assertEquals(clientAddr, tr2.getClientStaticIpv4Address());
- assertEquals(TETHERING_USB, tr2.getTetheringType());
- assertTrue(tr2.isExemptFromEntitlementCheck());
- assertFalse(tr2.getShouldShowEntitlementUi());
- }
-
- // Must poll the callback before looking at the member.
- private static class TestTetheringEventCallback implements TetheringEventCallback {
- private static final int TIMEOUT_MS = 30_000;
-
- public enum CallbackType {
- ON_SUPPORTED,
- ON_UPSTREAM,
- ON_TETHERABLE_REGEX,
- ON_TETHERABLE_IFACES,
- ON_TETHERED_IFACES,
- ON_ERROR,
- ON_CLIENTS,
- ON_OFFLOAD_STATUS,
- };
-
- public static class CallbackValue {
- public final CallbackType callbackType;
- public final Object callbackParam;
- public final int callbackParam2;
-
- private CallbackValue(final CallbackType type, final Object param, final int param2) {
- this.callbackType = type;
- this.callbackParam = param;
- this.callbackParam2 = param2;
- }
- }
-
- private final ArrayTrackRecord<CallbackValue> mHistory =
- new ArrayTrackRecord<CallbackValue>();
-
- private final ArrayTrackRecord<CallbackValue>.ReadHead mCurrent =
- mHistory.newReadHead();
-
- private TetheringInterfaceRegexps mTetherableRegex;
- private List<String> mTetherableIfaces;
- private List<String> mTetheredIfaces;
-
- @Override
- public void onTetheringSupported(boolean supported) {
- mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, (supported ? 1 : 0)));
- }
-
- @Override
- public void onUpstreamChanged(Network network) {
- mHistory.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0));
- }
-
- @Override
- public void onTetherableInterfaceRegexpsChanged(TetheringInterfaceRegexps reg) {
- mTetherableRegex = reg;
- mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0));
- }
-
- @Override
- public void onTetherableInterfacesChanged(List<String> interfaces) {
- mTetherableIfaces = interfaces;
- mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0));
- }
-
- @Override
- public void onTetheredInterfacesChanged(List<String> interfaces) {
- mTetheredIfaces = interfaces;
- mHistory.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0));
- }
-
- @Override
- public void onError(String ifName, int error) {
- mHistory.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error));
- }
-
- @Override
- public void onClientsChanged(Collection<TetheredClient> clients) {
- mHistory.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0));
- }
-
- @Override
- public void onOffloadStatusChanged(int status) {
- mHistory.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0));
- }
-
- public void expectTetherableInterfacesChanged(@NonNull List<String> regexs) {
- assertNotNull("No expected tetherable ifaces callback", mCurrent.poll(TIMEOUT_MS,
- (cv) -> {
- if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) return false;
- final List<String> interfaces = (List<String>) cv.callbackParam;
- return isIfaceMatch(regexs, interfaces);
- }));
- }
-
- public void expectTetheredInterfacesChanged(@NonNull List<String> regexs) {
- assertNotNull("No expected tethered ifaces callback", mCurrent.poll(TIMEOUT_MS,
- (cv) -> {
- if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) return false;
-
- final List<String> interfaces = (List<String>) cv.callbackParam;
-
- // Null regexs means no active tethering.
- if (regexs == null) return interfaces.isEmpty();
-
- return isIfaceMatch(regexs, interfaces);
- }));
- }
-
- public void expectCallbackStarted() {
- int receivedBitMap = 0;
- // The each bit represent a type from CallbackType.ON_*.
- // Expect all of callbacks except for ON_ERROR.
- final int expectedBitMap = 0xff ^ (1 << CallbackType.ON_ERROR.ordinal());
- // Receive ON_ERROR on started callback is not matter. It just means tethering is
- // failed last time, should able to continue the test this time.
- while ((receivedBitMap & expectedBitMap) != expectedBitMap) {
- final CallbackValue cv = mCurrent.poll(TIMEOUT_MS, c -> true);
- if (cv == null) {
- fail("No expected callbacks, " + "expected bitmap: "
- + expectedBitMap + ", actual: " + receivedBitMap);
- }
-
- receivedBitMap |= (1 << cv.callbackType.ordinal());
- }
- }
-
- public void expectOneOfOffloadStatusChanged(int... offloadStatuses) {
- assertNotNull("No offload status changed", mCurrent.poll(TIMEOUT_MS, (cv) -> {
- if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) return false;
-
- final int status = (int) cv.callbackParam;
- for (int offloadStatus : offloadStatuses) if (offloadStatus == status) return true;
-
- return false;
- }));
- }
-
- public void expectErrorOrTethered(final String iface) {
- assertNotNull("No expected callback", mCurrent.poll(TIMEOUT_MS, (cv) -> {
- if (cv.callbackType == CallbackType.ON_ERROR
- && iface.equals((String) cv.callbackParam)) {
- return true;
- }
- if (cv.callbackType == CallbackType.ON_TETHERED_IFACES
- && ((List<String>) cv.callbackParam).contains(iface)) {
- return true;
- }
-
- return false;
- }));
- }
-
- public Network getCurrentValidUpstream() {
- final CallbackValue result = mCurrent.poll(TIMEOUT_MS, (cv) -> {
- return (cv.callbackType == CallbackType.ON_UPSTREAM)
- && cv.callbackParam != null;
- });
-
- assertNotNull("No valid upstream", result);
- return (Network) result.callbackParam;
- }
-
- public void assumeTetheringSupported() {
- final ArrayTrackRecord<CallbackValue>.ReadHead history =
- mHistory.newReadHead();
- assertNotNull("No onSupported callback", history.poll(TIMEOUT_MS, (cv) -> {
- if (cv.callbackType != CallbackType.ON_SUPPORTED) return false;
-
- assumeTrue(cv.callbackParam2 == 1 /* supported */);
- return true;
- }));
- }
-
- public TetheringInterfaceRegexps getTetheringInterfaceRegexps() {
- return mTetherableRegex;
- }
-
- public List<String> getTetherableInterfaces() {
- return mTetherableIfaces;
- }
-
- public List<String> getTetheredInterfaces() {
- return mTetheredIfaces;
- }
- }
-
- private TestTetheringEventCallback registerTetheringEventCallback() {
- final TestTetheringEventCallback tetherEventCallback =
- new TestTetheringEventCallback();
-
- mTM.registerTetheringEventCallback(c -> c.run() /* executor */, tetherEventCallback);
- tetherEventCallback.expectCallbackStarted();
-
- return tetherEventCallback;
- }
-
- private void unregisterTetheringEventCallback(final TestTetheringEventCallback callback) {
- mTM.unregisterTetheringEventCallback(callback);
- }
-
- private List<String> getWifiTetherableInterfaceRegexps(
- final TestTetheringEventCallback callback) {
- return callback.getTetheringInterfaceRegexps().getTetherableWifiRegexs();
- }
-
- private boolean isWifiTetheringSupported(final TestTetheringEventCallback callback) {
- return !getWifiTetherableInterfaceRegexps(callback).isEmpty();
- }
-
- private void startWifiTethering(final TestTetheringEventCallback callback)
- throws InterruptedException {
- final List<String> wifiRegexs = getWifiTetherableInterfaceRegexps(callback);
- assertFalse(isIfaceMatch(wifiRegexs, callback.getTetheredInterfaces()));
-
- final StartTetheringCallback startTetheringCallback = new StartTetheringCallback();
- final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
- .setShouldShowEntitlementUi(false).build();
- mTM.startTethering(request, c -> c.run() /* executor */, startTetheringCallback);
- startTetheringCallback.verifyTetheringStarted();
-
- callback.expectTetheredInterfacesChanged(wifiRegexs);
-
- callback.expectOneOfOffloadStatusChanged(
- TETHER_HARDWARE_OFFLOAD_STARTED,
- TETHER_HARDWARE_OFFLOAD_FAILED);
- }
-
- private void stopWifiTethering(final TestTetheringEventCallback callback) {
- mTM.stopTethering(TETHERING_WIFI);
- expectSoftApDisabled();
- callback.expectTetheredInterfacesChanged(null);
- callback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
- }
-
- @Test
- public void testRegisterTetheringEventCallback() throws Exception {
- final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback();
- tetherEventCallback.assumeTetheringSupported();
-
- if (!isWifiTetheringSupported(tetherEventCallback)) {
- unregisterTetheringEventCallback(tetherEventCallback);
- return;
- }
-
- startWifiTethering(tetherEventCallback);
-
- final List<String> tetheredIfaces = tetherEventCallback.getTetheredInterfaces();
- assertEquals(1, tetheredIfaces.size());
- final String wifiTetheringIface = tetheredIfaces.get(0);
-
- stopWifiTethering(tetherEventCallback);
-
- try {
- final int ret = mTM.tether(wifiTetheringIface);
-
- // There is no guarantee that the wifi interface will be available after disabling
- // the hotspot, so don't fail the test if the call to tether() fails.
- assumeTrue(ret == TETHER_ERROR_NO_ERROR);
-
- // If calling #tether successful, there is a callback to tell the result of tethering
- // setup.
- tetherEventCallback.expectErrorOrTethered(wifiTetheringIface);
- } finally {
- mTM.untether(wifiTetheringIface);
- unregisterTetheringEventCallback(tetherEventCallback);
- }
- }
-
- @Test
- public void testGetTetherableInterfaceRegexps() {
- final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback();
- tetherEventCallback.assumeTetheringSupported();
-
- final TetheringInterfaceRegexps tetherableRegexs =
- tetherEventCallback.getTetheringInterfaceRegexps();
- final List<String> wifiRegexs = tetherableRegexs.getTetherableWifiRegexs();
- final List<String> usbRegexs = tetherableRegexs.getTetherableUsbRegexs();
- final List<String> btRegexs = tetherableRegexs.getTetherableBluetoothRegexs();
-
- assertEquals(wifiRegexs, Arrays.asList(mTM.getTetherableWifiRegexs()));
- assertEquals(usbRegexs, Arrays.asList(mTM.getTetherableUsbRegexs()));
- assertEquals(btRegexs, Arrays.asList(mTM.getTetherableBluetoothRegexs()));
-
- //Verify that any regex name should only contain in one array.
- wifiRegexs.forEach(s -> assertFalse(usbRegexs.contains(s)));
- wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s)));
- usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s)));
-
- unregisterTetheringEventCallback(tetherEventCallback);
- }
-
- @Test
- public void testStopAllTethering() throws Exception {
- final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback();
- tetherEventCallback.assumeTetheringSupported();
-
- try {
- if (!isWifiTetheringSupported(tetherEventCallback)) return;
-
- // TODO: start ethernet tethering here when TetheringManagerTest is moved to
- // TetheringIntegrationTest.
-
- startWifiTethering(tetherEventCallback);
-
- mTM.stopAllTethering();
- tetherEventCallback.expectTetheredInterfacesChanged(null);
- } finally {
- unregisterTetheringEventCallback(tetherEventCallback);
- }
- }
-
- @Test
- public void testEnableTetheringPermission() throws Exception {
- dropShellPermissionIdentity();
- final StartTetheringCallback startTetheringCallback = new StartTetheringCallback();
- mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(),
- c -> c.run() /* executor */, startTetheringCallback);
- startTetheringCallback.expectTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
- }
-
- private class EntitlementResultListener implements OnTetheringEntitlementResultListener {
- private final CompletableFuture<Integer> future = new CompletableFuture<>();
-
- @Override
- public void onTetheringEntitlementResult(int result) {
- future.complete(result);
- }
-
- public int get(long timeout, TimeUnit unit) throws Exception {
- return future.get(timeout, unit);
- }
-
- }
-
- private void assertEntitlementResult(final Consumer<EntitlementResultListener> functor,
- final int expect) throws Exception {
- final EntitlementResultListener listener = new EntitlementResultListener();
- functor.accept(listener);
-
- assertEquals(expect, listener.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
- }
-
- @Test
- public void testRequestLatestEntitlementResult() throws Exception {
- assumeTrue(mTM.isTetheringSupported());
- // Verify that requestLatestTetheringEntitlementResult() can get entitlement
- // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via listener.
- assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult(
- TETHERING_WIFI_P2P, false, c -> c.run(), listener),
- TETHER_ERROR_ENTITLEMENT_UNKNOWN);
-
- // Verify that requestLatestTetheringEntitlementResult() can get entitlement
- // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via receiver.
- assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult(
- TETHERING_WIFI_P2P,
- new ResultReceiver(null /* handler */) {
- @Override
- public void onReceiveResult(int resultCode, Bundle resultData) {
- listener.onTetheringEntitlementResult(resultCode);
- }
- }, false),
- TETHER_ERROR_ENTITLEMENT_UNKNOWN);
-
- // Do not request TETHERING_WIFI entitlement result if TETHERING_WIFI is not available.
- assumeTrue(mTM.getTetherableWifiRegexs().length > 0);
-
- // Verify that null listener will cause IllegalArgumentException.
- try {
- mTM.requestLatestTetheringEntitlementResult(
- TETHERING_WIFI, false, c -> c.run(), null);
- } catch (IllegalArgumentException expect) { }
-
- // Override carrier config to ignore entitlement check.
- final PersistableBundle bundle = new PersistableBundle();
- bundle.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, false);
- overrideCarrierConfig(bundle);
-
- // Verify that requestLatestTetheringEntitlementResult() can get entitlement
- // result TETHER_ERROR_NO_ERROR due to provisioning bypassed.
- assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult(
- TETHERING_WIFI, false, c -> c.run(), listener), TETHER_ERROR_NO_ERROR);
-
- // Reset carrier config.
- overrideCarrierConfig(null);
- }
-
- private void overrideCarrierConfig(PersistableBundle bundle) {
- final CarrierConfigManager configManager = (CarrierConfigManager) mContext
- .getSystemService(Context.CARRIER_CONFIG_SERVICE);
- final int subId = SubscriptionManager.getDefaultSubscriptionId();
- configManager.overrideConfig(subId, bundle);
- }
-
- @Test
- public void testTetheringUpstream() throws Exception {
- assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
- final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback();
- tetherEventCallback.assumeTetheringSupported();
- final boolean previousWifiEnabledState = mWm.isWifiEnabled();
-
- try {
- if (!isWifiTetheringSupported(tetherEventCallback)) return;
-
- if (previousWifiEnabledState) {
- mCtsNetUtils.disconnectFromWifi(null);
- }
-
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- Network activeNetwork = null;
- try {
- mCm.registerDefaultNetworkCallback(networkCallback);
- activeNetwork = networkCallback.waitForAvailable();
- } finally {
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- assertNotNull("No active network. Please ensure the device has working mobile data.",
- activeNetwork);
- final NetworkCapabilities activeNetCap = mCm.getNetworkCapabilities(activeNetwork);
-
- // If active nework is ETHERNET, tethering may not use cell network as upstream.
- assumeFalse(activeNetCap.hasTransport(TRANSPORT_ETHERNET));
-
- assertTrue(activeNetCap.hasTransport(TRANSPORT_CELLULAR));
-
- startWifiTethering(tetherEventCallback);
-
- final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
- Context.TELEPHONY_SERVICE);
- final boolean dunRequired = telephonyManager.isTetheringApnRequired();
- final int expectedCap = dunRequired ? NET_CAPABILITY_DUN : NET_CAPABILITY_INTERNET;
- final Network network = tetherEventCallback.getCurrentValidUpstream();
- final NetworkCapabilities netCap = mCm.getNetworkCapabilities(network);
- assertTrue(netCap.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(netCap.hasCapability(expectedCap));
-
- stopWifiTethering(tetherEventCallback);
- } finally {
- unregisterTetheringEventCallback(tetherEventCallback);
- if (previousWifiEnabledState) {
- mCtsNetUtils.connectToWifi();
- }
- }
- }
-}
diff --git a/tests/tests/textclassifier/Android.bp b/tests/tests/textclassifier/Android.bp
index cad6924..ffd193f 100644
--- a/tests/tests/textclassifier/Android.bp
+++ b/tests/tests/textclassifier/Android.bp
@@ -36,4 +36,5 @@
"src/**/*.java",
],
sdk_version: "test_current",
+ min_sdk_version: "29",
}
diff --git a/tests/tests/textclassifier/QueryTextClassifierServiceActivity/Android.bp b/tests/tests/textclassifier/QueryTextClassifierServiceActivity/Android.bp
index 17dd73c..f8c9dc4 100644
--- a/tests/tests/textclassifier/QueryTextClassifierServiceActivity/Android.bp
+++ b/tests/tests/textclassifier/QueryTextClassifierServiceActivity/Android.bp
@@ -26,4 +26,5 @@
"mts"
],
srcs: ["src/**/*.java"],
-}
\ No newline at end of file
+ min_sdk_version: "29",
+}
diff --git a/tests/tests/util/Android.bp b/tests/tests/util/Android.bp
index 8879628..9ed5826 100644
--- a/tests/tests/util/Android.bp
+++ b/tests/tests/util/Android.bp
@@ -20,6 +20,7 @@
"cts",
"vts10",
"general-tests",
+ "mts",
],
libs: ["android.test.runner.stubs"],
static_libs: [
diff --git a/tests/tests/util/AndroidTest.xml b/tests/tests/util/AndroidTest.xml
index b12f16e..5af112e 100644
--- a/tests/tests/util/AndroidTest.xml
+++ b/tests/tests/util/AndroidTest.xml
@@ -28,4 +28,8 @@
<option name="runtime-hint" value="9m" />
<option name="hidden-api-checks" value="false" />
</test>
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
+ </object>
</configuration>
diff --git a/tests/tests/util/src/android/util/cts/AndroidExceptionTest.java b/tests/tests/util/src/android/util/cts/AndroidExceptionTest.java
index 05a5bf6..04d56a2 100644
--- a/tests/tests/util/src/android/util/cts/AndroidExceptionTest.java
+++ b/tests/tests/util/src/android/util/cts/AndroidExceptionTest.java
@@ -50,5 +50,12 @@
} catch (AndroidException e) {
assertEquals(CAUSE, e.getCause());
}
+
+ try {
+ throw new AndroidException(NAME, CAUSE);
+ } catch (AndroidException e) {
+ assertEquals(NAME, e.getMessage());
+ assertEquals(CAUSE, e.getCause());
+ }
}
}
diff --git a/tests/tests/util/src/android/util/cts/ArrayMapTest.java b/tests/tests/util/src/android/util/cts/ArrayMapTest.java
index cc9feac..b70166b 100644
--- a/tests/tests/util/src/android/util/cts/ArrayMapTest.java
+++ b/tests/tests/util/src/android/util/cts/ArrayMapTest.java
@@ -39,6 +39,7 @@
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -671,4 +672,31 @@
assertEquals(a.hashCode(), b.hashCode());
}
+ @Test
+ public void testRemoveAll() {
+ final ArrayMap<Integer, String> map = new ArrayMap<>();
+ for (Integer i : Arrays.asList(0, 1, 2, 3, 4, 5)) {
+ map.put(i, i.toString());
+ }
+
+ final ArrayMap<Integer, String> expectedMap = new ArrayMap<>();
+ for (Integer i : Arrays.asList(2, 4)) {
+ expectedMap.put(i, String.valueOf(i));
+ }
+ map.removeAll(Arrays.asList(0, 1, 3, 5, 6));
+ if (!compare(map, expectedMap)) {
+ fail("ArrayMap removeAll failure, expect " + expectedMap + ", but " + map);
+ }
+
+ map.removeAll(Collections.emptyList());
+ if (!compare(map, expectedMap)) {
+ fail("ArrayMap removeAll failure for empty maps, expect " + expectedMap + ", but " +
+ map);
+ }
+
+ map.removeAll(Arrays.asList(2, 4));
+ if (!map.isEmpty()) {
+ fail("ArrayMap removeAll failure, expect empty, but " + map);
+ }
+ }
}
diff --git a/tests/tests/wifi/AndroidTest.xml b/tests/tests/wifi/AndroidTest.xml
index 4c6d2f4..d89498c 100644
--- a/tests/tests/wifi/AndroidTest.xml
+++ b/tests/tests/wifi/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.wifi.apex" />
<option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/ScheduleJobActivity.java b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/ScheduleJobActivity.java
index b447878..c1c292b 100644
--- a/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/ScheduleJobActivity.java
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/ScheduleJobActivity.java
@@ -57,7 +57,5 @@
jobScheduler.schedule(jobInfo);
Log.v(TAG,"Job scheduled: " + jobInfo);
-
- finish();
}
}
diff --git a/tests/tests/wifi/TEST_MAPPING b/tests/tests/wifi/TEST_MAPPING
new file mode 100644
index 0000000..d352809
--- /dev/null
+++ b/tests/tests/wifi/TEST_MAPPING
@@ -0,0 +1,22 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsWifiTestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.net.wifi.cts.VirtualDeviceNotSupported"
+ }
+ ]
+ }
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "CtsWifiTestCases[com.google.android.wifi.apex]",
+ "options": [
+ {
+ "exclude-annotation": "android.net.wifi.cts.VirtualDeviceNotSupported"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java b/tests/tests/wifi/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java
index b79bd16..d2700ec 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java
@@ -38,6 +38,7 @@
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@SmallTest
+@VirtualDeviceNotSupported
public class EasyConnectStatusCallbackTest extends WifiJUnit3TestBase {
private static final String TEST_SSID = "\"testSsid\"";
private static final String TEST_PASSPHRASE = "\"testPassword\"";
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/ScanResultTest.java b/tests/tests/wifi/src/android/net/wifi/cts/ScanResultTest.java
index 0dfeda8..98ba803 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/ScanResultTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/ScanResultTest.java
@@ -242,6 +242,7 @@
}
}
+ @VirtualDeviceNotSupported
public void testScanResultTimeStamp() throws Exception {
if (!WifiFeature.isWifiSupported(getContext())) {
// skip the test if WiFi is not supported
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/RequiredProperties.java b/tests/tests/wifi/src/android/net/wifi/cts/VirtualDeviceNotSupported.java
similarity index 60%
rename from hostsidetests/net/app/src/com/android/cts/net/hostside/RequiredProperties.java
rename to tests/tests/wifi/src/android/net/wifi/cts/VirtualDeviceNotSupported.java
index 96838bb..6c23f38f 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/RequiredProperties.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/VirtualDeviceNotSupported.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,19 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+package android.net.wifi.cts;
-import java.lang.annotation.Inherited;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@Retention(RUNTIME)
-@Target({METHOD, TYPE})
-@Inherited
-public @interface RequiredProperties {
- Property[] value();
-}
+/** Annotation for tests that don't pass on virtual devices (i.e. in presubmit). */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface VirtualDeviceNotSupported {}
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
index f4afa87..c52afff 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -118,7 +118,9 @@
private WifiLock mWifiLock;
private static MySync mMySync;
private List<ScanResult> mScanResults = null;
- private NetworkInfo mNetworkInfo;
+ private NetworkInfo mNetworkInfo =
+ new NetworkInfo(ConnectivityManager.TYPE_WIFI, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ "wifi", "unknown");
private final Object mLock = new Object();
private UiDevice mUiDevice;
private boolean mWasVerboseLoggingEnabled;
@@ -514,6 +516,7 @@
* To run this test in cts-tradefed:
* run cts --class android.net.wifi.cts.WifiManagerTest --method testWifiScanTimestamp
*/
+ @VirtualDeviceNotSupported
public void testWifiScanTimestamp() throws Exception {
if (!WifiFeature.isWifiSupported(getContext())) {
Log.d(TAG, "Skipping test as WiFi is not supported");
@@ -1882,30 +1885,37 @@
TestActionListener actionListener = new TestActionListener(mLock);
UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
List<WifiConfiguration> savedNetworks = null;
- WifiConfiguration savedNetwork = null;
+ WifiConfiguration currentConfig = null;
try {
uiAutomation.adoptShellPermissionIdentity();
// These below API's only work with privileged permissions (obtained via shell identity
// for test)
- savedNetworks = mWifiManager.getConfiguredNetworks();
-
- // Ensure that the saved network is not metered.
- savedNetwork = savedNetworks.get(0);
- assertNotEquals("Ensure that the saved network is configured as unmetered",
- savedNetwork.meteredOverride,
- WifiConfiguration.METERED_OVERRIDE_METERED);
// Trigger a scan & wait for connection to one of the saved networks.
mWifiManager.startScan();
waitForConnection();
+ WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+
+ // find the current network's WifiConfiguration
+ currentConfig = mWifiManager.getConfiguredNetworks()
+ .stream()
+ .filter(config -> config.networkId == wifiInfo.getNetworkId())
+ .findAny()
+ .get();
+
+ // Ensure that the current network is not metered.
+ assertNotEquals("Ensure that the saved network is configured as unmetered",
+ currentConfig.meteredOverride,
+ WifiConfiguration.METERED_OVERRIDE_METERED);
+
// Check the network capabilities to ensure that the network is marked not metered.
waitForNetworkCallbackAndCheckForMeteredness(false);
// Now mark the network metered and save.
synchronized (mLock) {
try {
- WifiConfiguration modSavedNetwork = new WifiConfiguration(savedNetwork);
+ WifiConfiguration modSavedNetwork = new WifiConfiguration(currentConfig);
modSavedNetwork.meteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED;
mWifiManager.save(modSavedNetwork, actionListener);
// now wait for callback
@@ -1923,8 +1933,8 @@
} finally {
// Restore original network config (restore the meteredness back);
- if (savedNetwork != null) {
- mWifiManager.updateNetwork(savedNetwork);
+ if (currentConfig != null) {
+ mWifiManager.updateNetwork(currentConfig);
}
uiAutomation.dropShellPermissionIdentity();
}
@@ -2004,6 +2014,7 @@
/**
* Tests {@link WifiManager#getFactoryMacAddresses()} returns at least one valid MAC address.
*/
+ @VirtualDeviceNotSupported
public void testGetFactoryMacAddresses() throws Exception {
if (!WifiFeature.isWifiSupported(getContext())) {
// skip the test if WiFi is not supported
@@ -2143,13 +2154,17 @@
boolean isStaApConcurrencySupported = mWifiManager.isStaApConcurrencySupported();
// start local only hotspot.
TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
- if (isStaApConcurrencySupported) {
- assertTrue(mWifiManager.isWifiEnabled());
- } else {
- // no concurrency, wifi should be disabled.
- assertFalse(mWifiManager.isWifiEnabled());
+ try {
+ if (isStaApConcurrencySupported) {
+ assertTrue(mWifiManager.isWifiEnabled());
+ } else {
+ // no concurrency, wifi should be disabled.
+ assertFalse(mWifiManager.isWifiEnabled());
+ }
+ } finally {
+ // clean up local only hotspot no matter if assertion passed or failed
+ stopLocalOnlyHotspot(callback, true);
}
- stopLocalOnlyHotspot(callback, true);
assertTrue(mWifiManager.isWifiEnabled());
}
diff --git a/tests/tests/wifi/src/android/net/wifi/rtt/cts/TestBase.java b/tests/tests/wifi/src/android/net/wifi/rtt/cts/TestBase.java
index 9c0078d..88113e9 100644
--- a/tests/tests/wifi/src/android/net/wifi/rtt/cts/TestBase.java
+++ b/tests/tests/wifi/src/android/net/wifi/rtt/cts/TestBase.java
@@ -31,7 +31,6 @@
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
-import android.test.AndroidTestCase;
import com.android.compatibility.common.util.SystemUtil;
@@ -56,6 +55,9 @@
// wait for network selection and connection finish
private static final int WAIT_FOR_CONNECTION_FINISH_MS = 30_000;
+ // Interval between failure scans
+ private static final int INTERVAL_BETWEEN_FAILURE_SCAN_MILLIS = 5_000;
+
protected WifiRttManager mWifiRttManager;
protected WifiManager mWifiManager;
private LocationManager mLocationManager;
@@ -234,10 +236,12 @@
bestTestAp = scanResult;
}
}
-
+ if (bestTestAp == null) {
+ // Ongoing connection may cause scan failure, wait for a while before next scan.
+ Thread.sleep(INTERVAL_BETWEEN_FAILURE_SCAN_MILLIS);
+ }
scanCount++;
}
-
return bestTestAp;
}
}
diff --git a/tools/cts-test-metrics/CtsCameraTestCases.reportlog.json b/tools/cts-test-metrics/CtsCameraTestCases.reportlog.json
new file mode 100644
index 0000000..81a9ef1
--- /dev/null
+++ b/tools/cts-test-metrics/CtsCameraTestCases.reportlog.json
@@ -0,0 +1 @@
+{"test_reprocessing_throughput":[{"camera_id":"0","format":35,"reprocess_type":"YUV reprocessing","capture_message":"capture latency","latency":[237.0,102.0,99.0,105.0,124.0,92.0],"camera_reprocessing_average_latency":126.5},{"camera_id":"0","format":34,"reprocess_type":"opaque reprocessing","capture_message":"capture latency","latency":[206.0,91.0,92.0,89.0,119.0,84.0],"camera_reprocessing_average_latency":113.5},{"camera_id":"1","format":35,"reprocess_type":"YUV reprocessing","capture_message":"capture latency","latency":[216.0,84.0,80.0,83.0,93.0,76.0],"camera_reprocessing_average_latency":105.33333333333333},{"camera_id":"1","format":34,"reprocess_type":"opaque reprocessing","capture_message":"capture latency","latency":[212.0,83.0,71.0,80.0,93.0,74.0],"camera_reprocessing_average_latency":102.16666666666667},{"camera_id":"0","format":35,"reprocess_type":"YUV reprocessing","capture_message":"capture latency","latency":[228.0,105.0,85.0,86.0,116.0,83.0],"camera_reprocessing_average_latency":117.16666666666667},{"camera_id":"0","format":34,"reprocess_type":"opaque reprocessing","capture_message":"capture latency","latency":[195.0,89.0,94.0,94.0,116.0,86.0],"camera_reprocessing_average_latency":112.33333333333333},{"camera_id":"1","format":35,"reprocess_type":"YUV reprocessing","capture_message":"capture latency","latency":[150.0,83.0,75.0,75.0,102.0,76.0],"camera_reprocessing_average_latency":93.5},{"camera_id":"1","format":34,"reprocess_type":"opaque reprocessing","capture_message":"capture latency","latency":[198.0,85.0,78.0,71.0,95.0,77.0],"camera_reprocessing_average_latency":100.66666666666667}],"test_camera_launch_average":[{"camera_launch_average_time_for_all_cameras":326.1},{"camera_launch_average_time_for_all_cameras":321.8}],"test_reprocessing_latency":[{"camera_id":"0","format":35,"reprocess_type":"YUV reprocessing","capture_message":"shot to shot latency","latency":[303.0,254.0,259.0,196.0,201.0,195.0],"camera_reprocessing_shot_to_shot_average_latency":234.66666666666666},{"camera_id":"0","format":34,"reprocess_type":"opaque reprocessing","capture_message":"shot to shot latency","latency":[248.0,172.0,209.0,188.0,201.0,204.0],"camera_reprocessing_shot_to_shot_average_latency":203.66666666666666},{"camera_id":"1","format":35,"reprocess_type":"YUV reprocessing","capture_message":"shot to shot latency","latency":[190.0,238.0,220.0,213.0,144.0,154.0],"camera_reprocessing_shot_to_shot_average_latency":193.16666666666666},{"camera_id":"1","format":34,"reprocess_type":"opaque reprocessing","capture_message":"shot to shot latency","latency":[237.0,166.0,153.0,148.0,162.0,140.0],"camera_reprocessing_shot_to_shot_average_latency":167.66666666666666},{"camera_id":"0","format":35,"reprocess_type":"YUV reprocessing","capture_message":"shot to shot latency","latency":[302.0,262.0,256.0,197.0,200.0,201.0],"camera_reprocessing_shot_to_shot_average_latency":236.33333333333334},{"camera_id":"0","format":34,"reprocess_type":"opaque reprocessing","capture_message":"shot to shot latency","latency":[251.0,166.0,199.0,199.0,213.0,201.0],"camera_reprocessing_shot_to_shot_average_latency":204.83333333333334},{"camera_id":"1","format":35,"reprocess_type":"YUV reprocessing","capture_message":"shot to shot latency","latency":[199.0,153.0,159.0,164.0,152.0,166.0],"camera_reprocessing_shot_to_shot_average_latency":165.5},{"camera_id":"1","format":34,"reprocess_type":"opaque reprocessing","capture_message":"shot to shot latency","latency":[210.0,143.0,161.0,162.0,158.0,156.0],"camera_reprocessing_shot_to_shot_average_latency":165.0}],"test_high_quality_reprocessing_latency":[{"camera_id":"0","format":35,"reprocess_type":"YUV reprocessing","capture_message":"shot to shot latency for High Quality noise reduction and edge modes","latency":[479.0,398.0,351.0,487.0,461.0,395.0],"camera_reprocessing_shot_to_shot_average_latency":428.5},{"camera_id":"0","format":34,"reprocess_type":"opaque reprocessing","capture_message":"shot to shot latency for High Quality noise reduction and edge modes","latency":[355.0,324.0,335.0,334.0,336.0,347.0],"camera_reprocessing_shot_to_shot_average_latency":338.5},{"camera_id":"1","format":35,"reprocess_type":"YUV reprocessing","capture_message":"shot to shot latency for High Quality noise reduction and edge modes","latency":[235.0,220.0,223.0,228.0,222.0,227.0],"camera_reprocessing_shot_to_shot_average_latency":225.83333333333334},{"camera_id":"1","format":34,"reprocess_type":"opaque reprocessing","capture_message":"shot to shot latency for High Quality noise reduction and edge modes","latency":[256.0,186.0,230.0,215.0,226.0,242.0],"camera_reprocessing_shot_to_shot_average_latency":225.83333333333334},{"camera_id":"0","format":35,"reprocess_type":"YUV reprocessing","capture_message":"shot to shot latency for High Quality noise reduction and edge modes","latency":[415.0,327.0,336.0,340.0,323.0,332.0],"camera_reprocessing_shot_to_shot_average_latency":345.5},{"camera_id":"0","format":34,"reprocess_type":"opaque reprocessing","capture_message":"shot to shot latency for High Quality noise reduction and edge modes","latency":[381.0,302.0,331.0,332.0,336.0,333.0],"camera_reprocessing_shot_to_shot_average_latency":335.8333333333333},{"camera_id":"1","format":35,"reprocess_type":"YUV reprocessing","capture_message":"shot to shot latency for High Quality noise reduction and edge modes","latency":[231.0,222.0,223.0,227.0,227.0,223.0],"camera_reprocessing_shot_to_shot_average_latency":225.5},{"camera_id":"1","format":34,"reprocess_type":"opaque reprocessing","capture_message":"shot to shot latency for High Quality noise reduction and edge modes","latency":[275.0,178.0,222.0,224.0,249.0,204.0],"camera_reprocessing_shot_to_shot_average_latency":225.33333333333334}],"test_single_capture":[{"camera_id":"0","camera_capture_latency":[476.0,639.0,654.0,639.0,665.0],"camera_capture_result_latency":[260.0,465.0,490.0,471.0,474.0]},{"camera_id":"1","camera_capture_latency":[461.0,639.0,627.0,637.0,631.0],"camera_capture_result_latency":[341.0,530.0,533.0,533.0,535.0]},{"camera_id":"0","camera_capture_latency":[465.0,643.0,660.0,649.0,642.0],"camera_capture_result_latency":[251.0,467.0,491.0,474.0,475.0]},{"camera_id":"1","camera_capture_latency":[457.0,541.0,533.0,546.0,534.0],"camera_capture_result_latency":[338.0,475.0,467.0,477.0,471.0]}],"test_single_capture_average":[{"camera_capture_result_average_latency_for_all_cameras":463.2},{"camera_capture_result_average_latency_for_all_cameras":438.6}],"test_reprocessing_capture_stall":[{"camera_id":"0","format":35,"reprocess_type":"YUV reprocessing","max_capture_timestamp_gaps":[66.929849,66.927076,66.827072],"capture_average_frame_duration":[66.742792,66.742792,66.742792],"camera_reprocessing_average_max_capture_timestamp_gaps":66.89466566666665},{"camera_id":"0","format":34,"reprocess_type":"opaque reprocessing","max_capture_timestamp_gaps":[66.838494,66.862969,67.054342],"capture_average_frame_duration":[66.742792,66.742792,66.742792],"camera_reprocessing_average_max_capture_timestamp_gaps":66.91860166666667},{"camera_id":"1","format":35,"reprocess_type":"YUV reprocessing","max_capture_timestamp_gaps":[75.091,75.156,75.092],"capture_average_frame_duration":[75.08460800000003,75.08460800000003,75.08460800000003],"camera_reprocessing_average_max_capture_timestamp_gaps":75.113},{"camera_id":"1","format":34,"reprocess_type":"opaque reprocessing","max_capture_timestamp_gaps":[75.096,75.09,75.091],"capture_average_frame_duration":[75.08460800000003,75.08460800000003,75.08460800000003],"camera_reprocessing_average_max_capture_timestamp_gaps":75.09233333333333},{"camera_id":"0","format":35,"reprocess_type":"YUV reprocessing","max_capture_timestamp_gaps":[66.810656,67.101617,66.811857],"capture_average_frame_duration":[66.742792,66.742792,66.742792],"camera_reprocessing_average_max_capture_timestamp_gaps":66.90804333333334},{"camera_id":"0","format":34,"reprocess_type":"opaque reprocessing","max_capture_timestamp_gaps":[133.322575,66.919741,66.95088],"capture_average_frame_duration":[66.742792,66.742792,66.742792],"camera_reprocessing_average_max_capture_timestamp_gaps":89.06439866666666},{"camera_id":"1","format":35,"reprocess_type":"YUV reprocessing","max_capture_timestamp_gaps":[80.088,80.091,80.089],"capture_average_frame_duration":[80.08507200000001,80.08507200000001,80.08507200000001],"camera_reprocessing_average_max_capture_timestamp_gaps":80.08933333333333},{"camera_id":"1","format":34,"reprocess_type":"opaque reprocessing","max_capture_timestamp_gaps":[80.092,80.091,80.091],"capture_average_frame_duration":[80.08507200000001,80.08507200000001,80.08507200000001],"camera_reprocessing_average_max_capture_timestamp_gaps":80.09133333333334}],"test_camera_launch":[{"camera_id":"0","camera_open_time":[116.0,85.0,88.0,83.0,86.0],"camera_configure_stream_time":[20.0,11.0,11.0,10.0,10.0],"camera_start_preview_time":[312.0,224.0,223.0,219.0,230.0],"camera_camera_stop_preview":[278.0,255.0,265.0,268.0,267.0],"camera_camera_close_time":[107.0,124.0,103.0,108.0,127.0],"camera_launch_time":[448.0,320.0,322.0,312.0,326.0]},{"camera_id":"1","camera_open_time":[72.0,67.0,67.0,67.0,65.0],"camera_configure_stream_time":[12.0,10.0,11.0,10.0,11.0],"camera_start_preview_time":[227.0,231.0,224.0,226.0,233.0],"camera_camera_stop_preview":[167.0,162.0,171.0,170.0,168.0],"camera_camera_close_time":[96.0,87.0,91.0,85.0,90.0],"camera_launch_time":[311.0,308.0,302.0,303.0,309.0]},{"camera_id":"0","camera_open_time":[96.0,85.0,89.0,89.0,84.0],"camera_configure_stream_time":[14.0,10.0,10.0,10.0,10.0],"camera_start_preview_time":[262.0,220.0,224.0,221.0,226.0],"camera_camera_stop_preview":[259.0,251.0,271.0,257.0,265.0],"camera_camera_close_time":[117.0,153.0,120.0,122.0,118.0],"camera_launch_time":[372.0,315.0,323.0,320.0,320.0]},{"camera_id":"1","camera_open_time":[71.0,67.0,68.0,70.0,69.0],"camera_configure_stream_time":[11.0,10.0,10.0,10.0,10.0],"camera_start_preview_time":[228.0,235.0,233.0,237.0,239.0],"camera_camera_stop_preview":[167.0,169.0,169.0,162.0,173.0],"camera_camera_close_time":[95.0,89.0,93.0,94.0,103.0],"camera_launch_time":[310.0,312.0,311.0,317.0,318.0]}],"test_high_quality_reprocessing_throughput":[{"camera_id":"0","format":35,"reprocess_type":"YUV reprocessing","capture_message":"capture latency for High Quality noise reduction and edge modes","latency":[272.0,246.0,211.0,210.0,235.0,202.0],"camera_reprocessing_average_latency":229.33333333333334},{"camera_id":"0","format":34,"reprocess_type":"opaque reprocessing","capture_message":"capture latency for High Quality noise reduction and edge modes","latency":[304.0,210.0,206.0,209.0,226.0,229.0],"camera_reprocessing_average_latency":230.66666666666666},{"camera_id":"1","format":35,"reprocess_type":"YUV reprocessing","capture_message":"capture latency for High Quality noise reduction and edge modes","latency":[246.0,123.0,116.0,114.0,131.0,109.0],"camera_reprocessing_average_latency":139.83333333333334},{"camera_id":"1","format":34,"reprocess_type":"opaque reprocessing","capture_message":"capture latency for High Quality noise reduction and edge modes","latency":[211.0,112.0,116.0,112.0,123.0,110.0],"camera_reprocessing_average_latency":130.66666666666666},{"camera_id":"0","format":35,"reprocess_type":"YUV reprocessing","capture_message":"capture latency for High Quality noise reduction and edge modes","latency":[349.0,215.0,214.0,214.0,238.0,213.0],"camera_reprocessing_average_latency":240.5},{"camera_id":"0","format":34,"reprocess_type":"opaque reprocessing","capture_message":"capture latency for High Quality noise reduction and edge modes","latency":[326.0,206.0,204.0,206.0,225.0,232.0],"camera_reprocessing_average_latency":233.16666666666666},{"camera_id":"1","format":35,"reprocess_type":"YUV reprocessing","capture_message":"capture latency for High Quality noise reduction and edge modes","latency":[238.0,119.0,130.0,116.0,130.0,114.0],"camera_reprocessing_average_latency":141.16666666666666},{"camera_id":"1","format":34,"reprocess_type":"opaque reprocessing","capture_message":"capture latency for High Quality noise reduction and edge modes","latency":[249.0,117.0,122.0,113.0,129.0,119.0],"camera_reprocessing_average_latency":141.5}]}
\ No newline at end of file
diff --git a/tools/cts-test-metrics/CtsUiHostTestCases.reportlog.json b/tools/cts-test-metrics/CtsUiHostTestCases.reportlog.json
new file mode 100644
index 0000000..6355fe3
--- /dev/null
+++ b/tools/cts-test-metrics/CtsUiHostTestCases.reportlog.json
@@ -0,0 +1 @@
+{"test_install_time":[{"install_time":[1950.0,1722.0,1762.0,1678.0,1738.0,1694.0,1787.0,1797.0,1799.0,1786.0],"install_time_average":1771.3},{"install_time":[1976.0,1986.0,1930.0,1729.0,1859.0,1875.0,1904.0,1805.0,1748.0,1875.0],"install_time_average":1868.7}]}
\ No newline at end of file
diff --git a/tools/cts-test-metrics/README b/tools/cts-test-metrics/README
new file mode 100644
index 0000000..cb68f3a
--- /dev/null
+++ b/tools/cts-test-metrics/README
@@ -0,0 +1,14 @@
+The parse_test_metrics.py script can be used to parse test metrics json files. Run the following
+command to see a demo:
+python parse_test_metrics.py CtsCameraTestCases.reportlog.json
+
+To parse multiple files, list all files as arguments. Try the following:
+python parse_test_metrics.py CtsCameraTestCases.reportlog.json CtsUiHostTestCases.reportlog.json
+python parse_test_metrics.py *.json
+
+Test metrics json files can be found in $CTS_ROOT/repository/results/$RESULT_DIR/report-log-files/
+directory.
+
+The MetricsParser class defines functions to parse a json file. The _Parse function takes a filename
+as input, reads the json file and adds the json object to json_data. The _PrintJson function
+takes the filename and corresponding json_data and prints out the streams as key, value pairs.
diff --git a/tools/cts-test-metrics/parse_test_metrics.py b/tools/cts-test-metrics/parse_test_metrics.py
new file mode 100755
index 0000000..839e372
--- /dev/null
+++ b/tools/cts-test-metrics/parse_test_metrics.py
@@ -0,0 +1,58 @@
+#!/usr/bin/python
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import argparse, json, sys
+
+class MetricsParser(object):
+ """Executor of this utility"""
+
+ def __init__(self):
+ self._parser = argparse.ArgumentParser('Parse CTS Test metrics jsons')
+ self._parser.add_argument('filenames', metavar='filenames', nargs='+',
+ help='filenames of metrics jsons to be parsed')
+ self._metrics = []
+
+ def _ParseArgs(self):
+ self._args = self._parser.parse_args()
+
+ def _Parse(self, filename):
+ json_file = open(filename)
+ json_data = json.load(json_file)
+ self._metrics.append(json_data)
+ self._PrintJson(filename, json_data)
+
+ def _PrintJson(self, filename, json_data):
+ print "\nFilename: %s" % filename
+ stream_names = json_data.keys()
+ for stream_name in stream_names:
+ metrics_list = json_data.get(stream_name)
+ for metrics in metrics_list:
+ print "\nStream Name: %s" % stream_name
+ for key in metrics.keys():
+ print "Key: %s \t Value: %s" % (key, str(metrics.get(key)))
+
+ def Run(self):
+ self._ParseArgs()
+ try:
+ for filename in self._args.filenames:
+ self._Parse(filename)
+ except (IOError, ValueError) as e:
+ print >> sys.stderr, e
+ raise KeyboardInterrupt
+
+if __name__ == '__main__':
+ MetricsParser().Run()
+
diff --git a/tools/cts-tradefed/Android.bp b/tools/cts-tradefed/Android.bp
new file mode 100644
index 0000000..93c2062
--- /dev/null
+++ b/tools/cts-tradefed/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_library_host {
+ name: "cts-tradefed-harness",
+
+ java_resource_dirs: ["res"],
+ libs: [
+ "tradefed",
+ "compatibility-host-util",
+ ],
+ static_libs: [
+ "compatibility-tradefed",
+ ],
+}
+
+tradefed_binary_host {
+ name: "cts-tradefed",
+ wrapper: "etc/cts-tradefed",
+ short_name: "CTS",
+ full_name: "Compatibility Test Suite",
+ version: "11_r2",
+ static_libs: ["cts-tradefed-harness"],
+ required: ["compatibility-host-util"],
+}
diff --git a/tools/cts-tradefed/DynamicConfig.xml b/tools/cts-tradefed/DynamicConfig.xml
new file mode 100644
index 0000000..60b0e98
--- /dev/null
+++ b/tools/cts-tradefed/DynamicConfig.xml
@@ -0,0 +1,21 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--TODO(b/117957288): Remove dynamic config from suite-level.-->
+<dynamicConfig>
+ <entry key="media_files_url">
+ <value>https://dl.google.com/dl/android/cts/android-cts-media-1.4.zip</value>
+ </entry>
+</dynamicConfig>
diff --git a/tools/cts-tradefed/README b/tools/cts-tradefed/README
new file mode 100644
index 0000000..99d155a
--- /dev/null
+++ b/tools/cts-tradefed/README
@@ -0,0 +1,83 @@
+CTS Trade Federation
+---------------------
+
+CTS Trade Federation, cts-tradefed for short, is the next
+generation test harness for CTS.
+
+cts-tradefed is built on top of the Android Trade Federation test harness.
+
+It works in a similar manner to the prior CTS harness, but supports some
+advanced features such as:
+
+ - modular, flexible extensible design. cts-tradefed can be extended to
+support running CTS in a continuous test environment.
+ - supports sharding a CTS test run across multiple devices in parallel
+ - automatically continue a CTS test run on another device if connection
+is lost
+
+Configuring cts-tradefed
+------------------------
+
+1. Ensure 'adb' is in your current PATH. adb can be found in the
+Android SDK available from http://developer.android.com
+
+Example:
+ PATH=$PATH:/home/myuser/android-sdk-linux_x86/platform-tools
+
+2. Follow the 'Setting up your device' steps documented in the
+CTS User Manual. The CTS User Manual can be downloaded at
+http://source.android.com/compatibility/downloads.html
+
+3. Connect the device to the host machine.
+
+4. Ensure device is visible via 'adb devices'
+
+Using cts-tradefed
+-------------------
+
+To run a test plan on a single device:
+
+1. Make sure you have at least one device connected
+2. Launch the cts-tradefed console by running the 'cts-tradefed'. If you've
+downloaded and extracted the CTS zip, the script can be found at
+ android-cts/tools/cts-tradefed
+Or else if you are working from the Android source tree and have run make cts,
+the script can be found at
+ out/host/linux-x86/cts/android-cts/tools/cts-tradefed
+3. Type:
+'run cts' to run the default CTS plan
+
+Some other useful commands are
+
+To run a test module:
+'run cts --module <module_name>'
+
+To run a specific test:
+'run cts --module <module_name> --test <test_name>'
+
+To shard a plan test run on multiple devices
+'run cts --shard-count <number of shards>
+note: all connected devices must be running the same build
+
+For more options:
+'run cts --help'
+
+CTS Tradefed Development
+------------------------
+See http://source.android.com for instructions on obtaining the Android
+platform source code and setting up a build environment.
+
+The source for the CTS extensions for tradefed can be found at
+<android source root>/cts/tools/tradefed-host
+
+The source for the tradefed framework can be found on the 'tradefed' branch.
+
+Perform these steps to build and run cts-tradefed from the development
+environment:
+cd <path to android source root>
+make cts
+cts-tradefed
+
+More documentation and details on using and extending trade federation will
+be forthcoming in the near future.
+
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
new file mode 100755
index 0000000..ed62d05
--- /dev/null
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -0,0 +1,142 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# launcher script for cts-tradefed harness
+# can be used from an Android build environment, or a standalone cts zip
+
+checkFile() {
+ if [ ! -f "$1" ]; then
+ echo "Unable to locate $1"
+ exit
+ fi;
+}
+
+checkPath() {
+ if ! type -P $1 &> /dev/null; then
+ echo "Unable to find $1 in path."
+ exit
+ fi;
+}
+
+# readlink does not work on MacOS so rely on our own realpath
+realpath() {
+ [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
+}
+
+checkPath aapt
+checkPath adb
+checkPath java
+
+# check java version
+JAVA_VERSION=$(java -version 2>&1 | grep -m 1 'version [ "]\(1\.8\|9\|11\).*[ "]')
+if [ "${JAVA_VERSION}" == "" ]; then
+ echo "Wrong java version. 1.8, 9, or 11 is required."
+ exit
+fi
+
+# check debug flag and set up remote debugging
+if [ -n "${TF_DEBUG}" ]; then
+ if [ -z "${TF_DEBUG_PORT}" ]; then
+ TF_DEBUG_PORT=10088
+ fi
+ RDBG_FLAG=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=${TF_DEBUG_PORT}
+fi
+
+JAVA_BINARY=${CTS_ROOT}/android-cts/jdk/bin/java
+
+if [ ! -f "${JAVA_BINARY}" ]; then
+ JAVA_BINARY=java
+fi
+
+# get OS
+HOST=`uname`
+if [ "$HOST" == "Linux" ]; then
+ OS="linux-x86"
+elif [ "$HOST" == "Darwin" ]; then
+ OS="darwin-x86"
+ # Bundled java is for linux so use host JDK on Darwin
+ JAVA_BINARY=java
+else
+ echo "Unrecognized OS"
+ exit
+fi
+
+# check if in Android build env
+if [ ! -z "${ANDROID_BUILD_TOP}" ]; then
+ if [ ! -z "${ANDROID_HOST_OUT}" ]; then
+ CTS_ROOT=${ANDROID_HOST_OUT}/cts
+ else
+ CTS_ROOT=${ANDROID_BUILD_TOP}/${OUT_DIR:-out}/host/${OS}/cts
+ fi
+ if [ ! -d ${CTS_ROOT} ]; then
+ echo "Could not find $CTS_ROOT in Android build environment. Try 'make cts'"
+ exit
+ fi;
+fi;
+
+if [ -z ${CTS_ROOT} ]; then
+ # assume we're in an extracted cts install
+ CTS_ROOT="$(dirname $(realpath $0))/../.."
+fi;
+
+JAR_DIR=${CTS_ROOT}/android-cts/tools
+JARS="tradefed
+ tradefed-test-framework
+ loganalysis
+ compatibility-host-util
+ compatibility-host-util-tests
+ cts-tradefed
+ cts-tradefed-tests
+ compatibility-common-util-tests
+ compatibility-tradefed-tests"
+
+for JAR in $JARS; do
+ checkFile ${JAR_DIR}/${JAR}.jar
+ JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
+done
+JAR_PATH=${JAR_PATH:1} # Strip off leading ':'
+
+OPTIONAL_JARS="
+ google-tradefed
+ google-tradefed-tests
+ google-tf-prod-tests"
+
+STANDALONE_JAR_DIR=${ANDROID_HOST_OUT}/framework
+for JAR in $OPTIONAL_JARS; do
+ if [ -f "${JAR_DIR}/${JAR}.jar" ]; then
+ JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
+ elif [ -f "${STANDALONE_JAR_DIR}/${JAR}.jar" ]; then
+ JAR_PATH=${JAR_PATH}:${STANDALONE_JAR_DIR}/${JAR}.jar
+ fi;
+done
+
+# load any shared libraries for host-side executables
+LIB_DIR=${CTS_ROOT}/android-cts/lib
+if [ "$HOST" == "Linux" ]; then
+ LD_LIBRARY_PATH=${LIB_DIR}:${LIB_DIR}64:${LD_LIBRARY_PATH}
+ export LD_LIBRARY_PATH
+elif [ "$HOST" == "Darwin" ]; then
+ DYLD_LIBRARY_PATH=${LIB_DIR}:${LIB_DIR}64:${DYLD_LIBRARY_PATH}
+ export DYLD_LIBRARY_PATH
+fi
+
+# include any host-side test jars
+for j in ${CTS_ROOT}/android-cts/testcases/*.jar; do
+ JAR_PATH=${JAR_PATH}:$j
+done
+
+${JAVA_BINARY} $RDBG_FLAG -Xmx6g -XX:+HeapDumpOnOutOfMemoryError -cp ${JAR_PATH} -DCTS_ROOT=${CTS_ROOT} com.android.compatibility.common.tradefed.command.CompatibilityConsole "$@"
+
diff --git a/tools/cts-tradefed/res/config/basic-reporters.xml b/tools/cts-tradefed/res/config/basic-reporters.xml
new file mode 100644
index 0000000..6fddf24
--- /dev/null
+++ b/tools/cts-tradefed/res/config/basic-reporters.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Configuration with basic CTS reporters" >
+</configuration>
diff --git a/tools/cts-tradefed/res/config/collect-tests-only.xml b/tools/cts-tradefed/res/config/collect-tests-only.xml
new file mode 100644
index 0000000..a3769a9
--- /dev/null
+++ b/tools/cts-tradefed/res/config/collect-tests-only.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS from a pre-existing CTS installation">
+
+ <include name="cts" />
+
+ <!-- This tells cts-tradefed and the server what the plan name is, reports that have this plan
+ name should not be accepted, as it doesn't actually run the tests it simply marks all of
+ them as passed.
+ Obviously no one would modify the report before uploading to falsify this
+ information, as that would be dishonest, and dishonesty kills kittens :'( -->
+ <option name="plan" value="collect-tests-only" />
+
+ <option name="skip-preconditions" value="true" />
+ <option name="skip-system-status-check" value="com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker" />
+ <option name="preparer-whitelist" value="com.android.tradefed.targetprep.suite.SuiteApkInstaller" />
+ <option name="preparer-whitelist" value="com.android.compatibility.common.tradefed.targetprep.ApkInstaller" />
+ <option name="preparer-whitelist" value="com.android.compatibility.common.tradefed.targetprep.FilePusher" />
+
+ <option name="compatibility:collect-tests-only" value="true" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/csi-known-failures.xml b/tools/cts-tradefed/res/config/csi-known-failures.xml
new file mode 100644
index 0000000..bbb98b7
--- /dev/null
+++ b/tools/cts-tradefed/res/config/csi-known-failures.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Known fialures on CSI">
+ <!-- Troublesome tests that often crash the system -->
+ <option name="compatibility:exclude-filter" value="CtsAppExitTestCases android.app.cts.ActivityManagerAppExitInfoTest#testCrash" />
+ <option name="compatibility:exclude-filter" value="CtsAppExitTestCases android.app.cts.ActivityManagerAppExitInfoTest#testNativeCrash" />
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.ExternalStorageHostTest#testMediaEscalation28" />
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.ExternalStorageHostTest#testMediaEscalation29" />
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.ExternalStorageHostTest#testMediaEscalation" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActivityManagerFgsBgStartTest#testFgsLocationPendingIntent" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_checkActivityFlagsDocumentLaunchMode" />
+ <option name="compatibility:exclude-filter" value="CtsDeviceIdleHostTestCases com.android.cts.deviceidle.DeviceIdleWhitelistTest#testRemovesPersistedAcrossReboots" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.DeviceOwnerTest#testProxyPacProxyTest" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedDeviceOwnerTest#testPackageInstallUserRestrictions" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#requestEmptyRoleThenDeniedAutomatically" />
+ <option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases android.cts.statsd.metric.MetricActivationTests#testRestart" />
+ <option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases android.cts.statsd.metric.MetricActivationTests#testMultipleActivations" />
+ <option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases android.cts.statsd.atom.UidAtomTests#testANROccurred" />
+ <option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases android.cts.statsd.atom.UidAtomTests#testAppCrashOccurred" />
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.SurfaceViewTests#testMovingWhiteSurfaceView" />
+
+ <!-- Exclude known failure of CtsMediaTestCases (mostly on some Pixel phones) -->
+ <!-- CSI doesn't seem to include ringtones. -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.RingtoneManagerTest" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.RingtoneTest" />
+
+ <!-- Following failures take about 10 min each, so exclude them to reduce test time. -->
+ <!-- CSI on Goldfish can pass the following tests in StreamingMediaPlayerTest. -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.StreamingMediaPlayerTest#testHTTP_H263_AMR_Video2" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.StreamingMediaPlayerTest#testHTTP_H264Base_AAC_Video2" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.StreamingMediaPlayerTest#testHTTP_MPEG4SP_AAC_Video2" />
+
+ <!-- CSI on Cuttlefish and Goldfish can pass the following tests in VideoCodecTest. -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoCodecTest#testParallelEncodingAndDecodingAVC" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoCodecTest#testParallelEncodingAndDecodingHEVC" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoCodecTest#testParallelEncodingAndDecodingVP8" />
+
+ <!-- Failures will crash the test harness, so exclude it here (even though only failed with VP9 decoder). -->
+ <!-- CSI on Cuttlefish and Goldfish can pass the following tests in VideoDecoderRotationTest. -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderRotationTest" />
+
+ <!-- CSI on Cuttlefish and Goldfish can pass the following tests in VideoDecoderPerfTest. -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther0Perf0320x0240" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther0Perf0720x0480" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther0Perf1280x0720" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther1Perf0320x0240" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther1Perf0720x0480" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther1Perf1280x0720" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther1Perf1920x1080" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther0Perf0352x0288" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther0Perf0640x0360" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther0Perf0720x0480" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther0Perf1280x0720" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther0Perf1920x1080" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther1Perf0352x0288" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther1Perf0640x0360" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther1Perf0720x0480" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther1Perf1280x0720" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther1Perf1920x1080" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther1Perf3840x2160" />
+
+ <!-- CSI on Cuttlefish and Goldfish can pass the following tests in VideoEncoderTest. -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH263SurfMinMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfArbitraryH" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfArbitraryW" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfMaxMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfMaxMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfMinMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfNearMaxMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfNearMaxMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfNearMinMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfQCIF" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfArbitraryH" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfArbitraryW" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfMaxMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfMinMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfNearMaxMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfNearMaxMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfNearMinMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfNearMinMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8Surf480p" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfArbitraryH" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfArbitraryW" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfMaxMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfMaxMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfMinMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfNearMaxMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfNearMaxMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfNearMinMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfQCIF" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9Surf480p" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfArbitraryH" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfArbitraryW" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfMaxMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfMaxMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfMinMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfNearMaxMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfNearMaxMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfNearMinMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfQCIF" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-automated.xml b/tools/cts-tradefed/res/config/cts-automated.xml
new file mode 100644
index 0000000..150f8b9
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-automated.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS with common options set for an automated run on userdebug/eng builds">
+
+ <include name="cts" />
+
+ <option name="plan" value="cts" />
+
+ <option name="skip-preconditions" value="false" />
+ <option name="skip-system-status-check" value="com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker" />
+
+ <!-- Tell all AndroidJUnitTests to exclude certain annotations -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
+
+ <!-- Tell all HostTests to exclude certain annotations -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
+ <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-camera.xml b/tools/cts-tradefed/res/config/cts-camera.xml
new file mode 100644
index 0000000..47377b4
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-camera.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS-camera from a pre-existing CTS installation">
+
+ <include name="cts" />
+
+ <option name="plan" value="cts-camera" />
+
+ <!-- All camera CTS tests -->
+ <option name="compatibility:include-filter" value="CtsCameraTestCases" />
+
+ <!-- Other camera related CTS tests -->
+ <option name="compatibility:include-filter"
+ value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testCameraFeatures"/>
+ <option name="compatibility:include-filter"
+ value="CtsPermissionTestCases android.permission.cts.CameraPermissionTest"/>
+ <option name="compatibility:include-filter"
+ value="CtsPermissionTestCases android.permission.cts.Camera2PermissionTest"/>
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-common.xml b/tools/cts-tradefed/res/config/cts-common.xml
new file mode 100644
index 0000000..c1dffd2
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-common.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Common configuration for cts and cts-reference-aosp">
+
+ <include name="everything" />
+ <option name="compatibility:run-suite-tag" value="cts" />
+ <!-- Enable module parameterization to run instant_app modules in main CTS -->
+ <option name="compatibility:enable-parameterized-modules" value="true" />
+ <include name="cts-preconditions" />
+ <include name="cts-system-checkers" />
+ <include name="cts-known-failures" />
+
+ <option name="test-tag" value="cts" />
+
+ <option name="enable-root" value="false" />
+ <!-- retain 200MB of host log -->
+ <option name="max-log-size" value="200" />
+ <!-- retain 200MB of logcat -->
+ <option name="max-tmp-logcat-file" value="209715200" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="settings put global package_verifier_enable 0" />
+ <option name="teardown-command" value="settings put global package_verifier_enable 1"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
+ <option name="property-name" value="ro.build.type" />
+ <option name="expected-value" value="user"/> <!-- Device should have user build -->
+ <option name="throw-error" value="false"/> <!-- Only print warning if not user build -->
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
+ <option name="property-name" value="ro.product.locale" />
+ <option name="expected-value" value="en-US"/> <!-- Device locale should be US English -->
+ <option name="throw-error" value="false"/> <!-- Only print warning if not en-US -->
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
+ <option name="property-name" value="persist.sys.test_harness" />
+ <option name="expected-value" value="false"/> <!-- Device shouldn't be in test harness mode -->
+ <option name="throw-error" value="true"/>
+ </target_preparer>
+
+ <template-include name="reporters" default="basic-reporters" />
+
+ <!-- Include additional test metadata output. -->
+ <template-include name="metadata-reporters" default="empty" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-dev.xml b/tools/cts-tradefed/res/config/cts-dev.xml
new file mode 100644
index 0000000..11c1052
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-dev.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS with common options set developer workflow: skips most checks">
+
+ <include name="cts" />
+
+ <option name="log-level" value="verbose" />
+ <option name="skip-preconditions" value="true" />
+ <option name="skip-device-info" value="true" />
+ <option name="result-reporter:compress-logs" value="false" />
+
+ <option name="plan" value="cts-dev" />
+ <option name="compatibility:skip-all-system-status-check" value="true" />
+ <option name="compatibility:primary-abi-only" value="true" />
+ <!-- Avoid module parameterization in cts-dev -->
+ <option name="compatibility:enable-parameterized-modules" value="false" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-device-files.xml b/tools/cts-tradefed/res/config/cts-device-files.xml
new file mode 100644
index 0000000..6acf7bb
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-device-files.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="CTS device files collection">
+ <option name="plan" value="cts-device-files" />
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DeviceFileCollector">
+ <option name="src-file" value="/sys/fs/selinux/policy" />
+ <option name="dest-file" value="vintf-files/sepolicy"/>
+ <option name="property" key="ro.treble.enabled" value="true"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DeviceFileCollector">
+ <option name="src-file" value="/proc/config.gz" />
+ <option name="dest-file" value="vintf-files/proc_config.gz"/>
+ <option name="property" key="ro.treble.enabled" value="true"/>
+ </target_preparer>
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-exclude-instant.xml b/tools/cts-tradefed/res/config/cts-exclude-instant.xml
new file mode 100644
index 0000000..402d227
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-exclude-instant.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Excluded tests applicable only to instant mode">
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:android.platform.test.annotations.AppModeInstant" />
+ <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:exclude-annotation:android.platform.test.annotations.AppModeInstant" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:exclude-annotation:android.platform.test.annotations.AppModeInstant" />
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-exclude.xml b/tools/cts-tradefed/res/config/cts-exclude.xml
new file mode 100644
index 0000000..f6899a4
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-exclude.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Excluded tests from main CTS runs">
+ <!-- b/64127136 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testNoExemptionsForBinderInVendorBan" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testNoExemptionsForSocketsBetweenCoreAndVendorBan" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testNoExemptionsForVendorExecutingCore" />
+
+ <!-- Test Harness Mode tests are not a part of CTS. They are a part
+ of their own testing plan, as they reset the device during the
+ test. It's possible and ideal in the future to incorporate the
+ tests into CTS, but until then, they should be excluded. -->
+ <option name="compatibility:exclude-filter" value="CtsTestHarnessModeTestCases" />
+
+ <!-- Exclude downstreaming tests from CTS, i.e. tests added after the
+ first major release for this API level (They are pulled into GTS
+ instead). -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:com.android.compatibility.common.util.CtsDownstreamingTest" />
+ <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:exclude-annotation:com.android.compatibility.common.util.CtsDownstreamingTest" />
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-filtered-sample.xml b/tools/cts-tradefed/res/config/cts-filtered-sample.xml
new file mode 100644
index 0000000..e4f454b
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-filtered-sample.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS from a pre-existing CTS installation">
+
+ <include name="common-compatibility-config" />
+
+ <option name="plan" value="cts-filtered-sample" />
+
+ <!-- Tell all AndroidJUnitTests to only run the medium sized tests -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:size:medium" />
+
+ <!-- Include 64bit CtsContentTestCases and tell it which timeout to use -->
+ <option name="compatibility:include-filter" value="arm64-v8a CtsContentTestCases" />
+ <option name="compatibility:module-arg" value="arm64-v8a CtsContentTestCases:test-timeout:600" />
+
+ <!-- Include CtsGestureTestCases but only run the tests on arm32 -->
+ <option name="compatibility:include-filter" value="armeabi-v7a CtsGestureTestCases" />
+
+ <!-- Exclude CtsMediaStressTestCases -->
+ <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases" />
+
+ <!-- Include CtsUtilTestCases but only run the small tests -->
+ <option name="compatibility:include-filter" value="CtsUtilTestCases" />
+ <option name="compatibility:module-arg" value="CtsUtilTestCases:size:small" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-foldable.xml b/tools/cts-tradefed/res/config/cts-foldable.xml
new file mode 100644
index 0000000..1a3e256
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-foldable.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="CTS plan for foldable devices">
+
+ <include name="cts" />
+
+ <option name="plan" value="cts-foldable" />
+ <option name="result-attribute" key="display_mode" value="1" />
+
+ <!-- CTS tests to be excluded in this plan-->
+ <option name="compatibility:exclude-filter" value="CtsDeqpTestCases" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-global-presubmit.xml b/tools/cts-tradefed/res/config/cts-global-presubmit.xml
new file mode 100644
index 0000000..5a858e7
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-global-presubmit.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS global presubmit test cases">
+
+ <include name="cts-automated" />
+
+ <option name="plan" value="cts" />
+
+ <!-- Include modules with presubmit test cases, repeat for each applicable module -->
+ <!--option name="compatibility:include-filter" value="<CTS module name goes here>" /-->
+
+ <!-- Only run tests with @GlobalPresubmit annotation. -->
+ <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:include-annotation:android.platform.test.annotations.GlobalPresubmit" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:include-annotation:android.platform.test.annotations.GlobalPresubmit" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:include-annotation:android.platform.test.annotations.GlobalPresubmit" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-java.xml b/tools/cts-tradefed/res/config/cts-java.xml
new file mode 100644
index 0000000..722d8f7
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-java.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs Core Java Tests from a pre-existing CTS installation">
+
+ <include name="cts" />
+
+ <option name="plan" value="cts-java" />
+
+ <!-- Include CtsLibcoreTestCases -->
+ <option name="compatibility:include-filter" value="CtsLibcoreTestCases" />
+
+ <!-- Exclude CtsLibcoreTestCases harmony -->
+ <option name="compatibility:exclude-filter" value="CtsLibcoreTestCases android.core.tests.libcore.package.harmony" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-jvmti.xml b/tools/cts-tradefed/res/config/cts-jvmti.xml
new file mode 100644
index 0000000..ce60582
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-jvmti.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs JVMTI Tests from a pre-existing CTS installation">
+
+ <!-- Using cts-dev to avoid system checkers. -->
+ <include name="cts-dev" />
+
+ <option name="plan" value="cts-jvmti" />
+
+ <!-- Include all JVMTI test cases -->
+ <option name="compatibility:include-filter" value="CtsJvmtiAttachingHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRedefineClassesHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest902HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest903HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest904HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest905HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest906HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest907HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest908HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest910HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest911HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest912HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest913HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest914HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest915HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest917HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest918HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest919HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest920HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest922HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest923HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest924HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest926HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest927HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest928HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest930HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest931HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest932HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest940HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest942HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest944HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest945HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest947HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest951HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest982HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest983HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest984HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest985HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest986HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest988HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest989HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest990HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest991HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest992HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest993HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest994HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest995HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest996HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest997HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1900HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1901HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1902HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1903HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1904HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1906HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1907HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1908HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1909HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1910HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1911HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1912HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1913HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1914HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1915HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1916HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1917HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1920HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1921HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1922HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1923HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1924HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1925HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1926HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1927HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1928HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1930HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1931HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1932HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1933HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1934HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1936HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1937HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1939HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1941HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1942HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1943HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1953HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiTaggingHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiTrackingHostTestCases" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
new file mode 100644
index 0000000..de90e52
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Configuration with CTS known failures" >
+ <!-- <option name="compatibility:exclude-filter" value="MODULE_NAME" /> Excludes whole module -->
+ <!-- <option name="compatibility:exclude-filter" value="MODULE_NAME PACKAGE_NAME" /> Excludes whole package -->
+ <!-- <option name="compatibility:exclude-filter" value="MODULE_NAME PACKAGE_NAME.CLASS_NAME" /> Excludes whole class -->
+ <!-- <option name="compatibility:exclude-filter" value="MODULE_NAME PACKAGE_NAME.CLASS_NAME#TEST_NAME" /> Excludes individual test -->
+
+ <!-- b/38182235 -->
+ <option name="compatibility:exclude-filter" value="CtsLocationTestCases android.location.cts.GnssTtffTests#testTtffWithNetwork" />
+ <option name="compatibility:exclude-filter" value="CtsLocationTestCases[instant] android.location.cts.GnssTtffTests#testTtffWithNetwork" />
+
+ <!-- b/23776893 -->
+ <option name="compatibility:exclude-filter" value="CtsDumpsysHostTestCases android.dumpsys.cts.DumpsysHostTest#testBatterystatsOutput" />
+ <option name="compatibility:exclude-filter" value="CtsDumpsysHostTestCases android.dumpsys.cts.DumpsysHostTest#testGfxinfoFramestats" />
+
+ <!-- b/16720689 -->
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch001" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch002" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch003" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch004" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowLaunchDebugger001#testDebugger002" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowLaunchDebugger002#testDebugger" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.ClassUnloadTest#testClassUnloadEvent" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorContendedEnteredTest#testMonitorContendedEnteredForClassMatch" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorContendedEnterTest#testMonitorContendedEnterForClassMatch" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassExclude" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchExact" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchFirst" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchSecond" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassOnly" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassExclude" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchExact" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchFirst" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchSecond" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassOnly" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.ReferenceType.ClassFileVersionTest#testClassFileVersion001" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.ReferenceType.NestedTypesTest#testNestedTypes001" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.ThreadReference.StopTest#testStop001" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.VirtualMachine.HoldEventsTest#testHoldEvents001" />
+ <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.VirtualMachine.ReleaseEventsTest#testReleaseEvents001" />
+
+ <!-- b/21262226 -->
+ <option name="compatibility:exclude-filter" value="CtsJobSchedulerTestCases android.jobscheduler.cts.ConnectivityConstraintTest#testConnectivityConstraintExecutes_withMobile" />
+ <option name="compatibility:exclude-filter" value="CtsJobSchedulerTestCases android.jobscheduler.cts.ConnectivityConstraintTest#testUnmeteredConstraintFails_withMobile" />
+
+ <!-- b/18682315 -->
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_bind" />
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_simple" />
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_wrapping" />
+
+ <!-- b/17394321 -->
+ <option name="compatibility:exclude-filter" value="CtsOpenGlPerfTestCases android.openglperf.cts.GlAppSwitchTest#testGlActivitySwitchingFast" />
+ <option name="compatibility:exclude-filter" value="CtsOpenGlPerfTestCases android.openglperf.cts.GlAppSwitchTest#testGlActivitySwitchingSlow" />
+
+ <!-- b/113071420-->
+ <option name="compatibility:exclude-filter" value="x86 CtsPerfettoTestCases PerfettoTest#TestFtraceProducer" />
+
+ <!-- b/18461670 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.AudioPolicyBinderTest#test_getStreamVolumeLeak" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.AudioPolicyBinderTest#test_isStreamActive" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.AudioPolicyBinderTest#test_isStreamActiveRemotely" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.AudioPolicyBinderTest#test_startAudioSource" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.AudioPolicyBinderTest#test_startOutput" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.AudioPolicyBinderTest#test_stopOutput" />
+ <!-- b/27218502 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.MediaCryptoTest#testMediaCryptoClearKey" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.MediaCryptoTest#testMediaCryptoWidevine" />
+
+ <!-- b/63916274 -->
+ <option name="compatibility:exclude-filter" value="CtsTelecomTestCases android.telecom.cts.WiredHeadsetTest" />
+
+ <!-- b/62302163 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityBulletinHostTestCases android.security.cts.Poc17_04#testPocCVE_2017_0564" />
+
+ <!-- b/72460579 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityBulletinHostTestCases android.security.cts.Poc17_05#testPocCVE_2017_0630" />
+
+ <!-- b/27873815 -->
+ <option name="compatibility:exclude-filter" value="arm64-v8a CtsRenderscriptLegacyTestCases" />
+ <option name="compatibility:exclude-filter" value="x86_64 CtsRenderscriptLegacyTestCases" />
+ <option name="compatibility:exclude-filter" value="mips64 CtsRenderscriptLegacyTestCases" />
+
+ <!-- b/17536113 -->
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.UsageStatsTest#testNoAccessSilentlyFails" />
+
+ <!-- b/26235244 -->
+ <option name="compatibility:exclude-filter" value="android.util.cts.EventLogTest#testWriteEventWithOversizeValue" />
+
+ <!-- b/63115400 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testAospFileContexts" />
+ <!-- b/64221494 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testAospPropertyContexts" />
+ <!-- b/64221494 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testAospSeappContexts" />
+
+ <!-- b/63378294 b/64382381 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxNeverallowRulesTest#testNeverallowRules440" />
+
+ <!-- b/36686383 -->
+ <option name="compatibility:exclude-filter" value="CtsIncidentHostTestCases com.android.server.cts.ErrorsTest#testANR" />
+
+ <!-- b/33090965 -->
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0320x0180" />
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0640x0360" />
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1280x0720" />
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1920x1080" />
+
+ <!-- b/63916274 -->
+ <option name="compatibility:exclude-filter" value="CtsTelecomTestCases android.telecom.cts.WiredHeadsetTest" />
+
+ <!-- b/38463882 -->
+ <option name="compatibility:exclude-filter" value="x86_64 CtsLiblogTestCases liblog#event_log_tags" />
+
+ <!-- b/38464828 -->
+ <option name="compatibility:exclude-filter" value="CtsFileSystemTestCases android.filesystem.cts.AlmostFullTest" />
+
+ <!-- b/37271927 -->
+ <option name="compatibility:exclude-filter" value="CtsViewTestCases android.view.cts.ViewTest#testUpdateDragShadow" />
+
+ <!-- b/62481870 -->
+ <option name="compatibility:exclude-filter" value="CtsNativeMediaAAudioTestCases android.nativemedia.aaudio.AAudioOutputStreamCallbackTest#testPlayback" />
+
+ <!-- b/134654621 -->
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.AppConfigurationTests#testTaskCloseRestoreFreeOrientation" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.AppConfigurationTests#testAppOrientationRequestConfigClears" />
+
+ <!-- b/62976713 -->
+ <option name="compatibility:exclude-filter" value="arm64-v8a CtsMediaBitstreamsTestCases" />
+ <option name="compatibility:exclude-filter" value="x86_64 CtsMediaBitstreamsTestCases" />
+ <option name="compatibility:exclude-filter" value="mips64 CtsMediaBitstreamsTestCases" />
+
+ <!-- b/38420898 -->
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyAccelMultiChannel" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyGyroMultiChannel" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyMagMultiChannel" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyAccelMultiMode" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyGyroMultiMode" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyMagMultiMode" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRegisterMultipleChannelsUsingSameMemory" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testCloseWithoutConfigStop" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyAccelGyroSingleChannel" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyAccelMagSingleChannel" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyGyroMagSingleChannel" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyAccelUncalAccelSingleChannel" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyGyroUncalGyroSingleChannel" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyMagUncalMagSingleChannel" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testTimestampAccel" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testTimestampGyro" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testTimestampMag" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testAtomicCounterAccel" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testAtomicCounterGyro" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testAtomicCounterMag" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRegisterMultipleChannels" />
+ <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testReconfigure" />
+
+ <!-- b/65843095 -->
+ <option name="compatibility:exclude-filter" value="CtsLogdTestCases logd#statistics" />
+ <option name="compatibility:exclude-filter" value="CtsLogdTestCases logd#sepolicy_rate_limiter" />
+
+ <!-- b/67377433 -->
+ <!-- fails only on angler/bullhead userdebug -->
+ <option name="compatibility:exclude-filter" value="CtsLiblogTestCases liblog#wrap_mode_blocks" />
+
+ <!-- b/132274449 -->
+ <option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases android.cts.statsd.validation.BatteryStatsValidationTests#testConnectivityStateChange" />
+ <option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases[instant] android.cts.statsd.validation.BatteryStatsValidationTests#testConnectivityStateChange" />
+
+ <!-- b/148080781 -->
+ <option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases android.cts.statsd.atom.UidAtomTests#testForegroundServiceState" />
+ <option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases[instant] android.cts.statsd.atom.UidAtomTests#testForegroundServiceState" />
+
+ <!-- b/110354076 -->
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageUser_DontSkipSetupWizard" />
+
+ <!-- b/123280814 -->
+ <option name="compatibility:exclude-filter" value="CtsLocation2TestCases android.location2.cts.LocationManagerTest#testGetCoarseLocationUpdates_withListener" />
+ <option name="compatibility:exclude-filter" value="CtsLocation2TestCases android.location2.cts.LocationManagerTest#testGetNetworkProviderLocationUpdates_withListener" />
+
+ <!-- b/116002979 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.ListeningPortsTest" />
+
+ <!-- b/117107760 -->
+ <option name="compatibility:exclude-filter" value="CtsHarmfulAppWarningHostTestCases android.harmfulappwarning.cts.HarmfulAppWarningTest#testDismissDialog" />
+ <option name="compatibility:exclude-filter" value="CtsHarmfulAppWarningHostTestCases android.harmfulappwarning.cts.HarmfulAppWarningTest#testLaunchAnyway" />
+ <option name="compatibility:exclude-filter" value="CtsHarmfulAppWarningHostTestCases android.harmfulappwarning.cts.HarmfulAppWarningTest#testUninstall" />
+
+ <!-- b/119312212 -->
+ <option name="compatibility:exclude-filter" value="CtsAngleIntegrationHostTestCases android.angle.cts.CtsAngleDebugOptionHostTest#testDebugOptionOn" />
+
+ <!-- b/129859594 -->
+ <option name="compatibility:exclude-filter" value="CtsAtomicInstallTestCases com.android.tests.atomicinstall.AtomicInstallTest#testFailInconsistentMultiPackageCommit" />
+
+ <!-- b/126548816 -->
+ <option name="compatibility:exclude-filter" value="CtsRcsTestCases" />
+
+ <!-- b/112688380 -->
+ <option name="compatibility:exclude-filter" value="CtsActivityManagerDeviceTestCases android.server.am.ActivityManagerAppConfigurationTests#testAppOrientationRequestConfigClears" />
+ <option name="compatibility:exclude-filter" value="CtsActivityManagerDeviceTestCases android.server.am.ActivityManagerAppConfigurationTests#testTaskCloseRestoreFreeOrientation" />
+ <!-- b/112688380, b/139936670 -->
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.AppConfigurationTests#testAppOrientationRequestConfigClears" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.AppConfigurationTests#testTaskCloseRestoreFreeOrientation" />
+
+ <!-- b/167931576 -->
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.ActivityVisibilityTests#testTurnScreenOnAttrNoLockScreen" />
+
+ <!-- b/135533962 -->
+ <option name="compatibility:exclude-filter" value="arm64-v8a CtsWrapWrapDebugMallocDebugTestCases" />
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-meerkat.xml b/tools/cts-tradefed/res/config/cts-meerkat.xml
new file mode 100644
index 0000000..99ac0ee
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-meerkat.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Tests monitored by Meerkat Platform team (anti-abuse related).">
+
+ <include name="cts" />
+
+ <option name="plan" value="cts-meerkat" />
+
+ <!-- Disable instant tests -->
+ <option name="compatibility:enable-parameterized-modules" value="false" />
+
+ <!-- Overlays & touches -->
+ <option name="compatibility:include-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.WindowInputTests"/>
+ <option name="compatibility:include-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.WindowUntrustedTouchTest"/>
+ <option name="compatibility:include-filter" value="CtsSecurityTestCases android.security.cts.MotionEventTest"/>
+
+ <!-- System Alert Window (SAW) -->
+ <option name="compatibility:include-filter" value="CtsSystemIntentTestCases"/>
+ <option name="compatibility:include-filter" value="CtsMediaTestCases android.media.cts.MediaProjectionTest"/>
+
+ <!-- Toasts -->
+ <option name="compatibility:include-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.ToastWindowTest"/>
+ <option name="compatibility:include-filter" value="CtsWidgetTestCases android.widget.cts.ToastTest"/>
+ <option name="compatibility:include-filter" value="CtsWidgetTestCases29 android.widget.cts29.ToastTest"/>
+ <option name="compatibility:include-filter" value="CtsToastTestCases android.widget.toast.cts.LegacyToastTest"/>
+
+ <!-- Background activity launch -->
+ <option name="compatibility:include-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.lifecycle.ActivityStarterTests"/>
+ <option name="compatibility:include-filter" value="CtsActivityManagerBackgroundActivityTestCases android.server.wm.BackgroundActivityLaunchTest"/>
+
+ <!-- Icon hiding -->
+ <option name="compatibility:include-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.LimitAppIconHidingTest"/>
+ <option name="compatibility:include-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.DeviceOwnerTest"/>
+ <option name="compatibility:include-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.LauncherAppsProfileTest"/>
+
+ <!-- App ops -->
+ <option name="compatibility:include-filter" value="CtsAppOpsTestCases android.app.appops.cts.AppOpsTest"/>
+ <option name="compatibility:include-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.AlertWindowsTests"/>
+ <option name="compatibility:include-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityLoggingTest"/>
+ <option name="compatibility:include-filter" value="CtsPackageInstallTestCases android.packageinstaller.install.cts.SessionTest"/>
+ <option name="compatibility:include-filter" value="CtsPackageInstallTestCases android.packageinstaller.install.cts.ExternalSourcesTestAppOpAllowed"/>
+ <option name="compatibility:include-filter" value="CtsPackageUninstallTestCases"/>
+
+ <!-- Tests that we've added for b/72485440 and in ag/3789406 -->
+ <option name="compatibility:include-filter" value="CtsContentTestCases android.content.cts.ContextTest"/>
+ <option name="compatibility:include-filter" value="CtsContentTestCases android.content.cts.ContextMoreTest"/>
+ <option name="compatibility:include-filter" value="CtsContentTestCases android.content.cts.ContextWrapperTest"/>
+
+ <!-- Tests that we've added for b/73451844 -->
+ <option name="compatibility:include-filter" value="CtsContentTestCases android.content.pm.cts.PackageManagerTest"/>
+
+ <!-- Network watchlist tests -->
+ <option name="compatibility:include-filter" value="CtsNetTestCases android.net.cts.NetworkWatchlistTest"/>
+
+ <!-- App data isolation -->
+ <option name="compatibility:include-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.AppDataIsolationTests"/>
+
+ <!-- Install attribution -->
+ <option name="compatibility:include-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.AppSecurityTests"/>
+ <option name="compatibility:include-filter" value="CtsPackageInstallTestCases android.packageinstaller.install.cts.InstallSourceInfoTest"/>
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-csi-cf.xml b/tools/cts-tradefed/res/config/cts-on-csi-cf.xml
new file mode 100644
index 0000000..787ab93
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-on-csi-cf.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Excluded tests for Cuttlefish">
+
+ <!-- Inherit from cts-on-csi for exclude list common for all CSI devices -->
+ <include name="cts-on-csi" />
+
+ <!-- Troublesome tests that often crash the system -->
+ <option name="compatibility:exclude-filter" value="CtsPackageInstallTestCases android.packageinstaller.install.cts.IntentTest#packageNotInstalledSecureFrp" />
+ <option name="compatibility:exclude-filter" value="CtsPermission3TestCases android.permission3.cts.PermissionReviewTest#testReviewPermissionWhenServiceIsBound" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-csi-no-apks.xml b/tools/cts-tradefed/res/config/cts-on-csi-no-apks.xml
new file mode 100644
index 0000000..b10f519
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-on-csi-no-apks.xml
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Excluded tests for APKs not in CSI">
+
+ <!-- No Browser2 -->
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.EphemeralTest#testEphemeralQuery" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testViewNormalUrl" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testViewSecureUrl" />
+ <option name="compatibility:exclude-filter" value="CtsMatchFlagTestCases android.matchflags.cts.MatchFlagTests#startNoBrowserRequireDefault" />
+ <option name="compatibility:exclude-filter" value="CtsMatchFlagTestCases android.matchflags.cts.MatchFlagTests#startNoBrowserIntentWithNoMatchingApps" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#openDefaultAppDetailsAndSetDefaultAppThenIsDefaultApp" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#requestRoleAndAllowThenIsRoleHolder" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#dontAddRoleHolderThenIsNotRoleHolder" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#openDefaultAppListAndSetDefaultAppThenIsDefaultApp" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#requestRoleAndDenyThenHasDontAskAgain" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#requestRoleAndDenyWithDontAskAgainThenDeniedAutomatically" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#requestRoleAndDenyWithDontAskAgainAndReinstallThenShowsUiWithoutDontAskAgain" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#openDefaultAppDetailsAndSetDefaultAppAndSetAnotherThenIsNotDefaultApp" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#requestRoleAndDenyWithDontAskAgainAndClearDataThenShowsUiWithoutDontAskAgain" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#openDefaultAppListAndSetDefaultAppThenIsDefaultAppInList" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#requestRoleFirstTimeNoDontAskAgain" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#requestHoldingRoleThenAllowedAutomatically" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#openDefaultAppDetailsThenIsNotDefaultApp" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#addAndRemoveRoleHolderThenRoleIsNotHeld" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#dontAddRoleHolderThenRoleIsNotHeld" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#addAndClearRoleHoldersThenIsNotRoleHolder" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#addAndRemoveRoleHolderThenIsNotRoleHolder" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#requestRoleAndDenyThenIsNotRoleHolder" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#requestRoleAndDenyWithDontAskAgainReturnsCanceled" />
+
+ <!-- No Calendar -->
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testCalendarAddAppointment" />
+
+ <!-- No Camera2 -->
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testCamera" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testImageCaptureIntentsHandledBySystem" />
+
+ <!-- No Contacts -->
+ <option name="compatibility:exclude-filter" value="CtsContactsProviderTestCases android.provider.cts.contacts.ContactsContractIntentsTest#testPickContactDir" />
+ <option name="compatibility:exclude-filter" value="CtsContactsProviderTestCases android.provider.cts.contacts.ContactsContractIntentsTest#testViewContactDir" />
+ <option name="compatibility:exclude-filter" value="CtsContactsProviderTestCases android.provider.cts.contacts.ContactsContract_ContactsTest#testContentUri" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testContactsCallLogs" />
+
+ <!-- No DeskClock -->
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testAlarmClockDismissAlarm" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testAlarmClockSetAlarm" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testAlarmClockSetTimer" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testAlarmClockShowAlarms" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testAlarmClockShowTimers" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testAlarmClockSnoozeAlarm" />
+
+ <!-- No Dialer -->
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testDialPhoneNumber" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testDialVoicemail" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedDeviceOwnerTest#testLockTask_defaultDialer" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedProfileOwnerTest#testLockTask_defaultDialer" />
+ <option name="compatibility:exclude-filter" value="CtsTelecomTestCases android.telecom.cts.DefaultDialerOperationsTest#testActionDialHandling" />
+ <option name="compatibility:exclude-filter" value="CtsTelecomTestCases android.telecom.cts.DefaultDialerOperationsTest#testDialerUI" />
+
+ <!-- No Gallery2 -->
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.ExternalStorageHostTest#testSystemGalleryExists" />
+ <option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.StrictModeTest#testFileUriExposure" />
+ <option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.StrictModeTest#testVmPenaltyListener" />
+ <option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.StrictModeTest#testContentUriWithoutPermission" />
+
+ <!-- No Gallery2, Music -->
+ <option name="compatibility:exclude-filter" value="CtsProviderTestCases android.provider.cts.media.MediaStoreIntentsTest" />
+
+ <!-- No Launcher and Home -->
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityEmbeddedDisplayTest" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityEmbeddedHierarchyTest" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityEndToEndTest" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityFocusAndInputFocusSyncTest" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityGestureDispatchTest" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityGlobalActionsTest" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityMagnificationTest#testA11yNodeInfoVisibility_whenOutOfMagnifiedArea_shouldVisible" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityPaneTest" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityTakeScreenshotTest#testTakeScreenshotWithSecureWindow_GetScreenshotAndVerifyBitmap" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityTextActionTest" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityTextTraversalTest" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityViewTreeReportingTest" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityWindowQueryTest" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityWindowReportingTest" />
+ <option name="compatibility:exclude-filter" value="CtsAdminPackageInstallerTestCases android.packageinstaller.admin.cts.SessionCommitBroadcastTest#testBroadcastNotReceivedForDifferentLauncher" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActivityManagerProcessStateTest#testBgRestrictedForegroundService" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActivityManagerProcessStateTest#testCantSaveStateLaunchAndBackground" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActivityManagerProcessStateTest#testCantSaveStateLaunchAndSwitch" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActivityManagerTest#testKillingPidsOnImperceptible" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActivityManagerTest#testTimeTrackingAPI_ChainedActivityExit" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActivityManagerTest#testTimeTrackingAPI_SimpleStartExit" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActivityManagerTest#testTimeTrackingAPI_SwitchAwayTriggers" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.BooleanTileServiceTest" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.TileServiceTest" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.QuietModeHostsideTest" />
+ <option name="compatibility:exclude-filter" value="CtsShortcutManagerLauncher1" />
+ <option name="compatibility:exclude-filter" value="CtsShortcutManagerLauncher2" />
+ <option name="compatibility:exclude-filter" value="CtsShortcutManagerLauncher3" />
+ <option name="compatibility:exclude-filter" value="CtsShortcutManagerLauncher4" />
+ <option name="compatibility:exclude-filter" value="CtsShortcutManagerPackage1" />
+ <option name="compatibility:exclude-filter" value="CtsShortcutManagerPackage2" />
+ <option name="compatibility:exclude-filter" value="CtsShortcutManagerPackage3" />
+ <option name="compatibility:exclude-filter" value="CtsShortcutManagerPackage4" />
+ <option name="compatibility:exclude-filter" value="CtsShortcutManagerTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsShortcutManagerThrottlingTest" />
+
+ <!-- No Music -->
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testMusicPlayback" />
+
+ <!-- No QuickSearchBox -->
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testWebSearchNormalUrl" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testWebSearchPlainText" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testWebSearchSecureUrl" />
+
+ <!-- No Settings -->
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilitySettingsTest" />
+ <option name="compatibility:exclude-filter" value="CtsAdminTestCases android.admin.cts.DeviceAdminActivationTest" />
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.StorageHostTest#testFullDisk" />
+ <option name="compatibility:exclude-filter" value="CtsAutoFillServiceTestCases android.autofillservice.cts.SettingsIntentTest" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testAddNetworksIntent" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testEasyConnectIntent" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testInteractAcrossProfilesSettings" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testLocationScanningSettings" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testNotificationPolicyDetailIntent" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testPictureInPictureSettings" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testPowerUsageSummarySettings" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testRequestSetAutofillServiceIntent" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testSettings" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testTapAnPaySettings" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testUsageAccessSettings" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testVoiceInputSettingsIntent" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.ManagedProfileTest#testSettingsIntents" />
+ <option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.AutoRevokeTest#testAutoRevoke_userWhitelisting" />
+ <option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.AutoRevokeTest#testInstallGrants_notRevokedImmediately" />
+ <option name="compatibility:exclude-filter" value="CtsPackageInstallTestCases android.packageinstaller.install.cts.ExternalSourcesTestAppOpAllowed#testManageUnknownSourcesExists" />
+ <option name="compatibility:exclude-filter" value="CtsProviderTestCases android.provider.cts.SettingsPanelTest" />
+ <option name="compatibility:exclude-filter" value="CtsProviderTestCases android.provider.cts.settings.SettingsTest#testUserDictionarySettingsExists" />
+ <option name="compatibility:exclude-filter" value="CtsSettingsHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleControllerManagerTest#settingsIsNotVisibleForHomeRole" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases android.app.role.cts.RoleManagerTest#openDefaultAppListThenIsNotDefaultAppInList" />
+
+ <!-- No SettingsIntelligence -->
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testSettingsSearchIntent" />
+
+ <!-- No StorageManager -->
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testManageStorage" />
+
+ <!-- No SystemUI -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.AudioPlaybackCaptureTest" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.MediaProjectionTest" />
+ <option name="compatibility:exclude-filter" value="CtsPermission3TestCases android.permission3.cts.PermissionTest22#testCompatRevoked" />
+ <option name="compatibility:exclude-filter" value="CtsPermission3TestCases android.permission3.cts.PermissionTest23#testGranted" />
+ <option name="compatibility:exclude-filter" value="CtsPermission3TestCases android.permission3.cts.PermissionTest23#testRevokeAffectsWholeGroup" />
+ <option name="compatibility:exclude-filter" value="CtsPermission3TestCases android.permission3.cts.PermissionTest23#testGrantPreviouslyRevokedWithPrejudiceShowsPrompt" />
+ <option name="compatibility:exclude-filter" value="CtsPermission3TestCases android.permission3.cts.PermissionTest23#testNoResidualPermissionsOnUninstall" />
+ <option name="compatibility:exclude-filter" value="CtsPermission3TestCases android.permission3.cts.PermissionUpgradeTest#testRevokePropagatedOnUpgradeOldToNewModel" />
+
+ <option name="compatibility:exclude-filter" value="CtsViewTestCases android.view.cts.SurfaceViewSyncTest" />
+ <option name="compatibility:exclude-filter" value="CtsViewTestCases android.view.cts.ASurfaceControlTest" />
+
+ <!-- No WebView -->
+ <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.WebViewTest#testWebView" />
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.EphemeralTest#testWebViewLoads" />
+ <option name="compatibility:exclude-filter" value="CtsAutoFillServiceTestCases android.autofillservice.cts.inline.InlineWebViewActivityTest" />
+ <option name="compatibility:exclude-filter" value="CtsAutoFillServiceTestCases android.autofillservice.cts.WebViewActivityTest" />
+ <option name="compatibility:exclude-filter" value="CtsAutoFillServiceTestCases android.autofillservice.cts.WebViewMultiScreenLoginActivityTest" />
+ <option name="compatibility:exclude-filter" value="CtsAutoFillServiceTestCases android.autofillservice.cts.inline.InlineWebViewActivityTest" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.ManagedProfileProvisioningTest#testWebview" />
+ <option name="compatibility:exclude-filter" value="CtsHostsideWebViewTests" />
+ <option name="compatibility:exclude-filter" value="CtsInputMethodTestCases android.view.inputmethod.cts.KeyboardVisibilityControlTest#testShowHideKeyboardOnWebView" />
+ <option name="compatibility:exclude-filter" value="CtsTextTestCases android.text.cts.EmojiTest" />
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.LayerTests#testWebViewScaledWithParentLayer" />
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.LayerTests#testWebViewWithAlpha" />
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.LayerTests#testWebViewWithAlphaLayer" />
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.LayerTests#testWebViewWithLayer" />
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.LayerTests#testWebViewWithOffsetLayer" />
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.LayerTests#testWebViewWithParentLayer" />
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.LayerTests#testWebViewWithUnclippedLayer" />
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.LayerTests#testWebViewWithUnclippedLayerAndComplexClip" />
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.PathClippingTests#testWebViewClipWithCircle" />
+ <option name="compatibility:exclude-filter" value="CtsWebkitTestCases" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-csi-wmd.xml b/tools/cts-tradefed/res/config/cts-on-csi-wmd.xml
new file mode 100644
index 0000000..240a149
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-on-csi-wmd.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Excluded tests for CtsWindowManagerDeviceTestCases">
+
+ <!-- Troublesome tests that often crash the system -->
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.ActivityVisibilityTests#testTurnScreenOnActivity_withRelayout" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.AnrTests" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.MultiDisplaySecurityTests#testNoInputConnectionForUntrustedVirtualDisplay" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.MultiDisplaySystemDecorationTests#testImeApiForBug118341760" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.MultiDisplaySystemDecorationTests#testCrossDisplayBasicImeOperations" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.StartActivityTests#testStartActivityByNavigateUpToFromDiffUid" />
+
+ <!-- No Home -->
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.MultiDisplaySystemDecorationTests#testLaunchHomeActivityOnSecondaryDisplayWithoutDecorations" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.MultiDisplaySystemDecorationTests#testLaunchSingleSecondaryHomeActivityOnDisplayWithDecorations" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.MultiDisplaySystemDecorationTests#testLaunchSingleHomeActivityOnDisplayWithDecorations" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.MultiDisplaySystemDecorationTests#testLaunchHomeActivityOnUntrustedVirtualSecondaryDisplay" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.MultiDisplaySystemDecorationTests#testLaunchSecondaryHomeActivityOnDisplayWithDecorations" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.MultiDisplaySystemDecorationTests#testLaunchHomeActivityOnDisplayWithDecorations" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.StartActivityTests#testStartHomeIfNoActivities" />
+
+ <!-- No SystemUI -->
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.SurfaceControlTest" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.SurfaceViewSurfaceValidatorTest" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-csi.xml b/tools/cts-tradefed/res/config/cts-on-csi.xml
new file mode 100644
index 0000000..7ec61d1
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-on-csi.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs a subset of CTS-on-GSI tests using a core system image (CSI)">
+
+ <include name="cts-on-gsi" />
+ <include name="cts-on-csi-no-apks" />
+ <include name="csi-known-failures" />
+
+ <!--
+ CtsWindowManagerDeviceTestCases has about two hundred failed tests on CSI,
+ so it has its own exclude list.
+ -->
+ <include name="cts-on-csi-wmd" />
+
+ <option name="plan" value="cts-on-csi" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
new file mode 100644
index 0000000..e369dfa
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Excluded tests from cts-on-gsi">
+ <!-- Tell all AndroidJUnitTests to exclude certain annotations -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
+
+ <!-- Tell all HostTests to exclude certain annotations -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
+ <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
+
+ <!-- Radio system of a general system image is not checked -->
+ <option name="compatibility:exclude-filter" value="CtsTelephonyTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsTelephony2TestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testLocationFeatures" />
+
+ <!-- Exclude telephony related testcases -->
+ <option name="compatibility:exclude-filter" value="CtsNetTestCasesLegacyApi22 android.net.cts.legacy.api22.ConnectivityManagerLegacyTest#testStartUsingNetworkFeature_enableHipri" />
+ <option name="compatibility:exclude-filter" value="CtsPermission2TestCases android.permission2.cts.NoReceiveSmsPermissionTest#testAppSpecificSmsToken" />
+ <option name="compatibility:exclude-filter" value="CtsPermission2TestCases android.permission2.cts.NoReceiveSmsPermissionTest#testReceiveTextMessage" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testNoExemptionsForBinderInVendorBan" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testNoExemptionsForSocketsBetweenCoreAndVendorBan" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testNoExemptionsForVendorExecutingCore" />
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testAppDetails" />
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testAppSummary" />
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testCallback" />
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testDeviceSummary" />
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testTagDetails" />
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testUidDetails" />
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testUserSummary" />
+
+ <!-- Exclude not applicable testcases-->
+ <option name="compatibility:exclude-filter" value="CtsSignatureTestCases" />
+
+ <!--
+ Exclude testcases failing on Pixel devices
+ TODO(jaeshin@): b/68300743
+ -->
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testVoiceCommand" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testVoiceSearchHandsFree" />
+
+ <!-- Excluded tese case - TODO(jiyong): b/67739526 to reenable that -->
+ <option name="compatibility:exclude-filter" value="CtsJniTestCases android.jni.cts.JniStaticTest#test_linker_namespaces" />
+
+ <!-- b/68190722: Remove testcases that require RRO which is planned for Pi -->
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActionBarTest#testOpenOptionsMenu" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActionBarTest#testOptionsMenuKey" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActivityKeyboardShortcutsTest#testRequestShowKeyboardShortcuts" />
+
+ <!-- b/71958344: Exclude until CTS releases it -->
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.OverlayHostTest#testInstallingOverlayHasNoEffect" />
+
+ <!-- b/161837932: Fix MediaPlayerTests that use "too small" resolution -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.MediaPlayerTest#testOnSubtitleDataListener" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.MediaPlayerTest#testChangeSubtitleTrack" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.MediaPlayerTest#testDeselectTrackForSubtitleTracks" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.MediaPlayerTest#testGetTrackInfoForVideoWithSubtitleTracks" />
+
+ <!-- b/74583365: CtsAppSecurityHostTestCases flaky -->
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.AdoptableHostTest#testApps " />
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.AdoptableHostTest#testEjected" />
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.AdoptableHostTest#testPackageInstaller" />
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.AdoptableHostTest#testPrimaryStorage" />
+
+ <!-- b/152359655: ResumeOnReboot can't work on GSI -->
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.ResumeOnRebootHostTest" />
+
+ <!-- b/77175538: CtsViewTestCases failure flaky -->
+ <option name="compatibility:exclude-filter" value="CtsViewTestCases android.view.cts.PixelCopyTest#testWindowProducerCopyToRGBA16F" />
+
+ <!-- b/73727333: CtsSystemUiTestCases failure flaky -->
+ <option name="compatibility:exclude-filter" value="CtsSystemUiTestCases android.systemui.cts.LightBarTests#testLightNavigationBar" />
+ <option name="compatibility:exclude-filter" value="CtsSystemUiTestCases android.systemui.cts.LightBarThemeTest#testNavigationBarDivider" />
+
+ <!-- b/80388296: CtsDevicePolicyManagerTestCases failure flaky -->
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testDisallowAutofill_allowed" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testPackageInstallUserRestrictions" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testPermissionAppUpdate" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testPermissionGrant" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testPermissionMixedPolicies" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testPermissionPolicy" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testSuspendPackage" />
+
+ <!-- b/80407835: CtsServicesHostTestCases failure flaky -->
+ <option name="compatibility:exclude-filter" value="CtsServicesHostTestCases android.server.cts.KeyguardTests#testDialogShowWhenLockedActivity" />
+ <option name="compatibility:exclude-filter" value="CtsServicesHostTestCases android.server.cts.KeyguardTests#testTranslucentShowWhenLockedActivity" />
+
+ <!-- b/80284482: Flaky tests -->
+ <option name="compatibility:exclude-filter" value="CtsAlarmManagerTestCases android.alarmmanager.cts.AppStandbyTests#testAllowWhileIdleAlarms" />
+ <option name="compatibility:exclude-filter" value="CtsAlarmManagerTestCases android.alarmmanager.cts.AppStandbyTests#testBucketUpgradeToNoDelay" />
+ <option name="compatibility:exclude-filter" value="CtsAlarmManagerTestCases android.alarmmanager.cts.AppStandbyTests#testBucketUpgradeToSmallerDelay" />
+ <option name="compatibility:exclude-filter" value="CtsAlarmManagerTestCases android.alarmmanager.cts.AppStandbyTests#testFrequentDelay" />
+ <option name="compatibility:exclude-filter" value="CtsAlarmManagerTestCases android.alarmmanager.cts.AppStandbyTests#testRareDelay" />
+ <option name="compatibility:exclude-filter" value="CtsAlarmManagerTestCases android.alarmmanager.cts.AppStandbyTests#testWorkingSetDelay" />
+
+ <!-- b/110260628: A confirmed GSI incompatibility (waiver) -->
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageUser_DontSkipSetupWizard" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.DeviceOwnerTest#testSecurityLoggingWithSingleUser" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedDeviceOwnerTest#testKeyManagement" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedProfileOwnerTest#testKeyManagement" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testKeyManagement" />
+
+ <!-- b/110405497: Flaky tests (waiver) -->
+ <option name="compatibility:exclude-filter" value="CtsKeystoreTestCases android.keystore.cts.KeyAttestationTest#testDeviceIdAttestation" />
+
+ <!-- b/141113818: Allows unlock for CTS-on-GSI -->
+ <option name="compatibility:exclude-filter" value="CtsKeystoreTestCases android.keystore.cts.KeyAttestationTest#testEcAttestation_DeviceLocked" />
+ <option name="compatibility:exclude-filter" value="CtsKeystoreTestCases android.keystore.cts.KeyAttestationTest#testRsaAttestation_DeviceLocked" />
+
+ <!-- b/110385515: Flaky due to a particular SIM card requirement (excluded) -->
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.ConnectivityManagerTest#testOpenConnection" />
+ <option name="compatibility:exclude-filter" value="CtsWifiTestCases android.net.wifi.rtt.cts.WifiRttTest#testRangingToTestAp" />
+
+ <!-- b/110417203: Flaky tests -->
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testUidTagStateDetails" />
+
+ <!-- b/80077786: MyVerizonServices fail -->
+ <option name="compatibility:exclude-filter" value="CtsPermission2TestCases android.permission2.cts.PrivappPermissionsTest#testPrivappPermissionsEnforcement" />
+
+ <!-- b/111101428: CtsOsTestCases irrelevant test cases -->
+ <option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.BuildTest#testIsSecureUserBuild" />
+ <option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.BuildVersionTest#testBuildFingerprint" />
+
+ <!-- b/110405126: CtsPermissionTestCases flaky (due to SIM card setting) -->
+ <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testGetDeviceId" />
+ <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testGetImei" />
+ <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testGetLine1Number" />
+ <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testGetSimSerialNumber" />
+ <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testGetSubscriberId" />
+ <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testSetDataEnabled" />
+ <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testVoiceMailNumber" />
+
+ <!-- b/111967702: CtsSecurityTestCases irrelevant test cases -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.BannedFilesTest#testNoSu" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.BannedFilesTest#testNoSuInPath" />
+
+ <!-- b/116170534: CtsMediaTestCases regression (9.0 R4 waiver) -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.DecoderTest#testH265HDR10StaticMetadata" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VolumeShaperTest#testPlayerCornerCase" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VolumeShaperTest#testPlayerCornerCase2" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VolumeShaperTest#testPlayerCubicMonotonic" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VolumeShaperTest#testPlayerDuck" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VolumeShaperTest#testPlayerJoin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VolumeShaperTest#testPlayerRamp" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VolumeShaperTest#testPlayerRunDuringPauseStop" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VolumeShaperTest#testPlayerStepRamp" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VolumeShaperTest#testPlayerTwoShapers" />
+
+ <!-- b/157286547 CtsIncidentHostTestCases ErrorsTest failure -->
+ <option name="compatibility:exclude-filter" value="CtsIncidentHostTestCases com.android.server.cts.ErrorsTest#testNativeCrash" />
+
+ <!-- b/111167329: CtsCameraTestCases failure -->
+ <option name="compatibility:exclude-filter" value="CtsCameraTestCases android.hardware.camera2.cts.SurfaceViewPreviewTest#testSurfaceSet"/>
+
+ <!-- b/135588722: CtsUsesLibraryHostTestCases (10_r1 waiver) -->
+ <option name="compatibility:exclude-filter" value="CtsUsesLibraryHostTestCases android.classloaders.cts.UsesLibraryHostTest#testMissingLibrary_full"/>
+ <option name="compatibility:exclude-filter" value="CtsUsesLibraryHostTestCases android.classloaders.cts.UsesLibraryHostTest#testUsesLibrary_full"/>
+ <option name="compatibility:exclude-filter" value="CtsCompilationTestCases android.compilation.cts.AdbRootDependentCompilationTest"/>
+
+ <!-- b/145371681: CtsContentSuggestionsTestCases and CtsAppPredictionServiceTestCases (10_r2 waiver) -->
+ <option name="compatibility:exclude-filter" value="CtsAppPredictionServiceTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsContentSuggestionsTestCases" />
+
+ <!-- b/143513519: CtsCameraTestCases (10_r3 waiver) -->
+ <option name="compatibility:exclude-filter" value="CtsCameraTestCases android.camera.cts.HeifWriterTest#testHeif"/>
+
+ <!-- b/155107044: CtsNetTestCases -->
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testInterfaceCountersUdp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm64Tcp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testInterfaceCountersUdp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacMd5Tcp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha512Tcp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacMd5Tcp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha512Tcp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha1Udp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha1Udp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha1Tcp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha1Tcp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm128Tcp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm128Tcp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm96Tcp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha1Tcp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm96Tcp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testCryptTcp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm128Udp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testCryptUdp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAuthUdp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testCryptUdp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAuthUdp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testCryptTcp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha1Udp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testCryptTcp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAuthUdp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testIkeOverUdpEncapSocket"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm128Udp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm128Udp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha256Tcp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha256Tcp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacMd5Udp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm96Tcp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testInterfaceCountersUdp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha512Udp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha512Udp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha256Tcp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha384Udp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha384Udp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha256Udp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm64Tcp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm64Tcp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha512Udp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm96Udp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha384Tcp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm96Udp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha384Udp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha256Udp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacMd5Udp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAuthTcp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacMd5Udp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAuthTcp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha384Tcp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm128Tcp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testCryptUdp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAuthTcp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacMd5Tcp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm64Udp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha256Udp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm64Udp4"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha384Tcp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm64Udp6"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesGcm96Udp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testAesCbcHmacSha512Tcp4UdpEncap"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.TrafficStatsTest#testTrafficStatsForLocalhost"/>
+ <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.TrafficStatsTest#testValidTotalStats"/>
+
+ <!-- b/150807956: Temporarily disabled due to bad experiment channel -->
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.LayerTests#testWebViewWithLayerAndComplexClip" />
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.PathClippingTests#testWebViewClipWithCircle" />
+
+ <!-- b/159295445, b/159294948: CtsDevicePolicyManagerTestCases -->
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedDeviceOwnerTest#testDelegatedCertInstallerDeviceIdAttestation" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testDelegatedCertInstallerDeviceIdAttestation" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testDeviceIdAttestationForProfileOwner" />
+
+ <!-- b/153032202: CtsSystemUiTestCases (10_r3 waiver) -->
+ <option name="compatibility:exclude-filter" value="CtsSystemUiTestCases android.systemui.cts.WindowInsetsBehaviorTests#swipeOutsideLimit_systemUiVisible_allEventsCanceled"/>
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-presubmit.xml b/tools/cts-tradefed/res/config/cts-on-gsi-presubmit.xml
new file mode 100644
index 0000000..3c42a12
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-presubmit.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs a subset of CTS-on-GSI tests selected for presubmit testing">
+ <option name="plan" value="cts-on-gsi-presubmit" />
+ <include name="cts-automated" />
+ <!-- CTS-on-GSI is not expected to run parameterized modules -->
+ <option name="compatibility:enable-parameterized-modules" value="false" />
+ <option name="compatibility:primary-abi-only" value="true" />
+
+ <include name="cts-on-gsi-exclude" />
+
+ <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:include-annotation:android.platform.test.annotations.Presubmit" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:include-annotation:android.platform.test.annotations.Presubmit" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:include-annotation:android.platform.test.annotations.Presubmit" />
+</configuration>
+
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-sim.xml b/tools/cts-tradefed/res/config/cts-on-gsi-sim.xml
new file mode 100644
index 0000000..5150942
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-sim.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs cts-on-gsi on device with SIM card">
+
+ <include name="cts-on-gsi" />
+
+ <include name="cts-sim-include" />
+
+ <option name="plan" value="cts-on-gsi-sim" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi.xml b/tools/cts-tradefed/res/config/cts-on-gsi.xml
new file mode 100644
index 0000000..a87ba2e
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-on-gsi.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs a subset of CTS tests using a general system image (GSI)">
+ <!-- Enforce collecting vendor build information -->
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsDeviceInfoCollector" />
+
+ <!-- Common CTS config -->
+ <include name="cts" />
+
+ <!-- CTS-on-GSI is not expected to run parameterized modules -->
+ <option name="compatibility:enable-parameterized-modules" value="false" />
+ <option name="compatibility:primary-abi-only" value="true" />
+
+ <include name="cts-on-gsi-exclude" />
+ <!-- Overwrite the "cts" plan configured in cts.xml -->
+ <option name="plan" value="cts-on-gsi" />
+
+ <!-- For CTS-on-GSI, override the suite name to VTS for the R release only -->
+ <option name="cts-on-gsi-variant" value="true" />
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-preconditions.xml b/tools/cts-tradefed/res/config/cts-preconditions.xml
new file mode 100644
index 0000000..6a4f47e
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-preconditions.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="CTS precondition configs">
+
+ <include name="cts-device-files" />
+
+ <option name="plan" value="cts-preconditions" />
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="host" />
+ <!-- the name under which to find the configuration -->
+ <option name="config-filename" value="cts" />
+ <option name="extract-from-resource" value="true" />
+ <!-- the name of the resource inside the jar -->
+ <option name="dynamic-resource-name" value="cts-tradefed" />
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.StayAwakePreparer" />
+
+ <!-- Disable "Android Beta Program" -->
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.PackageDisabler" >
+ <option name="package" value="com.android.yadayada"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.SettingsPreparer">
+ <option name="device-setting" value="verifier_verify_adb_installs"/>
+ <option name="setting-type" value="global"/>
+ <option name="set-value" value="0"/>
+ </target_preparer>
+
+ <!-- Disable crash error dialogs to avoid affecting following tests -->
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.SettingsPreparer">
+ <option name="device-setting" value="hide_error_dialogs"/>
+ <option name="setting-type" value="global"/>
+ <option name="set-value" value="1"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkPreconditionCheck">
+ <option name="apk" value="CtsPreconditions.apk"/>
+ <option name="package" value="com.android.preconditions.cts"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.WifiCheck" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="rm -rf /sdcard/device-info-files" />
+ <option name="run-command" value="rm -rf /sdcard/report-log-files" />
+ <!-- Disable keyguard -->
+ <option name="run-command" value="locksettings set-disabled true"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DeviceInfoCollector">
+ <option name="apk" value="CtsDeviceInfo.apk"/>
+ <option name="package" value="com.android.compatibility.common.deviceinfo"/>
+ <option name="src-dir" value="/sdcard/device-info-files/"/>
+ <option name="dest-dir" value="device-info-files/"/>
+ <option name="temp-dir" value="temp-device-info-files/"/>
+ <option name="throw-error" value="false"/>
+ </target_preparer>
+
+ <!-- The following values are used in cts/common/device-side/util/DeviceReportLog.java,
+ cts/harness/common/host-side/util/MetricsReportLog.java and tools/tradefed-host/util/ReportLogUtil.java.
+ Any change in these values must also be translated to the stated files.
+ -->
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ReportLogCollector">
+ <option name="src-dir" value="/sdcard/report-log-files/"/>
+ <option name="dest-dir" value="report-log-files/"/>
+ <option name="temp-dir" value="temp-report-logs/"/>
+ </target_preparer>
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-presubmit.xml b/tools/cts-tradefed/res/config/cts-presubmit.xml
new file mode 100644
index 0000000..5997779
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-presubmit.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS presubmit test cases">
+
+ <include name="cts-automated" />
+
+ <!-- Only run tests with @Presubmit annotation -->
+ <!-- This serve as a base config for CTS tests used for presubmit;
+ additional filtering parameters should be applied to further narrow
+ down the choice of tests, e.g. module filter
+ -->
+ <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:include-annotation:android.platform.test.annotations.Presubmit" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:include-annotation:android.platform.test.annotations.Presubmit" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:include-annotation:android.platform.test.annotations.Presubmit" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-sim-include.xml b/tools/cts-tradefed/res/config/cts-sim-include.xml
new file mode 100644
index 0000000..1614c18
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-sim-include.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Include CTS test that require SIM card">
+
+ <!-- CTS tests that need SIM card-->
+ <option name="compatibility:include-filter" value="signed-CtsOmapiTestCases" />
+ <option name="compatibility:include-filter" value="signed-CtsSecureElementAccessControlTestCases1" />
+ <option name="compatibility:include-filter" value="signed-CtsSecureElementAccessControlTestCases2" />
+ <option name="compatibility:include-filter" value="signed-CtsSecureElementAccessControlTestCases3" />
+ <option name="compatibility:include-filter" value="CtsCarrierApiTestCases" />
+ <option name="compatibility:include-filter" value="CtsJobSchedulerTestCases" />
+ <option name="compatibility:include-filter" value="CtsNetTestCases" />
+ <option name="compatibility:include-filter" value="CtsNetTestCasesLegacyApi22" />
+ <option name="compatibility:include-filter" value="CtsOmapiTestCases" />
+ <option name="compatibility:include-filter" value="CtsPermissionTestCases" />
+ <option name="compatibility:include-filter" value="CtsPermission2TestCases" />
+ <option name="compatibility:include-filter" value="CtsSecureElementAccessControlTestCases1" />
+ <option name="compatibility:include-filter" value="CtsSecureElementAccessControlTestCases2" />
+ <option name="compatibility:include-filter" value="CtsSecureElementAccessControlTestCases3" />
+ <option name="compatibility:include-filter" value="CtsSimRestrictedApisTestCases" />
+ <option name="compatibility:include-filter" value="CtsStatsdHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsTelecomTestCases" />
+ <option name="compatibility:include-filter" value="CtsTelecomTestCases2" />
+ <option name="compatibility:include-filter" value="CtsTelecomTestCases3" />
+ <option name="compatibility:include-filter" value="CtsTelephonyTestCases" />
+ <option name="compatibility:include-filter" value="CtsTelephony2TestCases" />
+ <option name="compatibility:include-filter" value="CtsTelephony3TestCases" />
+ <option name="compatibility:include-filter" value="CtsTelephonySdk28TestCases" />
+ <option name="compatibility:include-filter" value="CtsTetheringTest" />
+ <option name="compatibility:include-filter" value="CtsUsageStatsTestCases" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-sim.xml b/tools/cts-tradefed/res/config/cts-sim.xml
new file mode 100644
index 0000000..234c33f
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-sim.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS-sim on device with SIM card">
+
+ <include name="cts" />
+
+ <include name="cts-sim-include" />
+
+ <option name="plan" value="cts-sim" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-system-checkers.xml b/tools/cts-tradefed/res/config/cts-system-checkers.xml
new file mode 100644
index 0000000..7639bf9
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-system-checkers.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="CTS system checker configs">
+ <system_checker class="com.android.tradefed.suite.checker.UserChecker" />
+ <system_checker class="com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker" />
+ <system_checker class="com.android.tradefed.suite.checker.ShellStatusChecker" />
+ <system_checker class="com.android.tradefed.suite.checker.EnforcedSeLinuxChecker">
+ <!-- We expect selinux enforced for CTS -->
+ <option name="expect-enforced" value="true" />
+ </system_checker>
+ <system_checker class="com.android.tradefed.suite.checker.KeyguardStatusChecker" />
+ <system_checker class="com.android.tradefed.suite.checker.LeakedThreadStatusChecker" />
+ <system_checker class="com.android.tradefed.suite.checker.TimeStatusChecker" />
+ <system_checker class="com.android.tradefed.suite.checker.DeviceSettingChecker" />
+ <system_checker class="com.android.tradefed.suite.checker.SystemServerStatusChecker" />
+ <system_checker class="com.android.tradefed.suite.checker.SystemServerFileDescriptorChecker" />
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-virtual-device-stable.xml b/tools/cts-tradefed/res/config/cts-virtual-device-stable.xml
new file mode 100644
index 0000000..512e8a2
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-virtual-device-stable.xml
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs stable set of CTS tests for virtual devices">
+
+ <include name="cts-virtual-device" />
+
+ <option name="plan" value="cts-virtual-device-stable" />
+
+ <!-- CTS tests shown to be stable on virtual devices-->
+ <option name="compatibility:include-filter" value="CtsAccelerationTestCases" />
+ <option name="compatibility:include-filter" value="CtsAlarmClockTestCases" />
+ <option name="compatibility:include-filter" value="CtsAndroidTestBase27ApiSignatureTestCases" />
+ <option name="compatibility:include-filter" value="CtsAndroidTestMockCurrentApiSignatureTestCases" />
+ <option name="compatibility:include-filter" value="CtsAndroidTestRunnerCurrentApiSignatureTestCases" />
+ <option name="compatibility:include-filter" value="CtsAnimationTestCases" />
+ <option name="compatibility:include-filter" value="CtsApacheHttpLegacy27ApiSignatureTestCases" />
+ <option name="compatibility:include-filter" value="CtsApacheHttpLegacyCurrentApiSignatureTestCases" />
+ <option name="compatibility:include-filter" value="CtsApacheHttpLegacyUsesLibraryApiSignatureTestCases" />
+ <option name="compatibility:include-filter" value="CtsAppComponentFactoryTestCases" />
+ <option name="compatibility:include-filter" value="CtsAppUsageHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsAslrMallocTestCases" />
+ <option name="compatibility:include-filter" value="CtsAtraceHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsBackgroundRestrictionsTestCases" />
+ <option name="compatibility:include-filter" value="CtsBionicTestCases" />
+ <option name="compatibility:include-filter" value="CtsCalendarcommon2TestCases" />
+ <option name="compatibility:include-filter" value="CtsClassLoaderFactoryInMemoryDexClassLoaderTestCases" />
+ <option name="compatibility:include-filter" value="CtsClassLoaderFactoryPathClassLoaderTestCases" />
+ <option name="compatibility:include-filter" value="CtsCompilationTestCases" />
+ <option name="compatibility:include-filter" value="CtsContactsProviderWipe" />
+ <option name="compatibility:include-filter" value="CtsCppToolsTestCases" />
+ <option name="compatibility:include-filter" value="CtsCurrentApiSignatureTestCases" />
+ <option name="compatibility:include-filter" value="CtsDatabaseTestCases" />
+ <option name="compatibility:include-filter" value="CtsDebugTestCases" />
+ <option name="compatibility:include-filter" value="CtsDeviceIdleHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsDexMetadataHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsDreamsTestCases" />
+ <option name="compatibility:include-filter" value="CtsDynamicLinkerTestCases" />
+ <option name="compatibility:include-filter" value="CtsEdiHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsExtendedMockingTestCases" />
+ <option name="compatibility:include-filter" value="CtsFragmentTestCases" />
+ <option name="compatibility:include-filter" value="CtsFragmentTestCasesSdk26" />
+ <option name="compatibility:include-filter" value="CtsGestureTestCases" />
+ <option name="compatibility:include-filter" value="CtsHiddenApiBlocklistApi27TestCases" />
+ <option name="compatibility:include-filter" value="CtsHiddenApiBlocklistApi28TestCases" />
+ <option name="compatibility:include-filter" value="CtsHiddenApiBlocklistCurrentApiTestCases" />
+ <option name="compatibility:include-filter" value="CtsHiddenApiBlocklistDebugClassTestCases" />
+ <option name="compatibility:include-filter" value="CtsHiddenApiKillswitchDebugClassTestCases" />
+ <option name="compatibility:include-filter" value="CtsHiddenApiKillswitchSdkListTestCases" />
+ <option name="compatibility:include-filter" value="CtsHiddenApiKillswitchWildcardTestCases" />
+ <option name="compatibility:include-filter" value="CtsHostsideNumberBlockingTestCases" />
+ <option name="compatibility:include-filter" value="CtsHostsideTvTests" />
+ <option name="compatibility:include-filter" value="CtsHostsideWebViewTests" />
+ <option name="compatibility:include-filter" value="CtsHostTzDataTests" />
+ <option name="compatibility:include-filter" value="CtsIcuTestCases" />
+ <option name="compatibility:include-filter" value="CtsInlineMockingTestCases" />
+ <option name="compatibility:include-filter" value="CtsInputMethodTestCases" />
+ <option name="compatibility:include-filter" value="CtsIntentSignatureTestCases" />
+ <option name="compatibility:include-filter" value="CtsJankDeviceTestCases" />
+ <option name="compatibility:include-filter" value="CtsJdwpSecurityHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJdwpTestCases" />
+ <option name="compatibility:include-filter" value="CtsJniTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiAttachingHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiAttachingTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRedefineClassesHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1900HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1901HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1902HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1903HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1904HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1906HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1907HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1908HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1909HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1910HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1911HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1912HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1913HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1914HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1915HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1916HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1917HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1920HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1921HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1922HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1923HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1924HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1925HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1926HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1927HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1928HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1930HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1931HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1932HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1933HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1934HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1936HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1937HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1939HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1941HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1942HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1943HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1953HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1958HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest902HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest903HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest904HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest905HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest906HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest907HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest908HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest910HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest911HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest912HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest913HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest914HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest915HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest917HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest918HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest919HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest920HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest922HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest923HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest924HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest926HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest927HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest928HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest930HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest931HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest932HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest940HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest942HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest944HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest945HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest947HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest951HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest982HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest983HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest984HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest985HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest986HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest988HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest989HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest990HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest991HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest992HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest993HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest994HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest996HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest997HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiTaggingHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiTrackingHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsKernelConfigTestCases" />
+ <option name="compatibility:include-filter" value="CtsLeanbackJankTestCases" />
+ <option name="compatibility:include-filter" value="CtsLibcoreApiEvolutionTestCases" />
+ <option name="compatibility:include-filter" value="CtsLibcoreCoreApiTestCases" />
+ <option name="compatibility:include-filter" value="CtsLibcoreCorePlatformApiTestCases" />
+ <option name="compatibility:include-filter" value="CtsLibcoreJsr166TestCases" />
+ <option name="compatibility:include-filter" value="CtsLibcoreLegacy22TestCases" />
+ <option name="compatibility:include-filter" value="CtsLibcoreOjTestCases" />
+ <option name="compatibility:include-filter" value="CtsLibcoreOkHttpTestCases" />
+ <option name="compatibility:include-filter" value="CtsLibcoreSimpleMModuleTestCases" />
+ <option name="compatibility:include-filter" value="CtsLibcoreSimpleModuleTestCases" />
+ <option name="compatibility:include-filter" value="CtsLibcoreWycheproofBCTestCases" />
+ <option name="compatibility:include-filter" value="CtsLibcoreWycheproofConscryptTestCases" />
+ <option name="compatibility:include-filter" value="CtsLiblogTestCases" />
+ <option name="compatibility:include-filter" value="CtsLocationFineTestCases" />
+ <option name="compatibility:include-filter" value="CtsLocationCoarseTestCases" />
+ <option name="compatibility:include-filter" value="CtsLocationNoneTestCases" />
+ <option name="compatibility:include-filter" value="CtsLogdTestCases" />
+ <option name="compatibility:include-filter" value="CtsMockingDebuggableTestCases" />
+ <option name="compatibility:include-filter" value="CtsMockingTestCases" />
+ <option name="compatibility:include-filter" value="CtsMultiUserHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsNativeNetTestCases" />
+ <option name="compatibility:include-filter" value="CtsNativeNetTestCases" />
+ <option name="compatibility:include-filter" value="CtsNdefTestCases" />
+ <option name="compatibility:include-filter" value="CtsNdkBinderTestCases" />
+ <option name="compatibility:include-filter" value="CtsNetTestCasesLegacyPermission22" />
+ <option name="compatibility:include-filter" value="CtsNNAPITestCases" />
+ <option name="compatibility:include-filter" value="CtsOmapiTestCases" />
+ <option name="compatibility:include-filter" value="CtsPdfTestCases" />
+ <option name="compatibility:include-filter" value="CtsPermissionTestCasesSdk28" />
+ <option name="compatibility:include-filter" value="CtsPreference2TestCases" />
+ <option name="compatibility:include-filter" value="CtsPreferenceTestCases" />
+ <option name="compatibility:include-filter" value="CtsProtoTestCases" />
+ <option name="compatibility:include-filter" value="CtsRenderscriptLegacyTestCases" />
+ <option name="compatibility:include-filter" value="CtsRsBlasTestCases" />
+ <option name="compatibility:include-filter" value="CtsRsCppTestCases" />
+ <option name="compatibility:include-filter" value="CtsSecureElementAccessControlTestCases1" />
+ <option name="compatibility:include-filter" value="CtsSecureElementAccessControlTestCases2" />
+ <option name="compatibility:include-filter" value="CtsSecureElementAccessControlTestCases3" />
+ <option name="compatibility:include-filter" value="CtsSliceTestCases" />
+ <option name="compatibility:include-filter" value="CtsSustainedPerformanceHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsSystemApiAnnotationTestCases" />
+ <option name="compatibility:include-filter" value="CtsTelecomTestCases2" />
+ <option name="compatibility:include-filter" value="CtsTelephony2TestCases" />
+ <option name="compatibility:include-filter" value="CtsTelephony3TestCases" />
+ <option name="compatibility:include-filter" value="CtsTextTestCases" />
+ <option name="compatibility:include-filter" value="CtsToastTestCases" />
+ <option name="compatibility:include-filter" value="CtsTransitionTestCases" />
+ <option name="compatibility:include-filter" value="CtsTvProviderTestCases" />
+ <option name="compatibility:include-filter" value="CtsUiDeviceTestCases" />
+ <option name="compatibility:include-filter" value="CtsUsbTests" />
+ <option name="compatibility:include-filter" value="CtsVoiceInteractionTestCases" />
+ <option name="compatibility:include-filter" value="CtsVrTestCases" />
+ <option name="compatibility:include-filter" value="CtsWifiBroadcastsHostTestCases" />
+ <option name="compatibility:include-filter" value="CtsWrapWrapDebugMallocDebugTestCases" />
+ <option name="compatibility:include-filter" value="CtsWrapWrapDebugTestCases" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-virtual-device.xml b/tools/cts-tradefed/res/config/cts-virtual-device.xml
new file mode 100644
index 0000000..697ee2f
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-virtual-device.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS with common options set for an automated run on userdebug/eng builds, and per module rules suitable for virtual devices">
+
+ <include name="cts-automated" />
+
+ <!-- Tell all AndroidJUnitTests to exclude certain annotations -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:android.support.test.filters.RequiresDevice" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:androidx.test.filters.RequiresDevice" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:android.platform.test.annotations.RequiresDevice" />
+
+ <!-- Tell all HostTests to exclude certain annotations -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:exclude-annotation:android.platform.test.annotations.RequiresDevice" />
+ <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:exclude-annotation:android.platform.test.annotations.RequiresDevice" />
+
+ <!-- add per module rules for virtual devices below -->
+ <option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-GLES2.functional.prerequisite#*" />
+ <option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-EGL.*" />
+ <option name="compatibility:module-arg" value="CtsLibcoreTestCases:core-expectation:/virtualdeviceknownfailures.txt" />
+
+ <!-- Virtual devices usually run as root -->
+ <option name="compatibility:skip-system-status-check" value="com.android.tradefed.suite.checker.ShellStatusChecker" />
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts.xml b/tools/cts-tradefed/res/config/cts.xml
new file mode 100644
index 0000000..bc5c447
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS from a pre-existing CTS installation">
+
+ <include name="cts-common" />
+ <include name="cts-exclude" />
+ <include name="cts-exclude-instant" />
+
+ <option name="plan" value="cts" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/retry.xml b/tools/cts-tradefed/res/config/retry.xml
new file mode 100644
index 0000000..0a01dc3
--- /dev/null
+++ b/tools/cts-tradefed/res/config/retry.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs a retry of a previous CTS session.">
+ <object type="previous_loader" class="com.android.compatibility.common.tradefed.result.suite.PreviousResultLoader" />
+ <test class="com.android.tradefed.testtype.suite.retry.RetryRescheduler" />
+
+ <logger class="com.android.tradefed.log.FileLogger">
+ <option name="log-level-display" value="WARN" />
+ </logger>
+</configuration>
diff --git a/tools/cts-tradefed/res/config/security-bulletin.xml b/tools/cts-tradefed/res/config/security-bulletin.xml
new file mode 100644
index 0000000..02175a9
--- /dev/null
+++ b/tools/cts-tradefed/res/config/security-bulletin.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs Security Patch test cases">
+
+ <option name="plan" value="security-bulletin" />
+
+ <include name="cts"/>
+
+ <option name="compatibility:include-filter" value="CtsSecurityTestCases" />
+
+ <option name="compatibility:include-filter" value="CtsSecurityHostTestCases" />
+
+ <!-- Only run tests with @SecurityTest annotation. -->
+ <option name="compatibility:module-arg" value="CtsSecurityHostTestCases:include-annotation:android.platform.test.annotations.SecurityTest"/>
+
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:include-annotation:android.platform.test.annotations.SecurityTest" />
+
+</configuration>
diff --git a/hostsidetests/net/Android.bp b/tools/cts-tradefed/tests/Android.bp
similarity index 66%
copy from hostsidetests/net/Android.bp
copy to tools/cts-tradefed/tests/Android.bp
index 741c961..0d0bcea 100644
--- a/hostsidetests/net/Android.bp
+++ b/tools/cts-tradefed/tests/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014 The Android Open Source Project
+// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,19 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-java_test_host {
- name: "CtsHostsideNetworkTests",
- defaults: ["cts_defaults"],
- // Only compile source java files in this apk.
+java_library_host {
+ name: "cts-tradefed-tests",
+
srcs: ["src/**/*.java"],
+
libs: [
- "cts-tradefed",
"tradefed",
+ "cts-tradefed",
],
- // Tag this module as a cts test artifact
- test_suites: [
- "cts",
- "vts10",
- "general-tests",
- ],
+ // We ship the Deqp Runner tests with the CTS one to validate them.
+ static_libs: ["CtsDeqpRunnerTests"],
}
diff --git a/tools/cts-tradefed/tests/run_cts_tests.sh b/tools/cts-tradefed/tests/run_cts_tests.sh
new file mode 100755
index 0000000..428b9ec
--- /dev/null
+++ b/tools/cts-tradefed/tests/run_cts_tests.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A simple helper script that runs the CTS harness unit tests
+
+CTS_DIR=`dirname $0`/../etc
+
+${CTS_DIR}/cts-tradefed run singleCommand host -n \
+ --console-result-reporter:suppress-passed-tests \
+ --class com.android.compatibility.common.tradefed.UnitTests \
+ --class com.android.compatibility.common.util.HostUnitTests \
+ --class com.android.compatibility.common.util.UnitTests \
+ --class com.android.compatibility.tradefed.CtsTradefedTest \
+ --class com.drawelements.deqp.runner.DeqpTestRunnerTest \
+ "$@"
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java b/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java
new file mode 100644
index 0000000..5d5df59
--- /dev/null
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.tradefed;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.util.FileUtil;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+
+/**
+ * Tests for cts-tradefed.
+ */
+public class CtsTradefedTest extends TestCase {
+
+ private static final String PROPERTY_NAME = "CTS_ROOT";
+ private static final String SUITE_FULL_NAME = "Compatibility Test Suite";
+ private static final String SUITE_NAME = "CTS";
+ private static final String SUITE_PLAN = "cts";
+ private static final String DYNAMIC_CONFIG_URL = "";
+
+ private String mOriginalProperty = null;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mOriginalProperty = System.getProperty(PROPERTY_NAME);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mOriginalProperty != null) {
+ System.setProperty(PROPERTY_NAME, mOriginalProperty);
+ }
+ super.tearDown();
+ }
+
+ public void testSuiteInfoLoad() throws Exception {
+ // Test the values in the manifest can be loaded
+ File root = FileUtil.createTempDir("root");
+ System.setProperty(PROPERTY_NAME, root.getAbsolutePath());
+ File base = new File(root, "android-cts");
+ base.mkdirs();
+ File tests = new File(base, "testcases");
+ tests.mkdirs();
+ CompatibilityBuildProvider provider = new CompatibilityBuildProvider();
+ OptionSetter setter = new OptionSetter(provider);
+ setter.setOptionValue("plan", SUITE_PLAN);
+ setter.setOptionValue("dynamic-config-url", DYNAMIC_CONFIG_URL);
+ IBuildInfo info = provider.getBuild();
+ CompatibilityBuildHelper helper = new CompatibilityBuildHelper(info);
+ assertEquals("Incorrect suite full name", SUITE_FULL_NAME, helper.getSuiteFullName());
+ assertEquals("Incorrect suite name", SUITE_NAME, helper.getSuiteName());
+ FileUtil.recursiveDelete(root);
+ }
+}
diff --git a/tests/tests/net/util/Android.bp b/tools/manifest-generator/Android.bp
similarity index 61%
copy from tests/tests/net/util/Android.bp
copy to tools/manifest-generator/Android.bp
index 1f94613..9d6cdb8 100644
--- a/tests/tests/net/util/Android.bp
+++ b/tools/manifest-generator/Android.bp
@@ -1,25 +1,25 @@
-//
-// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
-// Common utilities for cts net tests.
-java_library {
- name: "cts-net-utils",
- srcs: ["java/**/*.java", "java/**/*.kt"],
- static_libs: [
- "compatibility-device-util-axt",
- "junit",
- ],
-}
\ No newline at end of file
+java_library_host {
+ name: "compatibility-manifest-generator",
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: ["kxml2-2.3.0"],
+
+ manifest: "MANIFEST.mf",
+
+ use_tools_jar: true,
+}
diff --git a/tools/manifest-generator/MANIFEST.mf b/tools/manifest-generator/MANIFEST.mf
new file mode 100644
index 0000000..4f62631
--- /dev/null
+++ b/tools/manifest-generator/MANIFEST.mf
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: com.android.compatibility.common.generator.ManifestGenerator
diff --git a/tools/manifest-generator/src/com/android/compatibility/common/generator/ManifestGenerator.java b/tools/manifest-generator/src/com/android/compatibility/common/generator/ManifestGenerator.java
new file mode 100644
index 0000000..c78723f
--- /dev/null
+++ b/tools/manifest-generator/src/com/android/compatibility/common/generator/ManifestGenerator.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.generator;
+
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.kxml2.io.KXmlSerializer;
+
+public class ManifestGenerator {
+
+ private static final String DEFAULT_MIN_SDK = "8";
+
+ private static final String USAGE =
+ "Usage: manifest-generator -n NAME -p PACKAGE_NAME -o OUTPUT_FILE -i INSTRUMENT_NAME "
+ + "[-s MIN_SDK_VERSION] [-t TARGET_SDK_VERSION] [-r PERMISSION]+ "
+ + "[-a ACTIVITY]+ [-l REQUIRED_LIBRARY]+ [-lo OPTIONAL_LIBRARY]+";
+ private static final String MANIFEST = "manifest";
+ private static final String USES_SDK = "uses-sdk";
+ private static final String USES_PERMISSION = "uses-permission";
+ private static final String APPLICATION = "application";
+ private static final String INSTRUMENTATION = "instrumentation";
+ private static final String ACTIVITY = "activity";
+ private static final String USES_LIBRARY = "uses-library";
+
+ public static void main(String[] args) {
+ String pkgName = null;
+ String instrumentName = null;
+ String minSdk = DEFAULT_MIN_SDK;
+ String targetSdk = null;
+ List<String> permissions = new ArrayList<>();
+ List<String> activities = new ArrayList<>();
+ List<String> libraries = new ArrayList<>();
+ List<String> optionalLibs = new ArrayList<>();
+ String output = null;
+
+ for (int i = 0; i < args.length - 1; i++) {
+ if (args[i].equals("-p")) {
+ pkgName = args[++i];
+ } else if (args[i].equals("-a")) {
+ activities.add(args[++i]);
+ } else if (args[i].equals("-l")) {
+ libraries.add(args[++i]);
+ } else if (args[i].equals("-lo")) {
+ optionalLibs.add(args[++i]);
+ } else if (args[i].equals("-o")) {
+ output = args[++i];
+ } else if (args[i].equals("-i")) {
+ instrumentName = args[++i];
+ } else if (args[i].equals("-r")) {
+ permissions.add(args[++i]);
+ } else if (args[i].equals("-s")) {
+ minSdk = args[++i];
+ } else if (args[i].equals("-t")) {
+ targetSdk = args[++i];
+ }
+ }
+
+ if (pkgName == null) {
+ error("Missing package name");
+ } else if (instrumentName == null) {
+ error("Missing instrumentation name");
+ } else if (activities.isEmpty()) {
+ error("No activities");
+ } else if (output == null) {
+ error("Missing output file");
+ }
+
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(output);
+ generate(
+ out,
+ pkgName,
+ instrumentName,
+ minSdk,
+ targetSdk,
+ permissions,
+ activities,
+ libraries,
+ optionalLibs);
+ } catch (Exception e) {
+ System.err.println("Couldn't create manifest file");
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ }
+ }
+
+ /*package*/ static void generate(
+ OutputStream out,
+ String pkgName,
+ String instrumentName,
+ String minSdk,
+ String targetSdk,
+ List<String> permissions,
+ List<String> activities,
+ List<String> libraries,
+ List<String> optionalLibs)
+ throws Exception {
+ final String ns = null;
+ KXmlSerializer serializer = new KXmlSerializer();
+ serializer.setOutput(out, "UTF-8");
+ serializer.startDocument("UTF-8", true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.startTag(ns, MANIFEST);
+ serializer.attribute(ns, "xmlns:android", "http://schemas.android.com/apk/res/android");
+ serializer.attribute(ns, "package", pkgName);
+ serializer.startTag(ns, USES_SDK);
+ serializer.attribute(ns, "android:minSdkVersion", minSdk);
+ if (targetSdk != null) {
+ serializer.attribute(ns, "android:targetSdkVersion", targetSdk);
+ }
+ serializer.endTag(ns, USES_SDK);
+ for (String permission : permissions) {
+ serializer.startTag(ns, USES_PERMISSION);
+ serializer.attribute(ns, "android:name", permission);
+ serializer.endTag(ns, USES_PERMISSION);
+ }
+ serializer.startTag(ns, APPLICATION);
+ for (String library : libraries) {
+ serializer.startTag(ns, USES_LIBRARY);
+ serializer.attribute(ns, "android:name", library);
+ serializer.endTag(ns, USES_LIBRARY);
+ }
+ for (String optionalLib : optionalLibs) {
+ serializer.startTag(ns, USES_LIBRARY);
+ serializer.attribute(ns, "android:name", optionalLib);
+ serializer.attribute(ns, "android:required", "false");
+ serializer.endTag(ns, USES_LIBRARY);
+ }
+ for (String activity : activities) {
+ serializer.startTag(ns, ACTIVITY);
+ serializer.attribute(ns, "android:name", activity);
+ serializer.endTag(ns, ACTIVITY);
+ }
+ serializer.endTag(ns, APPLICATION);
+ serializer.startTag(ns, INSTRUMENTATION);
+ serializer.attribute(ns, "android:name", instrumentName);
+ serializer.attribute(ns, "android:targetPackage", pkgName);
+ serializer.endTag(ns, INSTRUMENTATION);
+ serializer.endTag(ns, MANIFEST);
+ serializer.endDocument();
+ out.flush();
+ }
+
+ private static void error(String message) {
+ System.err.println(message);
+ System.err.println(USAGE);
+ System.exit(1);
+ }
+}
diff --git a/tests/tests/net/util/Android.bp b/tools/manifest-generator/tests/Android.bp
similarity index 64%
copy from tests/tests/net/util/Android.bp
copy to tools/manifest-generator/tests/Android.bp
index 1f94613..b8f012d 100644
--- a/tests/tests/net/util/Android.bp
+++ b/tools/manifest-generator/tests/Android.bp
@@ -1,25 +1,24 @@
-//
-// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
-// Common utilities for cts net tests.
-java_library {
- name: "cts-net-utils",
- srcs: ["java/**/*.java", "java/**/*.kt"],
- static_libs: [
- "compatibility-device-util-axt",
+java_test_host {
+ name: "compatibility-manifest-generator-tests",
+
+ srcs: ["src/**/*.java"],
+
+ libs: [
+ "compatibility-manifest-generator",
"junit",
],
-}
\ No newline at end of file
+}
diff --git a/tools/manifest-generator/tests/run_tests.sh b/tools/manifest-generator/tests/run_tests.sh
new file mode 100755
index 0000000..0a77a9b
--- /dev/null
+++ b/tools/manifest-generator/tests/run_tests.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Helper script for running unit tests for compatibility libraries
+
+HARNESS_DIR=$(dirname ${0})/../../../..
+source ${HARNESS_DIR}/test_defs.sh
+
+JARS="
+ compatibility-manifest-generator\
+ compatibility-manifest-generator-tests"
+
+run_tests "com.android.compatibility.common.generator.ManifestGeneratorTest" "${JARS}" "${@}"
+
diff --git a/tools/manifest-generator/tests/src/com/android/compatibility/common/generator/ManifestGeneratorTest.java b/tools/manifest-generator/tests/src/com/android/compatibility/common/generator/ManifestGeneratorTest.java
new file mode 100644
index 0000000..c95ec64
--- /dev/null
+++ b/tools/manifest-generator/tests/src/com/android/compatibility/common/generator/ManifestGeneratorTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.generator;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+/** Unit tests for {@link ManifestGenerator}. */
+public class ManifestGeneratorTest extends TestCase {
+
+ private static final String PACKAGE = "test.package";
+ private static final String INSTRUMENT = "test.package.TestInstrument";
+ private static final String MIN_SDK = "8";
+ private static final String TARGET_SDK = "17";
+ private static final String MANIFEST =
+ "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>\r\n"
+ + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" "
+ + "package=\"test.package\">\r\n"
+ + " <uses-sdk android:minSdkVersion=\"8\" android:targetSdkVersion=\"17\" "
+ + "/>\r\n"
+ + "%s"
+ + " <application>\r\n"
+ + "%s"
+ + "%s"
+ + "%s"
+ + " </application>\r\n"
+ + " <instrumentation android:name=\"test.package.TestInstrument\" "
+ + "android:targetPackage=\"test.package\" />\r\n"
+ + "</manifest>";
+ private static final String PERMISSION = " <uses-permission android:name=\"%s\" />\r\n";
+ private static final String PERMISSION_A = "android.permission.PermissionA";
+ private static final String PERMISSION_B = "android.permission.PermissionB";
+ private static final String ACTIVITY = " <activity android:name=\"%s\" />\r\n";
+ private static final String ACTIVITY_A = "test.package.ActivityA";
+ private static final String ACTIVITY_B = "test.package.ActivityB";
+ private static final String USES_LIBRARY = " <uses-library android:name=\"%s\" />\r\n";
+ private static final String USES_OPTIONAL_LIBRARY =
+ " <uses-library android:name=\"%s\" android:required=\"false\" />\r\n";
+ private static final String LIBRARY = "test.runner.library";
+ private static final String OPTIONAL_LIBRARY = "android.test.base";
+
+ public void testManifest() throws Exception {
+ List<String> permissions = new ArrayList<>();
+ permissions.add(PERMISSION_A);
+ permissions.add(PERMISSION_B);
+ List<String> activities = new ArrayList<>();
+ activities.add(ACTIVITY_A);
+ activities.add(ACTIVITY_B);
+ List<String> libraries = new ArrayList<>();
+ libraries.add(LIBRARY);
+ List<String> optionalLibs = new ArrayList<>();
+ optionalLibs.add(OPTIONAL_LIBRARY);
+ OutputStream output = new OutputStream() {
+ private StringBuilder string = new StringBuilder();
+ @Override
+ public void write(int b) throws IOException {
+ this.string.append((char) b);
+ }
+
+ @Override
+ public String toString(){
+ return this.string.toString();
+ }
+ };
+ ManifestGenerator.generate(
+ output,
+ PACKAGE,
+ INSTRUMENT,
+ MIN_SDK,
+ TARGET_SDK,
+ permissions,
+ activities,
+ libraries,
+ optionalLibs);
+ String permissionXml = String.format(PERMISSION, PERMISSION_A)
+ + String.format(PERMISSION, PERMISSION_B);
+ String activityXml = String.format(ACTIVITY, ACTIVITY_A)
+ + String.format(ACTIVITY, ACTIVITY_B);
+ String libraryXml = String.format(USES_LIBRARY, LIBRARY);
+ String optionalLibraryXml = String.format(USES_OPTIONAL_LIBRARY, OPTIONAL_LIBRARY);
+ String expected =
+ String.format(MANIFEST, permissionXml, libraryXml, optionalLibraryXml, activityXml);
+ assertEquals("Wrong manifest output", expected, output.toString());
+ }
+
+}