Merge changes I452376eb,Ib864a279
* changes:
[RESTRICT AUTOMERGE] Support lifecycle CTS on non-fullscreen display
[RESTRICT AUTOMERGE] Do not enforce minimized dock feature to all devices
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/appsecurity/test-apps/AppDataIsolationTestApp/Android.bp b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/Android.bp
index b00dcc3..38185ee 100644
--- a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/Android.bp
@@ -16,8 +16,8 @@
name: "CtsAppDataIsolationAppA",
defaults: ["cts_support_defaults"],
srcs: ["common/src/**/*.java", "AppA/src/**/*.java", "AppA/aidl/**/*.aidl"],
- sdk_version: "current",
- static_libs: ["androidx.test.rules", "truth-prebuilt", "testng", "ub-uiautomator"],
+ sdk_version: "test_current",
+ static_libs: ["androidx.test.rules", "truth-prebuilt", "testng", "ub-uiautomator", "compatibility-device-util-axt"],
libs: ["android.test.base"],
// tag this module as a cts test artifact
test_suites: [
@@ -35,8 +35,8 @@
name: "CtsAppDataIsolationAppSharedA",
defaults: ["cts_support_defaults"],
srcs: ["common/src/**/*.java", "AppA/src/**/*.java", "AppA/aidl/**/*.aidl"],
- sdk_version: "current",
- static_libs: ["androidx.test.rules", "truth-prebuilt", "testng", "ub-uiautomator"],
+ sdk_version: "test_current",
+ static_libs: ["androidx.test.rules", "truth-prebuilt", "testng", "ub-uiautomator", "compatibility-device-util-axt"],
libs: ["android.test.base"],
// tag this module as a cts test artifact
test_suites: [
@@ -54,8 +54,8 @@
name: "CtsAppDataIsolationAppDirectBootA",
defaults: ["cts_support_defaults"],
srcs: ["common/src/**/*.java", "AppA/src/**/*.java", "AppA/aidl/**/*.aidl"],
- sdk_version: "current",
- static_libs: ["androidx.test.rules", "truth-prebuilt", "testng", "ub-uiautomator"],
+ sdk_version: "test_current",
+ static_libs: ["androidx.test.rules", "truth-prebuilt", "testng", "ub-uiautomator", "compatibility-device-util-axt"],
libs: ["android.test.base"],
// tag this module as a cts test artifact
test_suites: [
@@ -73,8 +73,8 @@
name: "CtsAppDataIsolationAppB",
defaults: ["cts_support_defaults"],
srcs: ["common/src/**/*.java", "AppB/src/**/*.java"],
- sdk_version: "current",
- static_libs: ["androidx.test.rules", "truth-prebuilt", "testng"],
+ sdk_version: "test_current",
+ static_libs: ["androidx.test.rules", "truth-prebuilt", "testng", "compatibility-device-util-axt"],
libs: ["android.test.base"],
// tag this module as a cts test artifact
test_suites: [
@@ -92,8 +92,8 @@
name: "CtsAppDataIsolationAppSharedB",
defaults: ["cts_support_defaults"],
srcs: ["common/src/**/*.java", "AppB/src/**/*.java"],
- sdk_version: "current",
- static_libs: ["androidx.test.rules", "truth-prebuilt", "testng"],
+ sdk_version: "test_current",
+ static_libs: ["androidx.test.rules", "truth-prebuilt", "testng", "compatibility-device-util-axt"],
libs: ["android.test.base"],
// tag this module as a cts test artifact
test_suites: [
diff --git a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java
index 4e8cadf..bd76272 100644
--- a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java
+++ b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java
@@ -16,6 +16,7 @@
package com.android.cts.appdataisolation.appa;
+import static com.android.cts.appdataisolation.common.FileUtils.APPB_PKG;
import static com.android.cts.appdataisolation.common.FileUtils.CE_DATA_FILE_NAME;
import static com.android.cts.appdataisolation.common.FileUtils.DE_DATA_FILE_NAME;
import static com.android.cts.appdataisolation.common.FileUtils.EXTERNAL_DATA_FILE_NAME;
@@ -26,6 +27,7 @@
import static com.android.cts.appdataisolation.common.FileUtils.assertFileDoesNotExist;
import static com.android.cts.appdataisolation.common.FileUtils.assertFileExists;
import static com.android.cts.appdataisolation.common.FileUtils.touchFile;
+import static com.android.cts.appdataisolation.common.UserUtils.getCurrentUserId;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -171,7 +173,8 @@
@Test
public void testAppACurProfileDataAccessible() {
- assertDirIsAccessible("/data/misc/profiles/cur/0/" + mContext.getPackageName());
+ assertDirIsAccessible("/data/misc/profiles/cur/"+ getCurrentUserId() + "/"
+ + mContext.getPackageName());
}
@Test
@@ -181,12 +184,12 @@
@Test
public void testCannotAccessAppBDataDir() throws Exception {
- ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(
- FileUtils.APPB_PKG,0);
+ ApplicationInfo applicationInfo = mContext.getPackageManager()
+ .getApplicationInfo(APPB_PKG, 0);
assertDirDoesNotExist(applicationInfo.dataDir);
assertDirDoesNotExist(applicationInfo.deviceProtectedDataDir);
- assertDirDoesNotExist("/data/data/" + FileUtils.APPB_PKG);
- assertDirDoesNotExist("/data/misc/profiles/cur/0/" + FileUtils.APPB_PKG);
+ assertDirDoesNotExist("/data/data/" + APPB_PKG);
+ assertDirDoesNotExist("/data/misc/profiles/cur/" + getCurrentUserId() + "/" + APPB_PKG);
assertDirIsNotAccessible("/data/misc/profiles/ref");
}
diff --git a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/IsolatedService.java b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/IsolatedService.java
index 5b1ec66..d209a42 100644
--- a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/IsolatedService.java
+++ b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/IsolatedService.java
@@ -18,6 +18,7 @@
import static com.android.cts.appdataisolation.common.FileUtils.assertDirDoesNotExist;
import static com.android.cts.appdataisolation.common.FileUtils.assertDirIsNotAccessible;
+import static com.android.cts.appdataisolation.common.UserUtils.getCurrentUserId;
import android.app.Service;
import android.content.Intent;
@@ -38,7 +39,10 @@
assertDirDoesNotExist(applicationInfo.dataDir);
assertDirDoesNotExist(applicationInfo.deviceProtectedDataDir);
assertDirDoesNotExist("/data/data/" + getPackageName());
- assertDirDoesNotExist("/data/misc/profiles/cur/0/" + getPackageName());
+
+ int currentUserId = getCurrentUserId();
+ assertDirDoesNotExist("/data/misc/profiles/cur/" + currentUserId + "/"
+ + getPackageName());
assertDirIsNotAccessible("/data/misc/profiles/ref");
assertDirDoesNotExist(FileUtils.replacePackageAWithPackageB(
@@ -46,14 +50,16 @@
assertDirDoesNotExist(FileUtils.replacePackageAWithPackageB(
applicationInfo.deviceProtectedDataDir));
assertDirDoesNotExist("/data/data/" + FileUtils.APPB_PKG);
- assertDirDoesNotExist("/data/misc/profiles/cur/0/" + FileUtils.APPB_PKG);
+ assertDirDoesNotExist("/data/misc/profiles/cur/" + currentUserId + "/"
+ + FileUtils.APPB_PKG);
assertDirDoesNotExist(FileUtils.replacePackageAWithNotInstalledPkg(
applicationInfo.dataDir));
assertDirDoesNotExist(FileUtils.replacePackageAWithNotInstalledPkg(
applicationInfo.deviceProtectedDataDir));
assertDirDoesNotExist("/data/data/" + FileUtils.NOT_INSTALLED_PKG);
- assertDirDoesNotExist("/data/misc/profiles/cur/0/" + FileUtils.NOT_INSTALLED_PKG);
+ assertDirDoesNotExist("/data/misc/profiles/cur/" + currentUserId + "/"
+ + FileUtils.NOT_INSTALLED_PKG);
} catch (Throwable e) {
throw new IllegalStateException(e.getMessage());
}
diff --git a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppB/src/com/android/cts/appdataisolation/appb/AppBTests.java b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppB/src/com/android/cts/appdataisolation/appb/AppBTests.java
index c1e3a53..9229fa6 100644
--- a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppB/src/com/android/cts/appdataisolation/appb/AppBTests.java
+++ b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppB/src/com/android/cts/appdataisolation/appb/AppBTests.java
@@ -20,6 +20,7 @@
import static com.android.cts.appdataisolation.common.FileUtils.assertDirIsAccessible;
import static com.android.cts.appdataisolation.common.FileUtils.assertDirIsNotAccessible;
import static com.android.cts.appdataisolation.common.FileUtils.assertFileIsAccessible;
+import static com.android.cts.appdataisolation.common.UserUtils.getCurrentUserId;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -48,7 +49,8 @@
assertDirDoesNotExist(replacePackageBWithPackageA(applicationInfo.dataDir));
assertDirDoesNotExist(replacePackageBWithPackageA(applicationInfo.deviceProtectedDataDir));
assertDirDoesNotExist("/data/data/" + APPA_PKG);
- assertDirDoesNotExist("/data/misc/profiles/cur/0/" + APPA_PKG);
+ assertDirDoesNotExist("/data/misc/profiles/cur/" + getCurrentUserId() + "/"
+ + APPA_PKG);
assertDirIsNotAccessible("/data/misc/profiles/ref");
}
@@ -58,7 +60,8 @@
assertDirIsAccessible(replacePackageBWithPackageA(applicationInfo.dataDir));
assertDirIsAccessible(replacePackageBWithPackageA(applicationInfo.deviceProtectedDataDir));
assertDirIsAccessible("/data/data/" + APPA_PKG);
- assertFileIsAccessible("/data/misc/profiles/cur/0/" + APPA_PKG + "/primary.prof");
+ assertFileIsAccessible("/data/misc/profiles/cur/" + getCurrentUserId() + "/"
+ + APPA_PKG + "/primary.prof");
assertDirIsNotAccessible("/data/misc/profiles/ref");
}
diff --git a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/common/src/com/android/cts/appdataisolation/common/UserUtils.java b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/common/src/com/android/cts/appdataisolation/common/UserUtils.java
new file mode 100644
index 0000000..ea741c3
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/common/src/com/android/cts/appdataisolation/common/UserUtils.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.appdataisolation.common;
+
+import android.app.ActivityManager;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+public final class UserUtils {
+
+ // Suppress default constructor
+ private UserUtils() {
+ throw new AssertionError();
+ }
+
+ public static int getCurrentUserId() {
+ return ShellIdentityUtils.invokeStaticMethodWithShellPermissions(
+ () -> ActivityManager.getCurrentUser());
+ }
+}
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/HdmiCecClientWrapper.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
index dacac2a..b57794a 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
@@ -389,7 +389,7 @@
}
} catch (Exception e) {
/* If cec-client is not running, do not throw an exception, just return. */
- CLog.w("Unable to close cec-client", e);
+ CLog.w(new Exception("Unable to close cec-client", e));
}
}
}
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/statsd/src/android/cts/statsd/metric/DurationMetricsTests.java b/hostsidetests/statsd/src/android/cts/statsd/metric/DurationMetricsTests.java
index 1a553b2..65cef95 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/metric/DurationMetricsTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/DurationMetricsTests.java
@@ -500,12 +500,10 @@
builder.addPredicate(predicateA);
FieldMatcher.Builder dimensionsBuilder = FieldMatcher.newBuilder()
- .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER);
- dimensionsBuilder.addChild(FieldMatcher.newBuilder()
- .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)
- .setPosition(Position.FIRST)
+ .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER);
+ dimensionsBuilder
.addChild(FieldMatcher.newBuilder().setField(
- AppBreadcrumbReported.LABEL_FIELD_NUMBER)));
+ AppBreadcrumbReported.LABEL_FIELD_NUMBER));
Predicate predicateB =
Predicate.newBuilder()
.setId(MetricsUtils.StringToId("Predicate_B"))
@@ -527,12 +525,9 @@
.setBucket(StatsdConfigProto.TimeUnit.CTS)
.setDimensionsInWhat(
FieldMatcher.newBuilder()
- .setField(Atom.BATTERY_SAVER_MODE_STATE_CHANGED_FIELD_NUMBER)
- .addChild(FieldMatcher.newBuilder()
- .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
- .setPosition(Position.FIRST)
- .addChild(FieldMatcher.newBuilder().setField(
- AppBreadcrumbReported.LABEL_FIELD_NUMBER)))));
+ .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
+ .addChild(FieldMatcher.newBuilder().setField(
+ AppBreadcrumbReported.LABEL_FIELD_NUMBER))));
// Upload config.
uploadConfig(builder);
@@ -554,10 +549,21 @@
assertThat(metricReport.hasDurationMetrics()).isTrue();
StatsLogReport.DurationMetricDataWrapper durationData
= metricReport.getDurationMetrics();
- assertThat(durationData.getDataCount()).isEqualTo(1);
- assertThat(durationData.getData(0).getBucketInfoCount()).isGreaterThan(1);
+ assertThat(durationData.getDataCount()).isEqualTo(2);
+ assertThat(durationData.getData(0).getBucketInfoCount()).isGreaterThan(3);
+ assertThat(durationData.getData(1).getBucketInfoCount()).isGreaterThan(3);
+ long totalDuration = 0;
for (DurationBucketInfo bucketInfo : durationData.getData(0).getBucketInfoList()) {
- assertThat(bucketInfo.getDurationNanos()).isIn(Range.openClosed(0L, (long)1e9));
+ assertThat(bucketInfo.getDurationNanos()).isIn(Range.openClosed(0L, (long) 1e9));
+ totalDuration += bucketInfo.getDurationNanos();
}
+ // Duration for both labels is expected to be 4s.
+ assertThat(totalDuration).isIn(Range.open((long) 3e9, (long) 8e9));
+ totalDuration = 0;
+ for (DurationBucketInfo bucketInfo : durationData.getData(1).getBucketInfoList()) {
+ assertThat(bucketInfo.getDurationNanos()).isIn(Range.openClosed(0L, (long) 1e9));
+ totalDuration += bucketInfo.getDurationNanos();
+ }
+ assertThat(totalDuration).isIn(Range.open((long) 3e9, (long) 8e9));
}
}
diff --git a/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 3fcd640..0ac11b7 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
@@ -600,8 +600,8 @@
// Start resizeable activity that handles configuration changes.
separateTestJournal();
- launchActivity(TEST_ACTIVITY);
- launchActivity(RESIZEABLE_ACTIVITY);
+ launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
+ launchActivity(RESIZEABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
mWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
final int displayId = mWmState.getDisplayByActivity(RESIZEABLE_ACTIVITY);
@@ -647,8 +647,10 @@
TestActivitySession<ConfigChangeHandlingActivity> activitySession
= createManagedTestActivitySession();
- activitySession.launchTestActivityOnDisplaySync(ConfigChangeHandlingActivity.class,
- Display.DEFAULT_DISPLAY);
+ activitySession.launchTestActivityOnDisplaySync(
+ ConfigChangeHandlingActivity.class,
+ Display.DEFAULT_DISPLAY,
+ WINDOWING_MODE_FULLSCREEN);
final ConfigChangeHandlingActivity activity = activitySession.getActivity();
VirtualDisplaySession virtualDisplaySession = createManagedVirtualDisplaySession();
@@ -830,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/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 55008c7..587c538 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -26,6 +26,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.ACTION_MAIN;
import static android.content.Intent.CATEGORY_HOME;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
@@ -401,27 +402,45 @@
launchTestActivityOnDisplaySync(new Intent(mContext, activityClass), displayId);
}
+ void launchTestActivityOnDisplaySync(
+ Class<T> activityClass, int displayId, int windowingMode) {
+ launchTestActivityOnDisplaySync(
+ new Intent(mContext, activityClass), displayId, windowingMode);
+ }
+
void launchTestActivityOnDisplaySync(Intent intent, int displayId) {
- SystemUtil.runWithShellPermissionIdentity(() -> {
- mTestActivity = launchActivityOnDisplay(intent, displayId);
- // Check activity is launched and resumed.
- final ComponentName testActivityName = mTestActivity.getComponentName();
- waitAndAssertTopResumedActivity(testActivityName, displayId,
- "Activity must be resumed");
- });
+ launchTestActivityOnDisplaySync(intent, displayId, WINDOWING_MODE_UNDEFINED);
+ }
+
+ void launchTestActivityOnDisplaySync(Intent intent, int displayId, int windowingMode) {
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> {
+ mTestActivity = launchActivityOnDisplay(intent, displayId, windowingMode);
+ // Check activity is launched and resumed.
+ final ComponentName testActivityName = mTestActivity.getComponentName();
+ waitAndAssertTopResumedActivity(
+ testActivityName, displayId, "Activity must be resumed");
+ });
}
void launchTestActivityOnDisplay(Class<T> activityClass, int displayId) {
- SystemUtil.runWithShellPermissionIdentity(() -> {
- mTestActivity = launchActivityOnDisplay(new Intent(mContext, activityClass)
- .addFlags(FLAG_ACTIVITY_NEW_TASK), displayId);
- assertNotNull(mTestActivity);
- });
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> {
+ mTestActivity =
+ launchActivityOnDisplay(
+ new Intent(mContext, activityClass)
+ .addFlags(FLAG_ACTIVITY_NEW_TASK),
+ displayId,
+ WINDOWING_MODE_UNDEFINED);
+ assertNotNull(mTestActivity);
+ });
}
- private T launchActivityOnDisplay(Intent intent, int displayId) {
- final Bundle bundle = ActivityOptions.makeBasic()
- .setLaunchDisplayId(displayId).toBundle();
+ private T launchActivityOnDisplay(Intent intent, int displayId, int windowingMode) {
+ final ActivityOptions launchOptions = ActivityOptions.makeBasic();
+ launchOptions.setLaunchDisplayId(displayId);
+ launchOptions.setLaunchWindowingMode(windowingMode);
+ final Bundle bundle = launchOptions.toBundle();
final ActivityMonitor monitor = mInstrumentation.addMonitor((String) null, null, false);
mContext.startActivity(intent.addFlags(FLAG_ACTIVITY_NEW_TASK), bundle);
// Wait for activity launch with timeout.
diff --git a/tests/media/jni/NativeCodecDecoderTest.cpp b/tests/media/jni/NativeCodecDecoderTest.cpp
index 754ccb3..0b17d7e 100644
--- a/tests/media/jni/NativeCodecDecoderTest.cpp
+++ b/tests/media/jni/NativeCodecDecoderTest.cpp
@@ -228,8 +228,18 @@
if (mSaveToMem) {
size_t buffSize;
uint8_t* buf = AMediaCodec_getOutputBuffer(mCodec, bufferIndex, &buffSize);
- if (mIsAudio) mOutputBuff->saveToMemory(buf, info);
- mOutputBuff->updateChecksum(buf, info);
+ if (mIsAudio) {
+ mOutputBuff->saveToMemory(buf, info);
+ mOutputBuff->updateChecksum(buf, info);
+ } else {
+ AMediaFormat* format =
+ mIsCodecInAsyncMode ? mAsyncHandle.getOutputFormat() : mOutFormat;
+ int32_t width, height, stride;
+ AMediaFormat_getInt32(format, "width", &width);
+ AMediaFormat_getInt32(format, "height", &height);
+ AMediaFormat_getInt32(format, "stride", &stride);
+ mOutputBuff->updateChecksum(buf, info, width, height, stride);
+ }
}
mOutputBuff->saveOutPTS(info->presentationTimeUs);
mOutputCount++;
@@ -360,17 +370,17 @@
if (validateFormat) {
if (mIsCodecInAsyncMode ? !mAsyncHandle.hasOutputFormatChanged()
: !mSignalledOutFormatChanged) {
- ALOGE(log, "not received format change");
+ ALOGE("%s%s", log, "not received format change");
isPass = false;
} else if (!isFormatSimilar(mInpDecFormat, mIsCodecInAsyncMode
? mAsyncHandle.getOutputFormat()
: mOutFormat)) {
- ALOGE(log, "configured format and output format are not similar");
+ ALOGE("%s%s", log, "configured format and output format are not similar");
isPass = false;
}
}
if (checksum != ref->getChecksum()) {
- ALOGE(log, "sdk output and ndk output differ");
+ ALOGE("%s%s", log, "sdk output and ndk output differ");
isPass = false;
}
loopCounter++;
@@ -500,12 +510,12 @@
if (validateFormat) {
if (mIsCodecInAsyncMode ? !mAsyncHandle.hasOutputFormatChanged()
: !mSignalledOutFormatChanged) {
- ALOGE(log, "not received format change");
+ ALOGE("%s%s", log, "not received format change");
isPass = false;
} else if (!isFormatSimilar(mInpDecFormat, mIsCodecInAsyncMode
? mAsyncHandle.getOutputFormat()
: mOutFormat)) {
- ALOGE(log, "configured format and output format are not similar");
+ ALOGE("%s%s", log, "configured format and output format are not similar");
isPass = false;
}
}
@@ -632,12 +642,12 @@
if (validateFormat) {
if (mIsCodecInAsyncMode ? !mAsyncHandle.hasOutputFormatChanged()
: !mSignalledOutFormatChanged) {
- ALOGE(log, "not received format change");
+ ALOGE("%s%s", log, "not received format change");
isPass = false;
} else if (!isFormatSimilar(mInpDecFormat,
mIsCodecInAsyncMode ? mAsyncHandle.getOutputFormat()
: mOutFormat)) {
- ALOGE(log, "configured format and output format are not similar");
+ ALOGE("%s%s", log, "configured format and output format are not similar");
isPass = false;
}
}
diff --git a/tests/media/jni/NativeCodecTestBase.cpp b/tests/media/jni/NativeCodecTestBase.cpp
index 4e13e9c..d84e4d1 100644
--- a/tests/media/jni/NativeCodecTestBase.cpp
+++ b/tests/media/jni/NativeCodecTestBase.cpp
@@ -204,6 +204,31 @@
return result;
}
+void OutputManager::updateChecksum(
+ uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height, int stride) {
+ uint8_t flattenInfo[16];
+ int pos = 0;
+ if (width <= 0 || height <= 0 || stride <= 0) {
+ flattenField<int32_t>(flattenInfo, &pos, info->size);
+ }
+ flattenField<int32_t>(flattenInfo, &pos,
+ info->flags & ~AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
+ flattenField<int64_t>(flattenInfo, &pos, info->presentationTimeUs);
+ crc32value = crc32(crc32value, flattenInfo, pos);
+ if (width > 0 && height > 0 && stride > 0) {
+ // Only checksum Y plane
+ std::vector<uint8_t> tmp(width * height, 0u);
+ size_t offset = 0;
+ for (int i = 0; i < height; ++i) {
+ memcpy(tmp.data() + (i * width), buf + offset, width);
+ offset += stride;
+ }
+ crc32value = crc32(crc32value, tmp.data(), width * height);
+ } else {
+ crc32value = crc32(crc32value, buf, info->size);
+ }
+}
+
bool OutputManager::isOutPtsListIdenticalToInpPtsList(bool requireSorting) {
bool isEqual = true;
std::sort(inpPtsArray.begin(), inpPtsArray.end());
diff --git a/tests/media/jni/NativeCodecTestBase.h b/tests/media/jni/NativeCodecTestBase.h
index 87a46f9..4282e4a 100644
--- a/tests/media/jni/NativeCodecTestBase.h
+++ b/tests/media/jni/NativeCodecTestBase.h
@@ -103,18 +103,13 @@
bool isPtsStrictlyIncreasing(int64_t lastPts);
bool isOutPtsListIdenticalToInpPtsList(bool requireSorting);
void saveToMemory(uint8_t* buf, AMediaCodecBufferInfo* info) {
- memory.insert(memory.end(), buf + info->offset, buf + info->size);
+ memory.insert(memory.end(), buf, buf + info->size);
}
void updateChecksum(uint8_t* buf, AMediaCodecBufferInfo* info) {
- crc32value = crc32(crc32value, buf + info->offset, info->size);
- uint8_t flattenInfo[16];
- int pos = 0;
- flattenField<int32_t>(flattenInfo, &pos, info->size);
- flattenField<int32_t>(flattenInfo, &pos,
- info->flags & ~AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
- flattenField<int64_t>(flattenInfo, &pos, info->presentationTimeUs);
- crc32value = crc32(crc32value, flattenInfo, sizeof(flattenInfo));
+ updateChecksum(buf, info, 0, 0, 0);
}
+ void updateChecksum(
+ uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height, int stride);
uLong getChecksum() { return crc32value; }
void reset() {
inpPtsArray.clear();
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/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index 1350d6f..e7527bb7 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -283,11 +283,37 @@
}
void checksum(ByteBuffer buf, int size) {
+ checksum(buf, size, 0, 0, 0);
+ }
+
+ void checksum(ByteBuffer buf, int size, int width, int height, int stride) {
int cap = buf.capacity();
assertTrue("checksum() params are invalid: size = " + size + " cap = " + cap,
size > 0 && size <= cap);
if (buf.hasArray()) {
- mCrc32UsingBuffer.update(buf.array(), buf.position() + buf.arrayOffset(), size);
+ if (width > 0 && height > 0 && stride > 0) {
+ int offset = buf.position() + buf.arrayOffset();
+ byte[] bb = new byte[width * height];
+ for (int i = 0; i < height; ++i) {
+ System.arraycopy(buf.array(), offset, bb, i * width, width);
+ offset += stride;
+ }
+ mCrc32UsingBuffer.update(bb, 0, width * height);
+ } else {
+ mCrc32UsingBuffer.update(buf.array(), buf.position() + buf.arrayOffset(), size);
+ }
+ } else if (width > 0 && height > 0 && stride > 0) {
+ // Checksum only the Y plane
+ int pos = buf.position();
+ int offset = pos;
+ byte[] bb = new byte[width * height];
+ for (int i = 0; i < height; ++i) {
+ buf.position(offset);
+ buf.get(bb, i * width, width);
+ offset += stride;
+ }
+ mCrc32UsingBuffer.update(bb, 0, width * height);
+ buf.position(pos);
} else {
int pos = buf.position();
final int rdsize = Math.min(4096, size);
@@ -1039,8 +1065,11 @@
return format.containsKey("csd-0");
}
- void flattenBufferInfo(MediaCodec.BufferInfo info) {
- flatBuffer.putInt(info.size).putInt(info.flags & ~MediaCodec.BUFFER_FLAG_END_OF_STREAM)
+ void flattenBufferInfo(MediaCodec.BufferInfo info, boolean isAudio) {
+ if (isAudio) {
+ flatBuffer.putInt(info.size);
+ }
+ flatBuffer.putInt(info.flags & ~MediaCodec.BUFFER_FLAG_END_OF_STREAM)
.putLong(info.presentationTimeUs);
flatBuffer.flip();
}
@@ -1111,14 +1140,20 @@
void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
if (info.size > 0 && mSaveToMem) {
ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
- mOutputBuff.checksum(buf, info.size);
- flattenBufferInfo(info);
+ flattenBufferInfo(info, mIsAudio);
mOutputBuff.checksum(flatBuffer, flatBuffer.limit());
if (mIsAudio) {
+ mOutputBuff.checksum(buf, info.size);
mOutputBuff.saveToMemory(buf, info);
} else {
// tests both getOutputImage and getOutputBuffer. Can do time division
// multiplexing but lets allow it for now
+ MediaFormat format = mCodec.getOutputFormat();
+ int width = format.getInteger(MediaFormat.KEY_WIDTH);
+ int height = format.getInteger(MediaFormat.KEY_HEIGHT);
+ int stride = format.getInteger(MediaFormat.KEY_STRIDE);
+ mOutputBuff.checksum(buf, info.size, width, height, stride);
+
Image img = mCodec.getOutputImage(bufferIndex);
assertTrue(img != null);
mOutputBuff.checksum(img);
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/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ITest.aidl
index dad0716..7cd58e7 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ITest.aidl
@@ -81,6 +81,7 @@
void RepeatExtendableParcelable(in test_package.ExtendableParcelable input, out test_package.ExtendableParcelable output);
test_package.SimpleUnion RepeatSimpleUnion(in test_package.SimpleUnion u);
IBinder getICompatTest();
+ void RepeatExtendableParcelableWithoutExtension(in test_package.ExtendableParcelable input, out test_package.ExtendableParcelable output);
const int kZero = 0;
const int kOne = 1;
const int kOnes = -1;
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/itest_impl.h b/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
index 413e190..ae7e435 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
@@ -455,6 +455,7 @@
::ndk::ScopedAStatus RepeatExtendableParcelable(
const ::aidl::test_package::ExtendableParcelable& in_input,
::aidl::test_package::ExtendableParcelable* out_output) {
+ RepeatExtendableParcelableWithoutExtension(in_input, out_output);
std::unique_ptr<MyExt> ext = in_input.ext.getParcelable<MyExt>();
MyExt ext2;
ext2.a = ext->a;
@@ -463,6 +464,15 @@
return ::ndk::ScopedAStatus(AStatus_newOk());
}
+ ::ndk::ScopedAStatus RepeatExtendableParcelableWithoutExtension(
+ const ::aidl::test_package::ExtendableParcelable& in_input,
+ ::aidl::test_package::ExtendableParcelable* out_output) {
+ out_output->a = in_input.a;
+ out_output->b = in_input.b;
+ out_output->c = in_input.c;
+ return ::ndk::ScopedAStatus(AStatus_newOk());
+ }
+
::ndk::ScopedAStatus RepeatSimpleUnion(const SimpleUnion& in_u,
SimpleUnion* _aidl_return) override {
*_aidl_return = in_u;
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 10d6b65..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) {
@@ -958,7 +982,7 @@
}
TEST_P(NdkBinderTest_Aidl, ParcelableHolderCommunicationTest) {
ExtendableParcelable ep;
-
+ ep.c = 42L;
MyExt myext1;
myext1.a = 42;
myext1.b = "mystr";
@@ -967,11 +991,21 @@
ExtendableParcelable ep2;
EXPECT_OK(iface->RepeatExtendableParcelable(ep, &ep2));
std::unique_ptr<MyExt> myext2 = ep2.ext.getParcelable<MyExt>();
+ EXPECT_EQ(42L, ep2.c);
EXPECT_TRUE(myext2);
EXPECT_EQ(42, myext2->a);
EXPECT_EQ("mystr", myext2->b);
}
+TEST_P(NdkBinderTest_Aidl, EmptyParcelableHolderCommunicationTest) {
+ ExtendableParcelable ep;
+ ExtendableParcelable ep2;
+ ep.c = 42L;
+ EXPECT_OK(iface->RepeatExtendableParcelableWithoutExtension(ep, &ep2));
+
+ EXPECT_EQ(42L, ep2.c);
+}
+
std::shared_ptr<ITest> getProxyLocalService() {
std::shared_ptr<MyTest> test = SharedRefBase::make<MyTest>();
SpAIBinder binder = test->asBinder();
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/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
index d5d112b..084c7d7 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
@@ -130,4 +130,6 @@
SimpleUnion RepeatSimpleUnion(in SimpleUnion u);
IBinder getICompatTest();
+
+ void RepeatExtendableParcelableWithoutExtension(in ExtendableParcelable input, out ExtendableParcelable output);
}
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 e56c3c0..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
@@ -691,7 +696,7 @@
@Test
public void testParcelableHolder() throws RemoteException {
ExtendableParcelable ep = new ExtendableParcelable();
-
+ ep.c = 42L;
MyExt myext1 = new MyExt();
myext1.a = 42;
myext1.b = "mystr";
@@ -700,12 +705,22 @@
ExtendableParcelable ep2 = new ExtendableParcelable();
mInterface.RepeatExtendableParcelable(ep, ep2);
MyExt myext2 = ep2.ext.getParcelable(MyExt.class);
+ assertEquals(42L, ep2.c);
assertNotEquals(null, myext2);
assertEquals(42, myext2.a);
assertEquals("mystr", myext2.b);
}
@Test
+ public void testEmptyParcelableHolder() throws RemoteException {
+ ExtendableParcelable ep = new ExtendableParcelable();
+ ep.c = 42L;
+ ExtendableParcelable ep2 = new ExtendableParcelable();
+ mInterface.RepeatExtendableParcelableWithoutExtension(ep, ep2);
+ assertEquals(42L, ep2.c);
+ }
+
+ @Test
public void testRepeatSimpleUnion() throws RemoteException {
final int[] intArray = { 1, 2, 3 };
SimpleUnion origin = SimpleUnion.b(intArray);
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java b/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
index c65a99a..d16e8a7 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
@@ -398,6 +398,7 @@
@Override
public void RepeatExtendableParcelable(ExtendableParcelable in, ExtendableParcelable out) {
+ RepeatExtendableParcelableWithoutExtension(in, out);
MyExt ext = in.ext.getParcelable(MyExt.class);
MyExt ext2 = new MyExt();
ext2.a = ext.a;
@@ -405,6 +406,13 @@
out.ext.setParcelable(ext2);
}
+ @Override
+ public void RepeatExtendableParcelableWithoutExtension(ExtendableParcelable in, ExtendableParcelable out) {
+ out.a = in.a;
+ out.b = in.b;
+ out.c = in.c;
+ }
+
public SimpleUnion RepeatSimpleUnion(SimpleUnion in_u) {
return in_u;
}
diff --git a/tests/tests/contactsprovider/src/android/provider/cts/contacts/CallLogProviderTest.java b/tests/tests/contactsprovider/src/android/provider/cts/contacts/CallLogProviderTest.java
new file mode 100644
index 0000000..f91015a
--- /dev/null
+++ b/tests/tests/contactsprovider/src/android/provider/cts/contacts/CallLogProviderTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.provider.cts.contacts;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.CallLog;
+import android.provider.CallLog.Calls;
+import android.test.InstrumentationTestCase;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class CallLogProviderTest extends InstrumentationTestCase {
+ private ContentResolver mContentResolver;
+ private ContentProviderClient mProvider;
+
+ private static final String TEST_NUMBER = "5551234";
+ private static final int TIME_OUT_MILLIS = 5000;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContentResolver = getInstrumentation().getTargetContext().getContentResolver();
+ mProvider = mContentResolver.acquireContentProviderClient(CallLog.AUTHORITY);
+ }
+
+ public void testNoSubqueries() throws Exception {
+ // Add a single call just to make sure the call log has something inside
+ ContentValues values = new ContentValues();
+ values.put(CallLog.Calls.NUMBER, TEST_NUMBER);
+ values.put(CallLog.Calls.TYPE, Calls.OUTGOING_TYPE);
+ values.put(CallLog.Calls.DATE, Long.valueOf(0 /*start time*/));
+ values.put(CallLog.Calls.DURATION, Long.valueOf(5 /*call duration*/));
+
+ mContentResolver.insert(CallLog.Calls.CONTENT_URI, values);
+
+ // Attempt to do a query that contains a subquery -- this should fail since this test does
+ // not have READ_VOICEMAIL.
+ try {
+ Cursor c = mProvider.query(Calls.CONTENT_URI, null, CallLog.Calls.NUMBER + " = ?",
+ new String[]{TEST_NUMBER},
+ "date DESC LIMIT (SELECT count(*) + 1 FROM calls WHERE type = 4");
+ assertEquals(0, c.getCount());
+ } catch (IllegalArgumentException e) {
+ // expected/tolerated
+ }
+ }
+
+ public void testUpdate() throws Exception {
+ // Add a single call just to make sure the call log has something inside
+ ContentValues values = new ContentValues();
+ values.put(CallLog.Calls.NUMBER, TEST_NUMBER);
+ values.put(CallLog.Calls.TYPE, Calls.OUTGOING_TYPE);
+ values.put(CallLog.Calls.DATE, Long.valueOf(0 /*start time*/));
+ values.put(CallLog.Calls.DURATION, Long.valueOf(5 /*call duration*/));
+ Uri uri = mContentResolver.insert(CallLog.Calls.CONTENT_URI, values);
+
+ CountDownLatch changeLatch = new CountDownLatch(1);
+ mContentResolver.registerContentObserver(
+ CallLog.Calls.CONTENT_URI, true,
+ new ContentObserver(null /* handler */) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ mContentResolver.unregisterContentObserver(this);
+ changeLatch.countDown();
+ super.onChange(selfChange);
+ }
+ });
+
+ // Update it!
+ values.put(CallLog.Calls.DURATION, Long.valueOf(6 /*call duration*/));
+ int numUpdated = mContentResolver.update(uri, values, null, null);
+ assertEquals(1, numUpdated);
+ try {
+ assertTrue(changeLatch.await(TIME_OUT_MILLIS, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ fail("Expected update notification.");
+ }
+ }
+
+ public void testDelete() throws Exception {
+ // Add a single call just to make sure the call log has something inside
+ ContentValues values = new ContentValues();
+ values.put(CallLog.Calls.NUMBER, TEST_NUMBER);
+ values.put(CallLog.Calls.TYPE, Calls.OUTGOING_TYPE);
+ values.put(CallLog.Calls.DATE, Long.valueOf(0 /*start time*/));
+ values.put(CallLog.Calls.DURATION, Long.valueOf(5 /*call duration*/));
+ Uri uri = mContentResolver.insert(CallLog.Calls.CONTENT_URI, values);
+
+ CountDownLatch changeLatch = new CountDownLatch(1);
+ mContentResolver.registerContentObserver(
+ CallLog.Calls.CONTENT_URI, true,
+ new ContentObserver(null /* handler */) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ mContentResolver.unregisterContentObserver(this);
+ changeLatch.countDown();
+ super.onChange(selfChange);
+ }
+ });
+
+ // Delete it.
+ // Yuck, you can't just delete using the uri passed in; you need to build a where clause.
+ int count = mContentResolver.delete(Calls.CONTENT_URI, Calls._ID + "="
+ + ContentUris.parseId(uri), null);
+ assertEquals(1, count);
+ try {
+ assertTrue(changeLatch.await(TIME_OUT_MILLIS, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ fail("Expected update notification.");
+ }
+ }
+}
diff --git a/tests/tests/display/src/android/display/cts/BrightnessTest.java b/tests/tests/display/src/android/display/cts/BrightnessTest.java
index 7bbe88d..0ec6a3d 100644
--- a/tests/tests/display/src/android/display/cts/BrightnessTest.java
+++ b/tests/tests/display/src/android/display/cts/BrightnessTest.java
@@ -36,6 +36,7 @@
import android.hardware.display.DisplayManager;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
+import android.platform.test.annotations.AppModeFull;
import android.provider.Settings;
import android.util.Pair;
@@ -56,6 +57,7 @@
import java.util.Map;
import java.util.Scanner;
+@AppModeFull
@MediumTest
@RunWith(AndroidJUnit4.class)
public class BrightnessTest {
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/AudioAttributesTest.java b/tests/tests/media/src/android/media/cts/AudioAttributesTest.java
index e44dc3a..f4e86eb 100644
--- a/tests/tests/media/src/android/media/cts/AudioAttributesTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioAttributesTest.java
@@ -19,6 +19,7 @@
import static org.testng.Assert.assertThrows;
import static org.testng.Assert.expectThrows;
+import android.audio.policy.configuration.V7_0.AudioUsage;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.os.Parcel;
@@ -200,6 +201,27 @@
assertEquals(attr1, attr2);
}
+ // -----------------------------------------------------------------
+ // audio_policy_configuration.xsd converter tests
+ // ----------------------------------
+ public void testXsdStringToUsage_returnsCorrectUsage() {
+ int usage = AudioAttributes.xsdStringToUsage(AudioUsage.AUDIO_USAGE_MEDIA.toString());
+
+ assertEquals(AudioAttributes.USAGE_MEDIA, usage);
+ }
+
+ public void testXsdStringToUsage_withUnsupportedString_returnsUnknownUsage() {
+ int usage = AudioAttributes.xsdStringToUsage("not a usage");
+
+ assertEquals(AudioAttributes.USAGE_UNKNOWN, usage);
+ }
+
+ public void testUsageToXsdString_returnsCorrectString() {
+ String xsdUsage = AudioAttributes.usageToXsdString(AudioAttributes.USAGE_MEDIA);
+
+ assertEquals(AudioUsage.AUDIO_USAGE_MEDIA.toString(), xsdUsage);
+ }
+
// -------------------------------------------------------------------
// Reflection helpers for accessing system usage methods and fields
// -------------------------------------------------------------------
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/RcsUceAdapterTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
index dc4045c..dda4f82 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
@@ -258,7 +258,7 @@
@Override
public void onComplete() {}
@Override
- public void onError(int errorCode) {}
+ public void onError(int errorCode, long retryAfterMilliseconds) {}
});
fail("requestCapabilities should require READ_PRIVILEGED_PHONE_STATE.");
} catch (SecurityException e) {
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/widget/src/android/widget/cts/SpinnerTest.java b/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
index 3c4192c..c07d6f3 100644
--- a/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
@@ -67,6 +67,7 @@
private Activity mActivity;
private Spinner mSpinnerDialogMode;
private Spinner mSpinnerDropdownMode;
+ private static final int SPINNER_HAS_FOCUS_DELAY_MS = 500;
@Rule
public ActivityTestRule<SpinnerCtsActivity> mActivityRule =
@@ -402,7 +403,7 @@
TestUtils.assertAllPixelsOfColor("Drop down should be blue", dropDownBackground,
dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
false, Color.BLUE, 1, true);
-
+ waitForHasFocusMS(SPINNER_HAS_FOCUS_DELAY_MS);
// Dismiss the popup with the emulated back key
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
// Verify that we're not showing the popup
@@ -461,4 +462,13 @@
// And test that getPopupBackground returns null
assertNull(mSpinnerDialogMode.getPopupBackground());
}
+
+ private void waitForHasFocusMS(int milliseconds) {
+ try {
+ Thread.sleep(milliseconds);
+ } catch (InterruptedException e) {
+ fail("unexpected InterruptedException : "+ e);
+ }
+
+ }
}
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-csi-cf.xml b/tools/cts-tradefed/res/config/cts-on-csi-cf.xml
index 787ab93..3d5ecaa 100644
--- a/tools/cts-tradefed/res/config/cts-on-csi-cf.xml
+++ b/tools/cts-tradefed/res/config/cts-on-csi-cf.xml
@@ -20,6 +20,45 @@
<!-- Troublesome tests that often crash the system -->
<option name="compatibility:exclude-filter" value="CtsPackageInstallTestCases android.packageinstaller.install.cts.IntentTest#packageNotInstalledSecureFrp" />
- <option name="compatibility:exclude-filter" value="CtsPermission3TestCases android.permission3.cts.PermissionReviewTest#testReviewPermissionWhenServiceIsBound" />
+ <option name="compatibility:exclude-filter" value="CtsPermission3TestCases android.permission3.cts.PermissionReviewTest" />
+
+ <!-- CTS modules that fail to run to complete on Android S CSI/CF -->
+ <option name="compatibility:exclude-filter" value="CtsAppEnumerationTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAppTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAutoFillServiceTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsCameraTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsDeqpTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsFragmentTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsGraphicsTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsIcu4cTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsIdentityTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsInputMethodTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJobSchedulerTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsKeystoreTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaBitstreamsTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaV2TestCases" />
+ <option name="compatibility:exclude-filter" value="CtsNativeHardwareTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsOpenGLTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsOsTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsPermissionTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsPreferenceTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsResourcesLoaderTests" />
+ <option name="compatibility:exclude-filter" value="CtsRoleTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsSkQPTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsStatsdAtomHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsSyncManagerTestsCases" />
+ <option name="compatibility:exclude-filter" value="CtsTelephonyTestCasesPermissionReadPhoneState" />
+ <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsViewTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsWidgetTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases" />
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
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/cts-tradefed/res/config/cts-unit-tests.xml b/tools/cts-tradefed/res/config/cts-unit-tests.xml
index a80a244..9f30011 100644
--- a/tools/cts-tradefed/res/config/cts-unit-tests.xml
+++ b/tools/cts-tradefed/res/config/cts-unit-tests.xml
@@ -17,9 +17,6 @@
<option name="null-device" value="true" />
<build_provider class="com.android.tradefed.build.StubBuildProvider" />
<test class="com.android.tradefed.testtype.HostTest" >
- <option name="class" value="com.android.compatibility.common.tradefed.UnitTests" />
- <option name="class" value="com.android.compatibility.common.util.HostUnitTests" />
- <option name="class" value="com.android.compatibility.common.util.UnitTests" />
<option name="class" value="com.android.compatibility.tradefed.CtsUnitTests" />
<option name="class" value="com.drawelements.deqp.runner.DeqpTestRunnerTest" />
</test>
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java
index 7701279..c4055ef 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java
@@ -56,8 +56,7 @@
// Temporarily exclude some Tradefed jar while we work on unbundling them.
private static final Set<String> IGNORE_JARS =
ImmutableSet.of("tradefed-no-fwk.jar", "tradefed-test-framework.jar",
- "compatibility-tradefed-tests.jar",
- "compatibility-common-util-tests.jar", "compatibility-host-util-tests.jar");
+ "compatibility-tradefed.jar");
/** test if there are duplicate files in different jars. */
@Test
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"
}