Merge "mediav2: fix ByteBuffer mode image comparison"
diff --git a/apps/CtsVerifier/Android.bp b/apps/CtsVerifier/Android.bp
index 01c579e..69ef63f 100644
--- a/apps/CtsVerifier/Android.bp
+++ b/apps/CtsVerifier/Android.bp
@@ -2,3 +2,66 @@
name: "CtsVerifierMockVrListenerServiceFiles",
srcs: ["src/com/android/cts/verifier/vr/MockVrListenerService.java"],
}
+
+android_test {
+ name: "CtsVerifier",
+ defaults: ["cts_error_prone_rules_tests"],
+
+ compile_multilib: "both",
+
+ srcs: [
+ "src/**/*.java",
+ "src/**/I*.aidl",
+ ],
+
+ aidl: {
+ include_dirs: ["frameworks/native/aidl/gui"],
+ },
+
+ static_libs: [
+ "android-ex-camera2",
+ "compatibility-common-util-devicesidelib",
+ "cts-sensors-tests",
+ "cts-camera-performance-tests",
+ "ctstestrunner-axt",
+ "apache-commons-math",
+ "androidplot",
+ "ctsverifier-opencv",
+ "core-tests-support",
+ "androidx.legacy_legacy-support-v4",
+ "mockito-target-minus-junit4",
+ "mockwebserver",
+ "compatibility-device-util-axt",
+ "platform-test-annotations",
+ "cts-security-test-support-library",
+ "cts-midi-lib",
+ "cbor-java",
+ "CtsCameraUtils",
+ "androidx.legacy_legacy-support-v4",
+ "CtsForceStopHelper-constants",
+ ],
+
+ libs: ["telephony-common"] + ["android.test.runner.stubs"] + ["android.test.base.stubs"] + ["android.test.mock.stubs"] + ["android.car"] + ["voip-common"] + ["truth-prebuilt"],
+
+ platform_apis: true,
+
+ jni_libs: [
+ "libctsverifier_jni",
+ "libctsnativemidi_jni",
+ "libaudioloopback_jni",
+ ],
+
+ optimize: {
+ proguard_flags_files: ["proguard.flags"],
+ },
+
+ dex_preopt: {
+ enabled: false,
+ },
+}
+
+// opencv library
+java_import {
+ name: "ctsverifier-opencv",
+ jars: ["libs/opencv3-android.jar"],
+}
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 8e10b97..007be8c 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -15,66 +15,6 @@
#
LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_MULTILIB := both
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src) \
- ../ForceStopHelperApp/src/com/android/cts/forcestophelper/Constants.java
-
-LOCAL_AIDL_INCLUDES := \
- frameworks/native/aidl/gui
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-ex-camera2 \
- compatibility-common-util-devicesidelib \
- cts-sensors-tests \
- cts-camera-performance-tests \
- ctstestrunner-axt \
- apache-commons-math \
- androidplot \
- ctsverifier-opencv \
- core-tests-support \
- androidx.legacy_legacy-support-v4 \
- mockito-target-minus-junit4 \
- mockwebserver \
- compatibility-device-util-axt \
- platform-test-annotations \
- cts-security-test-support-library \
- cts-midi-lib \
- cbor-java \
- CtsCameraUtils
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
- androidx.legacy_legacy-support-v4
-
-LOCAL_JAVA_LIBRARIES += telephony-common
-LOCAL_JAVA_LIBRARIES += android.test.runner.stubs
-LOCAL_JAVA_LIBRARIES += android.test.base.stubs
-LOCAL_JAVA_LIBRARIES += android.test.mock.stubs
-LOCAL_JAVA_LIBRARIES += android.car
-LOCAL_JAVA_LIBRARIES += voip-common
-LOCAL_JAVA_LIBRARIES += truth-prebuilt
-
-LOCAL_PACKAGE_NAME := CtsVerifier
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_JNI_SHARED_LIBRARIES := \
- libctsverifier_jni \
- libctsnativemidi_jni \
- libaudioloopback_jni \
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-
-LOCAL_DEX_PREOPT := false
--include cts/error_prone_rules_tests.mk
-include $(BUILD_PACKAGE)
-
# Build CTS verifier framework as a libary.
include $(CLEAR_VARS)
@@ -101,14 +41,6 @@
include $(BUILD_STATIC_JAVA_LIBRARY)
-# opencv library
-include $(CLEAR_VARS)
-
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
- ctsverifier-opencv:libs/opencv3-android.jar
-
-include $(BUILD_MULTI_PREBUILT)
-
pre-installed-apps := \
CtsEmptyDeviceAdmin \
CtsEmptyDeviceOwner \
diff --git a/apps/ForceStopHelperApp/Android.bp b/apps/ForceStopHelperApp/Android.bp
index f438b87..85a2f6d 100644
--- a/apps/ForceStopHelperApp/Android.bp
+++ b/apps/ForceStopHelperApp/Android.bp
@@ -25,3 +25,8 @@
"general-tests",
],
}
+
+java_library {
+ name: "CtsForceStopHelper-constants",
+ srcs: ["src/com/android/cts/forcestophelper/Constants.java"],
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index 2a087dc..5c26531 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -135,6 +135,9 @@
getDevice().uninstallPackage(WRITE_PKG);
installPackage(WRITE_APK);
+ // Make sure user initialization is complete before testing
+ waitForBroadcastIdle();
+
for (int user : mUsers) {
runDeviceTests(WRITE_PKG, WRITE_CLASS, "testExternalStorageRename", user);
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageSetInstallerTest.kt b/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageSetInstallerTest.kt
index ba62f2f..4972c68 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageSetInstallerTest.kt
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageSetInstallerTest.kt
@@ -30,11 +30,13 @@
import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters
import android.cts.host.utils.DeviceJUnit4Parameterized
import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
+import java.lang.AssertionError
/**
* This test verifies protection for an exploit where any app could set the installer package
@@ -197,7 +199,9 @@
}
private fun assertPermission(granted: Boolean, permission: String) {
- assertThat(getPermissionString(permission)).contains("granted=$granted")
+ val dump = device.executeShellCommand("dumpsys package $TARGET_PKG")
+ assertWithMessage(dump).that(getPermissionString(dump, permission))
+ .contains("granted=$granted")
}
private fun grantPermission(permission: String) {
@@ -209,40 +213,50 @@
}
private fun assertGrantState(state: GrantState, permission: String) {
- val output = getPermissionString(permission)
+ val dump = device.executeShellCommand("dumpsys package $TARGET_PKG")
+ val output = getPermissionString(dump, permission)
when (state) {
GrantState.TRUE -> {
- assertThat(output).contains("granted=true")
- assertThat(output).doesNotContain("RESTRICTION")
- assertThat(output).doesNotContain("EXEMPT")
+ assertWithMessage(dump).that(output).contains("granted=true")
+ assertWithMessage(dump).that(output).doesNotContain("RESTRICTION")
+ assertWithMessage(dump).that(output).doesNotContain("EXEMPT")
}
GrantState.TRUE_EXEMPT -> {
- assertThat(output).contains("granted=true")
- assertThat(output).contains("RESTRICTION_INSTALLER_EXEMPT")
+ assertWithMessage(dump).that(output).contains("granted=true")
+ assertWithMessage(dump).that(output).contains("RESTRICTION_INSTALLER_EXEMPT")
}
GrantState.TRUE_RESTRICTED -> {
- assertThat(output).contains("granted=true")
- assertThat(output).contains("APPLY_RESTRICTION")
- assertThat(output).doesNotContain("EXEMPT")
+ assertWithMessage(dump).that(output).contains("granted=true")
+ assertWithMessage(dump).that(output).contains("APPLY_RESTRICTION")
+ assertWithMessage(dump).that(output).doesNotContain("EXEMPT")
}
GrantState.FALSE -> {
- assertThat(output).contains("granted=false")
+ assertWithMessage(dump).that(output).contains("granted=false")
}
}
}
- private fun getPermissionString(permission: String) =
- device.executeShellCommand("dumpsys package $TARGET_PKG")
- .lineSequence()
- .dropWhile { !it.startsWith("Packages:") } // Wait for package header
- .drop(1) // Drop the package header itself
- .takeWhile { it.isEmpty() || it.first().isWhitespace() } // Until next header
- .dropWhile { !it.trim().startsWith("User $mPrimaryUserId:") } // Find user
- .drop(1) // Drop the user header itself
- .takeWhile { !it.trim().startsWith("User") } // Until next user
- .filter { it.contains("$permission: granted=") }
- .single()
+ private fun getPermissionString(output: String, permission: String) = retry {
+ output.lineSequence()
+ .dropWhile { !it.startsWith("Packages:") } // Wait for package header
+ .drop(1) // Drop the package header itself
+ .takeWhile { it.isEmpty() || it.first().isWhitespace() } // Until next header
+ .dropWhile { !it.trim().startsWith("User $mPrimaryUserId:") } // Find user
+ .drop(1) // Drop the user header itself
+ .takeWhile { !it.trim().startsWith("User") } // Until next user
+ .filter { it.contains("$permission: granted=") }
+ .firstOrNull()
+ }
+
+ private fun <T> retry(block: () -> T?): T {
+ repeat(10) {
+ block()?.let { return it }
+ Thread.sleep(1000)
+ }
+
+ throw AssertionError("Never succeeded")
+ }
enum class GrantState {
// Granted in full, unrestricted
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
index d18a9fa..2f7444d 100755
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
@@ -376,7 +376,7 @@
private void validateDeviceIdAttestationData(Certificate leaf,
String expectedSerial, String expectedImei, String expectedMeid)
throws CertificateParsingException {
- Attestation attestationRecord = new Attestation((X509Certificate) leaf);
+ Attestation attestationRecord = Attestation.loadFromCertificate((X509Certificate) leaf);
AuthorizationList teeAttestation = attestationRecord.getTeeEnforced();
assertThat(teeAttestation).isNotNull();
validateBrandAttestationRecord(teeAttestation);
@@ -402,7 +402,7 @@
assertThat(attestation).isNotNull();
assertThat(attestation.size()).isGreaterThan(1);
X509Certificate leaf = (X509Certificate) attestation.get(0);
- Attestation attestationRecord = new Attestation(leaf);
+ Attestation attestationRecord = Attestation.loadFromCertificate(leaf);
assertThat(attestationRecord.getAttestationChallenge()).isEqualTo(providedChallenge);
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/DevicePolicyEventWrapper.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/DevicePolicyEventWrapper.java
index 71566d0..88286f3 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/DevicePolicyEventWrapper.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/DevicePolicyEventWrapper.java
@@ -24,7 +24,7 @@
/**
* Wrapper over <code>DevicePolicyEvent</code> atom as defined in
- * <code>frameworks/base/cmds/statsd/src/atoms.proto</code>.
+ * <code>frameworks/proto_logging/stats/atoms.proto</code>.
* @see Builder
*/
public final class DevicePolicyEventWrapper {
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java
index bbba1c4..f18268e 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java
@@ -99,14 +99,17 @@
/**
* Test 11.2.2-4
* Tests that the device sends a <INACTIVE_SOURCE> message when put on standby.
- * This test depends on One Touch Play, and will pass only if One Touch Play passes.
*/
@Test
public void cect_11_2_2_4_InactiveSourceOnStandby() throws Exception {
ITestDevice device = getDevice();
try {
int dumpsysPhysicalAddress = getDumpsysPhysicalAddress();
- device.executeShellCommand("input keyevent KEYCODE_HOME");
+ hdmiCecClient.sendCecMessage(
+ LogicalAddress.TV,
+ LogicalAddress.BROADCAST,
+ CecOperand.SET_STREAM_PATH,
+ CecMessage.formatParams(dumpsysPhysicalAddress));
device.executeShellCommand("input keyevent KEYCODE_SLEEP");
String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV,
CecOperand.INACTIVE_SOURCE);
diff --git a/hostsidetests/rollback/TEST_MAPPING b/hostsidetests/rollback/TEST_MAPPING
index a353a74..acec493 100644
--- a/hostsidetests/rollback/TEST_MAPPING
+++ b/hostsidetests/rollback/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "presubmit": [
+ "presubmit-large": [
{
"name": "CtsRollbackManagerHostTestCases"
}
diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
index f1a8035..47b45ed 100644
--- a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
+++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
@@ -3048,12 +3048,28 @@
assertThat(readPfd.getStatSize()).isEqualTo(writePfd.getStatSize());
}
+ private void assertStartsWith(String actual, String prefix, boolean expected) throws Exception {
+ String message = "String \"" + actual + "\" should start with \"" + prefix + "\"";
+
+ if (expected) {
+ assertTrue(message, actual.startsWith(prefix));
+ } else {
+ assertFalse(message, actual.startsWith(prefix));
+ }
+ }
+
private void assertLowerFsFd(ParcelFileDescriptor pfd) throws Exception {
- assertThat(Os.readlink("/proc/self/fd/" + pfd.getFd()).startsWith("/storage")).isTrue();
+ String path = Os.readlink("/proc/self/fd/" + pfd.getFd());
+ String prefix = "/storage";
+
+ assertStartsWith(path, prefix, true);
}
private void assertUpperFsFd(ParcelFileDescriptor pfd) throws Exception {
- assertThat(Os.readlink("/proc/self/fd/" + pfd.getFd()).startsWith("/mnt/user")).isTrue();
+ String path = Os.readlink("/proc/self/fd/" + pfd.getFd());
+ String prefix = "/mnt/user";
+
+ assertStartsWith(path, prefix, true);
}
private static void assertCanCreateFile(File file) throws IOException {
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/poc.cpp
index 121d5a9..419f4c6 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/poc.cpp
@@ -79,7 +79,7 @@
data.writeInt32(1);
audio_attributes_t attr;
memset(&attr, 0xff, sizeof(attr));
- attr.flags = 0;
+ attr.flags = AUDIO_FLAG_NONE;
memset(attr.tags, 0x41, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
data.write(&attr, sizeof(attr));
binder->transact(GET_OUTPUT_FOR_ATTR, data, &reply, 0);
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9313/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9313/Android.bp
index 0a19bec..0e9fbdd 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9313/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9313/Android.bp
@@ -29,12 +29,14 @@
"frameworks/native/include/media/openmax",
"frameworks/av/media/libstagefright",
"frameworks/native/include/media/hardware",
- "frameworks/av/media/libstagefright/codecs/mp3dec/include",
- "frameworks/av/media/libstagefright/codecs/mp3dec/src",
"frameworks/av/media/libmedia/include",
"frameworks/av/media/libstagefright/xmlparser/include",
],
+ header_libs: [
+ "libstagefright_mp3dec",
+ ],
+
shared_libs: [
"libstagefright",
"libstagefright_omx",
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9313/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9313/poc.cpp
index a559537..1ac7b76 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9313/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9313/poc.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
+#include <s_tmp3dec_file.h> // from the mp3dec library
+
#include "../includes/common.h"
#include "../includes/memutils_track.h"
#include "../includes/omxUtils.h"
-#include "codecs/mp3dec/src/s_tmp3dec_file.h"
#include "media/omx/1.0/WOmx.h"
#include "omx/include/media/stagefright/omx/1.0/Omx.h"
diff --git a/hostsidetests/userspacereboot/TEST_MAPPING b/hostsidetests/userspacereboot/TEST_MAPPING
index 40da059..cf97bfa 100644
--- a/hostsidetests/userspacereboot/TEST_MAPPING
+++ b/hostsidetests/userspacereboot/TEST_MAPPING
@@ -1,8 +1,7 @@
{
- "postsubmit" : [
+ "presubmit" : [
{
- "name": "CtsUserspaceRebootHostSideTestCases",
- "keywords": ["primary-device"]
+ "name": "CtsUserspaceRebootHostSideTestCases"
}
]
}
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index ff2fed4..cdc8a64 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -65,6 +65,7 @@
<activity
android:label="Full screen activity for gesture dispatch testing"
android:name=".AccessibilityGestureDispatchTest$GestureDispatchActivity"
+ android:theme="@style/Theme_NoSwipeDismiss"
android:screenOrientation="locked" />
<activity
diff --git a/tests/accessibilityservice/res/values/styles.xml b/tests/accessibilityservice/res/values/styles.xml
new file mode 100644
index 0000000..77c0405
--- /dev/null
+++ b/tests/accessibilityservice/res/values/styles.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<resources>
+ <style name="Theme_NoSwipeDismiss">
+ <item name="android:windowSwipeToDismiss">false</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index 7663cdb..ea984ee 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -590,6 +590,8 @@
|| windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
});
+ sUiAutomation.waitForIdle(TIMEOUT_WINDOW_STATE_IDLE, DEFAULT_TIMEOUT_MS);
+
assertTrue(
sUiAutomation.performGlobalAction(
AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN));
diff --git a/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java b/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
index c3fcf4c..fe194f2 100644
--- a/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
+++ b/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
@@ -101,7 +101,7 @@
private static final int EXIT_CODE = 123;
private static final int CRASH_SIGNAL = OsConstants.SIGSEGV;
- private static final int WAITFOR_MSEC = 5000;
+ private static final int WAITFOR_MSEC = 10000;
private static final int WAITFOR_SETTLE_DOWN = 2000;
private static final int CMD_PID = 1;
diff --git a/tests/app/TEST_MAPPING b/tests/app/TEST_MAPPING
index ca2dd6c..213ad1e 100644
--- a/tests/app/TEST_MAPPING
+++ b/tests/app/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "presubmit": [
+ "presubmit-large": [
{
"name": "CtsAppTestCases",
"options": [
diff --git a/tests/app/app/src/android/app/stubs/OrientationTestUtils.java b/tests/app/app/src/android/app/stubs/OrientationTestUtils.java
index 410c98d..29b71e0 100644
--- a/tests/app/app/src/android/app/stubs/OrientationTestUtils.java
+++ b/tests/app/app/src/android/app/stubs/OrientationTestUtils.java
@@ -20,6 +20,7 @@
import android.app.Activity;
import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
import android.view.DisplayInfo;
import java.util.concurrent.CountDownLatch;
@@ -71,8 +72,15 @@
/** Checks whether the display dimension is close to square. */
public static boolean isCloseToSquareDisplay(final Activity activity) {
- final float closeToSquareMaxAspectRatio = activity.getResources().getFloat(
- com.android.internal.R.dimen.config_closeToSquareDisplayMaxAspectRatio);
+ final Resources resources = activity.getResources();
+ final float closeToSquareMaxAspectRatio;
+ try {
+ closeToSquareMaxAspectRatio = resources.getFloat(resources.getIdentifier(
+ "config_closeToSquareDisplayMaxAspectRatio", "dimen", "android"));
+ } catch (Resources.NotFoundException e) {
+ // Assume device is not close to square.
+ return false;
+ }
final DisplayInfo displayInfo = new DisplayInfo();
activity.getDisplay().getDisplayInfo(displayInfo);
final int w = displayInfo.logicalWidth;
diff --git a/tests/camera/Android.bp b/tests/camera/Android.bp
new file mode 100644
index 0000000..bf39750
--- /dev/null
+++ b/tests/camera/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Reusable Camera performance test classes and helpers
+android_library {
+ name: "cts-camera-performance-tests",
+
+ static_libs: [
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "mockito-target-minus-junit4",
+ "CtsCameraUtils",
+ "truth-prebuilt",
+ "androidx.test.rules",
+ ],
+
+ manifest: "AndroidManifest-lib.xml",
+ resource_dirs: ["res"],
+ srcs: [
+ "src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java",
+ "src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java",
+ "src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java",
+ "src/android/hardware/camera2/cts/PerformanceTest.java",
+ "src/android/hardware/cts/CameraPerformanceTestHelper.java",
+ "src/android/hardware/cts/LegacyCameraPerformanceTest.java",
+ "src/android/hardware/camera2/cts/RecordingTest.java",
+ ],
+
+ sdk_version: "test_current",
+
+ libs: [
+ "android.test.runner.stubs",
+ "android.test.base.stubs",
+ ],
+}
diff --git a/tests/camera/Android.mk b/tests/camera/Android.mk
index 1dc75f3..749fed5 100644
--- a/tests/camera/Android.mk
+++ b/tests/camera/Android.mk
@@ -14,40 +14,6 @@
LOCAL_PATH:= $(call my-dir)
-# Reusable Camera performance test classes and helpers
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := cts-camera-performance-tests
-
-LOCAL_MODULE_TAGS := tests
-
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt \
- ctstestrunner-axt \
- mockito-target-minus-junit4 \
- CtsCameraUtils \
- truth-prebuilt \
- androidx.test.rules
-
-LOCAL_MANIFEST_FILE := AndroidManifest-lib.xml
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_SRC_FILES := \
- src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java \
- src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java \
- src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java \
- src/android/hardware/camera2/cts/PerformanceTest.java \
- src/android/hardware/cts/CameraPerformanceTestHelper.java \
- src/android/hardware/cts/LegacyCameraPerformanceTest.java \
- src/android/hardware/camera2/cts/RecordingTest.java
-
-LOCAL_SDK_VERSION := test_current
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
# CtsCameraTestCases package
include $(CLEAR_VARS)
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java
index 2552686..b8b7f25 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java
@@ -136,8 +136,12 @@
assertThat(featureRect.top).isAtLeast(0);
assertThat(featureRect.right).isAtLeast(0);
assertThat(featureRect.bottom).isAtLeast(0);
- assertThat(featureRect.right).isAtMost(mActivity.getWidth());
- assertThat(featureRect.bottom).isAtMost(mActivity.getHeight());
+
+ final Rect activityBounds =
+ mActivity.getWindowManager().getCurrentWindowMetrics().getBounds();
+
+ assertThat(featureRect.right).isAtMost(activityBounds.width());
+ assertThat(featureRect.bottom).isAtMost(activityBounds.height());
}
}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/wrapper/sidecarwrapperimpl/TestSidecarWindowLayoutInfo.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/wrapper/sidecarwrapperimpl/TestSidecarWindowLayoutInfo.java
index e784351..31e496ba 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/wrapper/sidecarwrapperimpl/TestSidecarWindowLayoutInfo.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/wrapper/sidecarwrapperimpl/TestSidecarWindowLayoutInfo.java
@@ -73,11 +73,55 @@
return false;
}
final TestSidecarWindowLayoutInfo other = (TestSidecarWindowLayoutInfo) obj;
- return mSidecarWindowLayoutInfo.equals(other.mSidecarWindowLayoutInfo);
+ return areSidecarWindowLayoutInfoEqual(mSidecarWindowLayoutInfo,
+ other.mSidecarWindowLayoutInfo);
}
@Override
public int hashCode() {
return mSidecarWindowLayoutInfo.hashCode();
}
+
+ /**
+ * Compares two {@link SidecarWindowLayoutInfo} with respect to their core data. This method is
+ * necessary because {@link SidecarWindowLayoutInfo} did not implement {@code equals}. Also
+ * Sidecar has been deprecated and frozen, so this method is stable.
+ *
+ * @param lhs {@link SidecarWindowLayoutInfo} to be compared.
+ * @param rhs {@link SidecarWindowLayoutInfo} to be compared.
+ * @return {@code true} if objects are equal with respect to data otherwise return
+ * {@code false}.
+ */
+ private static boolean areSidecarWindowLayoutInfoEqual(@NonNull SidecarWindowLayoutInfo lhs,
+ @NonNull SidecarWindowLayoutInfo rhs) {
+ if (lhs.displayFeatures == rhs.displayFeatures) {
+ return true;
+ }
+ if (lhs.displayFeatures == null || rhs.displayFeatures == null
+ || lhs.displayFeatures.size() != rhs.displayFeatures.size()) {
+ return false;
+ }
+ for (int i = 0; i < lhs.displayFeatures.size(); i++) {
+ if (!areSidecarDisplayFeatureEqual(lhs.displayFeatures.get(i),
+ rhs.displayFeatures.get(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Compares two {@link SidecarDisplayFeature} with respect to their core data. This method is
+ * necessary because {@link SidecarWindowLayoutInfo} did not implement {@code equals}. Also
+ * Sidecar has been deprecated and frozen, so this method is stable.
+ *
+ * @param lhs {@link SidecarDisplayFeature} to be compared.
+ * @param rhs {@link SidecarDisplayFeature} to be compared.
+ * @return {@code true} if objects are equal with respect to data otherwise return
+ * {@code false}.
+ */
+ private static boolean areSidecarDisplayFeatureEqual(@NonNull SidecarDisplayFeature lhs,
+ @NonNull SidecarDisplayFeature rhs) {
+ return lhs.getType() == rhs.getType() && lhs.getRect().equals(rhs.getRect());
+ }
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
index cfc9d0a..0ac11b7 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
@@ -832,7 +832,7 @@
// Move activity back to docked stack.
separateTestJournal();
- setActivityTaskWindowingMode(activityName, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ moveTaskToPrimarySplitScreen(mWmState.getTaskByActivity(activityName).mTaskId);
final SizeInfo finalDockedSizes = getActivityDisplaySize(activityName);
// After activity configuration was changed twice it must report same size as original one.
diff --git a/tests/media/jni/NativeCodecUnitTest.cpp b/tests/media/jni/NativeCodecUnitTest.cpp
index 724bf7b..aa27619 100644
--- a/tests/media/jni/NativeCodecUnitTest.cpp
+++ b/tests/media/jni/NativeCodecUnitTest.cpp
@@ -745,11 +745,12 @@
AMediaFormat* dupFormat = AMediaCodec_getInputFormat(mCodec);
const char* dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (!dupMime || strcmp(dupMime, mime) != 0) {
+ AMediaFormat_delete(dupFormat);
ALOGE("getInputFormat fails in initialized state");
return false;
}
+ AMediaFormat_delete(dupFormat);
CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
}
return !hasSeenError();
@@ -768,11 +769,12 @@
AMediaFormat* dupFormat = AMediaCodec_getInputFormat(mCodec);
const char* dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (!dupMime || strcmp(dupMime, mime) != 0) {
+ AMediaFormat_delete(dupFormat);
ALOGE("getInputFormat fails in running state");
return false;
}
+ AMediaFormat_delete(dupFormat);
CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
}
return !hasSeenError();
@@ -789,22 +791,24 @@
AMediaFormat* dupFormat = AMediaCodec_getInputFormat(mCodec);
const char* dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (dupMime) {
+ AMediaFormat_delete(dupFormat);
ALOGE("getInputFormat succeeds in uninitialized state");
return false;
}
+ AMediaFormat_delete(dupFormat);
if (!configureCodec(mFormat, isAsync, false, isEncoder)) return false;
CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
dupFormat = AMediaCodec_getInputFormat(mCodec);
dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (dupMime) {
+ AMediaFormat_delete(dupFormat);
ALOGE("getInputFormat succeeds in stopped state");
return false;
}
+ AMediaFormat_delete(dupFormat);
}
return !hasSeenError();
}
@@ -918,11 +922,12 @@
AMediaFormat* dupFormat = AMediaCodec_getOutputFormat(mCodec);
const char* dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (!dupMime || strcmp(dupMime, mime) != 0) {
+ AMediaFormat_delete(dupFormat);
ALOGE("getOutputFormat fails in initialized state");
return false;
}
+ AMediaFormat_delete(dupFormat);
CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
}
return !hasSeenError();
@@ -941,11 +946,12 @@
AMediaFormat* dupFormat = AMediaCodec_getOutputFormat(mCodec);
const char* dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (!dupMime || strcmp(dupMime, mime) != 0) {
+ AMediaFormat_delete(dupFormat);
ALOGE("getOutputFormat fails in running state");
return false;
}
+ AMediaFormat_delete(dupFormat);
CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
}
return !hasSeenError();
@@ -960,22 +966,24 @@
AMediaFormat* dupFormat = AMediaCodec_getOutputFormat(mCodec);
const char* dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (dupMime) {
+ AMediaFormat_delete(dupFormat);
ALOGE("getOutputFormat succeeds in uninitialized state");
return false;
}
+ AMediaFormat_delete(dupFormat);
if (!configureCodec(mFormat, isAsync, false, isEncoder)) return false;
CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
dupFormat = AMediaCodec_getOutputFormat(mCodec);
dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (dupMime) {
+ AMediaFormat_delete(dupFormat);
ALOGE("getOutputFormat succeeds in stopped state");
return false;
}
+ AMediaFormat_delete(dupFormat);
}
return !hasSeenError();
}
@@ -1373,11 +1381,12 @@
AMediaFormat* dupFormat = AMediaCodec_getBufferFormat(mCodec, 0);
const char* dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (dupMime) {
+ AMediaFormat_delete(dupFormat);
ALOGE("GetBufferFormat succeeds in initialized state");
return false;
}
+ AMediaFormat_delete(dupFormat);
CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
}
return !hasSeenError();
@@ -1397,11 +1406,12 @@
AMediaFormat* dupFormat = AMediaCodec_getBufferFormat(mCodec, -1);
const char* dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (dupMime) {
+ AMediaFormat_delete(dupFormat);
ALOGE("GetBufferFormat succeeds for bad buffer index -1");
return false;
}
+ AMediaFormat_delete(dupFormat);
if (!queueEOS()) return false;
if (!hasSeenError()) {
int bufferIndex = 0;
@@ -1414,11 +1424,12 @@
dupFormat = AMediaCodec_getBufferFormat(mCodec, bufferIndex);
dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (!dupMime || strcmp(dupMime, mime) != 0) {
+ AMediaFormat_delete(dupFormat);
ALOGE("GetBufferFormat fails in running state");
return false;
}
+ AMediaFormat_delete(dupFormat);
isOk = dequeueOutput(element.bufferIndex, &element.bufferInfo);
}
} else {
@@ -1427,11 +1438,12 @@
dupFormat = AMediaCodec_getBufferFormat(mCodec, bufferIndex);
dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (!dupMime || strcmp(dupMime, mime) != 0) {
+ AMediaFormat_delete(dupFormat);
ALOGE("GetBufferFormat fails in running state");
return false;
}
+ AMediaFormat_delete(dupFormat);
isOk = dequeueOutput(bufferIndex, &outInfo);
}
}
@@ -1443,11 +1455,12 @@
dupFormat = AMediaCodec_getBufferFormat(mCodec, bufferIndex);
dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (dupMime) {
+ AMediaFormat_delete(dupFormat);
ALOGE("GetBufferFormat succeeds for buffer index not owned by client");
return false;
}
+ AMediaFormat_delete(dupFormat);
} else {
ALOGE("Got unexpected error");
return false;
@@ -1466,22 +1479,24 @@
AMediaFormat* dupFormat = AMediaCodec_getBufferFormat(mCodec, 0);
const char* dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (dupMime) {
+ AMediaFormat_delete(dupFormat);
ALOGE("GetBufferFormat succeeds in uninitialized state");
return false;
}
+ AMediaFormat_delete(dupFormat);
if (!configureCodec(mFormat, isAsync, false, isEncoder)) return false;
CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
dupFormat = AMediaCodec_getBufferFormat(mCodec, 0);
dupMime = nullptr;
AMediaFormat_getString(dupFormat, AMEDIAFORMAT_KEY_MIME, &dupMime);
- AMediaFormat_delete(dupFormat);
if (dupMime) {
+ AMediaFormat_delete(dupFormat);
ALOGE("GetBufferFormat succeeds in stopped state");
return false;
}
+ AMediaFormat_delete(dupFormat);
}
return !hasSeenError();
}
diff --git a/tests/media/jni/NativeExtractorTest.cpp b/tests/media/jni/NativeExtractorTest.cpp
index e5c391a..de0fae8 100644
--- a/tests/media/jni/NativeExtractorTest.cpp
+++ b/tests/media/jni/NativeExtractorTest.cpp
@@ -93,7 +93,7 @@
setSampleInfo(refExtractor, &refSampleInfo);
setSampleInfo(testExtractor, &testSampleInfo);
if (!isSampleInfoValidAndIdentical(&refSampleInfo, &testSampleInfo)) {
- ALOGD(" Mime: %s mismatch for sample: %d", refMime, frameCount);
+ ALOGD(" Mime: %s mismatch for sample: %d", mime, frameCount);
ALOGD(" flags exp/got: %d / %d", refSampleInfo.flags, testSampleInfo.flags);
ALOGD(" size exp/got: %d / %d ", refSampleInfo.size, testSampleInfo.size);
ALOGD(" ts exp/got: %" PRId64 " / %" PRId64 "",
@@ -104,55 +104,53 @@
ssize_t refSz =
AMediaExtractor_readSampleData(refExtractor, refBuffer, maxSampleSize);
if (refSz != refSampleInfo.size) {
- ALOGD("Mime: %s Size exp/got: %d / %zd ", refMime, refSampleInfo.size, refSz);
+ ALOGD("Mime: %s Size exp/got: %d / %zd ", mime, refSampleInfo.size, refSz);
areTracksIdentical = false;
break;
}
ssize_t testSz =
AMediaExtractor_readSampleData(testExtractor, testBuffer, maxSampleSize);
if (testSz != testSampleInfo.size) {
- ALOGD("Mime: %s Size exp/got: %d / %zd ", refMime, testSampleInfo.size,
- testSz);
+ ALOGD("Mime: %s Size exp/got: %d / %zd ", mime, testSampleInfo.size, testSz);
areTracksIdentical = false;
break;
}
int trackIndex = AMediaExtractor_getSampleTrackIndex(refExtractor);
if (trackIndex != refTrackID) {
- ALOGD("Mime: %s TrackID exp/got: %zu / %d", refMime, refTrackID, trackIndex);
+ ALOGD("Mime: %s TrackID exp/got: %zu / %d", mime, refTrackID, trackIndex);
areTracksIdentical = false;
break;
}
trackIndex = AMediaExtractor_getSampleTrackIndex(testExtractor);
if (trackIndex != testTrackID) {
- ALOGD("Mime: %s TrackID exp/got %zd / %d : ", refMime, testTrackID,
- trackIndex);
+ ALOGD("Mime: %s TrackID exp/got %zd / %d : ", mime, testTrackID, trackIndex);
areTracksIdentical = false;
break;
}
if (memcmp(refBuffer, testBuffer, refSz)) {
- ALOGD("Mime: %s Mismatch in sample data", refMime);
+ ALOGD("Mime: %s Mismatch in sample data", mime);
areTracksIdentical = false;
break;
}
bool haveRefSamples = AMediaExtractor_advance(refExtractor);
bool haveTestSamples = AMediaExtractor_advance(testExtractor);
if (haveRefSamples != haveTestSamples) {
- ALOGD("Mime: %s Mismatch in sampleCount", refMime);
+ ALOGD("Mime: %s Mismatch in sampleCount", mime);
areTracksIdentical = false;
break;
}
if (!haveRefSamples && !isExtractorOKonEOS(refExtractor)) {
- ALOGD("Mime: %s calls post advance() are not OK", refMime);
+ ALOGD("Mime: %s calls post advance() are not OK", mime);
areTracksIdentical = false;
break;
}
if (!haveTestSamples && !isExtractorOKonEOS(testExtractor)) {
- ALOGD("Mime: %s calls post advance() are not OK", refMime);
+ ALOGD("Mime: %s calls post advance() are not OK", mime);
areTracksIdentical = false;
break;
}
- ALOGV("Mime: %s Sample: %d flags: %d size: %d ts: % " PRId64 "", refMime,
+ ALOGV("Mime: %s Sample: %d flags: %d size: %d ts: % " PRId64 "", mime,
frameCount, refSampleInfo.flags, refSampleInfo.size,
refSampleInfo.presentationTimeUs);
if (!haveRefSamples || frameCount >= sampleLimit) {
@@ -423,6 +421,7 @@
const char* currMime = nullptr;
bool hasKey = AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &currMime);
if (!hasKey || strcmp(currMime, mime) != 0) {
+ AMediaFormat_delete(format);
continue;
}
AMediaExtractor_selectTrack(extractor, trackID);
diff --git a/tests/media/jni/NativeMediaCommon.cpp b/tests/media/jni/NativeMediaCommon.cpp
index 8cccbc0..90540e0 100644
--- a/tests/media/jni/NativeMediaCommon.cpp
+++ b/tests/media/jni/NativeMediaCommon.cpp
@@ -47,8 +47,6 @@
const char* TBD_AMEDIAFORMAT_KEY_BIT_RATE_MODE = "bitrate-mode";
bool isCSDIdentical(AMediaFormat* refFormat, AMediaFormat* testFormat) {
- const char* mime;
- AMediaFormat_getString(refFormat, AMEDIAFORMAT_KEY_MIME, &mime);
for (int i = 0;; i++) {
std::pair<void*, size_t> refCsd;
std::pair<void*, size_t> testCsd;
diff --git a/tests/media/jni/NativeMuxerTest.cpp b/tests/media/jni/NativeMuxerTest.cpp
index cea162c7..b9eae64 100644
--- a/tests/media/jni/NativeMuxerTest.cpp
+++ b/tests/media/jni/NativeMuxerTest.cpp
@@ -271,6 +271,8 @@
AMediaFormat* thisFormat = mFormat[i];
const char* thisMime = nullptr;
AMediaFormat_getString(thisFormat, AMEDIAFORMAT_KEY_MIME, &thisMime);
+ int tolerance = !strncmp(thisMime, "video/", strlen("video/")) ? STTS_TOLERANCE_US : 0;
+ tolerance += 1; // rounding error
int j = 0;
for (; j < that->mTrackCount; j++) {
AMediaFormat* thatFormat = that->mFormat[j];
@@ -279,9 +281,6 @@
if (thisMime != nullptr && thatMime != nullptr && !strcmp(thisMime, thatMime)) {
if (!isFormatSimilar(thisFormat, thatFormat)) continue;
if (mBufferInfo[i].size() == that->mBufferInfo[j].size()) {
- int tolerance =
- !strncmp(thisMime, "video/", strlen("video/")) ? STTS_TOLERANCE_US : 0;
- tolerance += 1; // rounding error
int k = 0;
for (; k < mBufferInfo[i].size(); k++) {
AMediaCodecBufferInfo* thisInfo = mBufferInfo[i][k];
@@ -305,6 +304,7 @@
}
}
if (j == that->mTrackCount) {
+ AMediaFormat_getString(thisFormat, AMEDIAFORMAT_KEY_MIME, &thisMime);
ALOGV("For mime %s, Couldn't find a match", thisMime);
return false;
}
diff --git a/tests/security/Android.bp b/tests/security/Android.bp
index d9786a8..12168cc 100644
--- a/tests/security/Android.bp
+++ b/tests/security/Android.bp
@@ -17,6 +17,7 @@
static_libs: [
"bouncycastle-unbundled",
"bouncycastle-bcpkix-unbundled",
+ "cbor-java",
"guava",
"truth-prebuilt",
"testng",
diff --git a/tests/security/src/android/keystore/cts/Asn1Attestation.java b/tests/security/src/android/keystore/cts/Asn1Attestation.java
new file mode 100644
index 0000000..b454130
--- /dev/null
+++ b/tests/security/src/android/keystore/cts/Asn1Attestation.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+
+public class Asn1Attestation extends Attestation {
+ static final int ATTESTATION_VERSION_INDEX = 0;
+ static final int ATTESTATION_SECURITY_LEVEL_INDEX = 1;
+ static final int KEYMASTER_VERSION_INDEX = 2;
+ static final int KEYMASTER_SECURITY_LEVEL_INDEX = 3;
+ static final int ATTESTATION_CHALLENGE_INDEX = 4;
+ static final int UNIQUE_ID_INDEX = 5;
+ static final int SW_ENFORCED_INDEX = 6;
+ static final int TEE_ENFORCED_INDEX = 7;
+
+ int attestationSecurityLevel;
+
+ /**
+ * Constructs an {@code Asn1Attestation} object from the provided {@link X509Certificate},
+ * extracting the attestation data from the attestation extension.
+ *
+ * @throws CertificateParsingException if the certificate does not contain a properly-formatted
+ * attestation extension.
+ */
+ public Asn1Attestation(X509Certificate x509Cert) throws CertificateParsingException {
+ super(x509Cert);
+ ASN1Sequence seq = getAttestationSequence(x509Cert);
+
+ attestationVersion =
+ Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_VERSION_INDEX));
+ attestationSecurityLevel =
+ Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_SECURITY_LEVEL_INDEX));
+ keymasterVersion = Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_VERSION_INDEX));
+ keymasterSecurityLevel =
+ Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_SECURITY_LEVEL_INDEX));
+
+ attestationChallenge =
+ Asn1Utils.getByteArrayFromAsn1(seq.getObjectAt(ATTESTATION_CHALLENGE_INDEX));
+
+ uniqueId = Asn1Utils.getByteArrayFromAsn1(seq.getObjectAt(UNIQUE_ID_INDEX));
+
+ softwareEnforced = new AuthorizationList(seq.getObjectAt(SW_ENFORCED_INDEX));
+ teeEnforced = new AuthorizationList(seq.getObjectAt(TEE_ENFORCED_INDEX));
+ }
+
+ ASN1Sequence getAttestationSequence(X509Certificate x509Cert)
+ throws CertificateParsingException {
+ byte[] attestationExtensionBytes = x509Cert.getExtensionValue(Attestation.ASN1_OID);
+ if (attestationExtensionBytes == null || attestationExtensionBytes.length == 0) {
+ throw new CertificateParsingException("Did not find extension with OID " + ASN1_OID);
+ }
+ return Asn1Utils.getAsn1SequenceFromBytes(attestationExtensionBytes);
+ }
+
+ public int getAttestationSecurityLevel() {
+ return attestationSecurityLevel;
+ }
+
+ public RootOfTrust getRootOfTrust() {
+ return teeEnforced.getRootOfTrust();
+ }
+}
diff --git a/tests/security/src/android/keystore/cts/Attestation.java b/tests/security/src/android/keystore/cts/Attestation.java
index 2285cad..7414908 100644
--- a/tests/security/src/android/keystore/cts/Attestation.java
+++ b/tests/security/src/android/keystore/cts/Attestation.java
@@ -16,71 +16,69 @@
package android.keystore.cts;
+import co.nstant.in.cbor.CborException;
+
import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.BaseEncoding;
-import org.bouncycastle.asn1.ASN1Sequence;
-
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.Set;
-import java.util.stream.Collectors;
/**
* Parses an attestation certificate and provides an easy-to-use interface for examining the
* contents.
*/
-public class Attestation {
- static final String KEY_DESCRIPTION_OID = "1.3.6.1.4.1.11129.2.1.17";
- static final String KEY_USAGE_OID = "2.5.29.15"; // Standard key usage extension.
- static final int ATTESTATION_VERSION_INDEX = 0;
- static final int ATTESTATION_SECURITY_LEVEL_INDEX = 1;
- static final int KEYMASTER_VERSION_INDEX = 2;
- static final int KEYMASTER_SECURITY_LEVEL_INDEX = 3;
- static final int ATTESTATION_CHALLENGE_INDEX = 4;
- static final int UNIQUE_ID_INDEX = 5;
- static final int SW_ENFORCED_INDEX = 6;
- static final int TEE_ENFORCED_INDEX = 7;
+public abstract class Attestation {
+ static final String EAT_OID = "1.3.6.1.4.1.11129.2.1.25";
+ static final String ASN1_OID = "1.3.6.1.4.1.11129.2.1.17";
+ static final String KEY_USAGE_OID = "2.5.29.15"; // Standard key usage extension.
public static final int KM_SECURITY_LEVEL_SOFTWARE = 0;
public static final int KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1;
public static final int KM_SECURITY_LEVEL_STRONG_BOX = 2;
- private final int attestationVersion;
- private final int attestationSecurityLevel;
- private final int keymasterVersion;
- private final int keymasterSecurityLevel;
- private final byte[] attestationChallenge;
- private final byte[] uniqueId;
- private final AuthorizationList softwareEnforced;
- private final AuthorizationList teeEnforced;
- private final Set<String> unexpectedExtensionOids;
-
+ int attestationVersion;
+ int keymasterVersion;
+ int keymasterSecurityLevel;
+ byte[] attestationChallenge;
+ byte[] uniqueId;
+ AuthorizationList softwareEnforced;
+ AuthorizationList teeEnforced;
+ Set<String> unexpectedExtensionOids;
/**
* Constructs an {@code Attestation} object from the provided {@link X509Certificate},
* extracting the attestation data from the attestation extension.
*
+ * <p>This method ensures that at most one attestation extension is included in the certificate.
+ *
* @throws CertificateParsingException if the certificate does not contain a properly-formatted
- * attestation extension.
+ * attestation extension, if it contains multiple attestation extensions, or if the
+ * attestation extension can not be parsed.
*/
- public Attestation(X509Certificate x509Cert) throws CertificateParsingException {
- ASN1Sequence seq = getAttestationSequence(x509Cert);
+ public static Attestation loadFromCertificate(X509Certificate x509Cert)
+ throws CertificateParsingException {
+ if (x509Cert.getExtensionValue(EAT_OID) == null
+ && x509Cert.getExtensionValue(ASN1_OID) == null) {
+ throw new CertificateParsingException("No attestation extensions found");
+ }
+ if (x509Cert.getExtensionValue(EAT_OID) != null) {
+ if (x509Cert.getExtensionValue(ASN1_OID) != null) {
+ throw new CertificateParsingException("Multiple attestation extensions found");
+ }
+ try {
+ return new EatAttestation(x509Cert);
+ } catch (CborException cbe) {
+ throw new CertificateParsingException("Unable to parse EAT extension", cbe);
+ }
+ }
+ return new Asn1Attestation(x509Cert);
+ }
+
+ Attestation(X509Certificate x509Cert) {
unexpectedExtensionOids = retrieveUnexpectedExtensionOids(x509Cert);
-
- attestationVersion = Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_VERSION_INDEX));
- attestationSecurityLevel = Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_SECURITY_LEVEL_INDEX));
- keymasterVersion = Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_VERSION_INDEX));
- keymasterSecurityLevel = Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_SECURITY_LEVEL_INDEX));
-
- attestationChallenge =
- Asn1Utils.getByteArrayFromAsn1(seq.getObjectAt(Attestation.ATTESTATION_CHALLENGE_INDEX));
-
- uniqueId = Asn1Utils.getByteArrayFromAsn1(seq.getObjectAt(Attestation.UNIQUE_ID_INDEX));
-
- softwareEnforced = new AuthorizationList(seq.getObjectAt(SW_ENFORCED_INDEX));
- teeEnforced = new AuthorizationList(seq.getObjectAt(TEE_ENFORCED_INDEX));
}
public static String securityLevelToString(int attestationSecurityLevel) {
@@ -100,9 +98,9 @@
return attestationVersion;
}
- public int getAttestationSecurityLevel() {
- return attestationSecurityLevel;
- }
+ public abstract int getAttestationSecurityLevel();
+
+ public abstract RootOfTrust getRootOfTrust();
public int getKeymasterVersion() {
return keymasterVersion;
@@ -135,13 +133,15 @@
@Override
public String toString() {
StringBuilder s = new StringBuilder();
- s.append("Attest version: " + attestationVersion);
- s.append("\nAttest security: " + securityLevelToString(attestationSecurityLevel));
+ s.append("Extension type: " + getClass());
+ s.append("\nAttest version: " + attestationVersion);
+ s.append("\nAttest security: " + securityLevelToString(getAttestationSecurityLevel()));
s.append("\nKM version: " + keymasterVersion);
s.append("\nKM security: " + securityLevelToString(keymasterSecurityLevel));
s.append("\nChallenge");
- String stringChallenge = new String(attestationChallenge);
+ String stringChallenge =
+ attestationChallenge != null ? new String(attestationChallenge) : "null";
if (CharMatcher.ascii().matchesAllOf(stringChallenge)) {
s.append(": [" + stringChallenge + "]");
} else {
@@ -159,26 +159,16 @@
return s.toString();
}
- private ASN1Sequence getAttestationSequence(X509Certificate x509Cert)
- throws CertificateParsingException {
- byte[] attestationExtensionBytes = x509Cert.getExtensionValue(KEY_DESCRIPTION_OID);
- if (attestationExtensionBytes == null || attestationExtensionBytes.length == 0) {
- throw new CertificateParsingException(
- "Did not find extension with OID " + KEY_DESCRIPTION_OID);
- }
- return Asn1Utils.getAsn1SequenceFromBytes(attestationExtensionBytes);
- }
-
- private Set<String> retrieveUnexpectedExtensionOids(X509Certificate x509Cert) {
+ Set<String> retrieveUnexpectedExtensionOids(X509Certificate x509Cert) {
return new ImmutableSet.Builder<String>()
- .addAll(x509Cert.getCriticalExtensionOIDs()
- .stream()
- .filter(s -> !KEY_USAGE_OID.equals(s))
- .iterator())
- .addAll(x509Cert.getNonCriticalExtensionOIDs()
- .stream()
- .filter(s -> !KEY_DESCRIPTION_OID.equals(s))
- .iterator())
+ .addAll(
+ x509Cert.getCriticalExtensionOIDs().stream()
+ .filter(s -> !KEY_USAGE_OID.equals(s))
+ .iterator())
+ .addAll(
+ x509Cert.getNonCriticalExtensionOIDs().stream()
+ .filter(s -> !ASN1_OID.equals(s) && !EAT_OID.equals(s))
+ .iterator())
.build();
}
}
diff --git a/tests/security/src/android/keystore/cts/AuthorizationList.java b/tests/security/src/android/keystore/cts/AuthorizationList.java
index 85ac115..dce9b2a 100644
--- a/tests/security/src/android/keystore/cts/AuthorizationList.java
+++ b/tests/security/src/android/keystore/cts/AuthorizationList.java
@@ -19,6 +19,10 @@
import static com.google.common.base.Functions.forMap;
import static com.google.common.collect.Collections2.transform;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Number;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -166,6 +170,7 @@
.put(KM_PURPOSE_VERIFY, "VERIFY")
.build();
+ private Integer securityLevel;
private Set<Integer> purposes;
private Integer algorithm;
private Integer keySize;
@@ -331,6 +336,126 @@
}
+ public AuthorizationList(co.nstant.in.cbor.model.Map submodMap)
+ throws CertificateParsingException {
+ for (DataItem key : submodMap.getKeys()) {
+ int keyInt = ((Number) key).getValue().intValue();
+ switch (keyInt) {
+ default:
+ throw new CertificateParsingException("Unknown EAT tag: " + key);
+
+ case EatClaim.SECURITY_LEVEL:
+ securityLevel = eatSecurityLevelToKeymasterSecurityLevel(
+ CborUtils.getInt(submodMap, key));
+ break;
+ case EatClaim.PURPOSE:
+ purposes = CborUtils.getIntSet(submodMap, key);
+ break;
+ case EatClaim.ALGORITHM:
+ algorithm = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.KEY_SIZE:
+ keySize = CborUtils.getInt(submodMap, key);
+ Log.i("Attestation", "Found KEY SIZE, value: " + keySize);
+ break;
+ case EatClaim.DIGEST:
+ digests = CborUtils.getIntSet(submodMap, key);
+ break;
+ case EatClaim.PADDING:
+ paddingModes = CborUtils.getIntSet(submodMap, key);
+ break;
+ case EatClaim.RSA_PUBLIC_EXPONENT:
+ rsaPublicExponent = CborUtils.getLong(submodMap, key);
+ break;
+ case EatClaim.NO_AUTH_REQUIRED:
+ noAuthRequired = true;
+ break;
+ case EatClaim.IAT:
+ creationDateTime = CborUtils.getDate(submodMap, key);
+ break;
+ case EatClaim.ORIGIN:
+ origin = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.OS_VERSION:
+ osVersion = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.OS_PATCHLEVEL:
+ osPatchLevel = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.VENDOR_PATCHLEVEL:
+ vendorPatchLevel = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.BOOT_PATCHLEVEL:
+ bootPatchLevel = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.ACTIVE_DATETIME:
+ activeDateTime = CborUtils.getDate(submodMap, key);
+ break;
+ case EatClaim.ORIGINATION_EXPIRE_DATETIME:
+ originationExpireDateTime = CborUtils.getDate(submodMap, key);
+ break;
+ case EatClaim.USAGE_EXPIRE_DATETIME:
+ usageExpireDateTime = CborUtils.getDate(submodMap, key);
+ break;
+ case EatClaim.ROLLBACK_RESISTANT:
+ rollbackResistant = true;
+ break;
+ case EatClaim.ROLLBACK_RESISTANCE:
+ rollbackResistance = true;
+ break;
+ case EatClaim.AUTH_TIMEOUT:
+ authTimeout = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.ALLOW_WHILE_ON_BODY:
+ allowWhileOnBody = true;
+ break;
+ case EatClaim.EC_CURVE:
+ ecCurve = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.USER_AUTH_TYPE:
+ userAuthType = CborUtils.getInt(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_APPLICATION_ID:
+ // TODO: The attestation application ID is currently still encoded as an ASN.1
+ // structure. Parse a CBOR structure when it's available instead.
+ attestationApplicationId = new AttestationApplicationId(
+ Asn1Utils.getAsn1EncodableFromBytes(CborUtils.getBytes(submodMap, key)));
+ break;
+ case EatClaim.ATTESTATION_ID_BRAND:
+ brand = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_ID_DEVICE:
+ device = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_ID_PRODUCT:
+ product = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_ID_SERIAL:
+ serialNumber = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.UEID:
+ // TODO: Parse depending on encoding chosen in attestation_record.cpp.
+ imei = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_ID_MEID:
+ meid = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_ID_MANUFACTURER:
+ manufacturer = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.ATTESTATION_ID_MODEL:
+ model = CborUtils.getString(submodMap, key);
+ break;
+ case EatClaim.USER_PRESENCE_REQUIRED:
+ userPresenceRequired = CborUtils.getBoolean(submodMap, key);
+ break;
+ case EatClaim.TRUSTED_CONFIRMATION_REQUIRED:
+ confirmationRequired = true;
+ break;
+ }
+ }
+ }
+
public static String algorithmToString(int algorithm) {
switch (algorithm) {
case KM_ALGORITHM_RSA:
@@ -415,6 +540,10 @@
}
}
+ public Integer getSecurityLevel() {
+ return securityLevel;
+ }
+
public Set<Integer> getPurposes() {
return purposes;
}
@@ -607,6 +736,19 @@
return confirmationRequired;
}
+ static int eatSecurityLevelToKeymasterSecurityLevel(int eatSecurityLevel) {
+ switch(eatSecurityLevel) {
+ case EatClaim.SECURITY_LEVEL_UNRESTRICTED:
+ return Attestation.KM_SECURITY_LEVEL_SOFTWARE;
+ case EatClaim.SECURITY_LEVEL_SECURE_RESTRICTED:
+ return Attestation.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+ case EatClaim.SECURITY_LEVEL_HARDWARE:
+ return Attestation.KM_SECURITY_LEVEL_STRONG_BOX;
+ default:
+ throw new RuntimeException("Invalid EAT security level: " + eatSecurityLevel);
+ }
+ }
+
private String getStringFromAsn1Value(ASN1Primitive value) throws CertificateParsingException {
try {
return Asn1Utils.getStringFromAsn1OctetStreamAssumingUTF8(value);
diff --git a/tests/security/src/android/keystore/cts/CborUtils.java b/tests/security/src/android/keystore/cts/CborUtils.java
new file mode 100644
index 0000000..eeac9b5
--- /dev/null
+++ b/tests/security/src/android/keystore/cts/CborUtils.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Map;
+import co.nstant.in.cbor.model.NegativeInteger;
+import co.nstant.in.cbor.model.Number;
+import co.nstant.in.cbor.model.SimpleValue;
+import co.nstant.in.cbor.model.SimpleValueType;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+import java.nio.charset.StandardCharsets;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+class CborUtils {
+ public static Number toNumber(long l) {
+ return l >= 0 ? new UnsignedInteger(l) : new NegativeInteger(l);
+ }
+
+ public static int getInt(Map map, long index) {
+ DataItem item = map.get(CborUtils.toNumber(index));
+ return ((Number) item).getValue().intValue();
+ }
+
+ public static int getInt(Map map, DataItem index) {
+ DataItem item = map.get(index);
+ return ((Number) item).getValue().intValue();
+ }
+
+ public static long getLong(Map map, DataItem index) {
+ DataItem item = map.get(index);
+ return ((Number) item).getValue().longValue();
+ }
+
+ public static Set<Integer> getIntSet(Map map, DataItem index) {
+ Array array = (Array) map.get(index);
+ Set<Integer> result = new HashSet();
+ for (DataItem item : array.getDataItems()) {
+ result.add(((Number) item).getValue().intValue());
+ }
+ return result;
+ }
+
+ public static Boolean getBoolean(Map map, DataItem index) {
+ SimpleValueType value = ((SimpleValue) map.get(index)).getSimpleValueType();
+ if (value != SimpleValueType.TRUE && value != SimpleValueType.FALSE) {
+ throw new RuntimeException("Only expecting boolean values for " + index);
+ }
+ return (value == SimpleValueType.TRUE);
+ }
+
+ public static List<Boolean> getBooleanList(Map map, DataItem index) {
+ Array array = (Array) map.get(index);
+ List<Boolean> result = new ArrayList();
+ for (DataItem item : array.getDataItems()) {
+ SimpleValueType value = ((SimpleValue) item).getSimpleValueType();
+ if (value == SimpleValueType.FALSE) {
+ result.add(false);
+ } else if (value == SimpleValueType.TRUE) {
+ result.add(true);
+ } else {
+ throw new RuntimeException("Map contains more than booleans: " + map);
+ }
+ }
+ return result;
+ }
+
+ public static Date getDate(Map map, DataItem index) {
+ DataItem item = map.get(index);
+ long epochMillis = ((Number) item).getValue().longValue();
+ return new Date(epochMillis);
+ }
+
+ public static byte[] getBytes(Map map, DataItem index) {
+ DataItem item = map.get(index);
+ return ((ByteString) item).getBytes();
+ }
+
+ public static String getString(Map map, DataItem index) {
+ byte[] bytes = getBytes(map, index);
+ return new String(bytes, StandardCharsets.UTF_8);
+ }
+}
diff --git a/tests/security/src/android/keystore/cts/EatAttestation.java b/tests/security/src/android/keystore/cts/EatAttestation.java
new file mode 100644
index 0000000..21ef0db
--- /dev/null
+++ b/tests/security/src/android/keystore/cts/EatAttestation.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import android.util.Log;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Map;
+import co.nstant.in.cbor.model.Number;
+import co.nstant.in.cbor.model.UnicodeString;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+public class EatAttestation extends Attestation {
+ static final String TAG = "EatAttestation";
+ final Map extension;
+ final RootOfTrust rootOfTrust;
+
+ /**
+ * Constructs an {@code EatAttestation} object from the provided {@link X509Certificate},
+ * extracting the attestation data from the attestation extension.
+ *
+ * @throws CertificateParsingException if the certificate does not contain a properly-formatted
+ * attestation extension.
+ */
+ public EatAttestation(X509Certificate x509Cert)
+ throws CertificateParsingException, CborException {
+ super(x509Cert);
+ extension = getEatExtension(x509Cert);
+
+ RootOfTrust.Builder rootOfTrustBuilder = new RootOfTrust.Builder();
+ List<Boolean> bootState = null;
+ boolean officialBuild = false;
+
+ for (DataItem key : extension.getKeys()) {
+ int keyInt = ((Number) key).getValue().intValue();
+ switch (keyInt) {
+ default:
+ throw new CertificateParsingException(
+ "Unknown EAT tag: " + key + "\n in EAT extension:\n" + toString());
+
+ case EatClaim.ATTESTATION_VERSION:
+ attestationVersion = CborUtils.getInt(extension, key);
+ break;
+ case EatClaim.KEYMASTER_VERSION:
+ keymasterVersion = CborUtils.getInt(extension, key);
+ break;
+ case EatClaim.SECURITY_LEVEL:
+ keymasterSecurityLevel =
+ eatSecurityLevelToKeymintSecurityLevel(
+ CborUtils.getInt(extension, key));
+ break;
+ case EatClaim.SUBMODS:
+ Map submods = (Map) extension.get(key);
+ softwareEnforced =
+ new AuthorizationList(
+ (Map) submods.get(new UnicodeString(EatClaim.SUBMOD_SOFTWARE)));
+ teeEnforced =
+ new AuthorizationList(
+ (Map) submods.get(new UnicodeString(EatClaim.SUBMOD_TEE)));
+ break;
+ case EatClaim.VERIFIED_BOOT_KEY:
+ rootOfTrustBuilder.setVerifiedBootKey(CborUtils.getBytes(extension, key));
+ break;
+ case EatClaim.DEVICE_LOCKED:
+ rootOfTrustBuilder.setDeviceLocked(CborUtils.getBoolean(extension, key));
+ break;
+ case EatClaim.BOOT_STATE:
+ bootState = CborUtils.getBooleanList(extension, key);
+ break;
+ case EatClaim.OFFICIAL_BUILD:
+ officialBuild = CborUtils.getBoolean(extension, key);
+ break;
+ case EatClaim.NONCE:
+ attestationChallenge = CborUtils.getBytes(extension, key);
+ break;
+ case EatClaim.CTI:
+ Log.i(TAG, "Got CTI claim: " + CborUtils.getBytes(extension, key));
+ uniqueId = CborUtils.getBytes(extension, key);
+ break;
+ case EatClaim.VERIFIED_BOOT_HASH:
+ // TODO: ignored for now, as this is not checked in original ASN.1 tests
+ break;
+ }
+ }
+
+ if (bootState != null) {
+ rootOfTrustBuilder.setVerifiedBootState(
+ eatBootStateTypeToVerifiedBootState(bootState, officialBuild));
+ }
+ rootOfTrust = rootOfTrustBuilder.build();
+ }
+
+ /** Find the submod containing the key information, and return its security level. */
+ public int getAttestationSecurityLevel() {
+ if (teeEnforced != null && teeEnforced.getAlgorithm() != null) {
+ return teeEnforced.getSecurityLevel();
+ } else if (softwareEnforced != null && softwareEnforced.getAlgorithm() != null) {
+ return softwareEnforced.getSecurityLevel();
+ } else {
+ return -1;
+ }
+ }
+
+ public RootOfTrust getRootOfTrust() {
+ return rootOfTrust;
+ }
+
+ public String toString() {
+ return super.toString() + "\nEncoded CBOR: " + extension;
+ }
+
+ Map getEatExtension(X509Certificate x509Cert)
+ throws CertificateParsingException, CborException {
+ byte[] attestationExtensionBytes = x509Cert.getExtensionValue(Attestation.EAT_OID);
+ if (attestationExtensionBytes == null || attestationExtensionBytes.length == 0) {
+ throw new CertificateParsingException("Did not find extension with OID " + EAT_OID);
+ }
+ ASN1Encodable asn1 = Asn1Utils.getAsn1EncodableFromBytes(attestationExtensionBytes);
+ byte[] cborBytes = Asn1Utils.getByteArrayFromAsn1(asn1);
+ List<DataItem> cbor = CborDecoder.decode(cborBytes);
+ return (Map) cbor.get(0);
+ }
+
+ static int eatSecurityLevelToKeymintSecurityLevel(int eatSecurityLevel) {
+ switch (eatSecurityLevel) {
+ case EatClaim.SECURITY_LEVEL_UNRESTRICTED:
+ return Attestation.KM_SECURITY_LEVEL_SOFTWARE;
+ case EatClaim.SECURITY_LEVEL_SECURE_RESTRICTED:
+ return Attestation.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+ case EatClaim.SECURITY_LEVEL_HARDWARE:
+ return Attestation.KM_SECURITY_LEVEL_STRONG_BOX;
+ default:
+ throw new RuntimeException("Invalid EAT security level: " + eatSecurityLevel);
+ }
+ }
+
+ static int eatBootStateTypeToVerifiedBootState(List<Boolean> bootState, Boolean officialBuild) {
+ if (bootState.size() != 5) {
+ throw new RuntimeException("Boot state map has unexpected size: " + bootState.size());
+ }
+ if (bootState.get(4)) {
+ throw new RuntimeException("debug-permanent-disable must never be true: " + bootState);
+ }
+ boolean verifiedOrSelfSigned = bootState.get(0);
+ if (verifiedOrSelfSigned != bootState.get(1)
+ && verifiedOrSelfSigned != bootState.get(2)
+ && verifiedOrSelfSigned != bootState.get(3)) {
+ throw new RuntimeException("Unexpected boot state: " + bootState);
+ }
+
+ if (officialBuild) {
+ if (!verifiedOrSelfSigned) {
+ throw new AssertionError("Non-verified official build");
+ }
+ return RootOfTrust.KM_VERIFIED_BOOT_VERIFIED;
+ } else {
+ return verifiedOrSelfSigned
+ ? RootOfTrust.KM_VERIFIED_BOOT_SELF_SIGNED
+ : RootOfTrust.KM_VERIFIED_BOOT_UNVERIFIED;
+ }
+ }
+}
diff --git a/tests/security/src/android/keystore/cts/EatClaim.java b/tests/security/src/android/keystore/cts/EatClaim.java
new file mode 100644
index 0000000..1130037
--- /dev/null
+++ b/tests/security/src/android/keystore/cts/EatClaim.java
@@ -0,0 +1,112 @@
+package android.keystore.cts;
+
+import android.security.keymaster.KeymasterDefs;
+
+class EatClaim {
+ public static final int IAT = 6;
+ public static final int CTI = 7;
+
+ public static final int NONCE = -75008;
+ public static final int UEID = -75009;
+
+ public static final int SECURITY_LEVEL = -76002;
+ public static final int SECURITY_LEVEL_UNRESTRICTED = 1;
+ public static final int SECURITY_LEVEL_SECURE_RESTRICTED = 3;
+ public static final int SECURITY_LEVEL_HARDWARE = 4;
+
+ public static final int BOOT_STATE = -76003;
+ public static final int SUBMODS = -76000;
+
+ private static final int PRIVATE_BASE = -80000;
+
+ public static final int PURPOSE = PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_PURPOSE);
+ public static final int ALGORITHM =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ALGORITHM);
+ public static final int KEY_SIZE = PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_KEY_SIZE);
+ public static final int BLOCK_MODE =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_BLOCK_MODE);
+ public static final int DIGEST = PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_DIGEST);
+ public static final int PADDING = PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_PADDING);
+ public static final int CALLER_NONCE =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_CALLER_NONCE);
+ public static final int MIN_MAC_LENGTH =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_MIN_MAC_LENGTH);
+ public static final int KDF = PRIVATE_BASE - 9;
+
+ public static final int EC_CURVE = PRIVATE_BASE - 10;
+ public static final int EAT_EC_CURVE_P_224 = 0;
+ public static final int EAT_EC_CURVE_P_256 = 1;
+ public static final int EAT_EC_CURVE_P_384 = 2;
+ public static final int EAT_EC_CURVE_P_521 = 3;
+
+ public static final int RSA_PUBLIC_EXPONENT =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT);
+
+ public static final int ROLLBACK_RESISTANCE = PRIVATE_BASE - 303;
+ public static final int EARLY_BOOT_ONLY = PRIVATE_BASE - 305;
+
+ public static final int ACTIVE_DATETIME =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
+ public static final int ORIGINATION_EXPIRE_DATETIME =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
+ public static final int USAGE_EXPIRE_DATETIME =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
+
+ public static final int NO_AUTH_REQUIRED =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
+ public static final int USER_AUTH_TYPE =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_USER_AUTH_TYPE);
+ public static final int AUTH_TIMEOUT =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_AUTH_TIMEOUT);
+ public static final int ALLOW_WHILE_ON_BODY =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
+ public static final int USER_PRESENCE_REQUIRED = PRIVATE_BASE - 507;
+ public static final int TRUSTED_CONFIRMATION_REQUIRED =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
+ public static final int UNLOCKED_DEVICE_REQUIRED =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
+
+ public static final int APPLICATION_ID =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_APPLICATION_ID);
+
+ public static final int ORIGIN = PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ORIGIN);
+ // TODO: hardcoded while KeymasterDefs uses the same value for
+ // ROLLBACK_RESISTANCE and ROLLBACK_RESISTANT
+ public static final int ROLLBACK_RESISTANT = PRIVATE_BASE - 703;
+ public static final int OS_VERSION = PRIVATE_BASE - 705;
+ public static final int OS_PATCHLEVEL = PRIVATE_BASE - 706;
+ public static final int ATTESTATION_APPLICATION_ID = PRIVATE_BASE - 709;
+ public static final int ATTESTATION_ID_BRAND =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND);
+ public static final int ATTESTATION_ID_DEVICE =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE);
+ public static final int ATTESTATION_ID_PRODUCT =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT);
+ public static final int ATTESTATION_ID_SERIAL =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL);
+ public static final int ATTESTATION_ID_MEID =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID);
+ public static final int ATTESTATION_ID_MANUFACTURER =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER);
+ public static final int ATTESTATION_ID_MODEL =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL);
+ public static final int VENDOR_PATCHLEVEL =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_VENDOR_PATCHLEVEL);
+ public static final int BOOT_PATCHLEVEL =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_BOOT_PATCHLEVEL);
+ public static final int DEVICE_UNIQUE_ATTESTATION =
+ PRIVATE_BASE - (0x0FFFFFFF & KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION);
+ public static final int IDENTITY_CREDENTIAL_KEY = PRIVATE_BASE - 721;
+
+ private static final int NON_KM_BASE = PRIVATE_BASE - 2000;
+
+ public static final int VERIFIED_BOOT_KEY = NON_KM_BASE - 1;
+ public static final int DEVICE_LOCKED = NON_KM_BASE - 2;
+ public static final int VERIFIED_BOOT_HASH = NON_KM_BASE - 3;
+ public static final int ATTESTATION_VERSION = NON_KM_BASE - 4;
+ public static final int KEYMASTER_VERSION = NON_KM_BASE - 5;
+ public static final int OFFICIAL_BUILD = NON_KM_BASE - 6;
+
+ public static final String SUBMOD_SOFTWARE = "software";
+ public static final String SUBMOD_TEE = "tee";
+}
diff --git a/tests/security/src/android/keystore/cts/RootOfTrust.java b/tests/security/src/android/keystore/cts/RootOfTrust.java
index 9957702..a115874 100644
--- a/tests/security/src/android/keystore/cts/RootOfTrust.java
+++ b/tests/security/src/android/keystore/cts/RootOfTrust.java
@@ -51,6 +51,13 @@
Asn1Utils.getIntegerFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_STATE_INDEX));
}
+
+ RootOfTrust(byte[] verifiedBootKey, boolean deviceLocked, int verifiedBootState) {
+ this.verifiedBootKey = verifiedBootKey;
+ this.deviceLocked = deviceLocked;
+ this.verifiedBootState = verifiedBootState;
+ }
+
public static String verifiedBootStateToString(int verifiedBootState) {
switch (verifiedBootState) {
case KM_VERIFIED_BOOT_VERIFIED:
@@ -82,11 +89,35 @@
public String toString() {
return new StringBuilder()
.append("\nVerified boot Key: ")
- .append(BaseEncoding.base64().encode(verifiedBootKey))
+ .append(verifiedBootKey != null ?
+ BaseEncoding.base64().encode(verifiedBootKey) :
+ "null")
.append("\nDevice locked: ")
.append(deviceLocked)
.append("\nVerified boot state: ")
.append(verifiedBootStateToString(verifiedBootState))
.toString();
}
+
+ public static class Builder {
+ private byte[] verifiedBootKey;
+ private boolean deviceLocked = false;
+ private int verifiedBootState = -1;
+
+ public Builder setVerifiedBootKey(byte[] verifiedBootKey) {
+ this.verifiedBootKey = verifiedBootKey;
+ return this;
+ }
+ public Builder setDeviceLocked(boolean deviceLocked) {
+ this.deviceLocked = deviceLocked;
+ return this;
+ }
+ public Builder setVerifiedBootState(int verifiedBootState) {
+ this.verifiedBootState = verifiedBootState;
+ return this;
+ }
+ public RootOfTrust build() {
+ return new RootOfTrust(verifiedBootKey, deviceLocked, verifiedBootState);
+ }
+ }
}
diff --git a/tests/sensor/Android.bp b/tests/sensor/Android.bp
new file mode 100644
index 0000000..4930c6f
--- /dev/null
+++ b/tests/sensor/Android.bp
@@ -0,0 +1,100 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
+// Reusable Sensor test classes and helpers
+//
+java_library {
+ name: "cts-sensors-tests",
+ defaults: ["cts_error_prone_rules_tests"],
+
+ static_libs: ["compatibility-device-util-axt"],
+
+ libs: [
+ "platform-test-annotations",
+ "android.test.base.stubs",
+ ],
+
+ sdk_version: "test_current",
+
+ srcs: ["src/**/*.java"],
+}
+
+//
+// JNI components for testing NDK
+//
+cc_library_shared {
+ name: "libcts-sensors-ndk-jni",
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wextra",
+ ],
+
+ srcs: [
+ "jni/SensorTest.cpp",
+ "jni/SensorTestCases.cpp",
+ "jni/android_hardware_cts_SensorDirectReportTest.cpp",
+ "jni/android_hardware_cts_SensorNativeTest.cpp",
+ "jni/nativeTestHelper.cpp",
+ ],
+
+ header_libs: ["jni_headers"],
+
+ shared_libs: [
+ "libandroid",
+ "liblog",
+ ],
+
+ sdk_version: "current",
+
+ stl: "c++_shared",
+}
+
+//
+// CtsSensorTestCases package
+//
+android_test {
+ name: "CtsSensorTestCases",
+ defaults: [
+ "cts_defaults",
+ ],
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+
+ // include both the 32 and 64 bit versions
+ compile_multilib: "both",
+
+ static_libs: [
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "cts-sensors-tests",
+ ],
+
+ jni_libs: ["libcts-sensors-ndk-jni"],
+
+ sdk_version: "test_current",
+
+ libs: [
+ "android.test.runner.stubs",
+ "android.test.base.stubs",
+ ],
+
+ stl: "c++_shared",
+}
diff --git a/tests/sensor/Android.mk b/tests/sensor/Android.mk
deleted file mode 100644
index d198b04..0000000
--- a/tests/sensor/Android.mk
+++ /dev/null
@@ -1,96 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-#
-# Reusable Sensor test classes and helpers
-#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := cts-sensors-tests
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt
-
-LOCAL_JAVA_LIBRARIES := platform-test-annotations android.test.base.stubs
-
-LOCAL_SDK_VERSION := test_current
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
--include cts/error_prone_rules_tests.mk
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-#
-# JNI components for testing NDK
-#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libcts-sensors-ndk-jni
-
-LOCAL_CFLAGS += -Werror -Wall -Wextra
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
- jni/SensorTest.cpp \
- jni/SensorTestCases.cpp \
- jni/android_hardware_cts_SensorDirectReportTest.cpp \
- jni/android_hardware_cts_SensorNativeTest.cpp \
- jni/nativeTestHelper.cpp
-
-LOCAL_HEADER_LIBRARIES := jni_headers
-
-LOCAL_SHARED_LIBRARIES := libandroid liblog
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_NDK_STL_VARIANT := c++_shared
--include cts/error_prone_rules_tests.mk
-include $(BUILD_SHARED_LIBRARY)
-
-#
-# CtsSensorTestCases package
-#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-# include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- compatibility-device-util-axt \
- ctstestrunner-axt \
- cts-sensors-tests \
-
-LOCAL_JNI_SHARED_LIBRARIES := libcts-sensors-ndk-jni
-
-LOCAL_PACKAGE_NAME := CtsSensorTestCases
-
-LOCAL_SDK_VERSION := test_current
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_NDK_STL_VARIANT := c++_shared
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/sensor/src/android/hardware/cts/SensorTest.java b/tests/sensor/src/android/hardware/cts/SensorTest.java
index f48ed77..8b2e234 100644
--- a/tests/sensor/src/android/hardware/cts/SensorTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorTest.java
@@ -87,7 +87,8 @@
mAndroidSensorList = new ArrayList<>();
for (Sensor s : mSensorList) {
- if (s.getType() < Sensor.TYPE_DEVICE_PRIVATE_BASE) {
+ if (s.getType() < Sensor.TYPE_DEVICE_PRIVATE_BASE &&
+ (!context.getPackageManager().isInstantApp() || s.getType() != Sensor.TYPE_HEART_RATE)) {
mAndroidSensorList.add(s);
}
}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/Foo.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/Foo.aidl
index f2b551c..ddb6e8b 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/Foo.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/Foo.aidl
@@ -31,4 +31,16 @@
test_package.LongEnum[] shouldContainTwoLongFoos;
@nullable String[] g;
@nullable test_package.SimpleUnion u;
+ int shouldSetBit0AndBit2;
+ @nullable test_package.SimpleUnion shouldBeConstS1;
+ const int kZero = 0;
+ const int kOne = 1;
+ const int kOnes = -1;
+ const byte kByteOne = 1;
+ const long kLongOnes = -1;
+ const String kEmpty = "";
+ const String kFoo = "foo";
+ const int BIT0 = 1;
+ const int BIT1 = 2;
+ const int BIT2 = 4;
}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/SimpleUnion.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/SimpleUnion.aidl
index 7c1564a..e7fc95c 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/SimpleUnion.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/SimpleUnion.aidl
@@ -23,4 +23,12 @@
test_package.ByteEnum d;
test_package.ByteEnum[] e;
@nullable test_package.Bar f;
+ const int kZero = 0;
+ const int kOne = 1;
+ const int kOnes = -1;
+ const byte kByteOne = 1;
+ const long kLongOnes = -1;
+ const String kEmpty = "";
+ const String kFoo = "foo";
+ const String S1 = "a string constant";
}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
index 85e5599..e346e2b 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
@@ -202,7 +202,7 @@
EXPECT_EQ(getuid(), res);
}
-TEST_P(NdkBinderTest_Aidl, Constants) {
+TEST_P(NdkBinderTest_Aidl, ConstantsInInterface) {
ASSERT_EQ(0, ITest::kZero);
ASSERT_EQ(1, ITest::kOne);
ASSERT_EQ(0xffffffff, ITest::kOnes);
@@ -212,6 +212,26 @@
ASSERT_EQ(std::string("foo"), ITest::kFoo);
}
+TEST_P(NdkBinderTest_Aidl, ConstantsInParcelable) {
+ ASSERT_EQ(0, Foo::kZero);
+ ASSERT_EQ(1, Foo::kOne);
+ ASSERT_EQ(0xffffffff, Foo::kOnes);
+ ASSERT_EQ(1, Foo::kByteOne);
+ ASSERT_EQ(0xffffffffffffffff, Foo::kLongOnes);
+ ASSERT_EQ(std::string(""), Foo::kEmpty);
+ ASSERT_EQ(std::string("foo"), Foo::kFoo);
+}
+
+TEST_P(NdkBinderTest_Aidl, ConstantsInUnion) {
+ ASSERT_EQ(0, SimpleUnion::kZero);
+ ASSERT_EQ(1, SimpleUnion::kOne);
+ ASSERT_EQ(0xffffffff, SimpleUnion::kOnes);
+ ASSERT_EQ(1, SimpleUnion::kByteOne);
+ ASSERT_EQ(0xffffffffffffffff, SimpleUnion::kLongOnes);
+ ASSERT_EQ(std::string(""), SimpleUnion::kEmpty);
+ ASSERT_EQ(std::string("foo"), SimpleUnion::kFoo);
+}
+
TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveInt) {
int32_t out;
ASSERT_OK(iface->RepeatInt(3, &out));
@@ -545,6 +565,8 @@
foo.shouldContainTwoIntFoos = {IntEnum::FOO, IntEnum::FOO};
foo.shouldContainTwoLongFoos = {LongEnum::FOO, LongEnum::FOO};
foo.u = SimpleUnion::make<SimpleUnion::c>("hello");
+ foo.shouldSetBit0AndBit2 = Foo::BIT0 | Foo::BIT2;
+ foo.shouldBeConstS1 = SimpleUnion::S1;
Foo retFoo;
@@ -561,6 +583,8 @@
EXPECT_EQ(foo.shouldContainTwoIntFoos, retFoo.shouldContainTwoIntFoos);
EXPECT_EQ(foo.shouldContainTwoLongFoos, retFoo.shouldContainTwoLongFoos);
EXPECT_EQ(foo.u, retFoo.u);
+ EXPECT_EQ(foo.shouldSetBit0AndBit2, retFoo.shouldSetBit0AndBit2);
+ EXPECT_EQ(foo.shouldBeConstS1, retFoo.shouldBeConstS1);
}
TEST_P(NdkBinderTest_Aidl, RepeatGenericBar) {
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/Foo.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/Foo.aidl
index 9ecb97e..e6b6285 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/Foo.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/Foo.aidl
@@ -7,6 +7,14 @@
import test_package.SimpleUnion;
parcelable Foo {
+ const int kZero = 0;
+ const int kOne = 1;
+ const int kOnes = 0xffffffff;
+ const byte kByteOne = 1;
+ const long kLongOnes = 0xffffffffffffffff;
+ const String kEmpty = "";
+ const String kFoo = "foo";
+
String a="FOO";
int b=42;
float c=3.14f;
@@ -21,4 +29,13 @@
LongEnum[] shouldContainTwoLongFoos;
@nullable String[] g;
@nullable SimpleUnion u;
+
+ // example: using int constants
+ const int BIT0 = 0x1;
+ const int BIT1 = 0x1 << 1;
+ const int BIT2 = 0x1 << 2;
+ int shouldSetBit0AndBit2;
+
+ // example: using a String constant of union
+ @nullable SimpleUnion shouldBeConstS1;
}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/SimpleUnion.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/SimpleUnion.aidl
index 5fa906a..7bd33d4 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/SimpleUnion.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/SimpleUnion.aidl
@@ -4,10 +4,20 @@
import test_package.ByteEnum;
union SimpleUnion {
+ const int kZero = 0;
+ const int kOne = 1;
+ const int kOnes = 0xffffffff;
+ const byte kByteOne = 1;
+ const long kLongOnes = 0xffffffffffffffff;
+ const String kEmpty = "";
+ const String kFoo = "foo";
+
int a = 42;
int[] b;
String c;
ByteEnum d;
ByteEnum[] e;
@nullable Bar f;
+
+ const String S1 = "a string constant";
}
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java b/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
index 79f231a..2d57d82 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
@@ -607,6 +607,9 @@
foo.u = SimpleUnion.e(new byte[]{ByteEnum.FOO, ByteEnum.FOO});
+ foo.shouldSetBit0AndBit2 = Foo.BIT0 | Foo.BIT2;
+ foo.shouldBeConstS1 = SimpleUnion.c(SimpleUnion.S1);
+
Foo repeatedFoo = mInterface.repeatFoo(foo);
assertEquals(foo.a, repeatedFoo.a);
@@ -620,6 +623,8 @@
Assert.assertArrayEquals(foo.shouldContainTwoIntFoos, repeatedFoo.shouldContainTwoIntFoos);
Assert.assertArrayEquals(foo.shouldContainTwoLongFoos, repeatedFoo.shouldContainTwoLongFoos);
Assert.assertArrayEquals(foo.u.getE(), repeatedFoo.u.getE());
+ assertEquals(foo.shouldSetBit0AndBit2, repeatedFoo.shouldSetBit0AndBit2);
+ assertEquals(foo.shouldBeConstS1.getC(), repeatedFoo.shouldBeConstS1.getC());
}
@Test
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
index 371a637..55a7ac1 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
@@ -32,6 +32,7 @@
import android.graphics.Canvas;
import android.graphics.ColorSpace;
import android.graphics.Rect;
+import android.media.MediaFormat;
import android.os.ParcelFileDescriptor;
import androidx.test.InstrumentationRegistry;
@@ -40,6 +41,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.BitmapUtils;
+import com.android.compatibility.common.util.MediaUtils;
import org.junit.After;
import org.junit.Before;
@@ -641,6 +643,10 @@
@Test
public void testHeif() throws IOException {
+ if (!MediaUtils.hasDecoder(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
+ // HEIF support is optional when HEVC decoder is not supported.
+ return;
+ }
InputStream is = obtainInputStream(R.raw.heifwriter_input);
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
Bitmap region = decoder.decodeRegion(new Rect(0, 0, TILE_SIZE, TILE_SIZE), null);
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 867f8a3..121af43 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -43,6 +43,7 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
+import android.media.MediaFormat;
import android.net.Uri;
import android.util.DisplayMetrics;
import android.util.Size;
@@ -53,6 +54,7 @@
import androidx.test.filters.LargeTest;
import com.android.compatibility.common.util.BitmapUtils;
+import com.android.compatibility.common.util.MediaUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -65,6 +67,8 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.function.IntFunction;
import java.util.function.Supplier;
@@ -98,19 +102,24 @@
private static final ColorSpace sSRGB = ColorSpace.get(ColorSpace.Named.SRGB);
- static Object[] getRecords() {
- return new Record[] {
- new Record(R.drawable.baseline_jpeg, 1280, 960, "image/jpeg", false, false, sSRGB),
- new Record(R.drawable.grayscale_jpg, 128, 128, "image/jpeg", true, false, sSRGB),
- new Record(R.drawable.png_test, 640, 480, "image/png", false, false, sSRGB),
- new Record(R.drawable.gif_test, 320, 240, "image/gif", false, false, sSRGB),
- new Record(R.drawable.bmp_test, 320, 240, "image/bmp", false, false, sSRGB),
- new Record(R.drawable.webp_test, 640, 480, "image/webp", false, false, sSRGB),
- new Record(R.drawable.google_chrome, 256, 256, "image/x-ico", false, true, sSRGB),
- new Record(R.drawable.color_wheel, 128, 128, "image/x-ico", false, true, sSRGB),
- new Record(R.raw.sample_1mp, 600, 338, "image/x-adobe-dng", false, false, sSRGB),
- new Record(R.raw.heifwriter_input, 1920, 1080, "image/heif", false, false, sSRGB),
- };
+ static Record[] getRecords() {
+ ArrayList<Record> records = new ArrayList<>(Arrays.asList(new Record[] {
+ new Record(R.drawable.baseline_jpeg, 1280, 960, "image/jpeg", false, false, sSRGB),
+ new Record(R.drawable.grayscale_jpg, 128, 128, "image/jpeg", true, false, sSRGB),
+ new Record(R.drawable.png_test, 640, 480, "image/png", false, false, sSRGB),
+ new Record(R.drawable.gif_test, 320, 240, "image/gif", false, false, sSRGB),
+ new Record(R.drawable.bmp_test, 320, 240, "image/bmp", false, false, sSRGB),
+ new Record(R.drawable.webp_test, 640, 480, "image/webp", false, false, sSRGB),
+ new Record(R.drawable.google_chrome, 256, 256, "image/x-ico", false, true, sSRGB),
+ new Record(R.drawable.color_wheel, 128, 128, "image/x-ico", false, true, sSRGB),
+ new Record(R.raw.sample_1mp, 600, 338, "image/x-adobe-dng", false, false, sSRGB)
+ }));
+ if (MediaUtils.hasDecoder(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
+ // HEIF support is optional when HEVC decoder is not supported.
+ records.add(new Record(R.raw.heifwriter_input, 1920, 1080, "image/heif", false, false,
+ sSRGB));
+ }
+ return records.toArray(new Record[] {});
}
// offset is how many bytes to offset the beginning of the image.
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index d457995..1af904f 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -234,7 +234,8 @@
assertEquals(1, certificates.length);
X509Certificate attestationCert = (X509Certificate) certificates[0];
- assertNull(attestationCert.getExtensionValue(Attestation.KEY_DESCRIPTION_OID));
+ assertNull(attestationCert.getExtensionValue(Attestation.ASN1_OID));
+ assertNull(attestationCert.getExtensionValue(Attestation.EAT_OID));
} finally {
keyStore.deleteEntry(keystoreAlias);
}
@@ -272,7 +273,7 @@
verifyCertificateChain(certificates, TestUtils.hasStrongBox(getContext()));
X509Certificate attestationCert = (X509Certificate) certificates[0];
- checkDeviceLocked(new Attestation(attestationCert));
+ checkDeviceLocked(Attestation.loadFromCertificate(attestationCert));
} finally {
keyStore.deleteEntry(keystoreAlias);
}
@@ -402,7 +403,7 @@
assertEquals(1, certificates.length);
X509Certificate attestationCert = (X509Certificate) certificates[0];
- assertNull(attestationCert.getExtensionValue(Attestation.KEY_DESCRIPTION_OID));
+ assertNull(attestationCert.getExtensionValue(Attestation.ASN1_OID));
} finally {
keyStore.deleteEntry(keystoreAlias);
}
@@ -441,7 +442,7 @@
verifyCertificateChain(certificates, TestUtils.hasStrongBox(getContext()));
X509Certificate attestationCert = (X509Certificate) certificates[0];
- checkDeviceLocked(new Attestation(attestationCert));
+ checkDeviceLocked(Attestation.loadFromCertificate(attestationCert));
} finally {
keyStore.deleteEntry(keystoreAlias);
}
@@ -559,12 +560,13 @@
verifyCertificateChain(certificates, false /* expectStrongBox */);
X509Certificate attestationCert = (X509Certificate) certificates[0];
- Attestation attestation = new Attestation(attestationCert);
+ Attestation attestation = Attestation.loadFromCertificate(attestationCert);
- checkRsaKeyDetails(attestation, keySize, purposes, ImmutableSet.copyOf(paddingModes));
+ checkRsaKeyDetails(attestation, keySize, purposes,
+ ImmutableSet.copyOf(paddingModes));
checkKeyUsage(attestationCert, purposes);
- checkKeyIndependentAttestationInfo(challenge, purposes, startTime, includeValidityDates,
- devicePropertiesAttestation, attestation);
+ checkKeyIndependentAttestationInfo(challenge, purposes, startTime,
+ includeValidityDates, devicePropertiesAttestation, attestation);
} finally {
keyStore.deleteEntry(keystoreAlias);
}
@@ -618,12 +620,12 @@
verifyCertificateChain(certificates, false /* expectStrongBox */);
X509Certificate attestationCert = (X509Certificate) certificates[0];
- Attestation attestation = new Attestation(attestationCert);
+ Attestation attestation = Attestation.loadFromCertificate(attestationCert);
checkEcKeyDetails(attestation, ecCurve, keySize);
checkKeyUsage(attestationCert, purposes);
- checkKeyIndependentAttestationInfo(challenge, purposes, startTime, includeValidityDates,
- devicePropertiesAttestation, attestation);
+ checkKeyIndependentAttestationInfo(challenge, purposes, startTime,
+ includeValidityDates, devicePropertiesAttestation, attestation);
} finally {
keyStore.deleteEntry(keystoreAlias);
}
@@ -635,6 +637,7 @@
int kmVersion = attestation.getKeymasterVersion();
assertNull(attestation.getTeeEnforced().getAttestationApplicationId());
aaid = attestation.getSoftwareEnforced().getAttestationApplicationId();
+
if (kmVersion >= 3) {
// must be present and correct
assertNotNull(aaid);
@@ -695,9 +698,11 @@
checkUnexpectedOids(attestation);
checkAttestationSecurityLevelDependentParams(attestation);
assertNotNull(attestation.getAttestationChallenge());
- assertTrue(Arrays.equals(challenge, attestation.getAttestationChallenge()));
- assertNotNull(attestation.getUniqueId());
- assertEquals(0, attestation.getUniqueId().length);
+ assertThat(attestation.getAttestationChallenge(), is(challenge));
+ // In EAT, this is null if not filled in. In ASN.1, this is an array with length 0.
+ if (attestation.getUniqueId() != null) {
+ assertEquals(0, attestation.getUniqueId().length);
+ }
checkPurposes(attestation, purposes);
checkDigests(attestation,
ImmutableSet.of(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_512));
@@ -919,8 +924,8 @@
@SuppressWarnings("unchecked")
private void checkAttestationSecurityLevelDependentParams(Attestation attestation) {
- assertThat("Attestation version must be 1, 2, 3, or 4", attestation.getAttestationVersion(),
- either(is(1)).or(is(2)).or(is(3)).or(is(4)));
+ assertThat("Attestation version must be 1, 2, 3, 4 or 5", attestation.getAttestationVersion(),
+ either(is(1)).or(is(2)).or(is(3)).or(is(4)).or(is(5)));
AuthorizationList teeEnforced = attestation.getTeeEnforced();
AuthorizationList softwareEnforced = attestation.getSoftwareEnforced();
@@ -997,7 +1002,7 @@
}
private void checkRootOfTrust(Attestation attestation, boolean requireLocked) {
- RootOfTrust rootOfTrust = attestation.getTeeEnforced().getRootOfTrust();
+ RootOfTrust rootOfTrust = attestation.getRootOfTrust();
assertNotNull(rootOfTrust);
assertNotNull(rootOfTrust.getVerifiedBootKey());
assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length +
diff --git a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
index 24a598a..7b25b26 100644
--- a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
@@ -1033,6 +1033,11 @@
}
public void testGetImageAtIndex() throws Exception {
+ if (!MediaUtils.hasDecoder(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
+ MediaUtils.skipTest("no video decoders for resource");
+ return;
+ }
+
testGetImage("heifwriter_input.heic", 1920, 1080, 0 /*rotation*/,
4 /*imageCount*/, 3 /*primary*/, true /*useGrid*/, true /*checkColor*/);
}
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index a89ba85..cbcaf24 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -3011,6 +3011,12 @@
<permission android:name="android.permission.DUMP"
android:protectionLevel="signature|privileged|development" />
+ <!-- Allows an application to start tracing for InputMethod and WindowManager.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.CONTROL_UI_TRACING"
+ android:protectionLevel="signature|privileged|development" />
+
<!-- Allows an application to read the low-level system log files.
<p>Not for use by third-party applications, because
Log entries can contain the user's private information. -->
diff --git a/tests/tests/permission3/UsePermissionAppWithOverlay/src/android/permission3/cts/usepermission/OverlayActivity.kt b/tests/tests/permission3/UsePermissionAppWithOverlay/src/android/permission3/cts/usepermission/OverlayActivity.kt
index 2a61e12..89bb1da 100644
--- a/tests/tests/permission3/UsePermissionAppWithOverlay/src/android/permission3/cts/usepermission/OverlayActivity.kt
+++ b/tests/tests/permission3/UsePermissionAppWithOverlay/src/android/permission3/cts/usepermission/OverlayActivity.kt
@@ -1,6 +1,10 @@
package android.permission3.cts.usepermission
import android.app.Activity
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
import android.os.Bundle
import android.view.WindowManager
@@ -14,5 +18,15 @@
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+
+ registerReceiver(object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ if (intent?.action != RequestPermissionsActivity.ACTION_HIDE_OVERLAY) {
+ return
+ }
+
+ finish()
+ }
+ }, IntentFilter(RequestPermissionsActivity.ACTION_HIDE_OVERLAY))
}
}
\ No newline at end of file
diff --git a/tests/tests/permission3/UsePermissionAppWithOverlay/src/android/permission3/cts/usepermission/RequestPermissionsActivity.kt b/tests/tests/permission3/UsePermissionAppWithOverlay/src/android/permission3/cts/usepermission/RequestPermissionsActivity.kt
index 0d29202..54155f6 100644
--- a/tests/tests/permission3/UsePermissionAppWithOverlay/src/android/permission3/cts/usepermission/RequestPermissionsActivity.kt
+++ b/tests/tests/permission3/UsePermissionAppWithOverlay/src/android/permission3/cts/usepermission/RequestPermissionsActivity.kt
@@ -17,15 +17,29 @@
package android.permission3.cts.usepermission
import android.app.Activity
+import android.content.BroadcastReceiver
+import android.content.Context
import android.content.Intent
+import android.content.IntentFilter
import android.os.Bundle
import android.os.Handler
class RequestPermissionsActivity : Activity() {
+
var paused = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ registerReceiver(object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ if (intent?.action != ACTION_SHOW_OVERLAY) {
+ return
+ }
+
+ startActivity(Intent(context, OverlayActivity::class.java)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
+ }
+ }, IntentFilter(ACTION_SHOW_OVERLAY))
Handler(mainLooper).post(this::eventuallyRequestPermission)
}
@@ -34,11 +48,7 @@
* due to rapid install/uninstall tests do
*/
private fun eventuallyRequestPermission() {
- if (paused) {
- // Grant dialog should be in front at this point
- startActivity(Intent(this, OverlayActivity::class.java)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
- } else {
+ if (!paused) {
val permissions = intent.getStringArrayExtra("$packageName.PERMISSIONS")!!
requestPermissions(permissions, 1)
Handler(mainLooper).postDelayed(this::eventuallyRequestPermission, 200)
@@ -68,4 +78,9 @@
paused = false
super.onResume()
}
+
+ companion object {
+ const val ACTION_SHOW_OVERLAY = "android.permission3.cts.usepermission.ACTION_SHOW_OVERLAY"
+ const val ACTION_HIDE_OVERLAY = "android.permission3.cts.usepermission.ACTION_HIDE_OVERLAY"
+ }
}
diff --git a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
index 8aedb6d..cb181e3 100644
--- a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
@@ -88,108 +88,54 @@
protected val isAutomotive = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
private val platformResources = context.createPackageContext("android", 0).resources
- private val permissionToLabelResNameMap =
- if (!packageManager.arePermissionsIndividuallyControlled()) {
- mapOf(
- // Contacts
- android.Manifest.permission.READ_CONTACTS
+ private val permissionToLabelResNameMap = mapOf(
+ // Contacts
+ android.Manifest.permission.READ_CONTACTS
to "@android:string/permgrouplab_contacts",
- android.Manifest.permission.WRITE_CONTACTS
+ android.Manifest.permission.WRITE_CONTACTS
to "@android:string/permgrouplab_contacts",
- // Calendar
- android.Manifest.permission.READ_CALENDAR
+ // Calendar
+ android.Manifest.permission.READ_CALENDAR
to "@android:string/permgrouplab_calendar",
- android.Manifest.permission.WRITE_CALENDAR
+ android.Manifest.permission.WRITE_CALENDAR
to "@android:string/permgrouplab_calendar",
- // SMS
- android.Manifest.permission.SEND_SMS to "@android:string/permgrouplab_sms",
- android.Manifest.permission.RECEIVE_SMS to "@android:string/permgrouplab_sms",
- android.Manifest.permission.READ_SMS to "@android:string/permgrouplab_sms",
- android.Manifest.permission.RECEIVE_WAP_PUSH to "@android:string/permgrouplab_sms",
- android.Manifest.permission.RECEIVE_MMS to "@android:string/permgrouplab_sms",
- "android.permission.READ_CELL_BROADCASTS" to "@android:string/permgrouplab_sms",
- // Storage
- android.Manifest.permission.READ_EXTERNAL_STORAGE
+ // SMS
+ android.Manifest.permission.SEND_SMS to "@android:string/permgrouplab_sms",
+ android.Manifest.permission.RECEIVE_SMS to "@android:string/permgrouplab_sms",
+ android.Manifest.permission.READ_SMS to "@android:string/permgrouplab_sms",
+ android.Manifest.permission.RECEIVE_WAP_PUSH to "@android:string/permgrouplab_sms",
+ android.Manifest.permission.RECEIVE_MMS to "@android:string/permgrouplab_sms",
+ "android.permission.READ_CELL_BROADCASTS" to "@android:string/permgrouplab_sms",
+ // Storage
+ android.Manifest.permission.READ_EXTERNAL_STORAGE
to "@android:string/permgrouplab_storage",
- android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE
to "@android:string/permgrouplab_storage",
- // Location
- android.Manifest.permission.ACCESS_FINE_LOCATION
+ // Location
+ android.Manifest.permission.ACCESS_FINE_LOCATION
to "@android:string/permgrouplab_location",
- android.Manifest.permission.ACCESS_COARSE_LOCATION
+ android.Manifest.permission.ACCESS_COARSE_LOCATION
to "@android:string/permgrouplab_location",
- // Phone
- android.Manifest.permission.READ_PHONE_STATE
+ // Phone
+ android.Manifest.permission.READ_PHONE_STATE
to "@android:string/permgrouplab_phone",
- android.Manifest.permission.CALL_PHONE to "@android:string/permgrouplab_phone",
- "android.permission.ACCESS_IMS_CALL_SERVICE"
+ android.Manifest.permission.CALL_PHONE to "@android:string/permgrouplab_phone",
+ "android.permission.ACCESS_IMS_CALL_SERVICE"
to "@android:string/permgrouplab_phone",
- android.Manifest.permission.READ_CALL_LOG to "@android:string/permgrouplab_phone",
- android.Manifest.permission.WRITE_CALL_LOG to "@android:string/permgrouplab_phone",
- android.Manifest.permission.ADD_VOICEMAIL to "@android:string/permgrouplab_phone",
- android.Manifest.permission.USE_SIP to "@android:string/permgrouplab_phone",
- android.Manifest.permission.PROCESS_OUTGOING_CALLS
+ android.Manifest.permission.READ_CALL_LOG to "@android:string/permgrouplab_phone",
+ android.Manifest.permission.WRITE_CALL_LOG to "@android:string/permgrouplab_phone",
+ android.Manifest.permission.ADD_VOICEMAIL to "@android:string/permgrouplab_phone",
+ android.Manifest.permission.USE_SIP to "@android:string/permgrouplab_phone",
+ android.Manifest.permission.PROCESS_OUTGOING_CALLS
to "@android:string/permgrouplab_phone",
- // Microphone
- android.Manifest.permission.RECORD_AUDIO
+ // Microphone
+ android.Manifest.permission.RECORD_AUDIO
to "@android:string/permgrouplab_microphone",
- // Camera
- android.Manifest.permission.CAMERA to "@android:string/permgrouplab_camera",
- // Body sensors
- android.Manifest.permission.BODY_SENSORS to "@android:string/permgrouplab_sensors"
- )
- } else {
- mapOf(
- // Contacts
- android.Manifest.permission.READ_CONTACTS to "@android:string/permlab_readContacts",
- android.Manifest.permission.WRITE_CONTACTS
- to "@android:string/permlab_writeContacts",
- // Calendar
- android.Manifest.permission.READ_CALENDAR
- to "@android:string/permgrouplab_calendar",
- android.Manifest.permission.WRITE_CALENDAR
- to "@android:string/permgrouplab_calendar",
- // SMS
- android.Manifest.permission.SEND_SMS to "@android:string/permlab_sendSms",
- android.Manifest.permission.RECEIVE_SMS to "@android:string/permlab_receiveSms",
- android.Manifest.permission.READ_SMS to "@android:string/permlab_readSms",
- android.Manifest.permission.RECEIVE_WAP_PUSH
- to "@android:string/permlab_receiveWapPush",
- android.Manifest.permission.RECEIVE_MMS to "@android:string/permlab_receiveMms",
- "android.permission.READ_CELL_BROADCASTS"
- to "@android:string/permlab_readCellBroadcasts",
- // Storage
- android.Manifest.permission.READ_EXTERNAL_STORAGE
- to "@android:string/permgrouplab_storage",
- android.Manifest.permission.WRITE_EXTERNAL_STORAGE
- to "@android:string/permgrouplab_storage",
- // Location
- android.Manifest.permission.ACCESS_FINE_LOCATION
- to "@android:string/permgrouplab_location",
- android.Manifest.permission.ACCESS_COARSE_LOCATION
- to "@android:string/permgrouplab_location",
- // Phone
- android.Manifest.permission.READ_PHONE_STATE
- to "@android:string/permlab_readPhoneState",
- android.Manifest.permission.CALL_PHONE to "@android:string/permlab_callPhone",
- "android.permission.ACCESS_IMS_CALL_SERVICE"
- to "@android:string/permlab_accessImsCallService",
- android.Manifest.permission.READ_CALL_LOG to "@android:string/permlab_readCallLog",
- android.Manifest.permission.WRITE_CALL_LOG
- to "@android:string/permlab_writeCallLog",
- android.Manifest.permission.ADD_VOICEMAIL to "@android:string/permlab_addVoicemail",
- android.Manifest.permission.USE_SIP to "@android:string/permlab_use_sip",
- android.Manifest.permission.PROCESS_OUTGOING_CALLS
- to "@android:string/permlab_processOutgoingCalls",
- // Microphone
- android.Manifest.permission.RECORD_AUDIO
- to "@android:string/permgrouplab_microphone",
- // Camera
- android.Manifest.permission.CAMERA to "@android:string/permgrouplab_camera",
- // Body sensors
- android.Manifest.permission.BODY_SENSORS to "@android:string/permgrouplab_sensors"
- )
- }
+ // Camera
+ android.Manifest.permission.CAMERA to "@android:string/permgrouplab_camera",
+ // Body sensors
+ android.Manifest.permission.BODY_SENSORS to "@android:string/permgrouplab_sensors"
+ )
@Before
@After
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionReviewTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionReviewTest.kt
index f0b1f80..6b8678d 100644
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionReviewTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionReviewTest.kt
@@ -28,6 +28,7 @@
import androidx.test.runner.AndroidJUnit4
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
+import org.junit.Assume
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -36,6 +37,12 @@
@RunWith(AndroidJUnit4::class)
class PermissionReviewTest : BaseUsePermissionTest() {
+
+ @Before
+ fun assumeNotIndividuallyControlled() {
+ Assume.assumeFalse(packageManager.arePermissionsIndividuallyControlled())
+ }
+
@Before
fun installApp22CalendarOnly() {
installPackage(APP_APK_PATH_22_CALENDAR_ONLY)
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionTapjackingTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionTapjackingTest.kt
index a5f8939..5360f1d 100644
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionTapjackingTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionTapjackingTest.kt
@@ -17,6 +17,7 @@
package android.permission3.cts
import android.Manifest.permission.ACCESS_FINE_LOCATION
+import android.content.Intent
import android.content.pm.PackageManager
import android.support.test.uiautomator.By
import com.android.compatibility.common.util.SystemUtil
@@ -42,26 +43,46 @@
assertAppHasPermission(ACCESS_FINE_LOCATION, false)
requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) {}
+ val buttonCenter = waitFindObject(By.text(
+ getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT))).visibleCenter
+
// Wait for overlay to hide the dialog
+ context.sendBroadcast(Intent(ACTION_SHOW_OVERLAY))
waitFindObject(By.res("android.permission3.cts.usepermission:id/overlay_description"))
+
try {
// Try to grant the permission, this should fail
SystemUtil.eventually({
if (packageManager.checkPermission(ACCESS_FINE_LOCATION, APP_PACKAGE_NAME) ==
PackageManager.PERMISSION_DENIED) {
- clickPermissionRequestAllowForegroundButton(100)
+ uiDevice.click(buttonCenter.x, buttonCenter.y)
+ Thread.sleep(100)
}
assertAppHasPermission(ACCESS_FINE_LOCATION, true)
}, 10000)
} catch (e: RuntimeException) {
// expected
}
- // Permission should not be granted and dialog should still be showing
+ // Permission should not be granted
assertAppHasPermission(ACCESS_FINE_LOCATION, false)
// On Automotive the dialog gets closed by the tapjacking activity popping up
if (!isAutomotive) {
- clickPermissionRequestAllowForegroundButton()
+ // Verify that clicking the dialog without the overlay still works
+ context.sendBroadcast(Intent(ACTION_HIDE_OVERLAY))
+ SystemUtil.eventually({
+ if (packageManager.checkPermission(ACCESS_FINE_LOCATION, APP_PACKAGE_NAME) ==
+ PackageManager.PERMISSION_DENIED) {
+ uiDevice.click(buttonCenter.x, buttonCenter.y)
+ Thread.sleep(100)
+ }
+ assertAppHasPermission(ACCESS_FINE_LOCATION, true)
+ }, 10000)
}
}
-}
\ No newline at end of file
+
+ companion object {
+ const val ACTION_SHOW_OVERLAY = "android.permission3.cts.usepermission.ACTION_SHOW_OVERLAY"
+ const val ACTION_HIDE_OVERLAY = "android.permission3.cts.usepermission.ACTION_HIDE_OVERLAY"
+ }
+}
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionTest22.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionTest22.kt
old mode 100644
new mode 100755
index 7d06770..8fdddfb
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionTest22.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionTest22.kt
@@ -16,6 +16,7 @@
package android.permission3.cts
+import org.junit.Assume
import org.junit.Before
import org.junit.Test
@@ -23,8 +24,11 @@
* Runtime permission behavior tests for apps targeting API 22.
*/
class PermissionTest22 : BaseUsePermissionTest() {
+
@Before
fun installApp22AndApprovePermissionReview() {
+ Assume.assumeFalse(packageManager.arePermissionsIndividuallyControlled())
+
installPackage(APP_APK_PATH_22)
approvePermissionReview()
}
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionTest23.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionTest23.kt
index 59cb9aa..31e6f3a 100644
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionTest23.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionTest23.kt
@@ -17,6 +17,7 @@
package android.permission3.cts
import androidx.test.filters.FlakyTest
+import org.junit.Assume
import org.junit.Before
import org.junit.Test
@@ -232,6 +233,8 @@
@Test(timeout = 120000)
@FlakyTest
fun testNoResidualPermissionsOnUninstall() {
+ Assume.assumeFalse(packageManager.arePermissionsIndividuallyControlled())
+
// Grant all permissions
grantAppPermissions(
android.Manifest.permission.WRITE_CALENDAR,
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionUpgradeTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionUpgradeTest.kt
index fcfc1bb..de58d43 100644
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionUpgradeTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionUpgradeTest.kt
@@ -16,6 +16,7 @@
package android.permission3.cts
+import org.junit.Assume
import org.junit.Test
/**
@@ -25,6 +26,8 @@
@Test
fun testUpgradeKeepsPermissions() {
+ Assume.assumeFalse(packageManager.arePermissionsIndividuallyControlled())
+
installPackage(APP_APK_PATH_22)
approvePermissionReview()
@@ -80,6 +83,8 @@
@Test
fun testRevokePropagatedOnUpgradeOldToNewModel() {
+ Assume.assumeFalse(packageManager.arePermissionsIndividuallyControlled())
+
installPackage(APP_APK_PATH_22)
approvePermissionReview()
diff --git a/tests/tests/selinux/common/src/android/security/SELinuxTargetSdkTestBase.java b/tests/tests/selinux/common/src/android/security/SELinuxTargetSdkTestBase.java
index a7281fe..6ec352c 100644
--- a/tests/tests/selinux/common/src/android/security/SELinuxTargetSdkTestBase.java
+++ b/tests/tests/selinux/common/src/android/security/SELinuxTargetSdkTestBase.java
@@ -12,7 +12,6 @@
import java.util.Collections;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
-import org.junit.Assert;
abstract class SELinuxTargetSdkTestBase extends AndroidTestCase
{
@@ -20,8 +19,6 @@
System.loadLibrary("ctsselinux_jni");
}
- static final byte[] ANONYMIZED_HARDWARE_ADDRESS = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
protected static String getFile(String filename) throws IOException {
BufferedReader in = null;
try {
@@ -62,20 +59,36 @@
}
}
- protected static void noNetlinkRouteGetlink() throws IOException {
- assertEquals(
- "RTM_GETLINK is not allowed on netlink route sockets. Verify that the"
- + " following patch has been applied to your kernel: "
- + "https://android-review.googlesource.com/q/I7b44ce60ad98f858c412722d41b9842f8577151f",
- 13,
- checkNetlinkRouteGetlink());
+ protected static void checkNetlinkRouteGetlink(boolean expectAllowed) throws IOException {
+ if (!expectAllowed) {
+ assertEquals(
+ "RTM_GETLINK is not allowed on a netlink route sockets. Verify that the"
+ + " following patch has been applied to your kernel: "
+ + "https://android-review.googlesource.com/q/I7b44ce60ad98f858c412722d41b9842f8577151f",
+ 13,
+ checkNetlinkRouteGetlink());
+ } else {
+ assertEquals(
+ "RTM_GETLINK should be allowed netlink route sockets for apps with "
+ + "targetSdkVersion <= Q",
+ -1,
+ checkNetlinkRouteGetlink());
+ }
}
- protected static void noNetlinkRouteBind() throws IOException {
- assertEquals(
- "bind() is not allowed on netlink route sockets",
- 13,
- checkNetlinkRouteBind());
+ protected static void checkNetlinkRouteBind(boolean expectAllowed) throws IOException {
+ if (!expectAllowed) {
+ assertEquals(
+ "Bind() is not allowed on a netlink route sockets",
+ 13,
+ checkNetlinkRouteBind());
+ } else {
+ assertEquals(
+ "Bind() should succeed for netlink route sockets for apps with "
+ + "targetSdkVersion <= Q",
+ -1,
+ checkNetlinkRouteBind());
+ }
}
/**
@@ -156,17 +169,16 @@
}
/**
- * Verify that apps having targetSdkVersion <= 29 get an anonymized MAC
- * address (02:00:00:00:00:00) instead of a null MAC for ethernet interfaces.
+ * Verify that apps having targetSdkVersion <= 29 are able to see MAC
+ * addresses of ethernet devices.
* The counterpart of this test (testing for targetSdkVersion > 29) is
* {@link libcore.java.net.NetworkInterfaceTest#testGetHardwareAddress_returnsNull()}.
*/
- protected static void checkNetworkInterface_returnsAnonymizedHardwareAddresses()
- throws Exception {
+ protected static void checkNetworkInterface_returnsHardwareAddresses() throws Exception {
assertNotNull(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface nif : Collections.list(NetworkInterface.getNetworkInterfaces())) {
if (isEthernet(nif.getName())) {
- Assert.assertArrayEquals(ANONYMIZED_HARDWARE_ADDRESS, nif.getHardwareAddress());
+ assertEquals(6, nif.getHardwareAddress().length);
}
}
}
diff --git a/tests/tests/selinux/selinuxEphemeral/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxEphemeral/src/android/security/SELinuxTargetSdkTest.java
index 9153b8a..1ed366e 100644
--- a/tests/tests/selinux/selinuxEphemeral/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxEphemeral/src/android/security/SELinuxTargetSdkTest.java
@@ -79,10 +79,10 @@
}
public void testNoNetlinkRouteGetlink() throws IOException {
- noNetlinkRouteGetlink();
+ checkNetlinkRouteGetlink(false);
}
public void testNoNetlinkRouteBind() throws IOException {
- noNetlinkRouteBind();
+ checkNetlinkRouteBind(false);
}
}
diff --git a/tests/tests/selinux/selinuxTargetSdk27/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdk27/src/android/security/SELinuxTargetSdkTest.java
index 5e2f75d..a784464 100644
--- a/tests/tests/selinux/selinuxTargetSdk27/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdk27/src/android/security/SELinuxTargetSdkTest.java
@@ -66,6 +66,6 @@
}
public void testNetworkInterface() throws Exception {
- checkNetworkInterface_returnsAnonymizedHardwareAddresses();
+ checkNetworkInterface_returnsHardwareAddresses();
}
}
diff --git a/tests/tests/selinux/selinuxTargetSdk28/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdk28/src/android/security/SELinuxTargetSdkTest.java
index 29b68db..880ae1a 100644
--- a/tests/tests/selinux/selinuxTargetSdk28/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdk28/src/android/security/SELinuxTargetSdkTest.java
@@ -66,6 +66,6 @@
}
public void testNetworkInterface() throws Exception {
- checkNetworkInterface_returnsAnonymizedHardwareAddresses();
+ checkNetworkInterface_returnsHardwareAddresses();
}
}
diff --git a/tests/tests/selinux/selinuxTargetSdk29/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdk29/src/android/security/SELinuxTargetSdkTest.java
index 76fc772..1f1eaaa 100644
--- a/tests/tests/selinux/selinuxTargetSdk29/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdk29/src/android/security/SELinuxTargetSdkTest.java
@@ -43,12 +43,12 @@
}
}
- public void testNoNetlinkRouteGetlink() throws IOException {
- noNetlinkRouteGetlink();
+ public void testNetlinkRouteGetlinkSucceeds() throws IOException {
+ checkNetlinkRouteGetlink(true);
}
- public void testNoNetlinkRouteBind() throws IOException {
- noNetlinkRouteBind();
+ public void testNetlinkRouteBindSucceeds() throws IOException {
+ checkNetlinkRouteBind(true);
}
public void testCanNotExecuteFromHomeDir() throws Exception {
@@ -86,6 +86,6 @@
}
public void testNetworkInterface() throws Exception {
- checkNetworkInterface_returnsAnonymizedHardwareAddresses();
+ checkNetworkInterface_returnsHardwareAddresses();
}
}
diff --git a/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java
index 859864e..05fad31 100644
--- a/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java
@@ -34,11 +34,11 @@
}
public void testNoNetlinkRouteGetlink() throws IOException {
- noNetlinkRouteGetlink();
+ checkNetlinkRouteGetlink(false);
}
public void testNoNetlinkRouteBind() throws IOException {
- noNetlinkRouteBind();
+ checkNetlinkRouteBind(false);
}
public void testCanNotExecuteFromHomeDir() throws Exception {
diff --git a/tests/tests/telephony/current/Android.bp b/tests/tests/telephony/current/Android.bp
index 046587c..8bd31d9 100644
--- a/tests/tests/telephony/current/Android.bp
+++ b/tests/tests/telephony/current/Android.bp
@@ -21,6 +21,8 @@
"src/android/telephony/ims/cts/TestImsSmsImpl.java",
"src/android/telephony/ims/cts/TestImsConfig.java",
"src/android/telephony/ims/cts/TestSipTransport.java",
+ "src/android/telephony/ims/cts/TestSipDelegate.java",
+ "src/android/telephony/ims/cts/TestSipDelegateConnection.java",
"src/android/telephony/ims/cts/ImsUtils.java",
],
path: "src/",
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 da70f25..41d7070 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -58,6 +58,7 @@
import android.telephony.CarrierBandwidth;
import android.telephony.CarrierConfigManager;
import android.telephony.CellLocation;
+import android.telephony.DataThrottlingRequest;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.PinResult;
@@ -67,6 +68,7 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.ThermalMitigationRequest;
import android.telephony.UiccCardInfo;
import android.telephony.UiccSlotInfo;
import android.telephony.data.ApnSetting;
@@ -1074,6 +1076,14 @@
// succeeds, so just make sure nothing crashes.
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
tp -> tp.setSystemSelectionChannels(Collections.emptyList()));
+
+ // getSystemSelectionChannels was added in IRadio 1.6, so ensure it returns
+ // the value that was set by setSystemSelectionChannels.
+ if (mRadioVersion >= RADIO_HAL_VERSION_1_6) {
+ assertEquals(Collections.emptyList(),
+ ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+ TelephonyManager::getSystemSelectionChannels));
+ }
}
@Test
@@ -3138,6 +3148,115 @@
}
}
+ @Test
+ public void testSendThermalMitigationRequest() {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+ long arbitraryCompletionWindowSecs = 1L;
+
+
+ // Test a proper data throttling thermal mitigation request.
+ int thermalMitigationResult = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.sendThermalMitigationRequest(
+ new ThermalMitigationRequest.Builder()
+ .setThermalMitigationAction(ThermalMitigationRequest
+ .THERMAL_MITIGATION_ACTION_DATA_THROTTLING)
+ .setDataThrottlingRequest(new DataThrottlingRequest.Builder()
+ .setDataThrottlingAction(DataThrottlingRequest
+ .DATA_THROTTLING_ACTION_THROTTLE_SECONDARY_CARRIER)
+ .setCompletionDurationMillis(arbitraryCompletionWindowSecs)
+ .build())
+ .build()));
+ // Only verify the result for supported devices on IRadio 1.6+
+ if (mRadioVersion >= RADIO_HAL_VERSION_1_6) {
+ assertEquals(thermalMitigationResult,
+ TelephonyManager.THERMAL_MITIGATION_RESULT_SUCCESS);
+ }
+ // Test negative completionDurationSecs is an invalid parameter.
+ try {
+ thermalMitigationResult = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.sendThermalMitigationRequest(
+ new ThermalMitigationRequest.Builder()
+ .setThermalMitigationAction(ThermalMitigationRequest
+ .THERMAL_MITIGATION_ACTION_DATA_THROTTLING)
+ .setDataThrottlingRequest(new DataThrottlingRequest.Builder()
+ .setDataThrottlingAction(DataThrottlingRequest
+ .DATA_THROTTLING_ACTION_THROTTLE_PRIMARY_CARRIER
+ )
+ .setCompletionDurationMillis(-1)
+ .build())
+ .build()));
+ } catch (IllegalArgumentException e) {
+ }
+
+ // Test non-zero completionDurationSecs is an invalid parameter for data throttling hold.
+ try {
+ thermalMitigationResult = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.sendThermalMitigationRequest(
+ new ThermalMitigationRequest.Builder()
+ .setThermalMitigationAction(ThermalMitigationRequest
+ .THERMAL_MITIGATION_ACTION_DATA_THROTTLING)
+ .setDataThrottlingRequest(new DataThrottlingRequest.Builder()
+ .setDataThrottlingAction(
+ DataThrottlingRequest
+ .DATA_THROTTLING_ACTION_HOLD)
+ .setCompletionDurationMillis(
+ arbitraryCompletionWindowSecs)
+ .build())
+ .build()));
+ } catch (IllegalArgumentException e) {
+ }
+
+ // Test null DataThrottlingParams is an invalid parameter for data throttling request.
+ try {
+ thermalMitigationResult = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.sendThermalMitigationRequest(
+ new ThermalMitigationRequest.Builder()
+ .setThermalMitigationAction(ThermalMitigationRequest
+ .THERMAL_MITIGATION_ACTION_DATA_THROTTLING)
+ .build()));
+ } catch (IllegalArgumentException e) {
+ }
+
+ // Test non-null DataThrottlingParams is an invalid parameter for voice only request.
+ try {
+ thermalMitigationResult = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.sendThermalMitigationRequest(
+ new ThermalMitigationRequest.Builder()
+ .setThermalMitigationAction(
+ ThermalMitigationRequest
+ .THERMAL_MITIGATION_ACTION_VOICE_ONLY)
+ .setDataThrottlingRequest(new DataThrottlingRequest.Builder()
+ .setDataThrottlingAction(
+ DataThrottlingRequest
+ .DATA_THROTTLING_ACTION_THROTTLE_PRIMARY_CARRIER
+ )
+ .setCompletionDurationMillis(-1)
+ .build())
+ .build()));
+ } catch (IllegalArgumentException e) {
+ }
+
+ // Test non-null DataThrottlingParams is an invalid parameter for radio off request.
+ try {
+ thermalMitigationResult = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.sendThermalMitigationRequest(
+ new ThermalMitigationRequest.Builder()
+ .setThermalMitigationAction(
+ ThermalMitigationRequest
+ .THERMAL_MITIGATION_ACTION_RADIO_OFF)
+ .setDataThrottlingRequest(new DataThrottlingRequest.Builder()
+ .setDataThrottlingAction(DataThrottlingRequest
+ .DATA_THROTTLING_ACTION_THROTTLE_PRIMARY_CARRIER
+ )
+ .setCompletionDurationMillis(-1)
+ .build())
+ .build()));
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
/**
* Validate Emergency Number address that only contains the dialable character.
*
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
index d5ec9e0..6c207c4 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
@@ -56,6 +56,7 @@
private static final String COMMAND_BASE = "cmd phone ";
private static final String COMMAND_SET_IMS_SERVICE = "ims set-ims-service ";
private static final String COMMAND_GET_IMS_SERVICE = "ims get-ims-service ";
+ private static final String COMMAND_CLEAR_SERVICE_OVERRIDE = "ims clear-ims-service-override";
private static final String COMMAND_CARRIER_SERVICE_IDENTIFIER = "-c ";
private static final String COMMAND_DEVICE_SERVICE_IDENTIFIER = "-d ";
private static final String COMMAND_SLOT_IDENTIFIER = "-s ";
@@ -140,6 +141,7 @@
}
boolean overrideService(ImsFeatureConfiguration config) throws Exception {
+ mIsServiceOverridden = true;
switch (mConnectionType) {
case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
return bindCarrierImsService(config, PACKAGE_NAME);
@@ -148,8 +150,7 @@
return bindDeviceImsService(config, EXTERNAL_PACKAGE_NAME);
}
case CONNECTION_TYPE_DEFAULT_SMS_APP: {
- setDefaultSmsApp(PACKAGE_NAME);
- break;
+ return setDefaultSmsApp(PACKAGE_NAME);
}
}
return false;
@@ -159,6 +160,7 @@
if (!mIsServiceOverridden) {
return;
}
+ mIsServiceOverridden = false;
if (mOrigRcsServicePackage == null) {
mOrigRcsServicePackage = "";
@@ -170,8 +172,7 @@
switch (mConnectionType) {
case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
- setCarrierImsService(mOrigMmTelServicePackage, ImsFeature.FEATURE_MMTEL);
- setCarrierImsService(mOrigRcsServicePackage, ImsFeature.FEATURE_RCS);
+ clearCarrierImsServiceOverride();
break;
}
case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
@@ -255,7 +256,8 @@
mFeatureTypeToPackageOverrideMap.put(ImsFeature.FEATURE_RCS, packageName);
String result = TelephonyUtils.executeShellCommand(mInstrumentation,
constructSetImsServiceOverrideCommand(true, packageName, new int[] {
- ImsFeature.FEATURE_MMTEL, ImsFeature.FEATURE_RCS}));
+ ImsFeature.FEATURE_EMERGENCY_MMTEL, ImsFeature.FEATURE_MMTEL,
+ ImsFeature.FEATURE_RCS}));
if (ImsUtils.VDBG) {
Log.d(TAG, "setCarrierMmTelImsService result: " + result);
}
@@ -284,7 +286,19 @@
return "true".equals(result);
}
- private void setDefaultSmsApp(String packageName) throws Exception {
+ private boolean clearCarrierImsServiceOverride() throws Exception {
+ String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+ constructClearCarrierImsServiceOverrideCommand());
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "clearCarrierImsServiceOverride result: " + result);
+ }
+ return "true".equals(result);
+ }
+
+ private boolean setDefaultSmsApp(String packageName) throws Exception {
+ if (packageName == null) {
+ return false;
+ }
RoleManager roleManager = mInstrumentation.getContext()
.getSystemService(RoleManager.class);
Boolean result;
@@ -298,6 +312,7 @@
if (ImsUtils.VDBG) {
Log.d(TAG, "setDefaultSmsApp result: " + result);
}
+ return result;
}
private String getDefaultSmsApp() throws Exception {
@@ -378,6 +393,11 @@
+ COMMAND_FEATURE_IDENTIFIER + featureType;
}
+ private String constructClearCarrierImsServiceOverrideCommand() {
+ return COMMAND_BASE + COMMAND_CLEAR_SERVICE_OVERRIDE + COMMAND_SLOT_IDENTIFIER
+ + mSlotId;
+ }
+
private String getFeatureTypesString(int[] featureTypes) {
if (featureTypes.length == 0) return "";
StringBuilder builder = new StringBuilder();
@@ -459,8 +479,12 @@
return mDeviceServiceConnection.overrideService(config);
}
- void setDefaultSmsApp() throws Exception {
- mDefaultSmsAppConnection.overrideService(null);
+ boolean setDefaultSmsApp() throws Exception {
+ return mDefaultSmsAppConnection.overrideService(null);
+ }
+
+ void restoreDefaultSmsApp() throws Exception {
+ mDefaultSmsAppConnection.restoreOriginalPackage();
}
void disconnectCarrierImsService() throws Exception {
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
index 2c09de8..e691e51 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
@@ -24,6 +24,7 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.ims.SipMessage;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -43,6 +44,9 @@
public static final int ITEM_NON_COMPRESSED = 2000;
// Id for compressed auto configuration xml.
public static final int ITEM_COMPRESSED = 2001;
+ // TODO Replace with a real sip message once that logic is in.
+ public static final String TEST_TRANSACTION_ID = "z9hG4bK.TeSt";
+ public static final SipMessage TEST_SIP_MESSAGE = new SipMessage("A", "B", new byte[0]);
public static boolean shouldTestTelephony() {
final PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext()
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/SipDelegateManagerTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/SipDelegateManagerTest.java
index cb02a0c..3f786fa 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/SipDelegateManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/SipDelegateManagerTest.java
@@ -19,6 +19,7 @@
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
@@ -26,16 +27,23 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.Parcel;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.DelegateRequest;
+import android.telephony.ims.FeatureTagState;
import android.telephony.ims.ImsException;
import android.telephony.ims.ImsManager;
import android.telephony.ims.ImsService;
+import android.telephony.ims.SipDelegateImsConfiguration;
import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.ImsFeatureConfiguration;
+import android.util.ArraySet;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -49,20 +57,27 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
/**
* CTS tests for {@link SipDelegateManager} API.
*/
@RunWith(AndroidJUnit4.class)
public class SipDelegateManagerTest {
-
- private static int sTestSlot = 0;
- private static int sTestSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- private static ImsServiceConnector sServiceConnector;
- private static CarrierConfigReceiver sReceiver;
+ private static final String MMTEL_TAG =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\"";
+ private static final String ONE_TO_ONE_CHAT_TAG =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.oma.cpm.msg\"";
+ private static final String GROUP_CHAT_TAG =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.oma.cpm.session\"";
+ private static final String FILE_TRANSFER_HTTP_TAG =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gppapplication.ims.iari.rcs.fthttp\"";
private static class CarrierConfigReceiver extends BroadcastReceiver {
private CountDownLatch mLatch = new CountDownLatch(1);
@@ -91,6 +106,11 @@
}
}
+ private static int sTestSlot = 0;
+ private static int sTestSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private static ImsServiceConnector sServiceConnector;
+ private static CarrierConfigReceiver sReceiver;
+
@BeforeClass
public static void beforeAllTests() throws Exception {
// First, only populate test slot/sub
@@ -179,6 +199,7 @@
// is enabled.
if (sServiceConnector != null) {
sServiceConnector.disconnectCarrierImsService();
+ sServiceConnector.restoreDefaultSmsApp();
}
}
@@ -196,6 +217,14 @@
} catch (SecurityException e) {
//expected
}
+ DelegateRequest d = new DelegateRequest(Collections.emptySet());
+ TestSipDelegateConnection c = new TestSipDelegateConnection(d);
+ try {
+ manager.createSipDelegate(d, Runnable::run, c, c);
+ fail("createSipDelegate requires MODIFY_PHONE_STATE");
+ } catch (SecurityException e) {
+ //expected
+ }
}
@Test
@@ -354,7 +383,7 @@
overrideCarrierConfig(b);
assertTrue(sServiceConnector.connectCarrierImsServiceLocally());
- // NoytImplemented/capable
+ // Not Implemented/capable
ImsFeatureConfiguration c = getConfigForMmTelAndRcs();
assertTrue(sServiceConnector.triggerFrameworkConnectionToCarrierImsService(c));
verifyImsServiceState(c);
@@ -368,6 +397,506 @@
+ "set as capable in ImsService#getImsServiceCapabilities", result);
}
+ @Test
+ public void testCreateDestroyDelegateNotDefaultMessagingApp() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ connectTestImsServiceWithSipTransportAndConfig();
+
+ TestSipTransport transportImpl = sServiceConnector.getCarrierService().getSipTransport();
+ SipDelegateManager manager = getSipDelegateManager();
+ DelegateRequest request = getDefaultRequest();
+ TestSipDelegateConnection delegateConn = new TestSipDelegateConnection(request);
+
+ // wait for onCreated and registration state change to be called.
+ createSipDelegateConnectionNoDelegateExpected(manager, delegateConn, transportImpl);
+
+ // TODO deal with this case better when we can filter messages.
+ delegateConn.sendMessageAndVerifyFailure(ImsUtils.TEST_SIP_MESSAGE,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
+
+ destroySipDelegateConnectionNoDelegate(manager, delegateConn);
+ }
+
+ @Test
+ public void testCreateDelegateBasicUseCases() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ assertTrue(sServiceConnector.setDefaultSmsApp());
+ connectTestImsServiceWithSipTransportAndConfig();
+
+ TestSipTransport transportImpl = sServiceConnector.getCarrierService().getSipTransport();
+ SipDelegateManager manager = getSipDelegateManager();
+ DelegateRequest request = getDefaultRequest();
+ TestSipDelegateConnection delegateConn = new TestSipDelegateConnection(request);
+
+ TestSipDelegate delegate = createSipDelegateConnectionAndVerify(manager, delegateConn,
+ transportImpl, Collections.emptySet(), 0);
+ assertNotNull(delegate);
+
+ SipDelegateImsConfiguration c = new SipDelegateImsConfiguration.Builder(1)
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "123")
+ .build();
+ verifyRegisteredAndSendSipConfig(delegateConn, delegate, request.getFeatureTags(),
+ Collections.emptySet(), c);
+
+ sendMessageAndVerifyAck(delegateConn, delegate);
+ receiveMessageAndVerifyAck(delegateConn, delegate);
+
+ destroySipDelegateAndVerify(manager, transportImpl, delegateConn, delegate,
+ request.getFeatureTags());
+ assertEquals("There should be no more delegates", 0,
+ transportImpl.getDelegates().size());
+ }
+
+ @Test
+ public void testDelegateRegistrationChanges() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ assertTrue(sServiceConnector.setDefaultSmsApp());
+ connectTestImsServiceWithSipTransportAndConfig();
+
+ TestSipTransport transportImpl = sServiceConnector.getCarrierService().getSipTransport();
+ SipDelegateManager manager = getSipDelegateManager();
+ DelegateRequest request = getDefaultRequest();
+ TestSipDelegateConnection delegateConn = new TestSipDelegateConnection(request);
+
+ // Construct registered tags and denied tags, vendor denied FT tag.
+ Set<String> registeredTags = new ArraySet<>(request.getFeatureTags());
+ registeredTags.remove(FILE_TRANSFER_HTTP_TAG);
+ Set<FeatureTagState> deniedTags = new ArraySet<>(1);
+ deniedTags.add(new FeatureTagState(FILE_TRANSFER_HTTP_TAG,
+ SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE));
+ TestSipDelegate delegate = createSipDelegateConnectionAndVerify(manager, delegateConn,
+ transportImpl, deniedTags, 0);
+ assertNotNull(delegate);
+
+ SipDelegateImsConfiguration c = new SipDelegateImsConfiguration.Builder(1)
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "123")
+ .build();
+ verifyRegisteredAndSendSipConfig(delegateConn, delegate, registeredTags, deniedTags, c);
+
+ // TODO verify messages can be sent on registered tags, but generate error for denied tags.
+
+ // move reg state to deregistering and then deregistered
+ delegateConn.setOperationCountDownLatch(1);
+ DelegateRegistrationState s = getDeregisteringState(registeredTags,
+ DelegateRegistrationState.DEREGISTERING_REASON_PDN_CHANGE);
+ delegate.notifyImsRegistrationUpdate(s);
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ delegateConn.verifyRegistrationStateEquals(s);
+
+ delegateConn.setOperationCountDownLatch(1);
+ s = getRegisteredRegistrationState(registeredTags);
+ delegate.notifyImsRegistrationUpdate(s);
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ delegateConn.verifyRegistrationStateEquals(s);
+
+ destroySipDelegateAndVerify(manager, transportImpl, delegateConn, delegate,
+ registeredTags);
+ assertEquals("There should be no more delegates", 0,
+ transportImpl.getDelegates().size());
+ }
+
+ @Test
+ public void testCreateMultipleDelegates() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ assertTrue(sServiceConnector.setDefaultSmsApp());
+ connectTestImsServiceWithSipTransportAndConfig();
+ TestSipTransport transportImpl = sServiceConnector.getCarrierService().getSipTransport();
+ SipDelegateManager manager = getSipDelegateManager();
+
+ DelegateRequest request1 = getChatOnlyRequest();
+ TestSipDelegateConnection delegateConn1 = new TestSipDelegateConnection(request1);
+ Set<String> registeredTags1 = new ArraySet<>(request1.getFeatureTags());
+ TestSipDelegate delegate1 = createSipDelegateConnectionAndVerify(manager, delegateConn1,
+ transportImpl, Collections.emptySet(), 0);
+ assertNotNull(delegate1);
+
+ SipDelegateImsConfiguration c = new SipDelegateImsConfiguration.Builder(1)
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "123")
+ .build();
+ verifyRegisteredAndSendSipConfig(delegateConn1, delegate1, registeredTags1,
+ Collections.emptySet(), c);
+
+ // This will only be granted File transfer FT
+ DelegateRequest request2 = getDefaultRequest();
+ TestSipDelegateConnection delegateConn2 = new TestSipDelegateConnection(request2);
+ Set<String> registeredTags2 = new ArraySet<>();
+ registeredTags2.add(FILE_TRANSFER_HTTP_TAG);
+ TestSipDelegate delegate2 = createSipDelegateConnectionAndVerify(manager, delegateConn2,
+ transportImpl, Collections.emptySet(), 1);
+ assertNotNull(delegate2);
+ Set<FeatureTagState> deniedSet = generateDeniedSetFromRequest(request1.getFeatureTags(),
+ request2.getFeatureTags(),
+ SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE);
+ verifyRegisteredAndSendSipConfig(delegateConn2, delegate2, registeredTags2,
+ deniedSet, c);
+
+ // Destroying delegate 1 will transfer all feature tags over to delegate 2
+ delegateConn2.setOperationCountDownLatch(1);
+ destroySipDelegateAndVerify(manager, transportImpl, delegateConn1, delegate1,
+ registeredTags1);
+ delegateConn2.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ // This internally triggers the destruction of the internal delegate2 and then recreation
+ // of another delegate with the new feature set that it supports.
+ verifySipDelegateDestroyed(transportImpl, delegateConn2, delegate2, registeredTags2,
+ DelegateRegistrationState.DEREGISTERING_REASON_FEATURE_TAGS_CHANGING);
+ delegate2 = getSipDelegate(transportImpl, Collections.emptySet(), 0);
+ verifyRegisteredAndSendSipConfig(delegateConn2, delegate2, request2.getFeatureTags(),
+ Collections.emptySet(), c);
+
+ destroySipDelegateAndVerify(manager, transportImpl, delegateConn2, delegate2,
+ request2.getFeatureTags());
+ assertEquals("There should be no more delegates", 0,
+ transportImpl.getDelegates().size());
+ }
+
+ @Test
+ public void testCreateDelegateMessagingAppChangesToApp() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // start with no features granted
+ connectTestImsServiceWithSipTransportAndConfig();
+
+ TestSipTransport transportImpl = sServiceConnector.getCarrierService().getSipTransport();
+ SipDelegateManager manager = getSipDelegateManager();
+ DelegateRequest request = getDefaultRequest();
+ TestSipDelegateConnection delegateConn = new TestSipDelegateConnection(request);
+
+ // wait for onCreated and registration state change to be called.
+ createSipDelegateConnectionNoDelegateExpected(manager, delegateConn, transportImpl);
+
+ // Make this app the DMA
+ assertTrue(sServiceConnector.setDefaultSmsApp());
+ TestSipDelegate delegate = getSipDelegate(transportImpl, Collections.emptySet(), 0);
+ SipDelegateImsConfiguration c = new SipDelegateImsConfiguration.Builder(1)
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "123")
+ .build();
+ verifyRegisteredAndSendSipConfig(delegateConn, delegate, request.getFeatureTags(),
+ Collections.emptySet(), c);
+ destroySipDelegateAndVerify(manager, transportImpl, delegateConn, delegate,
+ request.getFeatureTags());
+ assertEquals("There should be no more delegates", 0,
+ transportImpl.getDelegates().size());
+ }
+
+ @Test
+ public void testCreateDelegateMessagingAppChangesAwayFromApp() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Make this app the DMA
+ assertTrue(sServiceConnector.setDefaultSmsApp());
+ connectTestImsServiceWithSipTransportAndConfig();
+ TestSipTransport transportImpl = sServiceConnector.getCarrierService().getSipTransport();
+ SipDelegateManager manager = getSipDelegateManager();
+
+ DelegateRequest request = getDefaultRequest();
+ TestSipDelegateConnection delegateConn = new TestSipDelegateConnection(request);
+ TestSipDelegate delegate = createSipDelegateConnectionAndVerify(manager, delegateConn,
+ transportImpl, Collections.emptySet(), 0);
+ assertNotNull(delegate);
+
+ SipDelegateImsConfiguration c = new SipDelegateImsConfiguration.Builder(1)
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "123")
+ .build();
+ verifyRegisteredAndSendSipConfig(delegateConn, delegate, request.getFeatureTags(),
+ Collections.emptySet(), c);
+
+
+ // Move DMA to another app, we should receive a registration update.
+ delegateConn.setOperationCountDownLatch(1);
+ sServiceConnector.restoreDefaultSmsApp();
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ // we should get another reg update with all tags denied.
+ delegateConn.setOperationCountDownLatch(1);
+ verifySipDelegateDestroyed(transportImpl, delegateConn, delegate, request.getFeatureTags(),
+ DelegateRegistrationState.DEREGISTERING_REASON_FEATURE_TAGS_CHANGING);
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ delegateConn.verifyRegistrationStateEmpty();
+ // All requested features should have been denied due to the app not being the default sms
+ // app.
+ delegateConn.verifyAllDenied(SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
+ // There should not be any delegates left, as the only delegate should have been cleaned up.
+ assertEquals("SipDelegate should not have any delegates", 0,
+ transportImpl.getDelegates().size());
+
+ destroySipDelegateConnectionNoDelegate(manager, delegateConn);
+ }
+ @Test
+ public void testParcelUnparcelDelegateRequest() {
+ ArraySet<String> testTags = new ArraySet<>();
+ testTags.add(MMTEL_TAG);
+ testTags.add(ONE_TO_ONE_CHAT_TAG);
+ testTags.add(GROUP_CHAT_TAG);
+ testTags.add(FILE_TRANSFER_HTTP_TAG);
+ DelegateRequest r = new DelegateRequest(testTags);
+ Parcel p = Parcel.obtain();
+ r.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ DelegateRequest unparcelled = DelegateRequest.CREATOR.createFromParcel(p);
+ assertEquals(r, unparcelled);
+ assertEquals(r.getFeatureTags(), unparcelled.getFeatureTags());
+ }
+
+ @Test
+ public void testParcelUnparcelFeatureTagState() {
+ FeatureTagState f = new FeatureTagState(MMTEL_TAG,
+ DelegateRegistrationState.DEREGISTERED_REASON_NOT_REGISTERED);
+ Parcel p = Parcel.obtain();
+ f.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ FeatureTagState unparcelled = FeatureTagState.CREATOR.createFromParcel(p);
+ assertEquals(f, unparcelled);
+ assertEquals(f.getFeatureTag(), unparcelled.getFeatureTag());
+ assertEquals(f.getState(), unparcelled.getState());
+ }
+
+ @Test
+ public void testParcelUnparcelRegistrationState() {
+ ArraySet<String> regTags = new ArraySet<>();
+ regTags.add(MMTEL_TAG);
+ DelegateRegistrationState s = new DelegateRegistrationState.Builder()
+ .addRegisteredFeatureTags(regTags)
+ .addRegisteredFeatureTag(ONE_TO_ONE_CHAT_TAG)
+ .addDeregisteringFeatureTag(GROUP_CHAT_TAG,
+ DelegateRegistrationState.DEREGISTERING_REASON_PDN_CHANGE)
+ .addDeregisteredFeatureTag(FILE_TRANSFER_HTTP_TAG,
+ DelegateRegistrationState.DEREGISTERED_REASON_NOT_REGISTERED)
+ .build();
+ Parcel p = Parcel.obtain();
+ s.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ DelegateRegistrationState unparcel = DelegateRegistrationState.CREATOR.createFromParcel(p);
+ assertEquals(s, unparcel);
+ assertEquals(s.getRegisteredFeatureTags(), unparcel.getRegisteredFeatureTags());
+ assertEquals(s.getDeregisteringFeatureTags(), unparcel.getDeregisteringFeatureTags());
+ assertEquals(s.getDeregisteredFeatureTags(), unparcel.getDeregisteredFeatureTags());
+ }
+
+ @Test
+ public void testParcelUnparcelImsConfiguration() {
+ SipDelegateImsConfiguration c = new SipDelegateImsConfiguration.Builder(1 /*version*/)
+ .addBoolean(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL, true)
+ .addInt(SipDelegateImsConfiguration.KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT, 1)
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "123")
+ .build();
+ Parcel p = Parcel.obtain();
+ c.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ SipDelegateImsConfiguration unparcel =
+ SipDelegateImsConfiguration.CREATOR.createFromParcel(p);
+ assertEquals(c.getVersion(), unparcel.getVersion());
+ assertEquals(c.getBoolean(
+ SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL, false),
+ unparcel.getBoolean(
+ SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL, false));
+ assertEquals(c.getInt(
+ SipDelegateImsConfiguration.KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT, -1),
+ unparcel.getInt(
+ SipDelegateImsConfiguration.KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT,
+ -1));
+ assertEquals(c.getString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING),
+ unparcel.getString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING));
+ }
+
+ @Test
+ public void testParcelUnparcelSipMessage() {
+ byte[] bytes = new byte[1];
+ bytes[0] = 'a';
+ SipMessage m = new SipMessage("A", "B", bytes);
+ Parcel p = Parcel.obtain();
+ m.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ SipMessage unparcel = SipMessage.CREATOR.createFromParcel(p);
+ assertEquals(m, unparcel);
+ assertEquals(m.getStartLine(), unparcel.getStartLine());
+ assertEquals(m.getHeaderSection(), unparcel.getHeaderSection());
+ assertTrue(Arrays.equals(m.getContent(), unparcel.getContent()));
+ }
+
+ private void createSipDelegateConnectionNoDelegateExpected(SipDelegateManager manager,
+ TestSipDelegateConnection conn, TestSipTransport transport) throws Exception {
+ // wait for onCreated and reg state changed
+ conn.setOperationCountDownLatch(2);
+ conn.connect(manager);
+ conn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ conn.verifyDelegateCreated();
+ conn.verifyRegistrationStateEmpty();
+ // All requested features should have been denied due to the app not being the default sms
+ // app.
+ conn.verifyAllDenied(SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
+ // There should not have been a call to create a SipDelegate on the service side, since all
+ // features were denied due to permissions issues.
+ assertEquals("SipDelegate should not have been created", 0,
+ transport.getDelegates().size());
+ }
+
+ private void destroySipDelegateConnectionNoDelegate(SipDelegateManager manager,
+ TestSipDelegateConnection delegateConn) throws Exception {
+ delegateConn.setOperationCountDownLatch(1);
+ delegateConn.disconnect(manager,
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ delegateConn.verifyDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ }
+
+ private void destroySipDelegateAndVerify(SipDelegateManager manager,
+ TestSipTransport transportImpl, TestSipDelegateConnection delegateConn,
+ TestSipDelegate delegate, Set<String> registeredTags) throws Exception {
+ // wait for registration change upon disconnecting state change
+ delegateConn.setOperationCountDownLatch(1);
+ delegateConn.disconnect(manager,
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ // verify we move to deregistering for registered tags.
+ DelegateRegistrationState s = getDeregisteringState(registeredTags,
+ DelegateRegistrationState.DEREGISTERING_REASON_DESTROY_PENDING);
+ delegateConn.verifyRegistrationStateEquals(s);
+ // wait for on destroyed
+ delegateConn.setOperationCountDownLatch(1);
+ transportImpl.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
+ delegate.notifyOnDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ delegateConn.verifyDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ }
+
+ private void verifySipDelegateDestroyed(TestSipTransport transportImpl,
+ TestSipDelegateConnection delegateConn, TestSipDelegate delegate,
+ Set<String> registeredTags, int deregReason) {
+ // verify we move to deregistering for registered tags.
+ DelegateRegistrationState s = getDeregisteringState(registeredTags, deregReason);
+ delegateConn.verifyRegistrationStateEquals(s);
+ transportImpl.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
+ delegate.notifyOnDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ }
+
+ private TestSipDelegate createSipDelegateConnectionAndVerify(SipDelegateManager manager,
+ TestSipDelegateConnection conn, TestSipTransport transport,
+ Set<FeatureTagState> deniedTags, int delegateIndex) throws Exception {
+ conn.setOperationCountDownLatch(1);
+ conn.connect(manager);
+ TestSipDelegate d = getSipDelegate(transport, deniedTags, delegateIndex);
+ conn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ conn.verifyDelegateCreated();
+ return d;
+ }
+
+ private TestSipDelegate getSipDelegate(TestSipTransport transport,
+ Set<FeatureTagState> deniedTags, int delegateIndex) {
+ transport.waitForLatchCountdownAndReset(TestSipTransport.LATCH_CREATE_DELEGATE);
+ // There must have been a call to create a SipDelegate on the service side.
+ assertEquals("SipDelegate should have been created", delegateIndex + 1,
+ transport.getDelegates().size());
+ TestSipDelegate d = transport.getDelegates().get(delegateIndex);
+ d.notifyOnCreated(deniedTags);
+ return d;
+ }
+
+ private void verifyRegisteredAndSendSipConfig(TestSipDelegateConnection delegateConn,
+ TestSipDelegate delegate, Set<String> registeredTags,
+ Set<FeatureTagState> deniedTags, SipDelegateImsConfiguration sipConfig) {
+ // wait for reg change to be called
+ delegateConn.setOperationCountDownLatch(1);
+ DelegateRegistrationState s = getRegisteredRegistrationState(registeredTags);
+ delegate.notifyImsRegistrationUpdate(s);
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ delegateConn.verifyRegistrationStateRegistered(registeredTags);
+ delegateConn.verifyDenied(deniedTags);
+
+ // send config change as well.
+ sendConfigChange(sipConfig, delegateConn, delegate);
+ }
+
+ private Set<FeatureTagState> generateDeniedSetFromRequest(Set<String> grantedTags,
+ Set<String> newTags, int reason) {
+ // Deny features from newTags that are already granted in grantedTags.
+ return grantedTags.stream().filter(newTags::contains)
+ .map(s -> new FeatureTagState(s, reason))
+ .collect(Collectors.toSet());
+ }
+
+ private void sendMessageAndVerifyAck(TestSipDelegateConnection delegateConn,
+ TestSipDelegate delegate) throws Exception {
+ // Send a message and ensure it gets received on the other end as well as acked
+ delegateConn.sendMessageAndVerifyCompletedSuccessfully(ImsUtils.TEST_SIP_MESSAGE);
+ delegate.verifyMessageSend(ImsUtils.TEST_SIP_MESSAGE);
+ // send a message and notify connection that it failed
+ delegate.setSendMessageDenyReason(
+ SipDelegateManager.MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE);
+ delegateConn.sendMessageAndVerifyFailure(ImsUtils.TEST_SIP_MESSAGE,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE);
+ delegate.verifyMessageSend(ImsUtils.TEST_SIP_MESSAGE);
+ }
+
+ private void receiveMessageAndVerifyAck(TestSipDelegateConnection delegateConn,
+ TestSipDelegate delegate) throws Exception {
+ // Receive a message and ensure it gets received on the other end as well as acked
+ delegate.receiveMessageAndVerifyReceivedCalled(ImsUtils.TEST_SIP_MESSAGE);
+ delegateConn.verifyMessageReceived(ImsUtils.TEST_SIP_MESSAGE);
+ // Receive a message and have connection notify that it didn't complete
+ delegateConn.setReceivedMessageErrorResponseReason(
+ SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT);
+ delegate.receiveMessageAndVerifyReceiveErrorCalled(ImsUtils.TEST_SIP_MESSAGE,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT);
+ }
+
+ private void sendConfigChange(SipDelegateImsConfiguration c,
+ TestSipDelegateConnection delegateConn, TestSipDelegate delegate) {
+ delegateConn.setOperationCountDownLatch(1);
+ delegate.notifyImsConfigurationUpdate(c);
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ delegateConn.verifyConfigEquals(c);
+ }
+
+ private DelegateRegistrationState getRegisteredRegistrationState(Set<String> registered) {
+ return new DelegateRegistrationState.Builder().addRegisteredFeatureTags(registered).build();
+ }
+
+ private DelegateRegistrationState getDeregisteringState(Set<String> deregisterTags,
+ int reason) {
+ DelegateRegistrationState.Builder b = new DelegateRegistrationState.Builder();
+ for (String t : deregisterTags) {
+ b.addDeregisteringFeatureTag(t, reason);
+ }
+ return b.build();
+ }
+
+ private DelegateRegistrationState getDeregistedState(Set<String> deregisterTags,
+ int reason) {
+ DelegateRegistrationState.Builder b = new DelegateRegistrationState.Builder();
+ for (String t : deregisterTags) {
+ b.addDeregisteredFeatureTag(t, reason);
+ }
+ return b.build();
+ }
+
+ private void connectTestImsServiceWithSipTransportAndConfig() throws Exception {
+ PersistableBundle b = new PersistableBundle();
+ b.putBoolean(CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, true);
+ overrideCarrierConfig(b);
+
+ assertTrue(sServiceConnector.connectCarrierImsServiceLocally());
+ sServiceConnector.getCarrierService().addCapabilities(
+ ImsService.CAPABILITY_SIP_DELEGATE_CREATION);
+ sServiceConnector.getCarrierService().setSipTransportImplemented();
+ ImsFeatureConfiguration c = getConfigForMmTelAndRcs();
+ assertTrue(sServiceConnector.triggerFrameworkConnectionToCarrierImsService(c));
+ verifyImsServiceState(c);
+ }
+
+
private void connectTestImsServiceWithSipTransport() throws Exception {
assertTrue(sServiceConnector.connectCarrierImsServiceLocally());
sServiceConnector.getCarrierService().addCapabilities(
@@ -422,6 +951,21 @@
return null;
}
+ private DelegateRequest getDefaultRequest() {
+ ArraySet<String> features = new ArraySet<>(3);
+ features.add(TestSipTransport.ONE_TO_ONE_CHAT_TAG);
+ features.add(TestSipTransport.GROUP_CHAT_TAG);
+ features.add(TestSipTransport.FILE_TRANSFER_HTTP_TAG);
+ return new DelegateRequest(features);
+ }
+
+ private DelegateRequest getChatOnlyRequest() {
+ ArraySet<String> features = new ArraySet<>(3);
+ features.add(TestSipTransport.ONE_TO_ONE_CHAT_TAG);
+ features.add(TestSipTransport.GROUP_CHAT_TAG);
+ return new DelegateRequest(features);
+ }
+
private ImsFeatureConfiguration getConfigForMmTelAndRcs() {
return new ImsFeatureConfiguration.Builder()
.addFeature(sTestSlot, ImsFeature.FEATURE_EMERGENCY_MMTEL)
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
index 89019b7..029b8c3 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
@@ -342,6 +342,12 @@
}
}
+ public TestSipTransport getSipTransport() {
+ synchronized (mLock) {
+ return mTestSipTransport;
+ }
+ }
+
public ImsRegistrationImplBase getImsRegistration() {
synchronized (mLock) {
return sImsRegistrationImplBase;
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegate.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegate.java
new file mode 100644
index 0000000..3d06dce
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegate.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.telephony.ims.DelegateMessageCallback;
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.DelegateRequest;
+import android.telephony.ims.DelegateStateCallback;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipMessage;
+import android.telephony.ims.stub.SipDelegate;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+
+import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class TestSipDelegate implements SipDelegate {
+ private static final String LOG_TAG = "CtsImsSipDelegate";
+
+ public final int subId;
+ public final DelegateRequest delegateRequest;
+ private final DelegateStateCallback mStateCallback;
+ private final DelegateMessageCallback mMessageCallback;
+
+ private final LinkedBlockingQueue<SipMessage> mIncomingMessages = new LinkedBlockingQueue<>();
+ // Pair is <transactionId, error reason>
+ private final LinkedBlockingQueue<Pair<String, Integer>> mReceivedMessageAcks =
+ new LinkedBlockingQueue<>();
+ private int mSendMessageDenyReason = -1;
+
+ public TestSipDelegate(int sub, DelegateRequest request, DelegateStateCallback cb,
+ DelegateMessageCallback mc) {
+ subId = sub;
+ delegateRequest = request;
+ mStateCallback = cb;
+ mMessageCallback = mc;
+ }
+
+ @Override
+ public void sendMessage(@NonNull SipMessage message, long configVersion) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "sendMessage");
+ mIncomingMessages.offer(message);
+ if (mSendMessageDenyReason > -1) {
+ mMessageCallback.onMessageSendFailure(ImsUtils.TEST_TRANSACTION_ID,
+ mSendMessageDenyReason);
+ } else {
+ mMessageCallback.onMessageSent(ImsUtils.TEST_TRANSACTION_ID);
+ }
+ }
+
+ @Override
+ public void closeDialog(@NonNull String callId) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "closeDialog");
+ // TODO: Test once dialogs are tracked in AOSP.
+ }
+
+ @Override
+ public void notifyMessageReceived(@NonNull String viaTransactionId) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "notifyMessageReceived");
+ mReceivedMessageAcks.offer(new Pair<>(viaTransactionId, -1));
+ }
+
+ @Override
+ public void notifyMessageReceiveError(@NonNull String viaTransactionId, int reason) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "notifyMessageReceiveError");
+ mReceivedMessageAcks.offer(new Pair<>(viaTransactionId, reason));
+ }
+
+ public void verifyMessageSend(SipMessage messageToVerify) throws Exception {
+ SipMessage m = mIncomingMessages.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ assertEquals(messageToVerify, m);
+ }
+
+ public void setSendMessageDenyReason(int reason) {
+ mSendMessageDenyReason = reason;
+ }
+
+ public void receiveMessageAndVerifyReceivedCalled(SipMessage m) throws Exception {
+ mMessageCallback.onMessageReceived(m);
+ Pair<String, Integer> transactionAndIdPair = mReceivedMessageAcks.poll(
+ ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ assertEquals(ImsUtils.TEST_TRANSACTION_ID, transactionAndIdPair.first);
+ assertNotNull(transactionAndIdPair.second);
+ assertEquals(-1, transactionAndIdPair.second.intValue());
+ }
+
+ public void receiveMessageAndVerifyReceiveErrorCalled(SipMessage m, int reason)
+ throws Exception {
+ mMessageCallback.onMessageReceived(m);
+ Pair<String, Integer> transactionAndIdPair = mReceivedMessageAcks.poll(
+ ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ assertEquals(ImsUtils.TEST_TRANSACTION_ID, transactionAndIdPair.first);
+ assertNotNull(transactionAndIdPair.second);
+ assertEquals(reason, transactionAndIdPair.second.intValue());
+ }
+
+ public void notifyImsRegistrationUpdate(DelegateRegistrationState state) {
+ mStateCallback.onFeatureTagRegistrationChanged(state);
+ }
+
+ public void notifyImsConfigurationUpdate(SipDelegateImsConfiguration config) {
+ mStateCallback.onImsConfigurationChanged(config);
+ }
+
+ public void notifyOnCreated(Set<FeatureTagState> deniedTags) {
+ mStateCallback.onCreated(this, deniedTags);
+ }
+
+ public void notifyOnDestroyed(int reason) {
+ mStateCallback.onDestroyed(reason);
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegateConnection.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegateConnection.java
new file mode 100644
index 0000000..6b3b134
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegateConnection.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims.cts;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.os.PersistableBundle;
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.DelegateRequest;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.SipDelegateConnection;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.telephony.ims.stub.DelegateConnectionMessageCallback;
+import android.telephony.ims.stub.DelegateConnectionStateCallback;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+public class TestSipDelegateConnection implements DelegateConnectionStateCallback,
+ DelegateConnectionMessageCallback {
+
+ private interface ExceptionRunnable {
+ void run() throws Exception;
+ }
+
+ private static final String LOG_TAG = "CtsImsSipDelegateC";
+
+ public int destroyReason = -1;
+ public SipDelegateConnection connection;
+ public Set<FeatureTagState> deniedTags;
+ public DelegateRegistrationState regState;
+ public SipDelegateImsConfiguration sipConfig;
+ public final DelegateRequest delegateRequest;
+
+ private int mReceivedMessageErrorResponseReason = -1;
+ private CountDownLatch mLatch;
+ // Pair is <transactionId, error reason>
+ private final LinkedBlockingQueue<SipMessage> mReceivedMessages = new LinkedBlockingQueue<>();
+ private final LinkedBlockingQueue<Pair<String, Integer>> mSentMessageAcks =
+ new LinkedBlockingQueue<>();
+
+ public TestSipDelegateConnection(DelegateRequest request) {
+ delegateRequest = request;
+ }
+
+ public void connect(SipDelegateManager manager) throws Exception {
+ callUntilImsServiceIsAvailableNoReturn(() ->
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
+ manager, (m) -> m.createSipDelegate(delegateRequest, Runnable::run, this,
+ this), ImsException.class,
+ "android.permission.MODIFY_PHONE_STATE"));
+ }
+
+ public void disconnect(SipDelegateManager manager, int reason) throws Exception {
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
+ manager, (m) -> m.destroySipDelegate(connection, reason),
+ ImsException.class, "android.permission.MODIFY_PHONE_STATE");
+ }
+
+ @Override
+ public void onMessageReceived(@NonNull SipMessage message) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "onMessageReceived");
+ mReceivedMessages.offer(message);
+ if (mReceivedMessageErrorResponseReason > -1) {
+ connection.notifyMessageReceiveError(ImsUtils.TEST_TRANSACTION_ID,
+ mReceivedMessageErrorResponseReason);
+ } else {
+ connection.notifyMessageReceived(ImsUtils.TEST_TRANSACTION_ID);
+ }
+ }
+
+ @Override
+ public void onMessageSent(@NonNull String viaTransactionId) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "onMessageSent");
+ mSentMessageAcks.offer(new Pair<>(viaTransactionId, -1));
+ }
+
+ @Override
+ public void onMessageSendFailure(@NonNull String viaTransactionId, int reason) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "onMessageSendFailure");
+ mSentMessageAcks.offer(new Pair<>(viaTransactionId, reason));
+ }
+
+ @Override
+ public void onCreated(@NonNull SipDelegateConnection c) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "onCreated");
+ connection = c;
+ mLatch.countDown();
+ }
+
+ @Override
+ public void onFeatureTagStatusChanged(@NonNull DelegateRegistrationState registrationState,
+ @NonNull Set<FeatureTagState> deniedFeatureTags) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "onFeatureTagStatusChanged");
+ regState = registrationState;
+ deniedTags = deniedFeatureTags;
+ mLatch.countDown();
+ }
+
+ @Override
+ public void onImsConfigurationChanged(
+ @NonNull SipDelegateImsConfiguration registeredSipConfig) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "onImsConfigurationChanged");
+ sipConfig = registeredSipConfig;
+ mLatch.countDown();
+ }
+
+ @Override
+ public void onDestroyed(int reason) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "onDestroyed");
+ connection = null;
+ destroyReason = reason;
+ mLatch.countDown();
+ }
+
+ public void sendMessageAndVerifyCompletedSuccessfully(SipMessage messageToSend)
+ throws Exception {
+ assertNotNull("SipDelegate was null when sending message", connection);
+ connection.sendMessage(messageToSend, sipConfig.getVersion());
+ Pair<String, Integer> ack = mSentMessageAcks.poll(ImsUtils.TEST_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
+ assertNotNull(ack);
+ assertEquals(ImsUtils.TEST_TRANSACTION_ID, ack.first);
+ assertNotNull(ack.second);
+ assertEquals(-1, ack.second.intValue());
+ }
+
+ public void sendMessageAndVerifyFailure(SipMessage messageToSend, int expectedReason)
+ throws Exception {
+ assertNotNull("SipDelegate was null when sending message", connection);
+ // send invalid version if it was not sent.
+ long version = (sipConfig != null) ? sipConfig.getVersion() : -1;
+ connection.sendMessage(messageToSend, version);
+ Pair<String, Integer> ack = mSentMessageAcks.poll(ImsUtils.TEST_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
+ assertNotNull(ack);
+ // TODO actually check this, but for now the platform can not inspect SipMessages and send
+ // the real transaction ID. So, just ensure it is null.
+ //assertEquals(ImsUtils.TEST_TRANSACTION_ID, ack.first);
+ assertNotNull(ack.second);
+ assertEquals(expectedReason, ack.second.intValue());
+ }
+
+ public void verifyMessageReceived(SipMessage messageToVerify)
+ throws Exception {
+ SipMessage m = mReceivedMessages.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ assertEquals(messageToVerify, m);
+ }
+
+ public void setReceivedMessageErrorResponseReason(int reason) {
+ mReceivedMessageErrorResponseReason = reason;
+ }
+
+ public void verifyDelegateCreated() {
+ assertNotNull("SipDelegate is null when it should have been created", connection);
+ }
+
+ public void verifyConfigEquals(SipDelegateImsConfiguration config) {
+ assertNotNull("SIP configuration should not be null", sipConfig);
+ assertEquals("IMS config version is not correct", config.getVersion(),
+ sipConfig.getVersion());
+ PersistableBundle b = config.copyBundle();
+ for (String key : b.keySet()) {
+ assertTrue("tracked sip config does not contain the key [" + key + "}",
+ sipConfig.containsKey(key));
+ // Not a true equality check, but close enough for the purposes of this test.
+ assertEquals(config.getString(key), sipConfig.getString(key));
+ assertEquals(config.getInt(key, -1), sipConfig.getInt(key, -1));
+ assertEquals(config.getBoolean(key, false),
+ sipConfig.getBoolean(key, false));
+ }
+ }
+
+ public void verifyRegistrationStateRegistered() {
+ verifyRegistrationStateRegistered(delegateRequest.getFeatureTags());
+ }
+
+ public void verifyRegistrationStateRegistered(Set<String> tags) {
+ assertNotNull(regState);
+ assertFalse("No registered features found",
+ regState.getRegisteredFeatureTags().isEmpty());
+ ArraySet<String> notRegistered = new ArraySet<>(tags);
+ notRegistered.removeAll(regState.getRegisteredFeatureTags());
+ assertTrue("Not all requested features were registered: " + notRegistered,
+ notRegistered.isEmpty());
+ assertTrue(regState.getDeregisteringFeatureTags().isEmpty());
+ assertTrue(regState.getDeregisteredFeatureTags().isEmpty());
+ }
+
+ public void verifyRegistrationStateEmpty() {
+ assertNotNull(regState);
+ assertTrue(regState.getRegisteredFeatureTags().isEmpty());
+ assertTrue(regState.getDeregisteringFeatureTags().isEmpty());
+ assertTrue(regState.getDeregisteredFeatureTags().isEmpty());
+ }
+
+ public void verifyRegistrationStateEquals(DelegateRegistrationState s) {
+ assertEquals("unexpected registered tags", s.getRegisteredFeatureTags(),
+ regState.getRegisteredFeatureTags());
+ assertEquals("unexpected deregistering tags", s.getDeregisteringFeatureTags(),
+ regState.getDeregisteringFeatureTags());
+ assertEquals("unexpected deregistered tags", s.getDeregisteredFeatureTags(),
+ regState.getDeregisteredFeatureTags());
+ }
+
+
+ public void verifyNoneDenied() {
+ assertNotNull(deniedTags);
+ assertTrue(deniedTags.isEmpty());
+ }
+
+ public void verifyDenied(Set<FeatureTagState> denied) {
+ assertNotNull(deniedTags);
+ assertEquals(denied, deniedTags);
+ }
+
+ public void verifyAllDenied(int reason) {
+ assertNotNull(deniedTags);
+ // Ensure that if the request is empty, the denied tags are also empty.
+ if (delegateRequest.getFeatureTags().isEmpty()) {
+ assertTrue(deniedTags.isEmpty());
+ }
+ // All should be denied with the same reason.
+ FeatureTagState incorrectReason = deniedTags.stream().filter((t) -> t.getState() != reason)
+ .findAny().orElse(null);
+ Set<String> deniedFeatures = deniedTags.stream().map(FeatureTagState::getFeatureTag)
+ .collect(Collectors.toSet());
+ assertNull(incorrectReason);
+
+ Set<String> requestedTags = new ArraySet<>(delegateRequest.getFeatureTags());
+ requestedTags.removeAll(deniedFeatures);
+ assertTrue("Not all tags denied: " + requestedTags, requestedTags.isEmpty());
+ }
+
+ public void verifyDestroyed(int reason) {
+ assertEquals(reason, destroyReason);
+ }
+
+ /**
+ * Set the number of operations that are expected to happen. Use {@link #waitForCountDown(long)}
+ * to wait for the operations to occur.
+ */
+ public void setOperationCountDownLatch(int operationCount) {
+ mLatch = new CountDownLatch(operationCount);
+ }
+
+ /**
+ * Wait for the latch set in {@link #setOperationCountDownLatch(int)} to complete.
+ * @param timeoutMs The time to wait before giving up.
+ * @return {@code true} if the latch successfully counted down, {@code false} if time elaptsed
+ * before it counted down.
+ */
+ public boolean waitForCountDown(long timeoutMs) {
+ while (mLatch.getCount() > 0) {
+ try {
+ return mLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException ignore) { }
+ }
+ return true;
+ }
+
+ /**
+ * Wait up to five seconds (retrying a command 1 time per second) until ImsExceptions due to the
+ * ImsService not being available go away.
+ */
+ private void callUntilImsServiceIsAvailableNoReturn(ExceptionRunnable command)
+ throws Exception {
+ int retry = 0;
+ while (retry < 5) {
+ try {
+ command.run();
+ return;
+ } catch (ImsException e) {
+ // we want to absorb only the unavailable error, as telephony may still be
+ // internally setting up. Any other type of ImsException is unexpected.
+ if (e.getCode() != ImsException.CODE_ERROR_SERVICE_UNAVAILABLE) {
+ throw e;
+ }
+ }
+ Thread.sleep(1000);
+ retry++;
+ }
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipTransport.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipTransport.java
index b7db4c8..ed5a07b 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipTransport.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipTransport.java
@@ -16,13 +16,103 @@
package android.telephony.ims.cts;
+import static org.junit.Assert.fail;
+
+import android.telephony.ims.DelegateMessageCallback;
+import android.telephony.ims.DelegateRequest;
+import android.telephony.ims.DelegateStateCallback;
+import android.telephony.ims.stub.SipDelegate;
import android.telephony.ims.stub.SipTransportImplBase;
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
public class TestSipTransport extends SipTransportImplBase {
+ public static final String ONE_TO_ONE_CHAT_TAG =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.oma.cpm.msg\"";
+ public static final String GROUP_CHAT_TAG =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.oma.cpm.session\"";
+ public static final String FILE_TRANSFER_HTTP_TAG =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gppapplication.ims.iari.rcs.fthttp\"";
+
+ public static final int LATCH_CREATE_DELEGATE = 0;
+ public static final int LATCH_DESTROY_DELEGATE = 1;
+ private static final int LATCH_MAX = 2;
+ protected static final CountDownLatch[] sLatches = new CountDownLatch[LATCH_MAX];
+ static {
+ for (int i = 0; i < LATCH_MAX; i++) {
+ sLatches[i] = new CountDownLatch(1);
+ }
+ }
+
+ private final ArrayList<TestSipDelegate> mDelegates = new ArrayList<>();
+ private final Object mLock = new Object();
+
public TestSipTransport(Executor executor) {
super(executor);
}
+
+ @Override
+ public void createSipDelegate(int subscriptionId, @NonNull DelegateRequest request,
+ @NonNull DelegateStateCallback dc, @NonNull DelegateMessageCallback mc) {
+ TestSipDelegate d = new TestSipDelegate(subscriptionId, request, dc, mc);
+ synchronized (mLock) {
+ mDelegates.add(d);
+ }
+ countDownLatch(LATCH_CREATE_DELEGATE);
+ }
+
+ @Override
+ public void destroySipDelegate(@NonNull SipDelegate delegate, int reason) {
+ if (delegate instanceof TestSipDelegate) {
+ synchronized (mLock) {
+ mDelegates.remove(delegate);
+ }
+ countDownLatch(LATCH_DESTROY_DELEGATE);
+ } else {
+ fail("unknown delegate passed in!");
+ }
+ }
+
+ public List<TestSipDelegate> getDelegates() {
+ synchronized (mLock) {
+ return mDelegates;
+ }
+ }
+
+ public TestSipDelegate getDelegate(DelegateRequest request) {
+ synchronized (mLock) {
+ return mDelegates.stream().filter((d) -> d.delegateRequest.equals(request))
+ .findFirst().orElse(null);
+ }
+ }
+
+ public boolean waitForLatchCountdownAndReset(int latchIndex) {
+ boolean complete = false;
+ try {
+ CountDownLatch latch;
+ synchronized (mLock) {
+ latch = sLatches[latchIndex];
+ }
+ complete = latch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // complete == false
+ }
+ synchronized (mLock) {
+ sLatches[latchIndex] = new CountDownLatch(1);
+ }
+ return complete;
+ }
+
+ private void countDownLatch(int latchIndex) {
+ synchronized (mLock) {
+ sLatches[latchIndex].countDown();
+ }
+ }
}
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index c30c71c..85d4fc8 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -291,7 +291,7 @@
</activity>
<activity android:name="android.widget.cts.PopupWindowCtsActivity"
- android:configChanges="keyboardHidden|orientation|screenSize"
+ android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:label="PopupWindowCtsActivity"
android:theme="@style/Theme.PopupWindowCtsActivity">
<intent-filter>
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 e8c5c27..115d02e 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -2100,13 +2100,17 @@
boolean isStaApConcurrencySupported = mWifiManager.isStaApConcurrencySupported();
// start local only hotspot.
TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
- if (isStaApConcurrencySupported) {
- assertTrue(mWifiManager.isWifiEnabled());
- } else {
- // no concurrency, wifi should be disabled.
- assertFalse(mWifiManager.isWifiEnabled());
+ try {
+ if (isStaApConcurrencySupported) {
+ assertTrue(mWifiManager.isWifiEnabled());
+ } else {
+ // no concurrency, wifi should be disabled.
+ assertFalse(mWifiManager.isWifiEnabled());
+ }
+ } finally {
+ // clean up local only hotspot no matter if assertion passed or failed
+ stopLocalOnlyHotspot(callback, true);
}
- stopLocalOnlyHotspot(callback, true);
assertTrue(mWifiManager.isWifiEnabled());
}
diff --git a/tools/cts-tradefed/res/config/cts-automated.xml b/tools/cts-tradefed/res/config/cts-automated.xml
index 150f8b9..80bcea7 100644
--- a/tools/cts-tradefed/res/config/cts-automated.xml
+++ b/tools/cts-tradefed/res/config/cts-automated.xml
@@ -15,6 +15,9 @@
-->
<configuration description="Runs CTS with common options set for an automated run on userdebug/eng builds">
+ <!-- template hook to allow users to attach additional target preparers -->
+ <template-include name="preparers" default="empty" />
+
<include name="cts" />
<option name="plan" value="cts" />
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
index e369dfa..0aad033 100644
--- a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
@@ -255,4 +255,7 @@
<!-- b/153032202: CtsSystemUiTestCases (10_r3 waiver) -->
<option name="compatibility:exclude-filter" value="CtsSystemUiTestCases android.systemui.cts.WindowInsetsBehaviorTests#swipeOutsideLimit_systemUiVisible_allEventsCanceled"/>
+
+ <!-- b/173662175: CtsStatsdHostTestCases due to insufficient processes running -->
+ <option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases android.cts.statsd.validation.ProcStatsValidationTests#testProcessStatePssValue"/>
</configuration>
diff --git a/tools/vm-tests-tf/TEST_MAPPING b/tools/vm-tests-tf/TEST_MAPPING
index a566107..4fbca3b 100644
--- a/tools/vm-tests-tf/TEST_MAPPING
+++ b/tools/vm-tests-tf/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "presubmit": [
+ "presubmit-large": [
{
"name": "vm-tests-tf"
}