Merge "cts: Add Khaje target to whitelist in the CTS test case"
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
deleted file mode 100644
index 1795c46..0000000
--- a/apps/CtsVerifier/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-#
-# Creates a "cts-verifier" directory that will contain:
-#
-# 1. Out directory with a "android-cts-verifier" containing the CTS Verifier
-# and other binaries it needs.
-#
-# 2. Zipped version of the android-cts-verifier directory to be included with
-# the build distribution.
-#
-cts-dir := $(HOST_OUT)/cts-verifier
-verifier-dir-name := android-cts-verifier
-verifier-dir := $(cts-dir)/$(verifier-dir-name)
-verifier-zip-name := $(verifier-dir-name).zip
-verifier-zip := $(cts-dir)/$(verifier-zip-name)
-
-cts : $(verifier-zip)
-$(verifier-zip): PRIVATE_DIR := $(cts-dir)
-$(verifier-zip): $(SOONG_ANDROID_CTS_VERIFIER_ZIP)
- rm -rf $(PRIVATE_DIR)
- mkdir -p $(PRIVATE_DIR)
- unzip -q -d $(PRIVATE_DIR) $<
- $(copy-file-to-target)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/build/Android.mk b/build/Android.mk
deleted file mode 100644
index 3c065c8..0000000
--- a/build/Android.mk
+++ /dev/null
@@ -1,160 +0,0 @@
-#
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# Makefile for producing CTS coverage reports.
-# Run "make cts-test-coverage" in the $ANDROID_BUILD_TOP directory.
-
-cts_api_coverage_exe := $(HOST_OUT_EXECUTABLES)/cts-api-coverage
-dexdeps_exe := $(HOST_OUT_EXECUTABLES)/dexdeps
-
-coverage_out := $(HOST_OUT)/cts-api-coverage
-
-api_xml_description := $(TARGET_OUT_COMMON_INTERMEDIATES)/api.xml
-
-napi_text_description := cts/tools/cts-api-coverage/etc/ndk-api.xml
-napi_xml_description := $(coverage_out)/ndk-api.xml
-$(napi_xml_description) : $(napi_text_description) $(ACP)
- $(hide) echo "Preparing NDK API XML: $@"
- $(hide) mkdir -p $(dir $@)
- $(hide) $(ACP) $< $@
-
-system_api_xml_description := $(TARGET_OUT_COMMON_INTERMEDIATES)/system-api.xml
-
-cts-test-coverage-report := $(coverage_out)/test-coverage.html
-cts-system-api-coverage-report := $(coverage_out)/system-api-coverage.html
-cts-system-api-xml-coverage-report := $(coverage_out)/system-api-coverage.xml
-cts-verifier-coverage-report := $(coverage_out)/verifier-coverage.html
-cts-combined-coverage-report := $(coverage_out)/combined-coverage.html
-cts-combined-xml-coverage-report := $(coverage_out)/combined-coverage.xml
-
-cts_api_coverage_dependencies := $(cts_api_coverage_exe) $(dexdeps_exe) $(api_xml_description) $(napi_xml_description)
-cts_system_api_coverage_dependencies := $(cts_api_coverage_exe) $(dexdeps_exe) $(system_api_xml_description)
-
-android_cts_zip := $(HOST_OUT)/cts/android-cts.zip
-cts_verifier_apk := $(call intermediates-dir-for,APPS,CtsVerifier)/package.apk
-
-$(cts-test-coverage-report): PRIVATE_TEST_CASES := $(COMPATIBILITY_TESTCASES_OUT_cts)
-$(cts-test-coverage-report): PRIVATE_CTS_API_COVERAGE_EXE := $(cts_api_coverage_exe)
-$(cts-test-coverage-report): PRIVATE_DEXDEPS_EXE := $(dexdeps_exe)
-$(cts-test-coverage-report): PRIVATE_API_XML_DESC := $(api_xml_description)
-$(cts-test-coverage-report): PRIVATE_NAPI_XML_DESC := $(napi_xml_description)
-$(cts-test-coverage-report) : $(android_cts_zip) $(cts_api_coverage_dependencies) | $(ACP)
- $(call generate-coverage-report-cts,"CTS Tests API-NDK Coverage Report",\
- $(PRIVATE_TEST_CASES),html)
-
-$(cts-system-api-coverage-report): PRIVATE_TEST_CASES := $(COMPATIBILITY_TESTCASES_OUT_cts)
-$(cts-system-api-coverage-report): PRIVATE_CTS_API_COVERAGE_EXE := $(cts_api_coverage_exe)
-$(cts-system-api-coverage-report): PRIVATE_DEXDEPS_EXE := $(dexdeps_exe)
-$(cts-system-api-coverage-report): PRIVATE_API_XML_DESC := $(system_api_xml_description)
-$(cts-system-api-coverage-report): PRIVATE_NAPI_XML_DESC := ""
-$(cts-system-api-coverage-report) : $(android_cts_zip) $(cts_system_api_coverage_dependencies) | $(ACP)
- $(call generate-coverage-report-cts,"CTS System API Coverage Report",\
- $(PRIVATE_TEST_CASES),html)
-
-$(cts-system-api-xml-coverage-report): PRIVATE_TEST_CASES := $(COMPATIBILITY_TESTCASES_OUT_cts)
-$(cts-system-api-xml-coverage-report): PRIVATE_CTS_API_COVERAGE_EXE := $(cts_api_coverage_exe)
-$(cts-system-api-xml-coverage-report): PRIVATE_DEXDEPS_EXE := $(dexdeps_exe)
-$(cts-system-api-xml-coverage-report): PRIVATE_API_XML_DESC := $(system_api_xml_description)
-$(cts-system-api-xml-coverage-report): PRIVATE_NAPI_XML_DESC := ""
-$(cts-system-api-xml-coverage-report) : $(android_cts_zip) $(cts_system_api_coverage_dependencies) | $(ACP)
- $(call generate-coverage-report-cts,"CTS System API Coverage Report - XML",\
- $(PRIVATE_TEST_CASES),xml)
-
-$(cts-verifier-coverage-report): PRIVATE_TEST_CASES := $(cts_verifier_apk)
-$(cts-verifier-coverage-report): PRIVATE_CTS_API_COVERAGE_EXE := $(cts_api_coverage_exe)
-$(cts-verifier-coverage-report): PRIVATE_DEXDEPS_EXE := $(dexdeps_exe)
-$(cts-verifier-coverage-report): PRIVATE_API_XML_DESC := $(api_xml_description)
-$(cts-verifier-coverage-report): PRIVATE_NAPI_XML_DESC := $(napi_xml_description)
-$(cts-verifier-coverage-report) : $(cts_verifier_apk) $(cts_api_coverage_dependencies) | $(ACP)
- $(call generate-coverage-report-cts,"CTS Verifier API Coverage Report",\
- $(PRIVATE_TEST_CASES),html)
-
-$(cts-combined-coverage-report): PRIVATE_TEST_CASES := $(foreach c, $(cts_verifier_apk) $(COMPATIBILITY_TESTCASES_OUT_cts), $(c))
-$(cts-combined-coverage-report): PRIVATE_CTS_API_COVERAGE_EXE := $(cts_api_coverage_exe)
-$(cts-combined-coverage-report): PRIVATE_DEXDEPS_EXE := $(dexdeps_exe)
-$(cts-combined-coverage-report): PRIVATE_API_XML_DESC := $(api_xml_description)
-$(cts-combined-coverage-report): PRIVATE_NAPI_XML_DESC := $(napi_xml_description)
-$(cts-combined-coverage-report) : $(android_cts_zip) $(cts_verifier_apk) $(cts_api_coverage_dependencies) | $(ACP)
- $(call generate-coverage-report-cts,"CTS Combined API Coverage Report",\
- $(PRIVATE_TEST_CASES),html)
-
-$(cts-combined-xml-coverage-report): PRIVATE_TEST_CASES := $(foreach c, $(cts_verifier_apk) $(COMPATIBILITY_TESTCASES_OUT_cts), $(c))
-$(cts-combined-xml-coverage-report): PRIVATE_CTS_API_COVERAGE_EXE := $(cts_api_coverage_exe)
-$(cts-combined-xml-coverage-report): PRIVATE_DEXDEPS_EXE := $(dexdeps_exe)
-$(cts-combined-xml-coverage-report): PRIVATE_API_XML_DESC := $(api_xml_description)
-$(cts-combined-xml-coverage-report): PRIVATE_NAPI_XML_DESC := $(napi_xml_description)
-$(cts-combined-xml-coverage-report) : $(android_cts_zip) $(cts_verifier_apk) $(cts_api_coverage_dependencies) | $(ACP)
- $(call generate-coverage-report-cts,"CTS Combined API Coverage Report - XML",\
- $(PRIVATE_TEST_CASES),xml)
-
-.PHONY: cts-test-coverage
-cts-test-coverage : $(cts-test-coverage-report)
-
-.PHONY: cts-system-api-coverage
-cts-system-api-coverage : $(cts-system-api-coverage-report)
-
-.PHONY: cts-system-api-xml-coverage
-cts-system-api-xml-coverage : $(cts-system-api-xml-coverage-report)
-
-.PHONY: cts-verifier-coverage
-cts-verifier-coverage : $(cts-verifier-coverage-report)
-
-.PHONY: cts-combined-coverage
-cts-combined-coverage : $(cts-combined-coverage-report)
-
-.PHONY: cts-combined-xml-coverage
-cts-combined-xml-coverage : $(cts-combined-xml-coverage-report)
-
-.PHONY: cts-coverage-report-all cts-api-coverage
-cts-coverage-report-all: cts-test-coverage cts-verifier-coverage cts-combined-coverage cts-combined-xml-coverage
-
-# Put the test coverage report in the dist dir if "cts-api-coverage" is among the build goals.
-$(call dist-for-goals, cts-api-coverage, $(cts-test-coverage-report):cts-test-coverage-report.html)
-$(call dist-for-goals, cts-api-coverage, $(cts-system-api-coverage-report):cts-system-api-coverage-report.html)
-$(call dist-for-goals, cts-api-coverage, $(cts-system-api-xml-coverage-report):cts-system-api-coverage-report.xml)
-$(call dist-for-goals, cts-api-coverage, $(cts-verifier-coverage-report):cts-verifier-coverage-report.html)
-$(call dist-for-goals, cts-api-coverage, $(cts-combined-coverage-report):cts-combined-coverage-report.html)
-$(call dist-for-goals, cts-api-coverage, $(cts-combined-xml-coverage-report):cts-combined-coverage-report.xml)
-
-# Arguments;
-# 1 - Name of the report printed out on the screen
-# 2 - List of apk files that will be scanned to generate the report
-# 3 - Format of the report
-define generate-coverage-report-cts
- $(hide) mkdir -p $(dir $@)
- $(hide) $(PRIVATE_CTS_API_COVERAGE_EXE) -d $(PRIVATE_DEXDEPS_EXE) -a $(PRIVATE_API_XML_DESC) -n $(PRIVATE_NAPI_XML_DESC) -f $(3) -o $@ $(2)
- @ echo $(1): file://$$(cd $(dir $@); pwd)/$(notdir $@)
-endef
-
-# Reset temp vars
-cts_api_coverage_dependencies :=
-cts_system_api_coverage_dependencies :=
-cts-combined-coverage-report :=
-cts-combined-xml-coverage-report :=
-cts-verifier-coverage-report :=
-cts-test-coverage-report :=
-cts-system-api-coverage-report :=
-cts-system-api-xml-coverage-report :=
-api_xml_description :=
-api_text_description :=
-system_api_xml_description :=
-napi_xml_description :=
-napi_text_description :=
-coverage_out :=
-dexdeps_exe :=
-cts_api_coverage_exe :=
-cts_verifier_apk :=
-android_cts_zip :=
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
index 7a5dfb8..bf2b551 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
@@ -16,6 +16,7 @@
package com.android.compatibility.common.deviceinfo;
import android.icu.util.ULocale;
+import android.icu.util.VersionInfo;
import android.util.Log;
import androidx.annotation.Nullable;
import com.android.compatibility.common.util.DeviceInfoStore;
@@ -31,6 +32,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* Locale device info collector.
@@ -66,35 +68,49 @@
* /apex/com.android.i18n/etc/icu/icudt65l.dat
*/
private void collectLocaleDataFilesInfo(DeviceInfoStore store) throws IOException {
+ int icuVersion = VersionInfo.ICU_VERSION.getMajor();
+ File[] fixedDatPaths = new File[] {
+ new File("/apex/com.android.tzdata/etc/icu/icu_tzdata.dat"),
+ new File("/apex/com.android.i18n/etc/icu/icudt" + icuVersion + "l.dat"),
+ };
+
+ // This property has been deprecated since Android 12. The property will not work if this
+ // app targets SDK level 31 or higher. Thus, we add the above fixedDatPaths in case that
+ // the property is not working. When this comment was written, this CTS app still targets
+ // SDK level 23.
String prop = System.getProperty("android.icu.impl.ICUBinary.dataPath");
store.startArray("icu_data_file_info");
+
+ List<File> datFiles = new ArrayList<>();
if (prop != null) {
String[] dataDirs = prop.split(":");
- // List all readable ".dat" files in the directories.
- List<File> datFiles = Arrays.stream(dataDirs)
+ // List all ".dat" files in the directories.
+ datFiles = Arrays.stream(dataDirs)
.filter((dir) -> dir != null && !dir.isEmpty())
.map((dir) -> new File(dir))
.filter((f) -> f.canRead() && f.isDirectory())
.map((f) -> f.listFiles())
.filter((files) -> files != null)
- .map((files) -> Arrays.asList(files))
- .reduce(new ArrayList<>(), (l1, l2) -> {
- l1.addAll(l2);
- return l1;
- })
- .stream()
- .filter((f) -> f != null && f.canRead() && f.getName().endsWith(".dat"))
+ .flatMap(files -> Stream.of(files))
.collect(Collectors.toList());
+ }
- for (File datFile : datFiles) {
- String sha256Hash = sha256(datFile);
+ datFiles.addAll(Arrays.asList(fixedDatPaths));
- store.startGroup();
- store.addResult("file_path", datFile.getPath());
- // Still store the null hash to indicate an error occurring when obtaining the hash.
- store.addResult("file_sha256", sha256Hash);
- store.endGroup();
- }
+ // Keep the readable paths only.
+ datFiles = datFiles.stream()
+ .distinct()
+ .filter((f) -> f != null && f.canRead() && f.getName().endsWith(".dat"))
+ .collect(Collectors.toList());
+
+ for (File datFile : datFiles) {
+ String sha256Hash = sha256(datFile);
+
+ store.startGroup();
+ store.addResult("file_path", datFile.getPath());
+ // Still store the null hash to indicate an error occurring when obtaining the hash.
+ store.addResult("file_sha256", sha256Hash);
+ store.endGroup();
}
store.endArray();
}
diff --git a/hostsidetests/angle/Android.bp b/hostsidetests/angle/Android.bp
index 794ea69..47ce8e0 100644
--- a/hostsidetests/angle/Android.bp
+++ b/hostsidetests/angle/Android.bp
@@ -20,7 +20,6 @@
name: "CtsAngleIntegrationHostTestCases",
defaults: ["cts_defaults"],
srcs: ["src/**/*.java"],
- java_resource_dirs: ["assets/"],
// tag this module as a cts test artifact
test_suites: [
"cts",
diff --git a/hostsidetests/angle/assets/emptyRules.json b/hostsidetests/angle/assets/emptyRules.json
deleted file mode 100644
index 77fa0c0..0000000
--- a/hostsidetests/angle/assets/emptyRules.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "Rules":[
- {
- "Rule":"Default Rule (i.e. use native driver)",
- "UseANGLE":false
- }
- ]
-}
diff --git a/hostsidetests/angle/assets/enableAngleRules.json b/hostsidetests/angle/assets/enableAngleRules.json
deleted file mode 100644
index 90f4893..0000000
--- a/hostsidetests/angle/assets/enableAngleRules.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "Rules":[
- {
- "Rule":"Default Rule (i.e. use native driver)",
- "UseANGLE":false
- },
- {
- "Rule":"Supported application(s) (e.g. Maps on Google devices)",
- "UseANGLE":true,
- "Applications":[
- {
- "AppName":"com.android.angleIntegrationTest.driverTest"
- }
- ]
- }
- ]
-}
diff --git a/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java b/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java
index 45bb43e..3fb5c6c 100644
--- a/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java
+++ b/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java
@@ -55,7 +55,6 @@
ANGLE_DRIVER_TEST_PKG + "/com.android.angleIntegrationTest.common.AngleIntegrationTestActivity";
static final String ANGLE_DRIVER_TEST_SEC_ACTIVITY =
ANGLE_DRIVER_TEST_SEC_PKG + "/com.android.angleIntegrationTest.common.AngleIntegrationTestActivity";
- static final String ANGLE_MAIN_ACTIVTY = "android.app.action.ANGLE_FOR_ANDROID";
enum OpenGlDriverChoice {
DEFAULT,
@@ -116,12 +115,6 @@
return (driverProp != null) && (driverProp.equals("angle"));
}
- static void startActivity(ITestDevice device, String action) throws Exception {
- // Run the ANGLE activity so it'll clear up any 'default' settings.
- device.executeShellCommand("am start --user " + device.getCurrentUser() +
- " -S -W -a \"" + action + "\"");
- }
-
static void stopPackage(ITestDevice device, String pkgName) throws Exception {
device.executeShellCommand("am force-stop " + pkgName);
}
diff --git a/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java b/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java
index 9431088..12770b1 100644
--- a/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java
+++ b/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java
@@ -62,8 +62,6 @@
setAndValidateAngleDevOptionPkgDriver(pkgName, sDriverGlobalSettingMap.get(driver));
- startActivity(getDevice(), ANGLE_MAIN_ACTIVTY);
-
CLog.logAndDisplay(LogLevel.INFO, "Validating driver selection (" +
driver + ") with method '" + sDriverTestMethodMap.get(driver) + "'");
@@ -288,8 +286,6 @@
sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE) + "," +
sDriverGlobalSettingMap.get(firstDriver));
- startActivity(getDevice(), ANGLE_MAIN_ACTIVTY);
-
CLog.logAndDisplay(LogLevel.INFO, "Validating driver selection (" +
firstDriver + ") with method '" + sDriverTestMethodMap.get(firstDriver) + "'");
@@ -302,8 +298,6 @@
sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE) + "," +
sDriverGlobalSettingMap.get(secondDriver));
- startActivity(getDevice(), ANGLE_MAIN_ACTIVTY);
-
CLog.logAndDisplay(LogLevel.INFO, "Validating driver selection (" +
secondDriver + ") with method '" + sDriverTestMethodMap.get(secondDriver) + "'");
@@ -311,9 +305,6 @@
ANGLE_DRIVER_TEST_SEC_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
sDriverTestMethodMap.get(secondDriver));
- // Make sure the first PKG's driver value was not modified
- startActivity(getDevice(), ANGLE_MAIN_ACTIVTY);
-
String devOptionPkg = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_PKGS);
String devOptionValue = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_VALUES);
CLog.logAndDisplay(LogLevel.INFO, "Validating: PKG name = '" +
@@ -327,129 +318,6 @@
}
/**
- * Test setting a driver to 'default' does not keep the value in the settings when the ANGLE
- * activity runs and cleans things up.
- */
- @Test
- public void testDefaultNotInSettings() throws Exception {
- Assume.assumeTrue(isAngleLoadable(getDevice()));
-
- // Install the package so the setting isn't removed because the package isn't present.
- installApp(ANGLE_DRIVER_TEST_APP);
-
- setAndValidateAngleDevOptionPkgDriver(ANGLE_DRIVER_TEST_PKG,
- sDriverGlobalSettingMap.get(OpenGlDriverChoice.DEFAULT));
-
- // Run the ANGLE activity so it'll clear up any 'default' settings.
- startActivity(getDevice(), ANGLE_MAIN_ACTIVTY);
-
- String devOptionPkg = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_PKGS);
- String devOptionValue = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_VALUES);
- CLog.logAndDisplay(LogLevel.INFO, "Validating: PKG name = '" +
- devOptionPkg + "', driver value = '" + devOptionValue + "'");
-
- Assert.assertEquals(
- "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_PKGS + " = '" + devOptionPkg + "'",
- "", devOptionPkg);
- Assert.assertEquals(
- "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_VALUES + " = '" + devOptionValue + "'",
- "", devOptionValue);
- }
-
- /**
- * Test uninstalled PKGs have their settings removed.
- */
- @Test
- public void testUninstalledPkgsNotInSettings() throws Exception {
- Assume.assumeTrue(isAngleLoadable(getDevice()));
-
- uninstallPackage(getDevice(), ANGLE_DRIVER_TEST_PKG);
-
- setAndValidateAngleDevOptionPkgDriver(ANGLE_DRIVER_TEST_PKG,
- sDriverGlobalSettingMap.get(OpenGlDriverChoice.NATIVE));
-
- // Run the ANGLE activity so it'll clear up any 'default' settings.
- startActivity(getDevice(), ANGLE_MAIN_ACTIVTY);
-
- String devOptionPkg = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_PKGS);
- String devOptionValue = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_VALUES);
- CLog.logAndDisplay(LogLevel.INFO, "Validating: PKG name = '" +
- devOptionPkg + "', driver value = '" + devOptionValue + "'");
-
- Assert.assertEquals(
- "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_PKGS + " = '" + devOptionPkg + "'",
- "", devOptionPkg);
- Assert.assertEquals(
- "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_VALUES + " = '" + devOptionValue + "'",
- "", devOptionValue);
- }
-
- /**
- * Test different PKGs can have different developer option values.
- * Primary: ANGLE
- * Secondary: Default
- *
- * Verify the PKG set to 'default' is removed from the settings.
- */
- @Test
- public void testMultipleDevOptionsAngleDefault() throws Exception {
- Assume.assumeTrue(isAngleLoadable(getDevice()));
-
- installApp(ANGLE_DRIVER_TEST_APP);
- installApp(ANGLE_DRIVER_TEST_SEC_APP);
-
- setAndValidateAngleDevOptionPkgDriver(ANGLE_DRIVER_TEST_PKG + "," + ANGLE_DRIVER_TEST_SEC_PKG,
- sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE) + "," +
- sDriverGlobalSettingMap.get(OpenGlDriverChoice.DEFAULT));
-
- // Run the ANGLE activity so it'll clear up any 'default' settings.
- startActivity(getDevice(), ANGLE_MAIN_ACTIVTY);
-
- String devOption = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_PKGS);
- Assert.assertEquals(
- "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_PKGS + " = '" + devOption + "'",
- ANGLE_DRIVER_TEST_PKG, devOption);
-
- devOption = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_VALUES);
- Assert.assertEquals(
- "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_VALUES + " = '" + devOption + "'",
- sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE), devOption);
- }
-
- /**
- * Test different PKGs can have different developer option values.
- * Primary: ANGLE
- * Secondary: Default
- *
- * Verify the uninstalled PKG is removed from the settings.
- */
- @Test
- public void testMultipleDevOptionsAngleNativeUninstall() throws Exception {
- Assume.assumeTrue(isAngleLoadable(getDevice()));
-
- installApp(ANGLE_DRIVER_TEST_SEC_APP);
-
- setAndValidateAngleDevOptionPkgDriver(ANGLE_DRIVER_TEST_PKG + "," + ANGLE_DRIVER_TEST_SEC_PKG,
- sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE) + "," +
- sDriverGlobalSettingMap.get(OpenGlDriverChoice.NATIVE));
-
- // Run the ANGLE activity so it'll clear up any 'default' settings.
- startActivity(getDevice(), ANGLE_MAIN_ACTIVTY);
-
- String devOptionPkg = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_PKGS);
- String devOptionValue = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_VALUES);
- CLog.logAndDisplay(LogLevel.INFO, "Validating: PKG name = '" +
- devOptionPkg + "', driver value = '" + devOptionValue + "'");
-
- Assert.assertEquals(
- "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_PKGS + " = '" + devOptionPkg + "'",
- ANGLE_DRIVER_TEST_SEC_PKG, devOptionPkg);
- Assert.assertEquals(
- "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_VALUES + " = '" + devOptionValue + "'",
- sDriverGlobalSettingMap.get(OpenGlDriverChoice.NATIVE), devOptionValue);
- }
-
- /**
* Test that the "ANGLE In Use" dialog box can be enabled when ANGLE is used.
*
* We can't actually make sure the dialog box shows up, just that enabling it and attempting to
diff --git a/hostsidetests/angle/src/android/angle/cts/CtsAngleRulesFileTest.java b/hostsidetests/angle/src/android/angle/cts/CtsAngleRulesFileTest.java
deleted file mode 100644
index 4f0859e..0000000
--- a/hostsidetests/angle/src/android/angle/cts/CtsAngleRulesFileTest.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.angle.cts;
-
-import static android.angle.cts.CtsAngleCommon.*;
-
-import com.google.common.io.ByteStreams;
-import com.google.common.io.Files;
-
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import com.android.tradefed.util.FileUtil;
-
-import java.io.File;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
-/**
- * Tests ANGLE Rules File Opt-In/Out functionality.
- */
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class CtsAngleRulesFileTest extends BaseHostJUnit4Test {
-
- private final String TAG = this.getClass().getSimpleName();
-
- private File mRulesFile;
- private String mAllowList;
-
- // Rules Files
- private static final String RULES_FILE_EMPTY = "emptyRules.json";
- private static final String RULES_FILE_ENABLE_ANGLE = "enableAngleRules.json";
-
- private void pushRulesFile(String hostFilename) throws Exception {
- byte[] rulesFileBytes =
- ByteStreams.toByteArray(getClass().getResourceAsStream("/" + hostFilename));
-
- Assert.assertTrue("Loaded empty rules file", rulesFileBytes.length > 0); // validity check
- mRulesFile = File.createTempFile("rulesFile", "tempRules.json");
- Files.write(rulesFileBytes, mRulesFile);
-
- Assert.assertTrue(getDevice().pushFile(mRulesFile, DEVICE_TEMP_RULES_FILE_PATH));
-
- setProperty(getDevice(), PROPERTY_TEMP_RULES_FILE, DEVICE_TEMP_RULES_FILE_PATH);
- }
-
- private void setAndValidateAngleDevOptionAllowlist(String allowList) throws Exception {
- // SETTINGS_GLOBAL_ALLOWLIST
- setGlobalSetting(getDevice(), SETTINGS_GLOBAL_ALLOWLIST, allowList);
-
- String devOption = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_ALLOWLIST);
- Assert.assertEquals(
- "Developer option '" + SETTINGS_GLOBAL_ALLOWLIST +
- "' was not set correctly: '" + devOption + "'",
- allowList, devOption);
- }
-
- @Before
- public void setUp() throws Exception {
- clearSettings(getDevice());
-
- mAllowList = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_ALLOWLIST);
-
- final String allowlist = ANGLE_DRIVER_TEST_PKG + "," + ANGLE_DRIVER_TEST_SEC_PKG;
- setAndValidateAngleDevOptionAllowlist(allowlist);
- }
-
- @After
- public void tearDown() throws Exception {
- clearSettings(getDevice());
-
- setAndValidateAngleDevOptionAllowlist(mAllowList);
-
- FileUtil.deleteFile(mRulesFile);
- }
-
- /**
- * Test ANGLE is not loaded when an empty rules file is used.
- */
- @Test
- public void testEmptyRulesFile() throws Exception {
- Assume.assumeTrue(isAngleLoadable(getDevice()));
- Assume.assumeFalse(isNativeDriverAngle(getDevice()));
-
- pushRulesFile(RULES_FILE_EMPTY);
-
- installPackage(ANGLE_DRIVER_TEST_APP);
-
- runDeviceTests(ANGLE_DRIVER_TEST_PKG,
- ANGLE_DRIVER_TEST_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
- ANGLE_DRIVER_TEST_NATIVE_METHOD);
- }
-
- /**
- * Test ANGLE is loaded for only the PKG the rules file specifies.
- */
- @Test
- public void testEnableAngleRulesFile() throws Exception {
- Assume.assumeTrue(isAngleLoadable(getDevice()));
- Assume.assumeFalse(isNativeDriverAngle(getDevice()));
-
- pushRulesFile(RULES_FILE_ENABLE_ANGLE);
-
- installPackage(ANGLE_DRIVER_TEST_APP);
- installPackage(ANGLE_DRIVER_TEST_SEC_APP);
-
- runDeviceTests(ANGLE_DRIVER_TEST_PKG,
- ANGLE_DRIVER_TEST_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
- ANGLE_DRIVER_TEST_ANGLE_METHOD);
-
- runDeviceTests(ANGLE_DRIVER_TEST_SEC_PKG,
- ANGLE_DRIVER_TEST_SEC_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
- ANGLE_DRIVER_TEST_NATIVE_METHOD);
- }
-}
diff --git a/hostsidetests/apex/src/android/apex/cts/ApexTest.java b/hostsidetests/apex/src/android/apex/cts/ApexTest.java
index 91920ad..4f7c43b 100644
--- a/hostsidetests/apex/src/android/apex/cts/ApexTest.java
+++ b/hostsidetests/apex/src/android/apex/cts/ApexTest.java
@@ -46,7 +46,9 @@
|| systemProduct.equals("aosp_x86")
|| systemProduct.equals("aosp_x86_64")
|| systemProduct.equals("aosp_tv_arm")
- || systemProduct.equals("aosp_tv_arm64"));
+ || systemProduct.equals("aosp_tv_arm64")
+ || systemProduct.equals("aosp_car_arm")
+ || systemProduct.equals("aosp_car_arm64"));
}
/**
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java
index 3059821..d090493 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java
@@ -56,8 +56,8 @@
"testAppADeDataDoesNotExist";
private static final String APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE =
"testAppACurProfileDataAccessible";
- private static final String APPA_METHOD_CHECK_REF_PROFILE_NOT_ACCESSIBLE =
- "testAppARefProfileDataNotAccessible";
+ private static final String APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE =
+ "testAppARefProfileDataAccessible";
private static final String APPA_METHOD_UNLOCK_DEVICE_AND_VERIFY_CE_DE_EXTERNAL_EXIST =
"testAppAUnlockDeviceAndVerifyCeDeExternalDataExist";
private static final String APPA_METHOD_CANNOT_ACCESS_APPB_DIR = "testCannotAccessAppBDataDir";
@@ -133,7 +133,7 @@
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
- runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_NOT_ACCESSIBLE);
+ runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
// Force stop and verify CE, DE and external storage contains data, cur profile is
// accessible and ref profile is not accessible, to confirm it's binding back the same data
@@ -143,7 +143,7 @@
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
- runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_NOT_ACCESSIBLE);
+ runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
}
@Test
@@ -164,7 +164,7 @@
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
- runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_NOT_ACCESSIBLE);
+ runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
// Reboot and verify CE, DE and external storage contains data, cur profile is accessible
// and ref profile is not accessible
@@ -173,7 +173,7 @@
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
- runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_NOT_ACCESSIBLE);
+ runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
}
private boolean isFbeModeEmulated() throws Exception {
@@ -212,7 +212,7 @@
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
- runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_NOT_ACCESSIBLE);
+ runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
try {
// Setup screenlock
@@ -243,7 +243,7 @@
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CE_DATA_DOES_NOT_EXIST);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_UNAVAILABLE);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
- runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_NOT_ACCESSIBLE);
+ runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
// Verify cannot access other apps data
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CANNOT_ACCESS_APPB_DIR);
@@ -258,7 +258,7 @@
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST);
runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
- runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_NOT_ACCESSIBLE);
+ runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
} finally {
try {
// Always try to unlock first, then clear screenlock setting
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ListeningPortsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ListeningPortsTest.java
index 3e78032..cfd0b8b 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ListeningPortsTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ListeningPortsTest.java
@@ -232,7 +232,8 @@
*/
private String parse(String procFilePath) throws IOException, DeviceNotAvailableException {
File procFile = File.createTempFile("ListeningPortsTest", "tmp");
- getDevice().pullFile(procFilePath, procFile);
+ boolean result = getDevice().pullFile(procFilePath, procFile);
+ assertTrue("failed to pull " + procFilePath, result);
procFile.deleteOnExit();
Scanner scanner = null;
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 c25d3d9..ca28ad8 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
@@ -178,8 +178,9 @@
}
@Test
- public void testAppARefProfileDataNotAccessible() {
- assertDirIsNotAccessible("/data/misc/profiles/ref");
+ public void testAppARefProfileDataAccessible() {
+ assertDirIsAccessible("/data/misc/profiles/ref/"
+ + mContext.getPackageName());
}
@Test
@@ -190,7 +191,7 @@
assertDirDoesNotExist(applicationInfo.deviceProtectedDataDir);
assertDirDoesNotExist("/data/data/" + APPB_PKG);
assertDirDoesNotExist("/data/misc/profiles/cur/" + getCurrentUserId() + "/" + APPB_PKG);
- assertDirIsNotAccessible("/data/misc/profiles/ref");
+ assertDirDoesNotExist("/data/misc/profiles/ref/" + APPB_PKG);
}
@Test
@@ -253,7 +254,7 @@
testAppADeDataExists();
testAppAExternalDirsDoExist();
testAppACurProfileDataAccessible();
- testAppARefProfileDataNotAccessible();
+ testAppARefProfileDataAccessible();
// Verify after unlocking device, app a has still no access to app b dir.
testCannotAccessAppBDataDir();
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 d209a42..9319c38 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
@@ -36,6 +36,7 @@
public void assertDataIsolated() throws RemoteException {
try {
ApplicationInfo applicationInfo = getApplicationInfo();
+
assertDirDoesNotExist(applicationInfo.dataDir);
assertDirDoesNotExist(applicationInfo.deviceProtectedDataDir);
assertDirDoesNotExist("/data/data/" + getPackageName());
@@ -43,7 +44,6 @@
int currentUserId = getCurrentUserId();
assertDirDoesNotExist("/data/misc/profiles/cur/" + currentUserId + "/"
+ getPackageName());
- assertDirIsNotAccessible("/data/misc/profiles/ref");
assertDirDoesNotExist(FileUtils.replacePackageAWithPackageB(
applicationInfo.dataDir));
@@ -52,6 +52,7 @@
assertDirDoesNotExist("/data/data/" + FileUtils.APPB_PKG);
assertDirDoesNotExist("/data/misc/profiles/cur/" + currentUserId + "/"
+ FileUtils.APPB_PKG);
+ assertDirDoesNotExist("/data/misc/profiles/ref/" + FileUtils.APPB_PKG);
assertDirDoesNotExist(FileUtils.replacePackageAWithNotInstalledPkg(
applicationInfo.dataDir));
@@ -60,6 +61,8 @@
assertDirDoesNotExist("/data/data/" + FileUtils.NOT_INSTALLED_PKG);
assertDirDoesNotExist("/data/misc/profiles/cur/" + currentUserId + "/"
+ FileUtils.NOT_INSTALLED_PKG);
+ assertDirDoesNotExist("/data/misc/profiles/ref/"
+ + 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 41ca80d..05a10be 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
@@ -52,7 +52,7 @@
assertDirDoesNotExist("/data/data/" + APPA_PKG);
assertDirDoesNotExist("/data/misc/profiles/cur/" + getCurrentUserId() + "/"
+ APPA_PKG);
- assertDirIsNotAccessible("/data/misc/profiles/ref");
+ assertDirDoesNotExist("/data/misc/profiles/ref/" + APPA_PKG);
}
@Test
@@ -65,7 +65,7 @@
}
assertFileIsAccessible("/data/misc/profiles/cur/" + getCurrentUserId() + "/"
+ APPA_PKG + "/primary.prof");
- assertDirIsNotAccessible("/data/misc/profiles/ref");
+ assertDirIsAccessible("/data/misc/profiles/ref/" + APPA_PKG);
}
@Test
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index befdc0c..54bb476 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -40,6 +40,7 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application
+ android:largeHeap="true"
android:testOnly="true">
<uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/OWNERS b/hostsidetests/devicepolicy/app/SimpleApp/OWNERS
index d9a2060..0fb0c30 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/OWNERS
+++ b/hostsidetests/devicepolicy/app/SimpleApp/OWNERS
@@ -1,2 +1 @@
-ctate@google.com
-hackbod@google.com
+include platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
index 52f03ea..0a4b116 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
@@ -353,14 +353,15 @@
try {
if (holdKey) {
- /* Repeat once between 200ms and 450ms for at least 5 seconds. Since message will be
- * sent once later, send 16 times in loop every 300ms. */
- int repeat = 16;
+ /* Repeat once every 450ms for at least 5 seconds. Send 11 times in loop every
+ * 450ms. The message is sent once after the loop as well.
+ * ((11 + 1) * 0.45 = 5.4s total) */
+ int repeat = 11;
for (int i = 0; i < repeat; i++) {
mOutputConsole.write(command);
mOutputConsole.newLine();
mOutputConsole.flush();
- TimeUnit.MILLISECONDS.sleep(300);
+ TimeUnit.MILLISECONDS.sleep(450);
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/RemoteControlPassthrough.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/RemoteControlPassthrough.java
new file mode 100644
index 0000000..6486313
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/RemoteControlPassthrough.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hdmicec.cts;
+
+import com.android.tradefed.device.ITestDevice;
+
+/** Helper class with methods to test the remote control passthrough functionality */
+public final class RemoteControlPassthrough {
+
+ /** The package name of the APK. */
+ private static final String PACKAGE = "android.hdmicec.app";
+ /** The class name of the main activity in the APK. */
+ private static final String CLASS = "HdmiCecKeyEventCapture";
+ /** The command to launch the main activity. */
+ private static final String START_COMMAND =
+ String.format(
+ "am start -W -a android.intent.action.MAIN -n %s/%s.%s",
+ PACKAGE, PACKAGE, CLASS);
+ /** The command to clear the main activity. */
+ private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE);
+
+ /**
+ * Tests that the device responds correctly to a {@code <USER_CONTROL_PRESSED>} message followed
+ * immediately by a {@code <USER_CONTROL_RELEASED>} message.
+ */
+ public static void checkUserControlPressAndRelease(
+ HdmiCecClientWrapper hdmiCecClient,
+ ITestDevice device,
+ LogicalAddress sourceDevice,
+ LogicalAddress dutLogicalAddress)
+ throws Exception {
+ // Clear activity
+ device.executeShellCommand(CLEAR_COMMAND);
+ // Clear logcat.
+ device.executeAdbCommand("logcat", "-c");
+ // Start the APK and wait for it to complete.
+ device.executeShellCommand(START_COMMAND);
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_UP, false);
+ LogHelper.assertLog(device, CLASS, "Short press KEYCODE_DPAD_UP");
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_DOWN, false);
+ LogHelper.assertLog(device, CLASS, "Short press KEYCODE_DPAD_DOWN");
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_LEFT, false);
+ LogHelper.assertLog(device, CLASS, "Short press KEYCODE_DPAD_LEFT");
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_RIGHT, false);
+ LogHelper.assertLog(device, CLASS, "Short press KEYCODE_DPAD_RIGHT");
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_SELECT, false);
+ LogHelper.assertLog(
+ device, CLASS, "Short press KEYCODE_DPAD_CENTER", "Short press KEYCODE_ENTER");
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_BACK, false);
+ LogHelper.assertLog(device, CLASS, "Short press KEYCODE_BACK");
+ }
+
+ /**
+ * Tests that the device responds correctly to a {@code <USER_CONTROL_PRESSED>} message for
+ * press and hold operations.
+ */
+ public static void checkUserControlPressAndHold(
+ HdmiCecClientWrapper hdmiCecClient,
+ ITestDevice device,
+ LogicalAddress sourceDevice,
+ LogicalAddress dutLogicalAddress)
+ throws Exception {
+ // Clear activity
+ device.executeShellCommand(CLEAR_COMMAND);
+ // Clear logcat.
+ device.executeAdbCommand("logcat", "-c");
+ // Start the APK and wait for it to complete.
+ device.executeShellCommand(START_COMMAND);
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_UP, true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_UP");
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_DOWN, true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_DOWN");
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_LEFT, true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_LEFT");
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_RIGHT, true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_RIGHT");
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_SELECT, true);
+ LogHelper.assertLog(
+ device, CLASS, "Long press KEYCODE_DPAD_CENTER", "Long press KEYCODE_ENTER");
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_BACK, true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_BACK");
+ }
+
+ /**
+ * Tests that the device responds correctly to a {@code <User Control Pressed>} message for
+ * press and hold operations when no {@code <User Control Released>} is sent.
+ */
+ public static void checkUserControlPressAndHoldWithNoRelease(
+ HdmiCecClientWrapper hdmiCecClient,
+ ITestDevice device,
+ LogicalAddress sourceDevice,
+ LogicalAddress dutLogicalAddress)
+ throws Exception {
+ // Clear activity
+ device.executeShellCommand(CLEAR_COMMAND);
+ // Clear logcat.
+ device.executeAdbCommand("logcat", "-c");
+ // Start the APK and wait for it to complete.
+ device.executeShellCommand(START_COMMAND);
+ hdmiCecClient.sendUserControlPress(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_UP, true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_UP");
+ hdmiCecClient.sendUserControlPress(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_DOWN, true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_DOWN");
+ hdmiCecClient.sendUserControlPress(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_LEFT, true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_LEFT");
+ hdmiCecClient.sendUserControlPress(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_RIGHT, true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_RIGHT");
+ hdmiCecClient.sendUserControlPress(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_SELECT, true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_CENTER");
+ hdmiCecClient.sendUserControlPress(
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_BACK, true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_BACK");
+ }
+
+ /**
+ * Tests that the device responds correctly to a {@code <User Control Pressed> [firstKeycode]}
+ * press and hold operation when interrupted by a {@code <User Control Pressed> [secondKeycode]}
+ * before a {@code <User Control Released> [firstKeycode]} is sent.
+ */
+ public static void checkUserControlInterruptedPressAndHoldWithNoRelease(
+ HdmiCecClientWrapper hdmiCecClient,
+ ITestDevice device,
+ LogicalAddress sourceDevice,
+ LogicalAddress dutLogicalAddress)
+ throws Exception {
+ // Clear activity
+ device.executeShellCommand(CLEAR_COMMAND);
+ // Clear logcat.
+ device.executeAdbCommand("logcat", "-c");
+ // Start the APK and wait for it to complete.
+ device.executeShellCommand(START_COMMAND);
+ hdmiCecClient.sendUserControlInterruptedPressAndHold(
+ sourceDevice,
+ dutLogicalAddress,
+ HdmiCecConstants.CEC_CONTROL_UP,
+ HdmiCecConstants.CEC_CONTROL_BACK,
+ true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_UP");
+ hdmiCecClient.sendUserControlInterruptedPressAndHold(
+ sourceDevice,
+ dutLogicalAddress,
+ HdmiCecConstants.CEC_CONTROL_DOWN,
+ HdmiCecConstants.CEC_CONTROL_UP,
+ true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_DOWN");
+ hdmiCecClient.sendUserControlInterruptedPressAndHold(
+ sourceDevice,
+ dutLogicalAddress,
+ HdmiCecConstants.CEC_CONTROL_LEFT,
+ HdmiCecConstants.CEC_CONTROL_DOWN,
+ true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_LEFT");
+ hdmiCecClient.sendUserControlInterruptedPressAndHold(
+ sourceDevice,
+ dutLogicalAddress,
+ HdmiCecConstants.CEC_CONTROL_RIGHT,
+ HdmiCecConstants.CEC_CONTROL_LEFT,
+ true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_RIGHT");
+ hdmiCecClient.sendUserControlInterruptedPressAndHold(
+ sourceDevice,
+ dutLogicalAddress,
+ HdmiCecConstants.CEC_CONTROL_SELECT,
+ HdmiCecConstants.CEC_CONTROL_RIGHT,
+ true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_CENTER");
+ hdmiCecClient.sendUserControlInterruptedPressAndHold(
+ sourceDevice,
+ dutLogicalAddress,
+ HdmiCecConstants.CEC_CONTROL_BACK,
+ HdmiCecConstants.CEC_CONTROL_SELECT,
+ true);
+ LogHelper.assertLog(device, CLASS, "Long press KEYCODE_BACK");
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java
index df03d54..120e9ac 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java
@@ -17,41 +17,26 @@
package android.hdmicec.cts.audio;
import android.hdmicec.cts.BaseHdmiCecCtsTest;
-import android.hdmicec.cts.HdmiCecClientWrapper;
import android.hdmicec.cts.HdmiCecConstants;
-import android.hdmicec.cts.LogHelper;
import android.hdmicec.cts.LogicalAddress;
-import android.hdmicec.cts.RequiredPropertyRule;
-import android.hdmicec.cts.RequiredFeatureRule;
+import android.hdmicec.cts.RemoteControlPassthrough;
-import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Ignore;
import org.junit.Rule;
+import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
-import org.junit.Test;
@Ignore("b/162820841")
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecRemoteControlPassThroughTest extends BaseHdmiCecCtsTest {
- /** The package name of the APK. */
- private static final String PACKAGE = "android.hdmicec.app";
-
- /** The class name of the main activity in the APK. */
- private static final String CLASS = "HdmiCecKeyEventCapture";
-
- /** The command to launch the main activity. */
- private static final String START_COMMAND = String.format(
- "am start -W -a android.intent.action.MAIN -n %s/%s.%s", PACKAGE, PACKAGE, CLASS);
-
- /** The command to clear the main activity. */
- private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE);
+ private static final int DUT_DEVICE_TYPE = HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM;
public HdmiCecRemoteControlPassThroughTest() {
- super(HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM);
+ super(DUT_DEVICE_TYPE);
}
@Rule
@@ -64,144 +49,54 @@
/**
* Test 11.2.13-1
- * Tests that the device responds correctly to a <User Control Pressed> message followed
- * immediately by a <User Control Released> message.
+ *
+ * <p>Tests that the device responds correctly to a {@code <User Control Pressed>} message
+ * followed immediately by a {@code <User Control Released>} message.
*/
@Test
public void cect_11_2_13_1_UserControlPressAndRelease() throws Exception {
- ITestDevice device = getDevice();
- // Clear activity
- device.executeShellCommand(CLEAR_COMMAND);
- // Clear logcat.
- device.executeAdbCommand("logcat", "-c");
- // Start the APK and wait for it to complete.
- device.executeShellCommand(START_COMMAND);
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_UP, false);
- LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_UP");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_DOWN, false);
- LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_DOWN");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_LEFT, false);
- LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_LEFT");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_RIGHT, false);
- LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_RIGHT");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_SELECT, false);
- LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_CENTER");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_BACK, false);
- LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_BACK");
+ LogicalAddress dutLogicalAddress = getTargetLogicalAddress(getDevice(), DUT_DEVICE_TYPE);
+ RemoteControlPassthrough.checkUserControlPressAndRelease(
+ hdmiCecClient, getDevice(), LogicalAddress.TV, dutLogicalAddress);
}
/**
* Test 11.2.13-2
- * Tests that the device responds correctly to a <User Control Pressed> message for press and
- * hold operations.
+ *
+ * <p>Tests that the device responds correctly to a {@code <User Control Pressed>} message for
+ * press and hold operations.
*/
@Test
public void cect_11_2_13_2_UserControlPressAndHold() throws Exception {
- ITestDevice device = getDevice();
- // Clear activity
- device.executeShellCommand(CLEAR_COMMAND);
- // Clear logcat.
- device.executeAdbCommand("logcat", "-c");
- // Start the APK and wait for it to complete.
- device.executeShellCommand(START_COMMAND);
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_UP, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_UP");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_DOWN, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_DOWN");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_LEFT, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_LEFT");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_RIGHT, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_RIGHT");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_SELECT, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_CENTER");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_BACK, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_BACK");
+ LogicalAddress dutLogicalAddress = getTargetLogicalAddress(getDevice(), DUT_DEVICE_TYPE);
+ RemoteControlPassthrough.checkUserControlPressAndHold(
+ hdmiCecClient, getDevice(), LogicalAddress.TV, dutLogicalAddress);
}
/**
* Test 11.2.13-3
- * Tests that the device responds correctly to a <User Control Pressed> message for press and
- * hold operations when no <User Control Released> is sent.
+ *
+ * <p>Tests that the device responds correctly to a {@code <User Control Pressed>} message for
+ * press and hold operations when no {@code <User Control Released>} is sent.
*/
@Test
public void cect_11_2_13_3_UserControlPressAndHoldWithNoRelease() throws Exception {
- ITestDevice device = getDevice();
- // Clear activity
- device.executeShellCommand(CLEAR_COMMAND);
- // Clear logcat.
- device.executeAdbCommand("logcat", "-c");
- // Start the APK and wait for it to complete.
- device.executeShellCommand(START_COMMAND);
- hdmiCecClient.sendUserControlPress(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_UP, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_UP");
- hdmiCecClient.sendUserControlPress(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_DOWN, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_DOWN");
- hdmiCecClient.sendUserControlPress(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_LEFT, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_LEFT");
- hdmiCecClient.sendUserControlPress(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_RIGHT, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_RIGHT");
- hdmiCecClient.sendUserControlPress(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_SELECT, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_CENTER");
- hdmiCecClient.sendUserControlPress(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
- HdmiCecConstants.CEC_CONTROL_BACK, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_BACK");
+ LogicalAddress dutLogicalAddress = getTargetLogicalAddress(getDevice(), DUT_DEVICE_TYPE);
+ RemoteControlPassthrough.checkUserControlPressAndHoldWithNoRelease(
+ hdmiCecClient, getDevice(), LogicalAddress.TV, dutLogicalAddress);
}
/**
* Test 11.2.13-4
- * Tests that the device responds correctly to a <User Control Pressed> [firstKeycode] press
- * and hold operation when interrupted by a <User Control Pressed> [secondKeycode] before a
- * <User Control Released> [firstKeycode] is sent.
+ *
+ * <p>Tests that the device responds correctly to a {@code <User Control Pressed>
+ * [firstKeycode]} press and hold operation when interrupted by a {@code <User Control Pressed>
+ * [secondKeycode]} before a {@code <User Control Released> [firstKeycode]} is sent.
*/
@Test
public void cect_11_2_13_4_UserControlInterruptedPressAndHoldWithNoRelease() throws Exception {
- ITestDevice device = getDevice();
- // Clear activity
- device.executeShellCommand(CLEAR_COMMAND);
- // Clear logcat.
- device.executeAdbCommand("logcat", "-c");
- // Start the APK and wait for it to complete.
- device.executeShellCommand(START_COMMAND);
- hdmiCecClient.sendUserControlInterruptedPressAndHold(LogicalAddress.TV,
- LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_UP,
- HdmiCecConstants.CEC_CONTROL_BACK, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_UP");
- hdmiCecClient.sendUserControlInterruptedPressAndHold(LogicalAddress.TV,
- LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_DOWN,
- HdmiCecConstants.CEC_CONTROL_UP, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_DOWN");
- hdmiCecClient.sendUserControlInterruptedPressAndHold(LogicalAddress.TV,
- LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_LEFT,
- HdmiCecConstants.CEC_CONTROL_DOWN, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_LEFT");
- hdmiCecClient.sendUserControlInterruptedPressAndHold(LogicalAddress.TV,
- LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_RIGHT,
- HdmiCecConstants.CEC_CONTROL_LEFT, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_RIGHT");
- hdmiCecClient.sendUserControlInterruptedPressAndHold(LogicalAddress.TV,
- LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_SELECT,
- HdmiCecConstants.CEC_CONTROL_RIGHT, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_CENTER");
- hdmiCecClient.sendUserControlInterruptedPressAndHold(LogicalAddress.TV,
- LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_BACK,
- HdmiCecConstants.CEC_CONTROL_SELECT, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_BACK");
+ LogicalAddress dutLogicalAddress = getTargetLogicalAddress(getDevice(), DUT_DEVICE_TYPE);
+ RemoteControlPassthrough.checkUserControlInterruptedPressAndHoldWithNoRelease(
+ hdmiCecClient, getDevice(), LogicalAddress.TV, dutLogicalAddress);
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecInvalidMessagesTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecInvalidMessagesTest.java
index d6f7ca8..ce4c4a1 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecInvalidMessagesTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecInvalidMessagesTest.java
@@ -16,6 +16,10 @@
package android.hdmicec.cts.common;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
import android.hdmicec.cts.BaseHdmiCecCtsTest;
import android.hdmicec.cts.CecMessage;
import android.hdmicec.cts.CecOperand;
@@ -32,9 +36,6 @@
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assume.assumeTrue;
-
/** HDMI CEC test to verify that device ignores invalid messages (Section 12) */
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecInvalidMessagesTest extends BaseHdmiCecCtsTest {
@@ -55,6 +56,7 @@
private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE);
private LogicalAddress source;
+ private LogicalAddress targetLogicalAddress;
@Rule
public RuleChain ruleChain =
@@ -63,9 +65,10 @@
.around(hdmiCecClient);
@Before
- public void setup() {
+ public void setup() throws Exception {
source = (hasDeviceType(HdmiCecConstants.CEC_DEVICE_TYPE_TV)) ? LogicalAddress.RECORDER_1
: LogicalAddress.TV;
+ targetLogicalAddress = getTargetLogicalAddress();
}
/**
@@ -180,4 +183,62 @@
source, LogicalAddress.BROADCAST, HdmiCecConstants.CEC_CONTROL_UP, false);
LogHelper.assertLogDoesNotContain(getDevice(), CLASS, "Short press KEYCODE_DPAD_UP");
}
+
+ /**
+ * <p>Tests that the device ignores a directly addressed message {@code <GIVE_PHYSICAL_ADDRESS>}
+ * if received as a broadcast message and its source is the device's logical address
+ */
+ @Test
+ public void cect_IgnoreDirectlyAddressedFromSameSource()
+ throws Exception {
+ hdmiCecClient.sendCecMessage(
+ targetLogicalAddress, targetLogicalAddress, CecOperand.GIVE_PHYSICAL_ADDRESS);
+ hdmiCecClient.checkOutputDoesNotContainMessage(
+ targetLogicalAddress, CecOperand.REPORT_PHYSICAL_ADDRESS);
+ }
+
+ /**
+ * <p>Tests that the device ignores a broadcasted message {@code <REQUEST_ACTIVE_SOURCE>} if its
+ * source has the logical address equal to device's logical address
+ */
+ @Test
+ public void cect_IgnoreBroadcastedFromSameSource()
+ throws Exception {
+ ITestDevice device = getDevice();
+ device.executeShellCommand("input keyevent KEYCODE_HOME");
+ // The device shall broadcast an <Active Source> message.
+ hdmiCecClient.checkExpectedOutput(
+ LogicalAddress.BROADCAST, CecOperand.ACTIVE_SOURCE);
+ hdmiCecClient.sendCecMessage(
+ targetLogicalAddress, LogicalAddress.BROADCAST, CecOperand.REQUEST_ACTIVE_SOURCE);
+ hdmiCecClient.checkOutputDoesNotContainMessage(
+ LogicalAddress.BROADCAST, CecOperand.ACTIVE_SOURCE);
+ }
+
+ /**
+ * <p>Tests that the device ignores a directly addressed message {@code <GIVE_POWER_STATUS>} if
+ * coming from the unregistered address F. This message should only be sent from a device with
+ * an allocated logical address
+ */
+ @Test
+ public void cect_IgnoreDirectlyAddressedFromUnknownAddress_giveDevicePowerStatus()
+ throws Exception {
+ hdmiCecClient.sendCecMessage(
+ LogicalAddress.UNKNOWN, targetLogicalAddress, CecOperand.GIVE_POWER_STATUS);
+ hdmiCecClient.checkOutputDoesNotContainMessage(
+ LogicalAddress.UNKNOWN, CecOperand.REPORT_POWER_STATUS);
+ }
+
+ /**
+ * <p>Tests that the device process a directly addressed message {@code <GIVE_PHYSICAL_ADDRESS>}
+ * if coming from the unregistered address F
+ */
+ @Test
+ public void cect_ProcessAddressedFromUnknownAddress_givePhysicalAddress()
+ throws Exception {
+ hdmiCecClient.sendCecMessage(
+ LogicalAddress.UNKNOWN, targetLogicalAddress, CecOperand.GIVE_PHYSICAL_ADDRESS);
+ hdmiCecClient.checkExpectedOutput(
+ LogicalAddress.UNKNOWN, CecOperand.REPORT_PHYSICAL_ADDRESS);
+ }
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java
index faab6e4..bc9f499 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java
@@ -17,45 +17,28 @@
package android.hdmicec.cts.playback;
import android.hdmicec.cts.BaseHdmiCecCtsTest;
-import android.hdmicec.cts.HdmiCecClientWrapper;
import android.hdmicec.cts.HdmiCecConstants;
-import android.hdmicec.cts.LogHelper;
import android.hdmicec.cts.LogicalAddress;
-import android.hdmicec.cts.RequiredPropertyRule;
-import android.hdmicec.cts.RequiredFeatureRule;
+import android.hdmicec.cts.RemoteControlPassthrough;
-import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Rule;
+import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
-import org.junit.Test;
-/** HDMI CEC test to check if the device reports power status correctly (Section 11.2.13) */
+/**
+ * HDMI CEC tests to ensure that the remote control passthrough to TV works as expected (Section
+ * 11.2.13)
+ */
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecRemoteControlPassThroughTest extends BaseHdmiCecCtsTest {
- /**
- * The package name of the APK.
- */
- private static final String PACKAGE = "android.hdmicec.app";
- /**
- * The class name of the main activity in the APK.
- */
- private static final String CLASS = "HdmiCecKeyEventCapture";
- /**
- * The command to launch the main activity.
- */
- private static final String START_COMMAND = String.format(
- "am start -W -a android.intent.action.MAIN -n %s/%s.%s", PACKAGE, PACKAGE, CLASS);
- /**
- * The command to clear the main activity.
- */
- private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE);
+ private static int DUT_DEVICE_TYPE = HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
public HdmiCecRemoteControlPassThroughTest() {
- super(HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+ super(DUT_DEVICE_TYPE);
}
@Rule
@@ -68,37 +51,15 @@
/**
* Test 11.2.13-1
- * Tests that the device responds correctly to a <USER_CONTROL_PRESSED> message followed
- * immediately by a <USER_CONTROL_RELEASED> message.
+ *
+ * <p>Tests that the device responds correctly to a {@code <USER_CONTROL_PRESSED>} message
+ * followed immediately by a {@code <USER_CONTROL_RELEASED>} message.
*/
@Test
public void cect_11_2_13_1_UserControlPressAndRelease() throws Exception {
- ITestDevice device = getDevice();
- // Clear activity
- device.executeShellCommand(CLEAR_COMMAND);
- // Clear logcat.
- device.executeAdbCommand("logcat", "-c");
- // Start the APK and wait for it to complete.
- device.executeShellCommand(START_COMMAND);
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1,
- HdmiCecConstants.CEC_CONTROL_UP, false);
- LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_UP");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1,
- HdmiCecConstants.CEC_CONTROL_DOWN, false);
- LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_DOWN");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1,
- HdmiCecConstants.CEC_CONTROL_LEFT, false);
- LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_LEFT");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1,
- HdmiCecConstants.CEC_CONTROL_RIGHT, false);
- LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_RIGHT");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1,
- HdmiCecConstants.CEC_CONTROL_SELECT, false);
- LogHelper.assertLog(getDevice(), CLASS,
- "Short press KEYCODE_DPAD_CENTER", "Short press KEYCODE_ENTER");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1,
- HdmiCecConstants.CEC_CONTROL_BACK, false);
- LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_BACK");
+ LogicalAddress dutLogicalAddress = getTargetLogicalAddress(getDevice(), DUT_DEVICE_TYPE);
+ RemoteControlPassthrough.checkUserControlPressAndRelease(
+ hdmiCecClient, getDevice(), LogicalAddress.TV, dutLogicalAddress);
}
/**
@@ -108,31 +69,8 @@
*/
@Test
public void cect_11_2_13_2_UserControlPressAndHold() throws Exception {
- ITestDevice device = getDevice();
- // Clear activity
- device.executeShellCommand(CLEAR_COMMAND);
- // Clear logcat.
- device.executeAdbCommand("logcat", "-c");
- // Start the APK and wait for it to complete.
- device.executeShellCommand(START_COMMAND);
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1,
- HdmiCecConstants.CEC_CONTROL_UP, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_UP");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1,
- HdmiCecConstants.CEC_CONTROL_DOWN, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_DOWN");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1,
- HdmiCecConstants.CEC_CONTROL_LEFT, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_LEFT");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1,
- HdmiCecConstants.CEC_CONTROL_RIGHT, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_RIGHT");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1,
- HdmiCecConstants.CEC_CONTROL_SELECT, true);
- LogHelper.assertLog(getDevice(), CLASS,
- "Long press KEYCODE_DPAD_CENTER", "Long press KEYCODE_ENTER");
- hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1,
- HdmiCecConstants.CEC_CONTROL_BACK, true);
- LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_BACK");
+ LogicalAddress dutLogicalAddress = getTargetLogicalAddress(getDevice(), DUT_DEVICE_TYPE);
+ RemoteControlPassthrough.checkUserControlPressAndHold(
+ hdmiCecClient, getDevice(), LogicalAddress.TV, dutLogicalAddress);
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/targetprep/CecPortDiscoverer.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/targetprep/CecPortDiscoverer.java
index a4aca15..4f1915a 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/targetprep/CecPortDiscoverer.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/targetprep/CecPortDiscoverer.java
@@ -20,6 +20,7 @@
import android.hdmicec.cts.CecMessage;
import android.hdmicec.cts.HdmiCecClientWrapper;
import android.hdmicec.cts.HdmiCecConstants;
+import android.hdmicec.cts.LogicalAddress;
import android.hdmicec.cts.error.CecClientWrapperException;
import android.hdmicec.cts.error.ErrorCodes;
@@ -107,15 +108,15 @@
throw new TargetSetupError("No adapters connected to host.");
}
- int targetDevice =
- BaseHdmiCecCtsTest.getTargetLogicalAddress(device).getLogicalAddressAsInt();
+ int targetDeviceType =
+ BaseHdmiCecCtsTest.getTargetLogicalAddress(device).getDeviceType();
int toDevice;
launchCommand.add("-t");
- if (targetDevice == 0) {
- toDevice = 4;
+ if (targetDeviceType == HdmiCecConstants.CEC_DEVICE_TYPE_TV) {
+ toDevice = LogicalAddress.PLAYBACK_1.getLogicalAddressAsInt();
launchCommand.add("p");
} else {
- toDevice = 0;
+ toDevice = LogicalAddress.TV.getLogicalAddressAsInt();
launchCommand.add("x");
}
@@ -128,7 +129,7 @@
*/
serialNoParam = serialNoParam.substring(1);
StringBuilder sendVendorCommand = new StringBuilder("cmd hdmi_control vendorcommand ");
- sendVendorCommand.append(" -t " + targetDevice);
+ sendVendorCommand.append(" -t " + targetDeviceType);
sendVendorCommand.append(" -d " + toDevice);
sendVendorCommand.append(" -a " + serialNoParam);
diff --git a/hostsidetests/packagemanager/dynamicmime/test/src/android/dynamicmime/testapp/preferred/PreferredActivitiesTest.java b/hostsidetests/packagemanager/dynamicmime/test/src/android/dynamicmime/testapp/preferred/PreferredActivitiesTest.java
index de23596..99f7e5b 100644
--- a/hostsidetests/packagemanager/dynamicmime/test/src/android/dynamicmime/testapp/preferred/PreferredActivitiesTest.java
+++ b/hostsidetests/packagemanager/dynamicmime/test/src/android/dynamicmime/testapp/preferred/PreferredActivitiesTest.java
@@ -43,6 +43,9 @@
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.UiObjectNotFoundException;
+import androidx.test.uiautomator.UiScrollable;
+import androidx.test.uiautomator.UiSelector;
import androidx.test.uiautomator.Until;
import org.junit.After;
@@ -60,7 +63,10 @@
private static final String NAV_BAR_INTERACTION_MODE_RES_NAME = "config_navBarInteractionMode";
private static final int NAV_BAR_INTERACTION_MODE_GESTURAL = 2;
- private static final BySelector BUTTON_ALWAYS = By.res("android:id/button_always");
+ private static final String BUTTON_ALWAYS_RES_ID = "android:id/button_always";
+ private static final BySelector BUTTON_ALWAYS = By.res(BUTTON_ALWAYS_RES_ID);
+ private static final UiSelector BUTTON_ALWAYS_UI_SELECTOR =
+ new UiSelector().resourceId(BUTTON_ALWAYS_RES_ID);
private static final BySelector RESOLVER_DIALOG = By.res(Pattern.compile(".*:id/contentPanel.*"));
private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(60L);
@@ -276,6 +282,9 @@
}
private void verifyDialogIsShown(boolean shouldBeShown) {
+ if (Utils.hasFeature(FEATURE_WEARABLE)) {
+ scrollToSelectorOnWatch(BUTTON_ALWAYS_UI_SELECTOR);
+ }
UiObject2 buttonAlways = getUiDevice().wait(Until.findObject(BUTTON_ALWAYS), TIMEOUT);
if (shouldBeShown) {
@@ -298,20 +307,48 @@
.wait(Until.findObject(RESOLVER_DIALOG), TIMEOUT)
.swipe(Direction.UP, 1f);
} else {
- getUiDevice()
- .wait(Until.findObject(BUTTON_ALWAYS), TIMEOUT)
- .swipe(Direction.RIGHT, 1f);
+ scrollToSelectorOnWatch(new UiSelector().text(label));
}
-
return getUiDevice().findObject(By.text(label));
}
private void chooseUseAlways() {
+ if (Utils.hasFeature(FEATURE_WEARABLE)) {
+ scrollToSelectorOnWatch(BUTTON_ALWAYS_UI_SELECTOR);
+ }
getUiDevice()
.wait(Until.findObject(BUTTON_ALWAYS), TIMEOUT)
.click();
}
+ private void scrollToSelectorOnWatch(UiSelector selector) {
+ try {
+ int resId = Resources.getSystem().getIdentifier(
+ "config_customResolverActivity", "string", "android");
+ String customResolverActivity = context().getString(resId);
+ String customResolverPackageName;
+ if (customResolverActivity.isEmpty()) {
+ // If custom resolver is not in use, it'll be using the Android default
+ customResolverPackageName = "android";
+ } else {
+ customResolverPackageName = customResolverActivity.split("/")[0];
+ }
+
+ UiSelector scrollableSelector =
+ new UiSelector()
+ .scrollable(true)
+ .packageName(customResolverPackageName);
+ UiScrollable scrollable = new UiScrollable(scrollableSelector);
+ scrollable.waitForExists(TIMEOUT);
+ if (scrollable.exists()) {
+ scrollable.scrollToBeginning(Integer.MAX_VALUE);
+ scrollable.scrollIntoView(selector);
+ }
+ } catch (UiObjectNotFoundException ignore) {
+ throw new AssertionError("Scrollable view was lost.");
+ }
+ }
+
private interface TestStrategy {
void prepareMimeGroups();
diff --git a/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java b/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java
index 92eafe3..f7877d5 100644
--- a/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java
+++ b/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java
@@ -50,6 +50,13 @@
if (PropertyUtil.getFirstApiLevel(mDevice) <= 29) {
return; // Requirement does not apply to devices running Q or earlier
}
+ if (PropertyUtil.propertyEquals(mDevice, "ro.crypto.type", "managed")) {
+ // Android is running in a virtualized environment and the file
+ // system is encrypted by the host system.
+ // Note: All encryption-related CDD requirements still must be met,
+ // but they can't be tested directly in this case.
+ return;
+ }
assertTrue("Metadata encryption must be enabled",
mDevice.getBooleanProperty("ro.crypto.metadata.enabled", false));
}
diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
index bc43c70..057b2e0 100644
--- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
@@ -728,7 +728,10 @@
// Check that content of /apex/apex-info-list.xml matches output of
// `adb shell pm list packages --apex-only --show-versioncode -f`.
- List<ApexInfo> apexInfoList = readApexInfoList();
+ List<ApexInfo> apexInfoList =
+ readApexInfoList().stream()
+ .filter(a -> a.getIsActive())
+ .collect(Collectors.toList());
Set<ITestDevice.ApexInfo> activeApexes = getDevice().getActiveApexes();
assertThat(apexInfoList.size()).isEqualTo(activeApexes.size());
for (ITestDevice.ApexInfo apex : activeApexes) {
diff --git a/hostsidetests/userspacereboot/Android.bp b/hostsidetests/userspacereboot/Android.bp
deleted file mode 100644
index f64c740..0000000
--- a/hostsidetests/userspacereboot/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-java_test_host {
- name: "CtsUserspaceRebootHostSideTestCases",
- defaults: ["cts_defaults"],
- srcs: ["src/**/*.java"],
- libs: [
- "cts-tradefed",
- "tradefed",
- "truth-prebuilt",
- "hamcrest",
- "hamcrest-library",
- ],
- data: [
- ":BasicUserspaceRebootTestApp",
- ":BootCompletedUserspaceRebootTestApp",
- ],
- test_suites: [
- "cts",
- "general-tests",
- ],
-}
diff --git a/hostsidetests/userspacereboot/AndroidTest.xml b/hostsidetests/userspacereboot/AndroidTest.xml
deleted file mode 100644
index 5df919f..0000000
--- a/hostsidetests/userspacereboot/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<configuration description="Runs userspace reboot CTS tests">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="framework" />
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
- <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
- <option name="class" value="com.android.cts.userspacereboot.host.UserspaceRebootHostTest" />
- </test>
-</configuration>
diff --git a/hostsidetests/userspacereboot/OWNERS b/hostsidetests/userspacereboot/OWNERS
deleted file mode 100644
index 7d30d02..0000000
--- a/hostsidetests/userspacereboot/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-dvander@google.com
-ioffe@google.com
diff --git a/hostsidetests/userspacereboot/TEST_MAPPING b/hostsidetests/userspacereboot/TEST_MAPPING
deleted file mode 100644
index cf97bfa..0000000
--- a/hostsidetests/userspacereboot/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit" : [
- {
- "name": "CtsUserspaceRebootHostSideTestCases"
- }
- ]
-}
diff --git a/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java b/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
deleted file mode 100755
index 4b903dc..0000000
--- a/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.userspacereboot.host;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
-
-import android.platform.test.annotations.RequiresDevice;
-
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import com.android.tradefed.util.CommandResult;
-import com.android.tradefed.util.CommandStatus;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.time.Duration;
-
-/**
- * Host side CTS tests verifying userspace reboot functionality.
- */
-@RequiresDevice
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class UserspaceRebootHostTest extends BaseHostJUnit4Test {
-
- private static final String USERSPACE_REBOOT_SUPPORTED_PROP =
- "init.userspace_reboot.is_supported";
-
- private static final String BASIC_TEST_APP_APK = "BasicUserspaceRebootTestApp.apk";
- private static final String BASIC_TEST_APP_PACKAGE_NAME =
- "com.android.cts.userspacereboot.basic";
-
- private static final String BOOT_COMPLETED_TEST_APP_APK =
- "BootCompletedUserspaceRebootTestApp.apk";
- private static final String BOOT_COMPLETED_TEST_APP_PACKAGE_NAME =
- "com.android.cts.userspacereboot.bootcompleted";
-
- private void runDeviceTest(String pkgName, String className, String testName) throws Exception {
- runDeviceTests(pkgName, pkgName + "." + className, testName);
- }
-
- private void runDeviceTest(String pkgName, String className, String testName, Duration timeout)
- throws Exception {
- runDeviceTests(
- getDevice(), pkgName, pkgName + "." + className, testName, timeout.toMillis());
- }
-
- private void installApk(String apkFileName) throws Exception {
- CompatibilityBuildHelper helper = new CompatibilityBuildHelper(getBuild());
- getDevice().installPackage(helper.getTestFile(apkFileName), false, true,
- getDevice().isAppEnumerationSupported()
- ? new String[]{"--force-queryable"}
- : new String[]{});
- }
-
- /**
- * Sets up device to run a test case.
- */
- @Before
- public void setUp() throws Exception {
- getDevice().uninstallPackage(BASIC_TEST_APP_PACKAGE_NAME);
- getDevice().uninstallPackage(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME);
- }
-
- /**
- * Cleans up device after a test case.
- */
- @After
- public void cleanUp() throws Exception {
- getDevice().uninstallPackage(BASIC_TEST_APP_PACKAGE_NAME);
- getDevice().uninstallPackage(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME);
- getDevice().disableAdbRoot();
- }
-
- /**
- * Asserts that only file-based encrypted devices can support userspace reboot.
- */
- @Test
- public void testOnlyFbeDevicesSupportUserspaceReboot() throws Exception {
- assumeTrue("Userspace reboot not supported on the device",
- getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
- assertThat(getDevice().getProperty("ro.crypto.state")).isEqualTo("encrypted");
- assertThat(getDevice().getProperty("ro.crypto.type")).isEqualTo("file");
- }
-
- /**
- * Tests that on devices supporting userspace reboot {@code
- * PowerManager.isRebootingUserspaceSupported()} returns {@code true}.
- */
- @Test
- public void testDeviceSupportsUserspaceReboot() throws Exception {
- assumeTrue("Userspace reboot not supported on the device",
- getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
- installApk(BASIC_TEST_APP_APK);
- runDeviceTest(BASIC_TEST_APP_PACKAGE_NAME, "BasicUserspaceRebootTest",
- "testUserspaceRebootIsSupported");
- }
-
- /**
- * Tests that on devices not supporting userspace reboot {@code
- * PowerManager.isRebootingUserspaceSupported()} returns {@code false}.
- */
- @Test
- public void testDeviceDoesNotSupportUserspaceReboot() throws Exception {
- assumeFalse("Userspace reboot supported on the device",
- getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
- installApk(BASIC_TEST_APP_APK);
- // Also verify that PowerManager.isRebootingUserspaceSupported will return true
- runDeviceTest(BASIC_TEST_APP_PACKAGE_NAME, "BasicUserspaceRebootTest",
- "testUserspaceRebootIsNotSupported");
- }
-
- /**
- * Tests that userspace reboot succeeds and doesn't fall back to full reboot.
- */
- @Test
- public void testUserspaceReboot() throws Exception {
- assumeTrue("Userspace reboot not supported on the device",
- getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
- rebootUserspaceAndWaitForBootComplete();
- assertUserspaceRebootSucceed();
- }
-
- /**
- * Tests that userspace reboot with fs-checkpointing succeeds and doesn't fall back to full
- * reboot.
- */
- @Test
- public void testUserspaceRebootWithCheckpoint() throws Exception {
- assumeTrue("Userspace reboot not supported on the device",
- getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
- assumeTrue("Device doesn't support fs checkpointing", isFsCheckpointingSupported());
- CommandResult result = getDevice().executeShellV2Command("sm start-checkpoint 1");
- Thread.sleep(500);
- assertWithMessage("Failed to start checkpoint : %s", result.getStderr()).that(
- result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
- rebootUserspaceAndWaitForBootComplete();
- assertUserspaceRebootSucceed();
- }
-
- /**
- * Tests that CE storage is unlocked after userspace reboot.
- */
- @Test
- public void testUserspaceReboot_verifyCeStorageIsUnlocked() throws Exception {
- assumeTrue("Userspace reboot not supported on the device",
- getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
- try {
- getDevice().executeShellV2Command("cmd lock_settings set-pin 1543");
- installApk(BOOT_COMPLETED_TEST_APP_APK);
- installApk(BASIC_TEST_APP_APK);
-
- prepareForCeTestCases();
-
- rebootUserspaceAndWaitForBootComplete();
- assertUserspaceRebootSucceed();
-
- // Now it's time to verify our assumptions.
- runDeviceTest(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME, "BootCompletedUserspaceRebootTest",
- "testVerifyCeStorageUnlocked");
- runDeviceTest(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME, "BootCompletedUserspaceRebootTest",
- "testVerifyReceivedLockedBootCompletedBroadcast", Duration.ofMinutes(3));
- runDeviceTest(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME, "BootCompletedUserspaceRebootTest",
- "testVerifyReceivedBootCompletedBroadcast", Duration.ofMinutes(6));
- } finally {
- getDevice().executeShellV2Command("cmd lock_settings clear --old 1543");
- getDevice().executeShellV2Command("reboot");
- }
- }
-
- /**
- * Tests that CE storage is unlocked after userspace reboot with fs-checkpointing.
- */
- @Test
- public void testUserspaceRebootWithCheckpoint_verifyCeStorageIsUnlocked() throws Exception {
- assumeTrue("Userspace reboot not supported on the device",
- getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
- assumeTrue("Device doesn't support fs checkpointing", isFsCheckpointingSupported());
- try {
- CommandResult result = getDevice().executeShellV2Command("sm start-checkpoint 1");
- Thread.sleep(500);
- assertWithMessage("Failed to start checkpoint : %s", result.getStderr()).that(
- result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
-
- getDevice().executeShellV2Command("cmd lock_settings set-pin 1543");
- installApk(BOOT_COMPLETED_TEST_APP_APK);
- installApk(BASIC_TEST_APP_APK);
-
- prepareForCeTestCases();
-
- rebootUserspaceAndWaitForBootComplete();
- assertUserspaceRebootSucceed();
- runDeviceTest(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME, "BootCompletedUserspaceRebootTest",
- "testVerifyCeStorageUnlocked");
- runDeviceTest(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME, "BootCompletedUserspaceRebootTest",
- "testVerifyReceivedLockedBootCompletedBroadcast", Duration.ofMinutes(3));
- runDeviceTest(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME, "BootCompletedUserspaceRebootTest",
- "testVerifyReceivedBootCompletedBroadcast", Duration.ofMinutes(6));
- } finally {
- getDevice().executeShellV2Command("cmd lock_settings clear --old 1543");
- getDevice().executeShellV2Command("reboot");
- }
- }
-
- private void prepareForCeTestCases() throws Exception {
- runDeviceTest(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME, "BootCompletedUserspaceRebootTest",
- "prepareFile");
- runDeviceTest(BASIC_TEST_APP_PACKAGE_NAME, "BasicUserspaceRebootTest", "prepareFile");
-
- // In order to test that broadcasts are correctly sent, we need to have a separate app that
- // is going to be listen for them. Unfortunately, we can't use BOOT_COMPLETED_TEST_APP_APK
- // because every call to `am instrument` force stops an app. This doesn't play well with
- // BOOT_COMPLETED broadcast, which is not sent to stopped apps.
- // Send an intent to our "broadcast listening" test app to kick it out from stopped state.
- getDevice().executeShellV2Command("am start -a android.intent.action.MAIN"
- + " --user 0"
- + " -c android.intent.category.LAUNCHER "
- + BASIC_TEST_APP_PACKAGE_NAME + "/.LauncherActivity");
- // Wait enough for PackageManager to persist new state of test app.
- // I wish there was a better way to synchronize here...
- Thread.sleep(15000);
- }
-
- /**
- * Asserts that fallback to hard reboot is triggered when a native process fails to stop in a
- * given timeout.
- */
- @Test
- @RequiresDevice // TODO(b/154709530): Remove dependency on physical device
- public void testUserspaceRebootFailsKillingProcesses() throws Exception {
- assumeTrue("Userspace reboot not supported on the device",
- getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
- assumeTrue("This test requires root", getDevice().enableAdbRoot());
- final String sigkillTimeout =
- getProperty("init.userspace_reboot.sigkill.timeoutmillis", "");
- final String sigtermTimeout =
- getProperty("init.userspace_reboot.sigterm.timeoutmillis", "");
- try {
- // Explicitly set a very low value to make sure that safety mechanism kicks in.
- getDevice().setProperty("init.userspace_reboot.sigkill.timeoutmillis", "10");
- getDevice().setProperty("init.userspace_reboot.sigterm.timeoutmillis", "10");
- rebootUserspaceAndWaitForBootComplete();
- assertUserspaceRebootFailed();
- assertLastBootReasonIs("userspace_failed,shutdown_aborted,sigkill");
- } finally {
- getDevice().setProperty("init.userspace_reboot.sigkill.timeoutmillis", sigkillTimeout);
- getDevice().setProperty("init.userspace_reboot.sigterm.timeoutmillis", sigtermTimeout);
- }
- }
-
- /**
- * Asserts that fallback to hard reboot is triggered when userspace reboot fails to finish in a
- * given time.
- */
- @Test
- public void testUserspaceRebootWatchdogTriggers() throws Exception {
- assumeTrue("Userspace reboot not supported on the device",
- getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
- assumeTrue("This test requires root", getDevice().enableAdbRoot());
- final String defaultValue = getProperty("init.userspace_reboot.watchdog.timeoutmillis", "");
- try {
- // Explicitly set a very low value to make sure that safety mechanism kicks in.
- getDevice().setProperty("init.userspace_reboot.watchdog.timeoutmillis", "1000");
- rebootUserspaceAndWaitForBootComplete();
- assertUserspaceRebootFailed();
- assertLastBootReasonIs("userspace_failed,watchdog_triggered,failed_to_boot");
- } finally {
- getDevice().setProperty("init.userspace_reboot.watchdog.timeoutmillis", defaultValue);
- }
- }
-
- // TODO(b/135984674): add test case that forces unmount of f2fs userdata.
-
- /**
- * Returns {@code true} if device supports fs-checkpointing.
- */
- private boolean isFsCheckpointingSupported() throws Exception {
- CommandResult result = getDevice().executeShellV2Command("sm supports-checkpoint");
- assertWithMessage("Failed to check if fs checkpointing is supported : %s",
- result.getStderr()).that(result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
- return "true".equals(result.getStdout().trim());
- }
-
- /**
- * Reboots a device and waits for the boot to complete.
- *
- * <p>Before rebooting, sets a value of sysprop {@code test.userspace_reboot.requested} to 1.
- * Querying this property is then used in {@link #assertUserspaceRebootSucceed()} to assert that
- * userspace reboot succeeded.
- */
- private void rebootUserspaceAndWaitForBootComplete() throws Exception {
- Duration timeout = Duration.ofMillis(getDevice().getIntProperty(
- "init.userspace_reboot.watchdog.timeoutmillis", 0)).plusMinutes(2);
- setProperty("test.userspace_reboot.requested", "1");
- getDevice().rebootUserspaceUntilOnline();
- assertWithMessage("Device did not boot within %s", timeout).that(
- getDevice().waitForBootComplete(timeout.toMillis())).isTrue();
- }
-
- /**
- * Asserts that userspace reboot succeeded by querying the value of {@code
- * test.userspace_reboot.requested} property.
- */
- private void assertUserspaceRebootSucceed() throws Exception {
- // If userspace reboot fails and fallback to hard reboot is triggered then
- // test.userspace_reboot.requested won't be set.
- final String bootReason = getProperty("sys.boot.reason.last", "");
- final boolean result = getDevice().getBooleanProperty("test.userspace_reboot.requested",
- false);
- assertWithMessage(
- "Userspace reboot failed and fallback to full reboot was triggered. Boot reason: "
- + "%s", bootReason).that(result).isTrue();
- }
-
- /**
- * Asserts that userspace reboot fails by querying the value of {@code
- * test.userspace_reboot.requested} property.
- */
- private void assertUserspaceRebootFailed() throws Exception {
- // If userspace reboot fails and fallback to hard reboot is triggered then
- // test.userspace_reboot.requested won't be set.
- final boolean result = getDevice().getBooleanProperty("test.userspace_reboot.requested",
- false);
- assertWithMessage("Fallback to full reboot wasn't triggered").that(result).isFalse();
- }
-
- /**
- * A wrapper over {@code adb shell setprop name value}.
- *
- * This is a temporary workaround until issues with {@code getDevice().setProperty()} API are
- * resolved.
- */
- private void setProperty(String name, String value) throws Exception {
- final String cmd = String.format("\"setprop %s %s\"", name, value);
- final CommandResult result = getDevice().executeShellV2Command(cmd);
- assertWithMessage("Failed to call adb shell %s: %s", cmd, result.getStderr())
- .that(result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
- }
-
- /**
- * Asserts that normalized value of {@code sys.boot.reason.last} is equal to {@code expected}.
- */
- private void assertLastBootReasonIs(final String expected) throws Exception {
- String reason = getProperty("sys.boot.reason.last", "");
- if (reason.startsWith("reboot,")) {
- reason = reason.substring("reboot,".length());
- }
- assertThat(reason).isEqualTo(expected);
- }
-
- /**
- * A wrapper over {@code getDevice().getProperty(name)} API that returns {@code defaultValue} if
- * property with the given {@code name} doesn't exist.
- */
- private String getProperty(String name, String defaultValue) throws Exception {
- String ret = getDevice().getProperty(name);
- return ret == null ? defaultValue : ret;
- }
-}
diff --git a/hostsidetests/userspacereboot/testapps/BasicTestApp/Android.bp b/hostsidetests/userspacereboot/testapps/BasicTestApp/Android.bp
deleted file mode 100644
index df1baed..0000000
--- a/hostsidetests/userspacereboot/testapps/BasicTestApp/Android.bp
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_test_helper_app {
- name: "BasicUserspaceRebootTestApp",
- srcs: ["src/**/*.java"],
- manifest : "AndroidManifest.xml",
- static_libs: [
- "androidx.test.runner",
- "androidx.test.core",
- "testng",
- "truth-prebuilt",
- ],
- min_sdk_version: "29",
- // TODO(ioffe): change to number when SDK is finalized.
- sdk_version: "system_current",
-}
diff --git a/hostsidetests/userspacereboot/testapps/BasicTestApp/AndroidManifest.xml b/hostsidetests/userspacereboot/testapps/BasicTestApp/AndroidManifest.xml
deleted file mode 100644
index 97ffde6..0000000
--- a/hostsidetests/userspacereboot/testapps/BasicTestApp/AndroidManifest.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.userspacereboot.basic" >
-
- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
- <application>
- <activity android:name=".LauncherActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- <uses-library android:name="android.test.runner" />
- <receiver android:name=".BasicUserspaceRebootTest$BootReceiver"
- android:exported="true"
- android:directBootAware="true">
- <intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED" />
- <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
- </intent-filter>
- </receiver>
- <provider android:name=".BasicUserspaceRebootTest$Provider"
- android:authorities="com.android.cts.userspacereboot.basic"
- android:exported="true"
- android:directBootAware="true">
- </provider>
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.cts.userspacereboot.basic"
- android:label="Basic userspace reboot device side tests"/>
-</manifest>
diff --git a/hostsidetests/userspacereboot/testapps/BasicTestApp/src/com/android/cts/userspacereboot/basic/BasicUserspaceRebootTest.java b/hostsidetests/userspacereboot/testapps/BasicTestApp/src/com/android/cts/userspacereboot/basic/BasicUserspaceRebootTest.java
deleted file mode 100644
index c41f221..0000000
--- a/hostsidetests/userspacereboot/testapps/BasicTestApp/src/com/android/cts/userspacereboot/basic/BasicUserspaceRebootTest.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.userspacereboot.basic;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import android.content.BroadcastReceiver;
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.net.Uri;
-import android.os.PowerManager;
-import android.util.Log;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-
-/**
- * A test app called from {@link com.android.cts.userspacereboot.host.UserspaceRebootHostTest} to
- * verify basic properties around userspace reboot.
- *
- * <p>Additionally it's used as a test app to receive {@link Intent.ACTION_BOOT_COMPLETED}
- * broadcast. Another test app {@link
- * com.android.cts.userspacereboot.bootcompleted.com.android.cts.userspacereboot.bootcompleted} will
- * query a {@link ContentProvider} exposed by this app in order to verify that broadcast was
- * received.
- *
- * <p>Such separation is required due to the fact, that when {@code adb shell am instrument} is
- * called for an app, it will always force stop that app. This means that if we start an
- * instrumentation test in the same app that listens for {@link Intent.ACTION_BOOT_COMPLETED}
- * broadcast, we might end up not receiving broadcast at all, because {@link
- * Intent.ACTION_BOOT_COMPLETED} is not delivered to stopped apps.
- */
-@RunWith(JUnit4.class)
-public class BasicUserspaceRebootTest {
-
- private static final String TAG = "UserspaceRebootTest";
-
- private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
-
- /**
- * Tests that {@link PowerManager#isRebootingUserspaceSupported()} returns {@code true}.
- */
- @Test
- public void testUserspaceRebootIsSupported() {
- PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- assertThat(powerManager.isRebootingUserspaceSupported()).isTrue();
- }
-
- /**
- * Tests that {@link PowerManager#isRebootingUserspaceSupported()} returns {@code false}.
- */
- @Test
- public void testUserspaceRebootIsNotSupported() {
- PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- assertThat(powerManager.isRebootingUserspaceSupported()).isFalse();
- assertThrows(UnsupportedOperationException.class,
- () -> powerManager.reboot("userspace"));
- }
-
- /**
- * Deletes test file in app data directory if necessary.
- */
- @Test
- public void prepareFile() throws Exception {
- Context de = mContext.createDeviceProtectedStorageContext();
- de.deleteFile(Intent.ACTION_BOOT_COMPLETED.toLowerCase());
- }
-
- /**
- * Receiver of {@link Intent.ACTION_LOCKED_BOOT_COMPLETED} and
- * {@link Intent.ACTION_BOOT_COMPLETED} broadcasts.
- */
- public static class BootReceiver extends BroadcastReceiver {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.i(TAG, "Received! " + intent);
- String fileName = intent.getAction().toLowerCase();
- try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(
- context.createDeviceProtectedStorageContext().openFileOutput(
- fileName, Context.MODE_PRIVATE)))) {
- writer.println(intent.getAction());
- } catch (IOException e) {
- Log.w(TAG, "Failed to append to " + fileName, e);
- }
- }
- }
-
- /**
- * Returns whenever {@link Intent.ACTION_LOCKED_BOOT_COMPLETED} and
- * {@link Intent.ACTION_BOOT_COMPLETED} broadcast were received.
- */
- public static class Provider extends ContentProvider {
-
- @Override
- public boolean onCreate() {
- return true;
- }
-
- @Override
- public String getType(Uri uri) {
- return "vnd.android.cursor.item/com.android.cts.userspacereboot.basic.exists";
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- Context de = getContext().createDeviceProtectedStorageContext();
- File locked_boot_completed = new File(
- de.getFilesDir(), Intent.ACTION_LOCKED_BOOT_COMPLETED.toLowerCase());
- File boot_completed = new File(
- de.getFilesDir(), Intent.ACTION_BOOT_COMPLETED.toLowerCase());
- MatrixCursor cursor = new MatrixCursor(
- new String[]{ "locked_boot_completed", "boot_completed"});
- cursor.addRow(new Object[] {
- locked_boot_completed.exists() ? 1 : 0, boot_completed.exists() ? 1 : 0 });
- return cursor;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException();
- }
- }
-}
diff --git a/hostsidetests/userspacereboot/testapps/BasicTestApp/src/com/android/cts/userspacereboot/basic/LauncherActivity.java b/hostsidetests/userspacereboot/testapps/BasicTestApp/src/com/android/cts/userspacereboot/basic/LauncherActivity.java
deleted file mode 100644
index cb07bae..0000000
--- a/hostsidetests/userspacereboot/testapps/BasicTestApp/src/com/android/cts/userspacereboot/basic/LauncherActivity.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.userspacereboot.basic;
-
-import android.app.Activity;
-
-/**
- * An empty launcher activity.
- */
-public class LauncherActivity extends Activity {
-}
diff --git a/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/Android.bp b/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/Android.bp
deleted file mode 100644
index 24952d7..0000000
--- a/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/Android.bp
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_test_helper_app {
- name: "BootCompletedUserspaceRebootTestApp",
- srcs: ["src/**/*.java"],
- manifest : "AndroidManifest.xml",
- static_libs: [
- "androidx.test.runner",
- "androidx.test.core",
- "compatibility-device-util-axt",
- "testng",
- "truth-prebuilt",
- ],
- min_sdk_version: "29",
- sdk_version: "29",
- target_sdk_version: "29",
-}
diff --git a/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/AndroidManifest.xml b/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/AndroidManifest.xml
deleted file mode 100644
index 03feb43..0000000
--- a/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/AndroidManifest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.userspacereboot.bootcompleted" >
-
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.cts.userspacereboot.bootcompleted"
- android:label="Boot Completed userspace reboot device side tests"/>
-</manifest>
diff --git a/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/src/com/android/cts/userspacereboot/bootcompleted/BootCompletedUserspaceRebootTest.java b/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/src/com/android/cts/userspacereboot/bootcompleted/BootCompletedUserspaceRebootTest.java
deleted file mode 100644
index 4a512ce..0000000
--- a/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/src/com/android/cts/userspacereboot/bootcompleted/BootCompletedUserspaceRebootTest.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.userspacereboot.bootcompleted;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.UserManager;
-import android.util.Log;
-
-import com.android.compatibility.common.util.TestUtils;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.io.OutputStreamWriter;
-import java.time.Duration;
-import java.util.Scanner;
-
-/**
- * A test app called from {@link com.android.cts.userspacereboot.host.UserspaceRebootHostTest} to
- * verify CE storage related properties of userspace reboot.
- */
-@RunWith(JUnit4.class)
-public class BootCompletedUserspaceRebootTest {
-
- private static final String TAG = "UserspaceRebootTest";
-
- private static final String FILE_NAME = "secret.txt";
- private static final String SECRET_MESSAGE = "wow, much secret";
-
- private static final Duration LOCKED_BOOT_TIMEOUT = Duration.ofMinutes(3);
- private static final Duration BOOT_TIMEOUT = Duration.ofMinutes(6);
-
- private final Context mCeContext = getInstrumentation().getContext();
- private final Context mDeContext = mCeContext.createDeviceProtectedStorageContext();
-
- /**
- * Writes to a file in CE storage of {@link BootCompletedUserspaceRebootTest}.
- *
- * <p>Reading content of this file is used by other test cases in this class to verify that CE
- * storage is unlocked after userspace reboot.
- */
- @Test
- public void prepareFile() throws Exception {
- try (OutputStreamWriter writer = new OutputStreamWriter(
- mCeContext.openFileOutput(FILE_NAME, Context.MODE_PRIVATE))) {
- writer.write(SECRET_MESSAGE);
- }
- }
-
- /**
- * Tests that CE storage is unlocked by reading content of a file in CE storage.
- */
- @Test
- public void testVerifyCeStorageUnlocked() throws Exception {
- UserManager um = getInstrumentation().getContext().getSystemService(UserManager.class);
- assertThat(um.isUserUnlocked()).isTrue();
- try (Scanner scanner = new Scanner(mCeContext.openFileInput(FILE_NAME))) {
- final String content = scanner.nextLine();
- assertThat(content).isEqualTo(SECRET_MESSAGE);
- }
- }
-
- /**
- * Tests that {@link Intent.ACTION_LOCKED_BOOT_COMPLETED} broadcast was sent.
- */
- @Test
- public void testVerifyReceivedLockedBootCompletedBroadcast() throws Exception {
- waitForBroadcast(Intent.ACTION_LOCKED_BOOT_COMPLETED, LOCKED_BOOT_TIMEOUT);
- }
-
- /**
- * Tests that {@link Intent.ACTION_BOOT_COMPLETED} broadcast was sent.
- */
- @Test
- public void testVerifyReceivedBootCompletedBroadcast() throws Exception {
- waitForBroadcast(Intent.ACTION_BOOT_COMPLETED, BOOT_TIMEOUT);
- }
-
- private void waitForBroadcast(String intent, Duration timeout) throws Exception {
- TestUtils.waitUntil(
- "Didn't receive broadcast " + intent + " in " + timeout,
- (int) timeout.getSeconds(),
- () -> queryBroadcast(intent));
- }
-
- private boolean queryBroadcast(String intent) {
- Uri uri = Uri.parse("content://com.android.cts.userspacereboot.basic/files/"
- + intent.toLowerCase());
- Cursor cursor = mDeContext.getContentResolver().query(uri, null, null, null, null);
- if (cursor == null) {
- return false;
- }
- if (!cursor.moveToFirst()) {
- Log.w(TAG, "Broadcast: " + intent + " cursor is empty");
- return false;
- }
- String column = intent.equals(Intent.ACTION_LOCKED_BOOT_COMPLETED)
- ? "locked_boot_completed"
- : "boot_completed";
- int index = cursor.getColumnIndex(column);
- return cursor.getInt(index) == 1;
- }
-}
diff --git a/libs/install/src/android/cts/install/lib/host/InstallUtilsHost.java b/libs/install/src/android/cts/install/lib/host/InstallUtilsHost.java
index f6de85b..53c813a 100644
--- a/libs/install/src/android/cts/install/lib/host/InstallUtilsHost.java
+++ b/libs/install/src/android/cts/install/lib/host/InstallUtilsHost.java
@@ -25,6 +25,7 @@
import com.android.tradefed.build.BuildInfoKey;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.TestInformation;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.util.CommandResult;
import com.android.tradefed.util.CommandStatus;
@@ -51,24 +52,31 @@
".*package:\\sname='(\\S+)\\'\\sversionCode='(\\d+)'\\s.*";
private final IRunUtil mRunUtil = new RunUtil();
- private final BaseHostJUnit4Test mTest;
+ private BaseHostJUnit4Test mTest = null;
+ private TestInformation mTestInfo = null;
public InstallUtilsHost(BaseHostJUnit4Test test) {
mTest = test;
}
+ public InstallUtilsHost(TestInformation testInfo) {
+ assertThat(testInfo).isNotNull();
+ mTestInfo = testInfo;
+ }
+
/**
* Return {@code true} if and only if device supports updating apex.
*/
public boolean isApexUpdateSupported() throws Exception {
- return mTest.getDevice().getBooleanProperty("ro.apex.updatable", false);
+ return getTestInfo().getDevice().getBooleanProperty("ro.apex.updatable", false);
}
/**
* Return {@code true} if and only if device supports file system checkpoint.
*/
public boolean isCheckpointSupported() throws Exception {
- CommandResult result = mTest.getDevice().executeShellV2Command("sm supports-checkpoint");
+ CommandResult result = getTestInfo().getDevice().executeShellV2Command(
+ "sm supports-checkpoint");
assertWithMessage("Failed to check if file system checkpoint is supported : %s",
result.getStderr()).that(result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
return "true".equals(result.getStdout().trim());
@@ -95,11 +103,12 @@
}
// Non system version is active, need to uninstall it and reboot the device.
Log.i(TAG, "Uninstalling shim apex");
- final String errorMessage = mTest.getDevice().uninstallPackage(SHIM_APEX_PACKAGE_NAME);
+ final String errorMessage =
+ getTestInfo().getDevice().uninstallPackage(SHIM_APEX_PACKAGE_NAME);
if (errorMessage != null) {
Log.e(TAG, "Failed to uninstall " + SHIM_APEX_PACKAGE_NAME + " : " + errorMessage);
} else {
- mTest.getDevice().reboot();
+ getTestInfo().getDevice().reboot();
final ITestDevice.ApexInfo shim = getShimApex().orElseThrow(
() -> new AssertionError("Can't find " + SHIM_APEX_PACKAGE_NAME));
assertThat(shim.versionCode).isEqualTo(1L);
@@ -111,7 +120,7 @@
* Returns the active shim apex as optional.
*/
public Optional<ITestDevice.ApexInfo> getShimApex() throws DeviceNotAvailableException {
- return mTest.getDevice().getActiveApexes().stream().filter(
+ return getTestInfo().getDevice().getActiveApexes().stream().filter(
apex -> apex.name.equals(SHIM_APEX_PACKAGE_NAME)).findAny();
}
@@ -137,7 +146,7 @@
* Installs packages using staged install flow and waits for pre-reboot verification to complete
*/
public String installStagedPackage(File pkg) throws Exception {
- return mTest.getDevice().installPackage(pkg, false, "--staged");
+ return getTestInfo().getDevice().installPackage(pkg, false, "--staged");
}
/**
@@ -149,7 +158,7 @@
for (int i = 0; i < filenames.length; i++) {
args[i + 1] = getTestFile(filenames[i]).getAbsolutePath();
}
- String stdout = mTest.getDevice().executeAdbCommand(args);
+ String stdout = getTestInfo().getDevice().executeAdbCommand(args);
assertThat(stdout).isNotNull();
}
@@ -159,7 +168,7 @@
public void waitForFileDeleted(String filePath, Duration timeout) throws Exception {
Stopwatch stopwatch = Stopwatch.createStarted();
while (true) {
- if (!mTest.getDevice().doesFileExist(filePath)) {
+ if (!getTestInfo().getDevice().doesFileExist(filePath)) {
return;
}
if (stopwatch.elapsed().compareTo(timeout) > 0) {
@@ -187,7 +196,7 @@
return testFile;
}
- File hostLinkedDir = mTest.getBuild().getFile(
+ File hostLinkedDir = getTestInfo().getBuildInfo().getFile(
BuildInfoKey.BuildInfoFileKey.HOST_LINKED_DIR);
if (hostLinkedDir != null) {
testFile = searchTestFile(hostLinkedDir, testFileName);
@@ -197,7 +206,7 @@
}
// Find the file in the buildinfo.
- File buildInfoFile = mTest.getBuild().getFile(testFileName);
+ File buildInfoFile = getTestInfo().getBuildInfo().getFile(testFileName);
if (buildInfoFile != null) {
return buildInfoFile;
}
@@ -228,5 +237,11 @@
return result.getStdout();
}
-
+ private TestInformation getTestInfo() {
+ if (mTestInfo == null) {
+ mTestInfo = mTest.getTestInformation();
+ assertThat(mTestInfo).isNotNull();
+ }
+ return mTestInfo;
+ }
}
diff --git a/tests/camera/Android.bp b/tests/camera/Android.bp
index 6cb0cee..28c0928 100644
--- a/tests/camera/Android.bp
+++ b/tests/camera/Android.bp
@@ -48,3 +48,66 @@
"android.test.base.stubs",
],
}
+
+// CtsCameraTestCases package
+android_test {
+ name: "CtsCameraTestCases",
+ defaults: ["cts_defaults"],
+ // Include both the 32 and 64 bit versions
+ compile_multilib: "both",
+ static_libs: [
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "mockito-target-minus-junit4",
+ "android-ex-camera2",
+ "CtsCameraUtils",
+ "truth-prebuilt",
+ "androidx.heifwriter_heifwriter",
+ "androidx.test.rules",
+ ],
+ jni_libs: [
+ "libctscamera2_jni",
+ "libnativehelper_compat_libc++",
+ ],
+ stl: "c++_shared",
+ srcs: [
+ "src/**/*.java",
+ ":CtsCameraTestCases-rscript{CtsCameraTestCases.srcjar}",
+ ],
+ resource_zips: [
+ ":CtsCameraTestCases-rscript{CtsCameraTestCases.res.zip}",
+ ],
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+ libs: [
+ "android.test.runner.stubs",
+ "android.test.base.stubs",
+ ],
+}
+
+genrule {
+ name: "CtsCameraTestCases-rscript",
+ srcs: [
+ "src/**/*.rscript",
+ ":rs_script_api",
+ ":rs_clang_headers",
+ ],
+ tools: [
+ "llvm-rs-cc",
+ "soong_zip",
+ ],
+ out: [
+ "CtsCameraTestCases.srcjar",
+ "CtsCameraTestCases.res.zip",
+ ],
+ cmd: "for f in $(locations src/**/*.rscript); do " +
+ " $(location llvm-rs-cc) -o $(genDir)/res/raw -p $(genDir)/src " +
+ " -I $$(dirname $$(echo $(locations :rs_script_api) | awk '{ print $$1 }')) " +
+ " -I $$(dirname $$(echo $(locations :rs_clang_headers) | awk '{ print $$1 }')) $${f}; " +
+ "done && " +
+ "$(location soong_zip) -srcjar -o $(location CtsCameraTestCases.srcjar) -C $(genDir)/src -D $(genDir)/src &&" +
+ "$(location soong_zip) -o $(location CtsCameraTestCases.res.zip) -C $(genDir)/res -D $(genDir)/res",
+}
diff --git a/tests/camera/Android.mk b/tests/camera/Android.mk
deleted file mode 100644
index f2bf9fc..0000000
--- a/tests/camera/Android.mk
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-# CtsCameraTestCases package
-
-include $(CLEAR_VARS)
-
-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 \
- android-ex-camera2 \
- CtsCameraUtils \
- truth-prebuilt \
- androidx.heifwriter_heifwriter \
- androidx.test.rules
-
-LOCAL_JNI_SHARED_LIBRARIES := \
- libctscamera2_jni \
- libnativehelper_compat_libc++ \
-
-LOCAL_NDK_STL_VARIANT := c++_shared
-
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-renderscript-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-LOCAL_PACKAGE_NAME := CtsCameraTestCases
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-
-LOCAL_SDK_VERSION := test_current
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-cts_runtime_hint := 120
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/camera/src/android/hardware/cts/CameraGLTest.java b/tests/camera/src/android/hardware/cts/CameraGLTest.java
index a9e82ef..7478e79 100644
--- a/tests/camera/src/android/hardware/cts/CameraGLTest.java
+++ b/tests/camera/src/android/hardware/cts/CameraGLTest.java
@@ -136,15 +136,15 @@
// Save the looper so that we can terminate this thread
// after we are done with it.
mLooper = Looper.myLooper();
- // These must be instantiated outside the UI thread, since the
- // UI thread will be doing a lot of waiting, stopping callbacks.
- mCamera = Camera.open(cameraId);
try {
mIsExternalCamera = CameraUtils.isExternal(
mActivityRule.getActivity().getApplicationContext(), cameraId);
} catch (Exception e) {
Log.e(TAG, "Unable to query external camera!" + e);
}
+ // These must be instantiated outside the UI thread, since the
+ // UI thread will be doing a lot of waiting, stopping callbacks.
+ mCamera = Camera.open(cameraId);
mSurfaceTexture = new SurfaceTexture(mRenderer.getTextureID());
Log.v(TAG, "Camera " + cameraId + " is opened.");
startDone.open();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
index d5b652f..441c862 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
@@ -100,8 +100,10 @@
@Test
public void testAnimationCallbacks_overlapping() {
- // Test requires navbar to create overlapping animations.
- assumeTrue(hasWindowInsets(mRootView, navigationBars()));
+ assumeTrue(
+ "Test requires navBar and statusBar to create overlapping animations.",
+ hasWindowInsets(mRootView, navigationBars())
+ && hasWindowInsets(mRootView, statusBars()));
WindowInsets before = mActivity.mLastWindowInsets;
MultiAnimCallback callbackInner = new MultiAnimCallback();
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java
index 4c27aed..5819bfb 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java
@@ -351,111 +351,111 @@
// aac-he
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_2ch_16kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_16kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_2ch_22kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_22kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_2ch_24kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_24kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_2ch_32kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_32kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_2ch_44kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_44kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_2ch_48kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_48kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_5ch_16kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_5ch_16kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_5ch_22kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_5ch_22kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_5ch_24kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_5ch_24kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_5ch_32kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_5ch_32kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_5ch_44kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_5ch_44kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_5ch_48kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_5ch_48kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_6ch_16kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_6ch_16kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_6ch_22kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_6ch_22kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_6ch_24kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_6ch_24kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_6ch_32kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_6ch_32kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_6ch_44kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_6ch_44kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_6ch_48kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_6ch_48kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
// aac-eld
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_16kHz_aac_eld.m4a"},
- "audio/bbb_1ch_16kHz_s16le_3s.raw", -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_1ch_16kHz_s16le_3s.raw", -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_22kHz_aac_eld.m4a"},
- "audio/bbb_1ch_22kHz_s16le_3s.raw", 24.959969f, -1L, CODEC_ALL},
+ "audio/bbb_1ch_22kHz_s16le_3s.raw", 24.959969f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_24kHz_aac_eld.m4a"},
- "audio/bbb_1ch_24kHz_s16le_3s.raw", 26.495283f, -1L, CODEC_ALL},
+ "audio/bbb_1ch_24kHz_s16le_3s.raw", 26.495283f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_32kHz_aac_eld.m4a"},
- "audio/bbb_1ch_32kHz_s16le_3s.raw", 31.464266f, -1L, CODEC_ALL},
+ "audio/bbb_1ch_32kHz_s16le_3s.raw", 31.464266f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_44kHz_aac_eld.m4a"},
- "audio/bbb_1ch_44kHz_s16le_3s.raw", 33.852623f, -1L, CODEC_ALL},
+ "audio/bbb_1ch_44kHz_s16le_3s.raw", 33.852623f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_48kHz_aac_eld.m4a"},
- "audio/bbb_1ch_48kHz_s16le_3s.raw", 33.136082f, -1L, CODEC_ALL},
+ "audio/bbb_1ch_48kHz_s16le_3s.raw", 33.136082f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_16kHz_aac_eld.m4a"},
- "audio/bbb_2ch_16kHz_s16le_3s.raw", -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_16kHz_s16le_3s.raw", -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_22kHz_aac_eld.m4a"},
- "audio/bbb_2ch_22kHz_s16le_3s.raw", 24.959969f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_22kHz_s16le_3s.raw", 24.959969f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_24kHz_aac_eld.m4a"},
- "audio/bbb_2ch_24kHz_s16le_3s.raw", 26.962938f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_24kHz_s16le_3s.raw", 26.962938f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_32kHz_aac_eld.m4a"},
- "audio/bbb_2ch_32kHz_s16le_3s.raw", 27.784887f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_32kHz_s16le_3s.raw", 27.784887f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_44kHz_aac_eld.m4a"},
- "audio/bbb_2ch_44kHz_s16le_3s.raw", 29.223278f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_44kHz_s16le_3s.raw", 29.223278f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_48kHz_aac_eld.m4a"},
- "audio/bbb_2ch_48kHz_s16le_3s.raw", 29.171904f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_48kHz_s16le_3s.raw", 29.171904f, -1L, CODEC_DEFAULT},
// aac-hev2
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_2ch_16kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_16kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_2ch_22kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_22kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_2ch_24kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_24kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_2ch_32kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_32kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_2ch_44kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_44kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
- "audio/bbb_2ch_48kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ "audio/bbb_2ch_48kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_DEFAULT},
// aac-usac
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_8kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_16kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_22kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_24kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_32kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_44kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_48kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_8kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_16kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_22kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_24kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_32kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_44kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_48kHz_usac.m4a"},
- null, -1.0f, -1L, CODEC_ALL},
+ null, -1.0f, -1L, CODEC_DEFAULT},
});
return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
}
@@ -475,9 +475,12 @@
if (mSupport == CODEC_ALL) {
fail("format(s) not supported by component: " + mCodecName + " for mime : " +
mMime);
- }
- if (mSupport != CODEC_OPTIONAL && selectCodecs(mMime, formats, null, false).isEmpty()) {
+ } else if (mSupport == CODEC_ANY && selectCodecs(mMime, formats, null,
+ false).isEmpty()) {
fail("format(s) not supported by any component for mime : " + mMime);
+ } else if (mSupport == CODEC_DEFAULT && isDefaultCodec(mCodecName, mMime, false)) {
+ fail("format(s) not supported by " + mCodecName
+ + " which is a default codec for mime : " + mMime);
}
return;
}
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index 7b41079..50c9664 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -512,13 +512,16 @@
static final String CODEC_PREFIX_KEY = "codec-prefix";
static final String MIME_SEL_KEY = "mime-sel";
static final Map<String, String> codecSelKeyMimeMap = new HashMap<>();
+ static final Map<String, String> mDefaultEncoders = new HashMap<>();
+ static final Map<String, String> mDefaultDecoders = new HashMap<>();
static final boolean ENABLE_LOGS = false;
static final int PER_TEST_TIMEOUT_LARGE_TEST_MS = 300000;
static final int PER_TEST_TIMEOUT_SMALL_TEST_MS = 60000;
static final int UNSPECIFIED = 0;
- static final int CODEC_ALL = 0; // All codecs should support
- static final int CODEC_ANY = 1; // Atleast one codec should support
- static final int CODEC_OPTIONAL = 2; // Codec support is optional
+ static final int CODEC_ALL = 0; // All codecs must support
+ static final int CODEC_ANY = 1; // At least one codec must support
+ static final int CODEC_DEFAULT = 2; // Default codec must support
+ static final int CODEC_OPTIONAL = 3; // Codec support is optional
// Maintain Timeouts in sync with their counterpart in NativeMediaCommon.h
static final long Q_DEQ_TIMEOUT_US = 5000; // block at most 5ms while looking for io buffers
static final int RETRY_LIMIT = 100; // max poll counter before test aborts and returns error
@@ -644,6 +647,20 @@
return isSupported;
}
+ static boolean isDefaultCodec(String codecName, String mime, boolean isEncoder)
+ throws IOException {
+ Map<String,String> mDefaultCodecs = isEncoder ? mDefaultEncoders: mDefaultDecoders;
+ if (mDefaultCodecs.containsKey(mime)) {
+ return mDefaultCodecs.get(mime).equalsIgnoreCase(codecName);
+ }
+ MediaCodec codec = isEncoder ? MediaCodec.createEncoderByType(mime)
+ : MediaCodec.createDecoderByType(mime);
+ boolean isDefault = codec.getName().equalsIgnoreCase(codecName);
+ mDefaultCodecs.put(mime, codec.getName());
+ codec.release();
+ return isDefault;
+ }
+
static ArrayList<String> compileRequiredMimeList(boolean isEncoder, boolean needAudio,
boolean needVideo) {
Set<String> list = new HashSet<>();
@@ -1229,6 +1246,9 @@
mOutputBuff.saveInPTS(info.presentationTimeUs);
mInputCount++;
}
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawInputEOS = true;
+ }
}
void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
diff --git a/tests/signature/api-check/hidden-api-killswitch-debug-class/AndroidTest.xml b/tests/signature/api-check/hidden-api-killswitch-debug-class/AndroidTest.xml
index c0fadbd..388e55f 100644
--- a/tests/signature/api-check/hidden-api-killswitch-debug-class/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-killswitch-debug-class/AndroidTest.xml
@@ -28,6 +28,7 @@
<option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
<option name="class" value="android.signature.cts.api.DebugClassKillswitchTest" />
<option name="runtime-hint" value="60s" />
+ <option name="shell-timeout" value="20m" />
</test>
<!-- Controller that will skip the module if a native bridge situation is detected -->
diff --git a/tests/signature/api-check/hidden-api-killswitch-sdklist/AndroidTest.xml b/tests/signature/api-check/hidden-api-killswitch-sdklist/AndroidTest.xml
index a9b1035..edfe124 100644
--- a/tests/signature/api-check/hidden-api-killswitch-sdklist/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-killswitch-sdklist/AndroidTest.xml
@@ -34,6 +34,7 @@
<option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
<option name="class" value="android.signature.cts.api.SdkListKillswitchTest" />
<option name="runtime-hint" value="60s" />
+ <option name="shell-timeout" value="20m" />
</test>
<!-- Controller that will skip the module if a native bridge situation is detected -->
diff --git a/tests/signature/api-check/hidden-api-killswitch-wildcard/AndroidTest.xml b/tests/signature/api-check/hidden-api-killswitch-wildcard/AndroidTest.xml
index 27b874c..c4dbd48 100644
--- a/tests/signature/api-check/hidden-api-killswitch-wildcard/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-killswitch-wildcard/AndroidTest.xml
@@ -34,6 +34,7 @@
<option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
<option name="class" value="android.signature.cts.api.WildcardKillswitchTest" />
<option name="runtime-hint" value="60s" />
+ <option name="shell-timeout" value="20m" />
</test>
<!-- Controller that will skip the module if a native bridge situation is detected -->
diff --git a/tests/signature/api-check/shared-libs-api/Android.bp b/tests/signature/api-check/shared-libs-api/Android.bp
index 7d2b3c4..e984ccd 100644
--- a/tests/signature/api-check/shared-libs-api/Android.bp
+++ b/tests/signature/api-check/shared-libs-api/Android.bp
@@ -26,3 +26,55 @@
"compatibility-device-util-axt",
],
}
+
+android_test {
+ name: "CtsSharedLibsApiSignatureTestCases",
+ defaults: ["cts_defaults"],
+ java_resources: [
+ ":CtsSharedLibsApiSignatureTestCases_cts-shared-libs-all.api",
+ ],
+ static_libs: [
+ "cts-api-signature-multilib-test",
+ "cts-api-signature-test",
+ ],
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ sdk_version: "current",
+ jni_libs: ["libclassdescriptors"],
+ compile_multilib: "both",
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+ use_embedded_native_libs: false,
+ srcs: ["src/**/*.java"],
+}
+
+genrule {
+ name: "CtsSharedLibsApiSignatureTestCases_cts-shared-libs-all.api",
+ srcs: [
+ ":prebuilt_sdk_system_public_api_txt",
+ ],
+ tools: [
+ "soong_zip",
+ "metalava",
+ ],
+ out: [
+ "shared-libs-all.api.zip",
+ ],
+ cmd: "for f in $(in); do " +
+ " fileName=$$(basename $${f} .txt) && " +
+ " if [ $${fileName} == android ] || [[ $${fileName} =~ removed ]] || [[ $${fileName} =~ incompatibilities ]]; " +
+ " then continue; fi && " +
+ " platformSdkVersion=$$(echo $${f} | awk -F/ '{print $$(3)}') && " +
+ " if [ $${platformSdkVersion} -lt 28 ]; then continue; fi && " +
+ " apiLevel=$$(echo $${f} | awk -F/ '{print $$(4)}') && " +
+ " $(location metalava) -J--add-opens=java.base/java.util=ALL-UNNAMED --no-banner " +
+ " -convert2xmlnostrip $${f} $(genDir)/list/$${fileName}-$${platformSdkVersion}-$${apiLevel}.api; " +
+ "done && " +
+ "$(location soong_zip) -o $(out) -C $(genDir)/list -D $(genDir)/list",
+}
\ No newline at end of file
diff --git a/tests/signature/api-check/shared-libs-api/Android.mk b/tests/signature/api-check/shared-libs-api/Android.mk
deleted file mode 100644
index faa0248..0000000
--- a/tests/signature/api-check/shared-libs-api/Android.mk
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-all_shared_libs_modules :=
-
-$(foreach ver,$(call int_range_list,28,$(PLATFORM_SDK_VERSION)),\
- $(foreach api_level,public system,\
- $(foreach lib,$(filter-out android,$(filter-out %removed,$(filter-out incompatibilities,\
- $(basename $(notdir $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/$(ver)/$(api_level)/api/*.txt)))))),\
- $(eval all_shared_libs_modules += $(lib)-$(ver)-$(api_level).api))))
-
-all_shared_libs_files := $(addprefix $(COMPATIBILITY_TESTCASES_OUT_cts)/,$(all_shared_libs_modules))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := cts-shared-libs-all.api
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_MODULE_STEM := shared-libs-all.api.zip
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH = $(TARGET_OUT_DATA_ETC)
-include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): $(SOONG_ZIP)
-$(LOCAL_BUILT_MODULE): PRIVATE_SHARED_LIBS_FILES := $(all_shared_libs_files)
-$(LOCAL_BUILT_MODULE): $(all_shared_libs_files)
- @echo "Zip API files $^ -> $@"
- @mkdir -p $(dir $@)
- $(hide) rm -f $@
- $(hide) $(SOONG_ZIP) -o $@ -P out -C $(OUT_DIR) $(addprefix -f ,$(PRIVATE_SHARED_LIBS_FILES))
-
-all_shared_libs_zip_file := $(LOCAL_BUILT_MODULE)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsSharedLibsApiSignatureTestCases
-
-LOCAL_JAVA_RESOURCE_FILES := $(all_shared_libs_zip_file)
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-multilib-test
-
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-include $(LOCAL_PATH)/../build_signature_apk.mk
-
-LOCAL_JAVA_SDK_LIBRARIES :=
-all_shared_libs_files :=
-all_shared_libs_modules :=
-all_shared_libs_zip_file :=
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java b/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java
index d1f019b..e0f22e2 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java
@@ -29,6 +29,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
+import java.util.Objects;
import java.util.stream.Stream;
@SuppressWarnings("deprecation")
@@ -38,7 +39,8 @@
@Override
public Stream<Class<?>> getAllClasses() {
maybeAttachJvmtiAgent();
- return Arrays.stream(getClassloaderDescriptors(Object.class.getClassLoader()))
+ return (Stream<Class<?>>)
+ Arrays.stream(getClassloaderDescriptors(Object.class.getClassLoader()))
.map(descriptor -> {
String classname = descriptor.replace('/', '.');
// omit L and ; at the front and at the end
@@ -48,9 +50,12 @@
try {
return getClass(classname);
} catch (ClassNotFoundException e) {
- throw new RuntimeException("Cannot load " + classname, e);
+ // It could be that a class failed to verify.
+ // No process will be able to load it, so it's ok to silently ignore.
+ return null;
}
- });
+ })
+ .filter(Objects::nonNull);
}
@Override
diff --git a/tests/signature/lib/android/src/android/signature/cts/DexMemberChecker.java b/tests/signature/lib/android/src/android/signature/cts/DexMemberChecker.java
index 181f9d4..a64a483 100644
--- a/tests/signature/lib/android/src/android/signature/cts/DexMemberChecker.java
+++ b/tests/signature/lib/android/src/android/signature/cts/DexMemberChecker.java
@@ -112,8 +112,12 @@
} else if (dexMember instanceof DexMethod) {
DexMethod method = (DexMethod) dexMember;
if (reflection) {
- observer.methodAccessibleViaReflection(hasMatchingMethod_Reflection(klass, method),
- method);
+ try {
+ observer.methodAccessibleViaReflection(
+ hasMatchingMethod_Reflection(klass, method), method);
+ } catch (ClassNotFoundException e) {
+ Log.w(TAG, "Failed resolution of " + dexMember.toString(), e);
+ }
}
if (jni) {
try {
@@ -164,11 +168,22 @@
return true;
} catch (NoSuchFieldException ex) {
return false;
+ } catch (NoClassDefFoundError ex) {
+ // The field has a type that cannot be loaded.
+ return true;
}
}
private static boolean hasMatchingField_JNI(Class<?> klass, DexField dexField) {
try {
+ DexMember.typeToClass(dexField.getDexType());
+ } catch (ClassNotFoundException e) {
+ Log.w(TAG, "Type of field not found: " + dexField.toString(), e);
+ // Skip this field, no process is able to load it.
+ return true;
+ }
+
+ try {
Field ifield = getField_JNI(klass, dexField.getName(), dexField.getDexType());
if (ifield.getDeclaringClass() == klass) {
return true;
@@ -189,22 +204,57 @@
return false;
}
- private static boolean hasMatchingMethod_Reflection(Class<?> klass, DexMethod dexMethod) {
- List<String> methodParams = dexMethod.getJavaParameterTypes();
+ private static boolean hasMatchingMethod_Reflection(Class<?> klass, DexMethod dexMethod)
+ throws ClassNotFoundException {
+ // If we fail to resolve all parameters or return type, we will throw
+ // ClassNotFoundException.
+ Class<?>[] parameterClasses = dexMethod.getJavaParameterClasses();
+ Class<?> returnClass = DexMember.typeToClass(dexMethod.getDexType());
if (dexMethod.isConstructor()) {
- for (Constructor<?> constructor : klass.getDeclaredConstructors()) {
- if (typesMatch(constructor.getParameterTypes(), methodParams)) {
+ try {
+ if (klass.getDeclaredConstructor(parameterClasses) != null) {
return true;
}
+ } catch (NoSuchMethodException e) {
+ return false;
}
- } else {
+ } else if (!dexMethod.isStaticConstructor()) {
+ List<String> methodParams = dexMethod.getJavaParameterTypes();
String methodReturnType = dexMethod.getJavaType();
- for (Method method : klass.getDeclaredMethods()) {
- if (method.getName().equals(dexMethod.getName())
- && method.getReturnType().getTypeName().equals(methodReturnType)
- && typesMatch(method.getParameterTypes(), methodParams)) {
- return true;
+ try {
+ // First try with getDeclaredMethods, hoping all parameter and return types can be
+ // resolved.
+ for (Method method : klass.getDeclaredMethods()) {
+ if (method.getName().equals(dexMethod.getName())
+ && method.getReturnType().getTypeName().equals(methodReturnType)
+ && typesMatch(method.getParameterTypes(), methodParams)) {
+ return true;
+ }
+ }
+ } catch (NoClassDefFoundError ncdfe) {
+ // Try with getMethods, which does not check parameter and return types are
+ // resolved, but only returns public methods.
+ for (Method method : klass.getMethods()) {
+ if (method.getName().equals(dexMethod.getName())
+ && method.getClass() == klass
+ && method.getReturnType().getTypeName().equals(methodReturnType)
+ && typesMatch(method.getParameterTypes(), methodParams)) {
+ return true;
+ }
+ }
+ // Last chance, try with getDeclaredMethod.
+ try {
+ Method m = klass.getDeclaredMethod(dexMethod.getName(), parameterClasses);
+ if (m.getReturnType().getTypeName().equals(dexMethod.getJavaType())) {
+ return true;
+ }
+ // This means we found a method with a different return type. We cannot make
+ // any conclusion here: the method may exisit or not. However, given we have
+ // not found the method through getMethods and getDeclaredMethods, we know
+ // this method won't be accessible through reflection.
+ } catch (NoSuchMethodException nsme) {
+ return false;
}
}
}
diff --git a/tests/signature/lib/common/src/android/signature/cts/DexMember.java b/tests/signature/lib/common/src/android/signature/cts/DexMember.java
index c8470b9..165341a 100644
--- a/tests/signature/lib/common/src/android/signature/cts/DexMember.java
+++ b/tests/signature/lib/common/src/android/signature/cts/DexMember.java
@@ -97,4 +97,35 @@
return javaType + javaDimension;
}
+
+ public static Class<?> typeToClass(String type) throws ClassNotFoundException {
+ if ("V".equals(type)) {
+ return void.class;
+ } else if ("Z".equals(type)) {
+ return boolean.class;
+ } else if ("B".equals(type)) {
+ return byte.class;
+ } else if ("C".equals(type)) {
+ return char.class;
+ } else if ("S".equals(type)) {
+ return short.class;
+ } else if ("I".equals(type)) {
+ return int.class;
+ } else if ("J".equals(type)) {
+ return long.class;
+ } else if ("F".equals(type)) {
+ return float.class;
+ } else if ("D".equals(type)) {
+ return double.class;
+ } else {
+ // Class names expected for Class.forName are:
+ // * for reference types: Ljava/lang/String; -> java.lang.String
+ // * for array types: [Ljava/lang/String; -> [Ljava.lang.String;
+ type = type.startsWith("L")
+ ? type.substring(1, type.length() - 1).replace('/', '.')
+ : type.replace('/', '.');
+ }
+
+ return Class.forName(type, /* initialize */ false, DexMember.class.getClassLoader());
+ }
}
diff --git a/tests/signature/lib/common/src/android/signature/cts/DexMethod.java b/tests/signature/lib/common/src/android/signature/cts/DexMethod.java
index 967a5a8..972f69c 100644
--- a/tests/signature/lib/common/src/android/signature/cts/DexMethod.java
+++ b/tests/signature/lib/common/src/android/signature/cts/DexMethod.java
@@ -42,6 +42,17 @@
return mParamTypeList.stream().map(DexMember::dexToJavaType).collect(Collectors.toList());
}
+ public Class<?>[] getJavaParameterClasses() throws ClassNotFoundException {
+ // Ideally we'd use streams, but DexMember.typeToClass throws a checked exception, and that's
+ // tricky to handle.
+ Class<?>[] classes = new Class<?>[mParamTypeList.size()];
+ int i = 0;
+ for (String param : mParamTypeList) {
+ classes[i++] = DexMember.typeToClass(param);
+ }
+ return classes;
+ }
+
public boolean isConstructor() {
return "<init>".equals(getName()) && "V".equals(getDexType());
}
diff --git a/tests/tests/art/Android.bp b/tests/tests/art/Android.bp
new file mode 100644
index 0000000..86f1d60
--- /dev/null
+++ b/tests/tests/art/Android.bp
@@ -0,0 +1,16 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsArtTestCases",
+ defaults: ["cts_defaults"],
+ static_libs: ["ctstestrunner-axt"],
+ srcs: ["**/*.java"],
+ manifest: "AndroidManifest.xml",
+ sdk_version: "current",
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+}
diff --git a/tests/tests/art/AndroidManifest.xml b/tests/tests/art/AndroidManifest.xml
new file mode 100644
index 0000000..ef7cf1a
--- /dev/null
+++ b/tests/tests/art/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.art_cts"
+ android:targetSandboxVersion="2">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation
+ android:targetPackage="com.android.art_cts"
+ android:name="androidx.test.runner.AndroidJUnitRunner" />
+</manifest>
diff --git a/tests/tests/art/AndroidTest.xml b/tests/tests/art/AndroidTest.xml
new file mode 100644
index 0000000..8036c6f
--- /dev/null
+++ b/tests/tests/art/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<configuration description="Config for CTS ART test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="art" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsArtTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.art_cts" />
+ </test>
+</configuration>
diff --git a/tests/tests/art/OWNERS b/tests/tests/art/OWNERS
new file mode 100644
index 0000000..ef86412
--- /dev/null
+++ b/tests/tests/art/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include platform/art:/OWNERS
diff --git a/tests/tests/art/com/android/art_cts/ArtTest.java b/tests/tests/art/com/android/art_cts/ArtTest.java
new file mode 100644
index 0000000..9e65048
--- /dev/null
+++ b/tests/tests/art/com/android/art_cts/ArtTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.art_cts;
+
+import junit.framework.TestCase;
+
+import static junit.framework.Assert.assertEquals;
+
+public class ArtTest extends TestCase {
+
+ static class Helper_b197981962 {
+ int myField;
+ static Helper_b197981962 escape;
+
+ static void runTest(boolean condition) {
+ Helper_b197981962 l = new Helper_b197981962();
+ // LSE will find that this store can be removed, as both branches override the value
+ // with a new one.
+ l.myField = 42;
+ if (condition) {
+ // LSE will remove this store as well, as it's the value after the store of 42 is removed.
+ l.myField = 0;
+ // This makes sure `m` gets materialized. At this point, the bug is that the partial LSE
+ // optimization thinks the value incoming this block for `m.myField` is 42, however that
+ // store, as well as the store to 0, have been removed.
+ escape = l;
+ // Do something the compiler cannot explore.
+ escape.getClass().getDeclaredMethods();
+ assertEquals(0, escape.myField);
+ } else {
+ l.myField = 3;
+ assertEquals(3, l.myField);
+ }
+ }
+ }
+
+ public void test_b197981962() {
+ // Run enough times to trigger compilation.
+ for (int i = 0; i < 100000; ++i) {
+ Helper_b197981962.runTest(true);
+ Helper_b197981962.runTest(false);
+ }
+ }
+}
diff --git a/tests/tests/identity/Android.bp b/tests/tests/identity/Android.bp
index 01e9914..13a43de 100644
--- a/tests/tests/identity/Android.bp
+++ b/tests/tests/identity/Android.bp
@@ -32,6 +32,7 @@
"androidx.test.rules",
"compatibility-device-util-axt",
"ctstestrunner-axt",
+ "identity-credential-util",
"junit",
"cts-security-test-support-library",
"cts-keystore-user-auth-helper-library",
diff --git a/tests/tests/identity/src/android/security/identity/cts/AttestationTest.java b/tests/tests/identity/src/android/security/identity/cts/AttestationTest.java
index c63b793..884d124 100644
--- a/tests/tests/identity/src/android/security/identity/cts/AttestationTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/AttestationTest.java
@@ -51,7 +51,7 @@
@Test
public void attestationTest() throws Exception {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
diff --git a/tests/tests/identity/src/android/security/identity/cts/CreateItemsRequestTest.java b/tests/tests/identity/src/android/security/identity/cts/CreateItemsRequestTest.java
index 9dbd20c..e48a467 100644
--- a/tests/tests/identity/src/android/security/identity/cts/CreateItemsRequestTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/CreateItemsRequestTest.java
@@ -18,6 +18,8 @@
import static org.junit.Assert.assertEquals;
+import com.android.security.identity.internal.Util;
+
import org.junit.Test;
import java.util.Arrays;
diff --git a/tests/tests/identity/src/android/security/identity/cts/DynamicAuthTest.java b/tests/tests/identity/src/android/security/identity/cts/DynamicAuthTest.java
index f61273e..4d99052 100644
--- a/tests/tests/identity/src/android/security/identity/cts/DynamicAuthTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/DynamicAuthTest.java
@@ -33,6 +33,7 @@
import android.security.identity.NoAuthenticationKeyAvailableException;
import android.security.identity.ResultData;
import androidx.test.InstrumentationRegistry;
+import com.android.security.identity.internal.Util;
import org.junit.Test;
@@ -62,7 +63,7 @@
@Test
public void dynamicAuthTest() throws Exception {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -460,14 +461,14 @@
@Test
public void dynamicAuthWithExpirationTest() throws Exception {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
assumeTrue(
"IdentityCredential.storeStaticAuthenticationData(X509Certificate, Instant, byte[]) " +
"not supported",
- Util.getFeatureVersion() >= 202101);
+ TestUtil.getFeatureVersion() >= 202101);
String credentialName = "test";
diff --git a/tests/tests/identity/src/android/security/identity/cts/EphemeralKeyTest.java b/tests/tests/identity/src/android/security/identity/cts/EphemeralKeyTest.java
index 4441dd5..0198602 100644
--- a/tests/tests/identity/src/android/security/identity/cts/EphemeralKeyTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/EphemeralKeyTest.java
@@ -30,6 +30,7 @@
import android.security.identity.IdentityCredentialException;
import android.security.identity.IdentityCredentialStore;
import androidx.test.InstrumentationRegistry;
+import com.android.security.identity.internal.Util;
import org.junit.Test;
@@ -60,7 +61,7 @@
@Test
public void createEphemeralKey() throws IdentityCredentialException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
diff --git a/tests/tests/identity/src/android/security/identity/cts/HkdfTest.java b/tests/tests/identity/src/android/security/identity/cts/HkdfTest.java
deleted file mode 100644
index eee69f6..0000000
--- a/tests/tests/identity/src/android/security/identity/cts/HkdfTest.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.identity.cts;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.security.GeneralSecurityException;
-import java.util.Random;
-
-/*
- * This is based on https://github.com/google/tink/blob/master/java/src/test/java/com/google
- * /crypto/tink/subtle/HkdfTest.java
- * which is also Copyright (c) Google and licensed under the Apache 2 license.
- */
-@RunWith(JUnit4.class)
-public class HkdfTest {
-
- static Random sRandom = new Random();
-
- /** Encodes a byte array to hex. */
- static String hexEncode(final byte[] bytes) {
- String chars = "0123456789abcdef";
- StringBuilder result = new StringBuilder(2 * bytes.length);
- for (byte b : bytes) {
- // convert to unsigned
- int val = b & 0xff;
- result.append(chars.charAt(val / 16));
- result.append(chars.charAt(val % 16));
- }
- return result.toString();
- }
-
- /** Decodes a hex string to a byte array. */
- static byte[] hexDecode(String hex) {
- if (hex.length() % 2 != 0) {
- throw new IllegalArgumentException("Expected a string of even length");
- }
- int size = hex.length() / 2;
- byte[] result = new byte[size];
- for (int i = 0; i < size; i++) {
- int hi = Character.digit(hex.charAt(2 * i), 16);
- int lo = Character.digit(hex.charAt(2 * i + 1), 16);
- if ((hi == -1) || (lo == -1)) {
- throw new IllegalArgumentException("input is not hexadecimal");
- }
- result[i] = (byte) (16 * hi + lo);
- }
- return result;
- }
-
- static byte[] randBytes(int numBytes) {
- byte[] bytes = new byte[numBytes];
- sRandom.nextBytes(bytes);
- return bytes;
- }
-
- @Test
- public void testNullSaltOrInfo() throws Exception {
- byte[] ikm = randBytes(20);
- byte[] info = randBytes(20);
- int size = 40;
-
- byte[] hkdfWithNullSalt = Util.computeHkdf("HmacSha256", ikm, null, info, size);
- byte[] hkdfWithEmptySalt = Util.computeHkdf("HmacSha256", ikm, new byte[0], info, size);
- assertArrayEquals(hkdfWithNullSalt, hkdfWithEmptySalt);
-
- byte[] salt = randBytes(20);
- byte[] hkdfWithNullInfo = Util.computeHkdf("HmacSha256", ikm, salt, null, size);
- byte[] hkdfWithEmptyInfo = Util.computeHkdf("HmacSha256", ikm, salt, new byte[0], size);
- assertArrayEquals(hkdfWithNullInfo, hkdfWithEmptyInfo);
- }
-
- @Test
- public void testInvalidCodeSize() throws Exception {
- try {
- Util.computeHkdf("HmacSha256", new byte[0], new byte[0], new byte[0], 32 * 256);
- fail("Invalid size, should have thrown exception");
- } catch (RuntimeException expected) {
-
- // Expected
- }
- }
-
- /**
- * Tests the implementation against the test vectors from RFC 5869.
- */
- @Test
- public void testVectors() throws Exception {
- // Test case 1
- assertEquals(
- "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf"
- + "1a5a4c5db02d56ecc4c5bf34007208d5b887185865",
- computeHkdfHex("HmacSha256",
- "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
- "000102030405060708090a0b0c",
- "f0f1f2f3f4f5f6f7f8f9",
- 42));
-
- // Test case 2
- assertEquals(
- "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c"
- + "59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71"
- + "cc30c58179ec3e87c14c01d5c1f3434f1d87",
- computeHkdfHex("HmacSha256",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
- + "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
- + "404142434445464748494a4b4c4d4e4f",
- "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
- + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"
- + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
- "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
- + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef"
- + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
- 82));
-
- // Test case 3: salt is empty
- assertEquals(
- "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d"
- + "9d201395faa4b61a96c8",
- computeHkdfHex("HmacSha256",
- "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "", "",
- 42));
-
- // Test Case 4
- assertEquals(
- "085a01ea1b10f36933068b56efa5ad81a4f14b822f"
- + "5b091568a9cdd4f155fda2c22e422478d305f3f896",
- computeHkdfHex(
- "HmacSha1",
- "0b0b0b0b0b0b0b0b0b0b0b",
- "000102030405060708090a0b0c",
- "f0f1f2f3f4f5f6f7f8f9",
- 42));
-
- // Test Case 5
- assertEquals(
- "0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe"
- + "8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e"
- + "927336d0441f4c4300e2cff0d0900b52d3b4",
- computeHkdfHex(
- "HmacSha1",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
- + "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
- + "404142434445464748494a4b4c4d4e4f",
- "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
- + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"
- + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
- "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
- + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef"
- + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
- 82));
-
- // Test Case 6: salt is empty
- assertEquals(
- "0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0"
- + "ea00033de03984d34918",
- computeHkdfHex("HmacSha1", "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "", "",
- 42));
-
- // Test Case 7
- assertEquals(
- "2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5"
- + "673a081d70cce7acfc48",
- computeHkdfHex("HmacSha1", "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", "", "",
- 42));
- }
-
- /**
- * Test version of Hkdf where all inputs and outputs are hexadecimal.
- */
- private String computeHkdfHex(String macAlgorithm, String ikmHex, String saltHex,
- String infoHex,
- int size) throws GeneralSecurityException {
- return hexEncode(
- Util.computeHkdf(macAlgorithm, hexDecode(ikmHex), hexDecode(saltHex),
- hexDecode(infoHex), size));
- }
-
-}
diff --git a/tests/tests/identity/src/android/security/identity/cts/ProvisioningTest.java b/tests/tests/identity/src/android/security/identity/cts/ProvisioningTest.java
index b78cb98..fdd623c 100644
--- a/tests/tests/identity/src/android/security/identity/cts/ProvisioningTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/ProvisioningTest.java
@@ -42,6 +42,7 @@
import android.security.identity.WritableIdentityCredential;
import android.security.identity.SessionTranscriptMismatchException;
import androidx.test.InstrumentationRegistry;
+import com.android.security.identity.internal.Util;
import org.junit.Test;
@@ -368,7 +369,7 @@
@Test
public void alreadyPersonalized() throws IdentityCredentialException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -387,7 +388,7 @@
@Test
public void nonExistent() throws IdentityCredentialException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -400,7 +401,7 @@
@Test
public void defaultStoreSupportsAnyDocumentType() throws IdentityCredentialException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -412,7 +413,7 @@
@Test
public void deleteCredentialByName()
throws IdentityCredentialException, CborException, CertificateEncodingException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -450,11 +451,11 @@
@Test
public void deleteCredential()
throws IdentityCredentialException, CborException, CertificateEncodingException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
- assumeTrue("IdentityCredential.delete() not supported", Util.getFeatureVersion() >= 202101);
+ assumeTrue("IdentityCredential.delete() not supported", TestUtil.getFeatureVersion() >= 202101);
store.deleteCredentialByName("test");
assertNull(store.deleteCredentialByName("test"));
@@ -494,11 +495,11 @@
@Test
public void proofOfOwnership()
throws IdentityCredentialException, CborException, CertificateEncodingException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
- assumeTrue("IdentityCredential.proveOwnership() not supported", Util.getFeatureVersion() >= 202101);
+ assumeTrue("IdentityCredential.proveOwnership() not supported", TestUtil.getFeatureVersion() >= 202101);
store.deleteCredentialByName("test");
assertNull(store.deleteCredentialByName("test"));
@@ -535,7 +536,7 @@
@Test
public void testProvisionAndRetrieve() throws IdentityCredentialException, CborException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -625,7 +626,7 @@
@Test
public void testProvisionAndRetrieveMultipleTimes() throws IdentityCredentialException,
InvalidKeyException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -688,7 +689,7 @@
@Test
public void testProvisionAndRetrieveWithFiltering() throws IdentityCredentialException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -741,7 +742,7 @@
@Test
public void testProvisionAndRetrieveElementWithNoACP() throws IdentityCredentialException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -782,7 +783,7 @@
@Test
public void testProvisionAndRetrieveWithEntryNotInRequest() throws IdentityCredentialException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -838,7 +839,7 @@
@Test
public void nonExistentEntries() throws IdentityCredentialException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -883,7 +884,7 @@
@Test
public void multipleNamespaces() throws IdentityCredentialException, CborException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -978,7 +979,7 @@
@Test
public void testProvisionAcpIdNotInValidRange() throws IdentityCredentialException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -1016,7 +1017,7 @@
@Test
public void testProvisionAcpIdNotStartingAtZero() throws
IdentityCredentialException, CborException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
@@ -1105,11 +1106,11 @@
@Test
public void testUpdateCredential() throws IdentityCredentialException, CborException, NoSuchAlgorithmException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
Context appContext = InstrumentationRegistry.getTargetContext();
IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
- assumeTrue("IdentityCredential.update() not supported", Util.getFeatureVersion() >= 202101);
+ assumeTrue("IdentityCredential.update() not supported", TestUtil.getFeatureVersion() >= 202101);
// Create the credential...
//
diff --git a/tests/tests/identity/src/android/security/identity/cts/ReaderAuthTest.java b/tests/tests/identity/src/android/security/identity/cts/ReaderAuthTest.java
index ce5e311..f01a1fd 100644
--- a/tests/tests/identity/src/android/security/identity/cts/ReaderAuthTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/ReaderAuthTest.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
+import com.android.security.identity.internal.Util;
import android.security.identity.AccessControlProfile;
import android.security.identity.AccessControlProfileId;
@@ -86,7 +87,7 @@
KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException,
NoSuchProviderException, InvalidKeyException, SignatureException {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
// We create two reader keys - 'A' and 'B' - and then generate certificates for each of
// them, signed by a third key 'C'. We then provision a document with four elements where
diff --git a/tests/tests/identity/src/android/security/identity/cts/TestUtil.java b/tests/tests/identity/src/android/security/identity/cts/TestUtil.java
new file mode 100644
index 0000000..882439a
--- /dev/null
+++ b/tests/tests/identity/src/android/security/identity/cts/TestUtil.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity.cts;
+
+import android.security.identity.ResultData;
+import android.security.identity.IdentityCredentialStore;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.FeatureInfo;
+import android.os.SystemProperties;
+import android.security.keystore.KeyProperties;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.ECGenParameterSpec;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Formatter;
+import java.util.Map;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECPoint;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OctetString;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.builder.ArrayBuilder;
+import co.nstant.in.cbor.builder.MapBuilder;
+import co.nstant.in.cbor.model.AbstractFloat;
+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.DoublePrecisionFloat;
+import co.nstant.in.cbor.model.MajorType;
+import co.nstant.in.cbor.model.NegativeInteger;
+import co.nstant.in.cbor.model.SimpleValue;
+import co.nstant.in.cbor.model.SimpleValueType;
+import co.nstant.in.cbor.model.SpecialType;
+import co.nstant.in.cbor.model.UnicodeString;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+class TestUtil {
+ private static final String TAG = "Util";
+
+ // Returns 0 if not implemented. Otherwise returns the feature version.
+ //
+ static int getFeatureVersion() {
+ Context appContext = InstrumentationRegistry.getTargetContext();
+ PackageManager pm = appContext.getPackageManager();
+
+ int featureVersionFromPm = 0;
+ if (pm.hasSystemFeature(PackageManager.FEATURE_IDENTITY_CREDENTIAL_HARDWARE)) {
+ FeatureInfo info = null;
+ FeatureInfo[] infos = pm.getSystemAvailableFeatures();
+ for (int n = 0; n < infos.length; n++) {
+ FeatureInfo i = infos[n];
+ if (i.name.equals(PackageManager.FEATURE_IDENTITY_CREDENTIAL_HARDWARE)) {
+ info = i;
+ break;
+ }
+ }
+ if (info != null) {
+ featureVersionFromPm = info.version;
+ }
+ }
+
+ // Use of the system feature is not required since Android 12. So for Android 11
+ // return 202009 which is the feature version shipped with Android 11.
+ if (featureVersionFromPm == 0) {
+ IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
+ if (store != null) {
+ featureVersionFromPm = 202009;
+ }
+ }
+
+ return featureVersionFromPm;
+ }
+
+ // Returns true if, and only if, the Identity Credential HAL (and credstore) is implemented
+ // on the device under test.
+ static boolean isHalImplemented() {
+ Context appContext = InstrumentationRegistry.getTargetContext();
+ IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
+ if (store != null) {
+ return true;
+ }
+ return false;
+ }
+
+ // Returns true if, and only if, the Direct Access Identity Credential HAL (and credstore) is
+ // implemented on the device under test.
+ static boolean isDirectAccessHalImplemented() {
+ Context appContext = InstrumentationRegistry.getTargetContext();
+ IdentityCredentialStore store = IdentityCredentialStore.getDirectAccessInstance(appContext);
+ if (store != null) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/tests/tests/identity/src/android/security/identity/cts/UserAuthTest.java b/tests/tests/identity/src/android/security/identity/cts/UserAuthTest.java
index 2c55042..e4bd81f 100644
--- a/tests/tests/identity/src/android/security/identity/cts/UserAuthTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/UserAuthTest.java
@@ -27,6 +27,7 @@
import android.security.identity.IdentityCredentialStore;
import android.security.identity.WritableIdentityCredential;
import android.security.identity.ResultData;
+import com.android.security.identity.internal.Util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -197,7 +198,7 @@
}
void doTestUserAuth(DeviceLockSession dl, KeyguardManager keyguardManager) throws Exception {
- assumeTrue("IC HAL is not implemented", Util.isHalImplemented());
+ assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
// This test creates two different access control profiles:
//
diff --git a/tests/tests/identity/src/android/security/identity/cts/Util.java b/tests/tests/identity/src/android/security/identity/cts/Util.java
deleted file mode 100644
index 733a401..0000000
--- a/tests/tests/identity/src/android/security/identity/cts/Util.java
+++ /dev/null
@@ -1,1363 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.identity.cts;
-
-import android.security.identity.ResultData;
-import android.security.identity.IdentityCredentialStore;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.FeatureInfo;
-import android.os.SystemProperties;
-import android.security.keystore.KeyProperties;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.test.InstrumentationRegistry;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.KeyStore;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
-import java.security.PrivateKey;
-import java.security.Signature;
-import java.security.SignatureException;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.security.spec.ECGenParameterSpec;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Formatter;
-import java.util.Map;
-
-import javax.crypto.KeyAgreement;
-import javax.crypto.Mac;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-
-import java.security.interfaces.ECPublicKey;
-import java.security.spec.ECPoint;
-
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1OctetString;
-
-import co.nstant.in.cbor.CborBuilder;
-import co.nstant.in.cbor.CborDecoder;
-import co.nstant.in.cbor.CborEncoder;
-import co.nstant.in.cbor.CborException;
-import co.nstant.in.cbor.builder.ArrayBuilder;
-import co.nstant.in.cbor.builder.MapBuilder;
-import co.nstant.in.cbor.model.AbstractFloat;
-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.DoublePrecisionFloat;
-import co.nstant.in.cbor.model.MajorType;
-import co.nstant.in.cbor.model.NegativeInteger;
-import co.nstant.in.cbor.model.SimpleValue;
-import co.nstant.in.cbor.model.SimpleValueType;
-import co.nstant.in.cbor.model.SpecialType;
-import co.nstant.in.cbor.model.UnicodeString;
-import co.nstant.in.cbor.model.UnsignedInteger;
-
-class Util {
- private static final String TAG = "Util";
-
- // Returns 0 if not implemented. Otherwise returns the feature version.
- //
- static int getFeatureVersion() {
- Context appContext = InstrumentationRegistry.getTargetContext();
- PackageManager pm = appContext.getPackageManager();
-
- int featureVersionFromPm = 0;
- if (pm.hasSystemFeature(PackageManager.FEATURE_IDENTITY_CREDENTIAL_HARDWARE)) {
- FeatureInfo info = null;
- FeatureInfo[] infos = pm.getSystemAvailableFeatures();
- for (int n = 0; n < infos.length; n++) {
- FeatureInfo i = infos[n];
- if (i.name.equals(PackageManager.FEATURE_IDENTITY_CREDENTIAL_HARDWARE)) {
- info = i;
- break;
- }
- }
- if (info != null) {
- featureVersionFromPm = info.version;
- }
- }
-
- // Use of the system feature is not required since Android 12. So for Android 11
- // return 202009 which is the feature version shipped with Android 11.
- if (featureVersionFromPm == 0) {
- IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
- if (store != null) {
- featureVersionFromPm = 202009;
- }
- }
-
- return featureVersionFromPm;
- }
-
- static byte[] canonicalizeCbor(byte[] encodedCbor) throws CborException {
- ByteArrayInputStream bais = new ByteArrayInputStream(encodedCbor);
- List<DataItem> dataItems = new CborDecoder(bais).decode();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- for(DataItem dataItem : dataItems) {
- CborEncoder encoder = new CborEncoder(baos);
- encoder.encode(dataItem);
- }
- return baos.toByteArray();
- }
-
-
- static String cborPrettyPrint(byte[] encodedBytes) throws CborException {
- StringBuilder sb = new StringBuilder();
-
- ByteArrayInputStream bais = new ByteArrayInputStream(encodedBytes);
- List<DataItem> dataItems = new CborDecoder(bais).decode();
- int count = 0;
- for (DataItem dataItem : dataItems) {
- if (count > 0) {
- sb.append(",\n");
- }
- cborPrettyPrintDataItem(sb, 0, dataItem);
- count++;
- }
-
- return sb.toString();
- }
-
- // Returns true iff all elements in |items| are not compound (e.g. an array or a map).
- static boolean cborAreAllDataItemsNonCompound(List<DataItem> items) {
- for (DataItem item : items) {
- switch (item.getMajorType()) {
- case ARRAY:
- case MAP:
- return false;
- default:
- // continue inspecting other data items
- }
- }
- return true;
- }
-
- static void cborPrettyPrintDataItem(StringBuilder sb, int indent, DataItem dataItem) {
- StringBuilder indentBuilder = new StringBuilder();
- for (int n = 0; n < indent; n++) {
- indentBuilder.append(' ');
- }
- String indentString = indentBuilder.toString();
-
- if (dataItem.hasTag()) {
- sb.append(String.format("tag %d ", dataItem.getTag().getValue()));
- }
-
- switch (dataItem.getMajorType()) {
- case INVALID:
- // TODO: throw
- sb.append("<invalid>");
- break;
- case UNSIGNED_INTEGER: {
- // Major type 0: an unsigned integer.
- BigInteger value = ((UnsignedInteger) dataItem).getValue();
- sb.append(value);
- }
- break;
- case NEGATIVE_INTEGER: {
- // Major type 1: a negative integer.
- BigInteger value = ((NegativeInteger) dataItem).getValue();
- sb.append(value);
- }
- break;
- case BYTE_STRING: {
- // Major type 2: a byte string.
- byte[] value = ((ByteString) dataItem).getBytes();
- sb.append("[");
- int count = 0;
- for (byte b : value) {
- if (count > 0) {
- sb.append(", ");
- }
- sb.append(String.format("0x%02x", b));
- count++;
- }
- sb.append("]");
- }
- break;
- case UNICODE_STRING: {
- // Major type 3: string of Unicode characters that is encoded as UTF-8 [RFC3629].
- String value = ((UnicodeString) dataItem).getString();
- // TODO: escape ' in |value|
- sb.append("'" + value + "'");
- }
- break;
- case ARRAY: {
- // Major type 4: an array of data items.
- List<DataItem> items = ((co.nstant.in.cbor.model.Array) dataItem).getDataItems();
- if (items.size() == 0) {
- sb.append("[]");
- } else if (cborAreAllDataItemsNonCompound(items)) {
- // The case where everything fits on one line.
- sb.append("[");
- int count = 0;
- for (DataItem item : items) {
- cborPrettyPrintDataItem(sb, indent, item);
- if (++count < items.size()) {
- sb.append(", ");
- }
- }
- sb.append("]");
- } else {
- sb.append("[\n" + indentString);
- int count = 0;
- for (DataItem item : items) {
- sb.append(" ");
- cborPrettyPrintDataItem(sb, indent + 2, item);
- if (++count < items.size()) {
- sb.append(",");
- }
- sb.append("\n" + indentString);
- }
- sb.append("]");
- }
- }
- break;
- case MAP: {
- // Major type 5: a map of pairs of data items.
- Collection<DataItem> keys = ((co.nstant.in.cbor.model.Map) dataItem).getKeys();
- if (keys.size() == 0) {
- sb.append("{}");
- } else {
- sb.append("{\n" + indentString);
- int count = 0;
- for (DataItem key : keys) {
- sb.append(" ");
- DataItem value = ((co.nstant.in.cbor.model.Map) dataItem).get(key);
- cborPrettyPrintDataItem(sb, indent + 2, key);
- sb.append(" : ");
- cborPrettyPrintDataItem(sb, indent + 2, value);
- if (++count < keys.size()) {
- sb.append(",");
- }
- sb.append("\n" + indentString);
- }
- sb.append("}");
- }
- }
- break;
- case TAG:
- // Major type 6: optional semantic tagging of other major types
- //
- // We never encounter this one since it's automatically handled via the
- // DataItem that is tagged.
- throw new RuntimeException("Semantic tag data item not expected");
-
- case SPECIAL:
- // Major type 7: floating point numbers and simple data types that need no
- // content, as well as the "break" stop code.
- if (dataItem instanceof SimpleValue) {
- switch (((SimpleValue) dataItem).getSimpleValueType()) {
- case FALSE:
- sb.append("false");
- break;
- case TRUE:
- sb.append("true");
- break;
- case NULL:
- sb.append("null");
- break;
- case UNDEFINED:
- sb.append("undefined");
- break;
- case RESERVED:
- sb.append("reserved");
- break;
- case UNALLOCATED:
- sb.append("unallocated");
- break;
- }
- } else if (dataItem instanceof DoublePrecisionFloat) {
- DecimalFormat df = new DecimalFormat("0",
- DecimalFormatSymbols.getInstance(Locale.ENGLISH));
- df.setMaximumFractionDigits(340);
- sb.append(df.format(((DoublePrecisionFloat) dataItem).getValue()));
- } else if (dataItem instanceof AbstractFloat) {
- DecimalFormat df = new DecimalFormat("0",
- DecimalFormatSymbols.getInstance(Locale.ENGLISH));
- df.setMaximumFractionDigits(340);
- sb.append(df.format(((AbstractFloat) dataItem).getValue()));
- } else {
- sb.append("break");
- }
- break;
- }
- }
-
- public static byte[] encodeCbor(List<DataItem> dataItems) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- CborEncoder encoder = new CborEncoder(baos);
- try {
- encoder.encode(dataItems);
- } catch (CborException e) {
- throw new RuntimeException("Error encoding data", e);
- }
- return baos.toByteArray();
- }
-
- public static byte[] coseBuildToBeSigned(byte[] encodedProtectedHeaders,
- byte[] payload,
- byte[] detachedContent) {
- CborBuilder sigStructure = new CborBuilder();
- ArrayBuilder<CborBuilder> array = sigStructure.addArray();
-
- array.add("Signature1");
- array.add(encodedProtectedHeaders);
-
- // We currently don't support Externally Supplied Data (RFC 8152 section 4.3)
- // so external_aad is the empty bstr
- byte emptyExternalAad[] = new byte[0];
- array.add(emptyExternalAad);
-
- // Next field is the payload, independently of how it's transported (RFC
- // 8152 section 4.4). Since our API specifies only one of |data| and
- // |detachedContent| can be non-empty, it's simply just the non-empty one.
- if (payload != null && payload.length > 0) {
- array.add(payload);
- } else {
- array.add(detachedContent);
- }
- array.end();
- return encodeCbor(sigStructure.build());
- }
-
- private static final int COSE_LABEL_ALG = 1;
- private static final int COSE_LABEL_X5CHAIN = 33; // temporary identifier
-
- // From "COSE Algorithms" registry
- private static final int COSE_ALG_ECDSA_256 = -7;
- private static final int COSE_ALG_HMAC_256_256 = 5;
-
- private static byte[] signatureDerToCose(byte[] signature) {
- if (signature.length > 128) {
- throw new RuntimeException("Unexpected length " + signature.length
- + ", expected less than 128");
- }
- if (signature[0] != 0x30) {
- throw new RuntimeException("Unexpected first byte " + signature[0]
- + ", expected 0x30");
- }
- if ((signature[1] & 0x80) != 0x00) {
- throw new RuntimeException("Unexpected second byte " + signature[1]
- + ", bit 7 shouldn't be set");
- }
- int rOffset = 2;
- int rSize = signature[rOffset + 1];
- byte[] rBytes = stripLeadingZeroes(
- Arrays.copyOfRange(signature,rOffset + 2, rOffset + rSize + 2));
-
- int sOffset = rOffset + 2 + rSize;
- int sSize = signature[sOffset + 1];
- byte[] sBytes = stripLeadingZeroes(
- Arrays.copyOfRange(signature, sOffset + 2, sOffset + sSize + 2));
-
- if (rBytes.length > 32) {
- throw new RuntimeException("rBytes.length is " + rBytes.length + " which is > 32");
- }
- if (sBytes.length > 32) {
- throw new RuntimeException("sBytes.length is " + sBytes.length + " which is > 32");
- }
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- for (int n = 0; n < 32 - rBytes.length; n++) {
- baos.write(0x00);
- }
- baos.write(rBytes);
- for (int n = 0; n < 32 - sBytes.length; n++) {
- baos.write(0x00);
- }
- baos.write(sBytes);
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- return baos.toByteArray();
- }
-
- // Adds leading 0x00 if the first encoded byte MSB is set.
- private static byte[] encodePositiveBigInteger(BigInteger i) {
- byte[] bytes = i.toByteArray();
- if ((bytes[0] & 0x80) != 0) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- baos.write(0x00);
- baos.write(bytes);
- } catch (IOException e) {
- e.printStackTrace();
- throw new RuntimeException("Failed writing data", e);
- }
- bytes = baos.toByteArray();
- }
- return bytes;
- }
-
- private static byte[] signatureCoseToDer(byte[] signature) {
- if (signature.length != 64) {
- throw new RuntimeException("signature.length is " + signature.length + ", expected 64");
- }
- BigInteger r = new BigInteger(Arrays.copyOfRange(signature, 0, 32));
- BigInteger s = new BigInteger(Arrays.copyOfRange(signature, 32, 64));
- byte[] rBytes = encodePositiveBigInteger(r);
- byte[] sBytes = encodePositiveBigInteger(s);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- baos.write(0x30);
- baos.write(2 + rBytes.length + 2 + sBytes.length);
- baos.write(0x02);
- baos.write(rBytes.length);
- baos.write(rBytes);
- baos.write(0x02);
- baos.write(sBytes.length);
- baos.write(sBytes);
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- return baos.toByteArray();
- }
-
- public static byte[] coseSign1Sign(PrivateKey key,
- @Nullable byte[] data,
- byte[] detachedContent,
- @Nullable Collection<X509Certificate> certificateChain)
- throws NoSuchAlgorithmException, InvalidKeyException, CertificateEncodingException {
-
- int dataLen = (data != null ? data.length : 0);
- int detachedContentLen = (detachedContent != null ? detachedContent.length : 0);
- if (dataLen > 0 && detachedContentLen > 0) {
- throw new RuntimeException("data and detachedContent cannot both be non-empty");
- }
-
- CborBuilder protectedHeaders = new CborBuilder();
- MapBuilder<CborBuilder> protectedHeadersMap = protectedHeaders.addMap();
- protectedHeadersMap.put(COSE_LABEL_ALG, COSE_ALG_ECDSA_256);
- byte[] protectedHeadersBytes = encodeCbor(protectedHeaders.build());
-
- byte[] toBeSigned = coseBuildToBeSigned(protectedHeadersBytes, data, detachedContent);
-
- byte[] coseSignature = null;
- try {
- Signature s = Signature.getInstance("SHA256withECDSA");
- s.initSign(key);
- s.update(toBeSigned);
- byte[] derSignature = s.sign();
- coseSignature = signatureDerToCose(derSignature);
- } catch (SignatureException e) {
- throw new RuntimeException("Error signing data");
- }
-
- CborBuilder builder = new CborBuilder();
- ArrayBuilder<CborBuilder> array = builder.addArray();
- array.add(protectedHeadersBytes);
- MapBuilder<ArrayBuilder<CborBuilder>> unprotectedHeaders = array.addMap();
- if (certificateChain != null && certificateChain.size() > 0) {
- if (certificateChain.size() == 1) {
- X509Certificate cert = certificateChain.iterator().next();
- unprotectedHeaders.put(COSE_LABEL_X5CHAIN, cert.getEncoded());
- } else {
- ArrayBuilder<MapBuilder<ArrayBuilder<CborBuilder>>> x5chainsArray =
- unprotectedHeaders.putArray(COSE_LABEL_X5CHAIN);
- for (X509Certificate cert : certificateChain) {
- x5chainsArray.add(cert.getEncoded());
- }
- }
- }
- if (data == null || data.length == 0) {
- array.add(new SimpleValue(SimpleValueType.NULL));
- } else {
- array.add(data);
- }
- array.add(coseSignature);
-
- return encodeCbor(builder.build());
- }
-
- public static boolean coseSign1CheckSignature(byte[] signatureCose1,
- byte[] detachedContent,
- PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException {
- ByteArrayInputStream bais = new ByteArrayInputStream(signatureCose1);
- List<DataItem> dataItems = null;
- try {
- dataItems = new CborDecoder(bais).decode();
- } catch (CborException e) {
- throw new RuntimeException("Given signature is not valid CBOR", e);
- }
- if (dataItems.size() != 1) {
- throw new RuntimeException("Expected just one data item");
- }
- DataItem dataItem = dataItems.get(0);
- if (dataItem.getMajorType() != MajorType.ARRAY) {
- throw new RuntimeException("Data item is not an array");
- }
- List<DataItem> items = ((co.nstant.in.cbor.model.Array) dataItem).getDataItems();
- if (items.size() < 4) {
- throw new RuntimeException("Expected at least four items in COSE_Sign1 array");
- }
- if (items.get(0).getMajorType() != MajorType.BYTE_STRING) {
- throw new RuntimeException("Item 0 (protected headers) is not a byte-string");
- }
- byte[] encodedProtectedHeaders =
- ((co.nstant.in.cbor.model.ByteString) items.get(0)).getBytes();
- byte[] payload = new byte[0];
- if (items.get(2).getMajorType() == MajorType.SPECIAL) {
- if (((co.nstant.in.cbor.model.Special) items.get(2)).getSpecialType()
- != SpecialType.SIMPLE_VALUE) {
- throw new RuntimeException("Item 2 (payload) is a special but not a simple value");
- }
- SimpleValue simple = (co.nstant.in.cbor.model.SimpleValue) items.get(2);
- if (simple.getSimpleValueType() != SimpleValueType.NULL) {
- throw new RuntimeException("Item 2 (payload) is a simple but not the value null");
- }
- } else if (items.get(2).getMajorType() == MajorType.BYTE_STRING) {
- payload = ((co.nstant.in.cbor.model.ByteString) items.get(2)).getBytes();
- } else {
- throw new RuntimeException("Item 2 (payload) is not nil or byte-string");
- }
- if (items.get(3).getMajorType() != MajorType.BYTE_STRING) {
- throw new RuntimeException("Item 3 (signature) is not a byte-string");
- }
- byte[] coseSignature = ((co.nstant.in.cbor.model.ByteString) items.get(3)).getBytes();
-
- byte[] derSignature = signatureCoseToDer(coseSignature);
-
- int dataLen = payload.length;
- int detachedContentLen = (detachedContent != null ? detachedContent.length : 0);
- if (dataLen > 0 && detachedContentLen > 0) {
- throw new RuntimeException("data and detachedContent cannot both be non-empty");
- }
-
- byte[] toBeSigned = Util.coseBuildToBeSigned(encodedProtectedHeaders,
- payload, detachedContent);
-
- try {
- Signature verifier = Signature.getInstance("SHA256withECDSA");
- verifier.initVerify(publicKey);
- verifier.update(toBeSigned);
- return verifier.verify(derSignature);
- } catch (SignatureException e) {
- throw new RuntimeException("Error verifying signature");
- }
- }
-
- // Returns the empty byte-array if no data is included in the structure.
- //
- // Throws RuntimeException if the given bytes aren't valid COSE_Sign1.
- //
- public static byte[] coseSign1GetData(byte[] signatureCose1) {
- ByteArrayInputStream bais = new ByteArrayInputStream(signatureCose1);
- List<DataItem> dataItems = null;
- try {
- dataItems = new CborDecoder(bais).decode();
- } catch (CborException e) {
- throw new RuntimeException("Given signature is not valid CBOR", e);
- }
- if (dataItems.size() != 1) {
- throw new RuntimeException("Expected just one data item");
- }
- DataItem dataItem = dataItems.get(0);
- if (dataItem.getMajorType() != MajorType.ARRAY) {
- throw new RuntimeException("Data item is not an array");
- }
- List<DataItem> items = ((co.nstant.in.cbor.model.Array) dataItem).getDataItems();
- if (items.size() < 4) {
- throw new RuntimeException("Expected at least four items in COSE_Sign1 array");
- }
- byte[] payload = new byte[0];
- if (items.get(2).getMajorType() == MajorType.SPECIAL) {
- if (((co.nstant.in.cbor.model.Special) items.get(2)).getSpecialType()
- != SpecialType.SIMPLE_VALUE) {
- throw new RuntimeException("Item 2 (payload) is a special but not a simple value");
- }
- SimpleValue simple = (co.nstant.in.cbor.model.SimpleValue) items.get(2);
- if (simple.getSimpleValueType() != SimpleValueType.NULL) {
- throw new RuntimeException("Item 2 (payload) is a simple but not the value null");
- }
- } else if (items.get(2).getMajorType() == MajorType.BYTE_STRING) {
- payload = ((co.nstant.in.cbor.model.ByteString) items.get(2)).getBytes();
- } else {
- throw new RuntimeException("Item 2 (payload) is not nil or byte-string");
- }
- return payload;
- }
-
- // Returns the empty collection if no x5chain is included in the structure.
- //
- // Throws RuntimeException if the given bytes aren't valid COSE_Sign1.
- //
- public static Collection<X509Certificate> coseSign1GetX5Chain(byte[] signatureCose1)
- throws CertificateException {
- ArrayList<X509Certificate> ret = new ArrayList<>();
- ByteArrayInputStream bais = new ByteArrayInputStream(signatureCose1);
- List<DataItem> dataItems = null;
- try {
- dataItems = new CborDecoder(bais).decode();
- } catch (CborException e) {
- throw new RuntimeException("Given signature is not valid CBOR", e);
- }
- if (dataItems.size() != 1) {
- throw new RuntimeException("Expected just one data item");
- }
- DataItem dataItem = dataItems.get(0);
- if (dataItem.getMajorType() != MajorType.ARRAY) {
- throw new RuntimeException("Data item is not an array");
- }
- List<DataItem> items = ((co.nstant.in.cbor.model.Array) dataItem).getDataItems();
- if (items.size() < 4) {
- throw new RuntimeException("Expected at least four items in COSE_Sign1 array");
- }
- if (items.get(1).getMajorType() != MajorType.MAP) {
- throw new RuntimeException("Item 1 (unprocted headers) is not a map");
- }
- co.nstant.in.cbor.model.Map map = (co.nstant.in.cbor.model.Map) items.get(1);
- DataItem x5chainItem = map.get(new UnsignedInteger(COSE_LABEL_X5CHAIN));
- if (x5chainItem != null) {
- CertificateFactory factory = CertificateFactory.getInstance("X.509");
- if (x5chainItem instanceof ByteString) {
- ByteArrayInputStream certBais =
- new ByteArrayInputStream(((ByteString) x5chainItem).getBytes());
- ret.add((X509Certificate) factory.generateCertificate(certBais));
- } else if (x5chainItem instanceof Array) {
- for (DataItem certItem : ((Array) x5chainItem).getDataItems()) {
- if (!(certItem instanceof ByteString)) {
- throw new RuntimeException(
- "Unexpected type for array item in x5chain value");
- }
- ByteArrayInputStream certBais =
- new ByteArrayInputStream(((ByteString) certItem).getBytes());
- ret.add((X509Certificate) factory.generateCertificate(certBais));
- }
- } else {
- throw new RuntimeException("Unexpected type for x5chain value");
- }
- }
- return ret;
- }
-
- public static byte[] coseBuildToBeMACed(byte[] encodedProtectedHeaders,
- byte[] payload,
- byte[] detachedContent) {
- CborBuilder macStructure = new CborBuilder();
- ArrayBuilder<CborBuilder> array = macStructure.addArray();
-
- array.add("MAC0");
- array.add(encodedProtectedHeaders);
-
- // We currently don't support Externally Supplied Data (RFC 8152 section 4.3)
- // so external_aad is the empty bstr
- byte emptyExternalAad[] = new byte[0];
- array.add(emptyExternalAad);
-
- // Next field is the payload, independently of how it's transported (RFC
- // 8152 section 4.4). Since our API specifies only one of |data| and
- // |detachedContent| can be non-empty, it's simply just the non-empty one.
- if (payload != null && payload.length > 0) {
- array.add(payload);
- } else {
- array.add(detachedContent);
- }
-
- return encodeCbor(macStructure.build());
- }
-
- public static byte[] coseMac0(SecretKey key,
- @Nullable byte[] data,
- byte[] detachedContent)
- throws NoSuchAlgorithmException, InvalidKeyException, CertificateEncodingException {
-
- int dataLen = (data != null ? data.length : 0);
- int detachedContentLen = (detachedContent != null ? detachedContent.length : 0);
- if (dataLen > 0 && detachedContentLen > 0) {
- throw new RuntimeException("data and detachedContent cannot both be non-empty");
- }
-
- CborBuilder protectedHeaders = new CborBuilder();
- MapBuilder<CborBuilder> protectedHeadersMap = protectedHeaders.addMap();
- protectedHeadersMap.put(COSE_LABEL_ALG, COSE_ALG_HMAC_256_256);
- byte[] protectedHeadersBytes = encodeCbor(protectedHeaders.build());
-
- byte[] toBeMACed = coseBuildToBeMACed(protectedHeadersBytes, data, detachedContent);
-
- byte[] mac = null;
- Mac m = Mac.getInstance("HmacSHA256");
- m.init(key);
- m.update(toBeMACed);
- mac = m.doFinal();
-
- CborBuilder builder = new CborBuilder();
- ArrayBuilder<CborBuilder> array = builder.addArray();
- array.add(protectedHeadersBytes);
- MapBuilder<ArrayBuilder<CborBuilder>> unprotectedHeaders = array.addMap();
- if (data == null || data.length == 0) {
- array.add(new SimpleValue(SimpleValueType.NULL));
- } else {
- array.add(data);
- }
- array.add(mac);
-
- return encodeCbor(builder.build());
- }
-
- public static String replaceLine(String text, int lineNumber, String replacementLine) {
- String[] lines = text.split("\n");
- int numLines = lines.length;
- if (lineNumber < 0) {
- lineNumber = numLines - (-lineNumber);
- }
- StringBuilder sb = new StringBuilder();
- for (int n = 0; n < numLines; n++) {
- if (n == lineNumber) {
- sb.append(replacementLine);
- } else {
- sb.append(lines[n]);
- }
- // Only add terminating newline if passed-in string ends in a newline.
- if (n == numLines - 1) {
- if (text.endsWith(("\n"))) {
- sb.append('\n');
- }
- } else {
- sb.append('\n');
- }
- }
- return sb.toString();
- }
-
- static byte[] cborEncode(DataItem dataItem) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- new CborEncoder(baos).encode(dataItem);
- } catch (CborException e) {
- // This should never happen and we don't want cborEncode() to throw since that
- // would complicate all callers. Log it instead.
- e.printStackTrace();
- Log.e(TAG, "Error encoding DataItem");
- }
- return baos.toByteArray();
- }
-
- static byte[] cborEncodeBoolean(boolean value) {
- return cborEncode(new CborBuilder().add(value).build().get(0));
- }
-
- static byte[] cborEncodeString(@NonNull String value) {
- return cborEncode(new CborBuilder().add(value).build().get(0));
- }
-
- static byte[] cborEncodeBytestring(@NonNull byte[] value) {
- return cborEncode(new CborBuilder().add(value).build().get(0));
- }
-
- static byte[] cborEncodeInt(long value) {
- return cborEncode(new CborBuilder().add(value).build().get(0));
- }
-
- static final int CBOR_SEMANTIC_TAG_ENCODED_CBOR = 24;
-
- static DataItem cborToDataItem(byte[] data) {
- ByteArrayInputStream bais = new ByteArrayInputStream(data);
- try {
- List<DataItem> dataItems = new CborDecoder(bais).decode();
- if (dataItems.size() != 1) {
- throw new RuntimeException("Expected 1 item, found " + dataItems.size());
- }
- return dataItems.get(0);
- } catch (CborException e) {
- throw new RuntimeException("Error decoding data", e);
- }
- }
-
- static boolean cborDecodeBoolean(@NonNull byte[] data) {
- return cborToDataItem(data) == SimpleValue.TRUE;
- }
-
- static String cborDecodeString(@NonNull byte[] data) {
- return ((co.nstant.in.cbor.model.UnicodeString) cborToDataItem(data)).getString();
- }
-
- static long cborDecodeInt(@NonNull byte[] data) {
- return ((co.nstant.in.cbor.model.Number) cborToDataItem(data)).getValue().longValue();
- }
-
- static byte[] cborDecodeBytestring(@NonNull byte[] data) {
- return ((co.nstant.in.cbor.model.ByteString) cborToDataItem(data)).getBytes();
- }
-
- static String getStringEntry(ResultData data, String namespaceName, String name) {
- return Util.cborDecodeString(data.getEntry(namespaceName, name));
- }
-
- static boolean getBooleanEntry(ResultData data, String namespaceName, String name) {
- return Util.cborDecodeBoolean(data.getEntry(namespaceName, name));
- }
-
- static long getIntegerEntry(ResultData data, String namespaceName, String name) {
- return Util.cborDecodeInt(data.getEntry(namespaceName, name));
- }
-
- static byte[] getBytestringEntry(ResultData data, String namespaceName, String name) {
- return Util.cborDecodeBytestring(data.getEntry(namespaceName, name));
- }
-
- /*
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: ecdsa-with-SHA256
- Issuer: CN=fake
- Validity
- Not Before: Jan 1 00:00:00 1970 GMT
- Not After : Jan 1 00:00:00 2048 GMT
- Subject: CN=fake
- Subject Public Key Info:
- Public Key Algorithm: id-ecPublicKey
- Public-Key: (256 bit)
- 00000000 04 9b 60 70 8a 99 b6 bf e3 b8 17 02 9e 93 eb 48 |..`p...........H|
- 00000010 23 b9 39 89 d1 00 bf a0 0f d0 2f bd 6b 11 bc d1 |#.9......./.k...|
- 00000020 19 53 54 28 31 00 f5 49 db 31 fb 9f 7d 99 bf 23 |.ST(1..I.1..}..#|
- 00000030 fb 92 04 6b 23 63 55 98 ad 24 d2 68 c4 83 bf 99 |...k#cU..$.h....|
- 00000040 62 |b|
- Signature Algorithm: ecdsa-with-SHA256
- 30:45:02:20:67:ad:d1:34:ed:a5:68:3f:5b:33:ee:b3:18:a2:
- eb:03:61:74:0f:21:64:4a:a3:2e:82:b3:92:5c:21:0f:88:3f:
- 02:21:00:b7:38:5c:9b:f2:9c:b1:27:86:37:44:df:eb:4a:b2:
- 6c:11:9a:c1:ff:b2:80:95:ce:fc:5f:26:b4:20:6e:9b:0d
- */
-
-
- static @NonNull X509Certificate signPublicKeyWithPrivateKey(String keyToSignAlias,
- String keyToSignWithAlias) {
-
- KeyStore ks = null;
- try {
- ks = KeyStore.getInstance("AndroidKeyStore");
- ks.load(null);
-
- /* First note that KeyStore.getCertificate() returns a self-signed X.509 certificate
- * for the key in question. As per RFC 5280, section 4.1 an X.509 certificate has the
- * following structure:
- *
- * Certificate ::= SEQUENCE {
- * tbsCertificate TBSCertificate,
- * signatureAlgorithm AlgorithmIdentifier,
- * signatureValue BIT STRING }
- *
- * Conveniently, the X509Certificate class has a getTBSCertificate() method which
- * returns the tbsCertificate blob. So all we need to do is just sign that and build
- * signatureAlgorithm and signatureValue and combine it with tbsCertificate. We don't
- * need a full-blown ASN.1/DER encoder to do this.
- */
- X509Certificate selfSignedCert = (X509Certificate) ks.getCertificate(keyToSignAlias);
- byte[] tbsCertificate = selfSignedCert.getTBSCertificate();
-
- KeyStore.Entry keyToSignWithEntry = ks.getEntry(keyToSignWithAlias, null);
- Signature s = Signature.getInstance("SHA256withECDSA");
- s.initSign(((KeyStore.PrivateKeyEntry) keyToSignWithEntry).getPrivateKey());
- s.update(tbsCertificate);
- byte[] signatureValue = s.sign();
-
- /* The DER encoding for a SEQUENCE of length 128-65536 - the length is updated below.
- *
- * We assume - and test for below - that the final length is always going to be in
- * this range. This is a sound assumption given we're using 256-bit EC keys.
- */
- byte[] sequence = new byte[]{
- 0x30, (byte) 0x82, 0x00, 0x00
- };
-
- /* The DER encoding for the ECDSA with SHA-256 signature algorithm:
- *
- * SEQUENCE (1 elem)
- * OBJECT IDENTIFIER 1.2.840.10045.4.3.2 ecdsaWithSHA256 (ANSI X9.62 ECDSA
- * algorithm with SHA256)
- */
- byte[] signatureAlgorithm = new byte[]{
- 0x30, 0x0a, 0x06, 0x08, 0x2a, (byte) 0x86, 0x48, (byte) 0xce, 0x3d, 0x04, 0x03,
- 0x02
- };
-
- /* The DER encoding for a BIT STRING with one element - the length is updated below.
- *
- * We assume the length of signatureValue is always going to be less than 128. This
- * assumption works since we know ecdsaWithSHA256 signatures are always 69, 70, or
- * 71 bytes long when DER encoded.
- */
- byte[] bitStringForSignature = new byte[]{0x03, 0x00, 0x00};
-
- // Calculate sequence length and set it in |sequence|.
- int sequenceLength = tbsCertificate.length
- + signatureAlgorithm.length
- + bitStringForSignature.length
- + signatureValue.length;
- if (sequenceLength < 128 || sequenceLength > 65535) {
- throw new Exception("Unexpected sequenceLength " + sequenceLength);
- }
- sequence[2] = (byte) (sequenceLength >> 8);
- sequence[3] = (byte) (sequenceLength & 0xff);
-
- // Calculate signatureValue length and set it in |bitStringForSignature|.
- int signatureValueLength = signatureValue.length + 1;
- if (signatureValueLength >= 128) {
- throw new Exception("Unexpected signatureValueLength " + signatureValueLength);
- }
- bitStringForSignature[1] = (byte) signatureValueLength;
-
- // Finally concatenate everything together.
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- baos.write(sequence);
- baos.write(tbsCertificate);
- baos.write(signatureAlgorithm);
- baos.write(bitStringForSignature);
- baos.write(signatureValue);
- byte[] resultingCertBytes = baos.toByteArray();
-
- CertificateFactory cf = CertificateFactory.getInstance("X.509");
- ByteArrayInputStream bais = new ByteArrayInputStream(resultingCertBytes);
- X509Certificate result = (X509Certificate) cf.generateCertificate(bais);
- return result;
- } catch (Exception e) {
- throw new RuntimeException("Error signing public key with private key", e);
- }
- }
-
- static byte[] buildDeviceAuthenticationCbor(String docType,
- byte[] encodedSessionTranscript,
- byte[] deviceNameSpacesBytes) {
- ByteArrayOutputStream daBaos = new ByteArrayOutputStream();
- try {
- ByteArrayInputStream bais = new ByteArrayInputStream(encodedSessionTranscript);
- List<DataItem> dataItems = null;
- dataItems = new CborDecoder(bais).decode();
- DataItem sessionTranscript = dataItems.get(0);
- ByteString deviceNameSpacesBytesItem = new ByteString(deviceNameSpacesBytes);
- deviceNameSpacesBytesItem.setTag(CBOR_SEMANTIC_TAG_ENCODED_CBOR);
- new CborEncoder(daBaos).encode(new CborBuilder()
- .addArray()
- .add("DeviceAuthentication")
- .add(sessionTranscript)
- .add(docType)
- .add(deviceNameSpacesBytesItem)
- .end()
- .build());
- } catch (CborException e) {
- throw new RuntimeException("Error encoding DeviceAuthentication", e);
- }
- return daBaos.toByteArray();
- }
-
- static byte[] buildReaderAuthenticationBytesCbor(
- byte[] encodedSessionTranscript,
- byte[] requestMessageBytes) {
-
- ByteArrayOutputStream daBaos = new ByteArrayOutputStream();
- try {
- ByteArrayInputStream bais = new ByteArrayInputStream(encodedSessionTranscript);
- List<DataItem> dataItems = null;
- dataItems = new CborDecoder(bais).decode();
- DataItem sessionTranscript = dataItems.get(0);
- ByteString requestMessageBytesItem = new ByteString(requestMessageBytes);
- requestMessageBytesItem.setTag(CBOR_SEMANTIC_TAG_ENCODED_CBOR);
- new CborEncoder(daBaos).encode(new CborBuilder()
- .addArray()
- .add("ReaderAuthentication")
- .add(sessionTranscript)
- .add(requestMessageBytesItem)
- .end()
- .build());
- } catch (CborException e) {
- throw new RuntimeException("Error encoding ReaderAuthentication", e);
- }
- byte[] readerAuthentication = daBaos.toByteArray();
- return Util.prependSemanticTagForEncodedCbor(readerAuthentication);
- }
-
- static byte[] prependSemanticTagForEncodedCbor(byte[] encodedCbor) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- ByteString taggedBytestring = new ByteString(encodedCbor);
- taggedBytestring.setTag(CBOR_SEMANTIC_TAG_ENCODED_CBOR);
- new CborEncoder(baos).encode(taggedBytestring);
- } catch (CborException e) {
- throw new RuntimeException("Error encoding with semantic tag for CBOR encoding", e);
- }
- return baos.toByteArray();
- }
-
- static byte[] concatArrays(byte[] a, byte[] b) {
- byte[] ret = new byte[a.length + b.length];
- System.arraycopy(a, 0, ret, 0, a.length);
- System.arraycopy(b, 0, ret, a.length, b.length);
- return ret;
- }
-
- static SecretKey calcEMacKeyForReader(PublicKey authenticationPublicKey,
- PrivateKey ephemeralReaderPrivateKey,
- byte[] encodedSessionTranscript) {
- try {
- KeyAgreement ka = KeyAgreement.getInstance("ECDH");
- ka.init(ephemeralReaderPrivateKey);
- ka.doPhase(authenticationPublicKey, true);
- byte[] sharedSecret = ka.generateSecret();
-
- byte[] sessionTranscriptBytes =
- Util.prependSemanticTagForEncodedCbor(encodedSessionTranscript);
-
- byte[] salt = MessageDigest.getInstance("SHA-256").digest(sessionTranscriptBytes);
- byte[] info = new byte[] {'E', 'M', 'a', 'c', 'K', 'e', 'y'};
- byte[] derivedKey = Util.computeHkdf("HmacSha256", sharedSecret, salt, info, 32);
- SecretKey secretKey = new SecretKeySpec(derivedKey, "");
- return secretKey;
- } catch (InvalidKeyException
- | NoSuchAlgorithmException e) {
- throw new RuntimeException("Error performing key agreement", e);
- }
- }
-
- /**
- * Computes an HKDF.
- *
- * This is based on https://github.com/google/tink/blob/master/java/src/main/java/com/google
- * /crypto/tink/subtle/Hkdf.java
- * which is also Copyright (c) Google and also licensed under the Apache 2 license.
- *
- * @param macAlgorithm the MAC algorithm used for computing the Hkdf. I.e., "HMACSHA1" or
- * "HMACSHA256".
- * @param ikm the input keying material.
- * @param salt optional salt. A possibly non-secret random value. If no salt is
- * provided (i.e. if
- * salt has length 0) then an array of 0s of the same size as the hash
- * digest is used as salt.
- * @param info optional context and application specific information.
- * @param size The length of the generated pseudorandom string in bytes. The maximal
- * size is
- * 255.DigestSize, where DigestSize is the size of the underlying HMAC.
- * @return size pseudorandom bytes.
- */
- static byte[] computeHkdf(
- String macAlgorithm, final byte[] ikm, final byte[] salt, final byte[] info, int size) {
- Mac mac = null;
- try {
- mac = Mac.getInstance(macAlgorithm);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException("No such algorithm: " + macAlgorithm, e);
- }
- if (size > 255 * mac.getMacLength()) {
- throw new RuntimeException("size too large");
- }
- try {
- if (salt == null || salt.length == 0) {
- // According to RFC 5869, Section 2.2 the salt is optional. If no salt is provided
- // then HKDF uses a salt that is an array of zeros of the same length as the hash
- // digest.
- mac.init(new SecretKeySpec(new byte[mac.getMacLength()], macAlgorithm));
- } else {
- mac.init(new SecretKeySpec(salt, macAlgorithm));
- }
- byte[] prk = mac.doFinal(ikm);
- byte[] result = new byte[size];
- int ctr = 1;
- int pos = 0;
- mac.init(new SecretKeySpec(prk, macAlgorithm));
- byte[] digest = new byte[0];
- while (true) {
- mac.update(digest);
- mac.update(info);
- mac.update((byte) ctr);
- digest = mac.doFinal();
- if (pos + digest.length < size) {
- System.arraycopy(digest, 0, result, pos, digest.length);
- pos += digest.length;
- ctr++;
- } else {
- System.arraycopy(digest, 0, result, pos, size - pos);
- break;
- }
- }
- return result;
- } catch (InvalidKeyException e) {
- throw new RuntimeException("Error MACing", e);
- }
- }
-
- static byte[] stripLeadingZeroes(byte[] value) {
- int n = 0;
- while (n < value.length && value[n] == 0) {
- n++;
- }
- int newLen = value.length - n;
- byte[] ret = new byte[newLen];
- int m = 0;
- while (n < value.length) {
- ret[m++] = value[n++];
- }
- return ret;
- }
-
- static void hexdump(String name, byte[] data) {
- int n, m, o;
- StringBuilder sb = new StringBuilder();
- Formatter fmt = new Formatter(sb);
- for (n = 0; n < data.length; n += 16) {
- fmt.format("%04x ", n);
- for (m = 0; m < 16 && n + m < data.length; m++) {
- fmt.format("%02x ", data[n + m]);
- }
- for (o = m; o < 16; o++) {
- sb.append(" ");
- }
- sb.append(" ");
- for (m = 0; m < 16 && n + m < data.length; m++) {
- int c = data[n + m] & 0xff;
- fmt.format("%c", Character.isISOControl(c) ? '.' : c);
- }
- sb.append("\n");
- }
- sb.append("\n");
- Log.e(TAG, name + ": dumping " + data.length + " bytes\n" + fmt.toString());
- }
-
-
- // This returns a SessionTranscript which satisfy the requirement
- // that the uncompressed X and Y coordinates of the public key for the
- // mDL's ephemeral key-pair appear somewhere in the encoded
- // DeviceEngagement.
- static byte[] buildSessionTranscript(KeyPair ephemeralKeyPair) {
- // Make the coordinates appear in an already encoded bstr - this
- // mimics how the mDL COSE_Key appear as encoded data inside the
- // encoded DeviceEngagement
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- ECPoint w = ((ECPublicKey) ephemeralKeyPair.getPublic()).getW();
- // X and Y are always positive so for interop we remove any leading zeroes
- // inserted by the BigInteger encoder.
- byte[] x = stripLeadingZeroes(w.getAffineX().toByteArray());
- byte[] y = stripLeadingZeroes(w.getAffineY().toByteArray());
- baos.write(new byte[]{42});
- baos.write(x);
- baos.write(y);
- baos.write(new byte[]{43, 44});
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- byte[] blobWithCoords = baos.toByteArray();
-
- baos = new ByteArrayOutputStream();
- try {
- new CborEncoder(baos).encode(new CborBuilder()
- .addArray()
- .add(blobWithCoords)
- .end()
- .build());
- } catch (CborException e) {
- e.printStackTrace();
- return null;
- }
- ByteString encodedDeviceEngagementItem = new ByteString(baos.toByteArray());
- ByteString encodedEReaderKeyItem = new ByteString(cborEncodeString("doesn't matter"));
- encodedDeviceEngagementItem.setTag(CBOR_SEMANTIC_TAG_ENCODED_CBOR);
- encodedEReaderKeyItem.setTag(CBOR_SEMANTIC_TAG_ENCODED_CBOR);
-
- baos = new ByteArrayOutputStream();
- try {
- new CborEncoder(baos).encode(new CborBuilder()
- .addArray()
- .add(encodedDeviceEngagementItem)
- .add(encodedEReaderKeyItem)
- .end()
- .build());
- } catch (CborException e) {
- e.printStackTrace();
- return null;
- }
- return baos.toByteArray();
- }
-
- /*
- * Helper function to create a CBOR data for requesting data items. The IntentToRetain
- * value will be set to false for all elements.
- *
- * <p>The returned CBOR data conforms to the following CDDL schema:</p>
- *
- * <pre>
- * ItemsRequest = {
- * ? "docType" : DocType,
- * "nameSpaces" : NameSpaces,
- * ? "RequestInfo" : {* tstr => any} ; Additional info the reader wants to provide
- * }
- *
- * NameSpaces = {
- * + NameSpace => DataElements ; Requested data elements for each NameSpace
- * }
- *
- * DataElements = {
- * + DataElement => IntentToRetain
- * }
- *
- * DocType = tstr
- *
- * DataElement = tstr
- * IntentToRetain = bool
- * NameSpace = tstr
- * </pre>
- *
- * @param entriesToRequest The entries to request, organized as a map of namespace
- * names with each value being a collection of data elements
- * in the given namespace.
- * @param docType The document type or {@code null} if there is no document
- * type.
- * @return CBOR data conforming to the CDDL mentioned above.
- */
- static @NonNull byte[] createItemsRequest(
- @NonNull Map<String, Collection<String>> entriesToRequest,
- @Nullable String docType) {
- CborBuilder builder = new CborBuilder();
- MapBuilder<CborBuilder> mapBuilder = builder.addMap();
- if (docType != null) {
- mapBuilder.put("docType", docType);
- }
-
- MapBuilder<MapBuilder<CborBuilder>> nsMapBuilder = mapBuilder.putMap("nameSpaces");
- for (String namespaceName : entriesToRequest.keySet()) {
- Collection<String> entryNames = entriesToRequest.get(namespaceName);
- MapBuilder<MapBuilder<MapBuilder<CborBuilder>>> entryNameMapBuilder =
- nsMapBuilder.putMap(namespaceName);
- for (String entryName : entryNames) {
- entryNameMapBuilder.put(entryName, false);
- }
- }
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- CborEncoder encoder = new CborEncoder(baos);
- try {
- encoder.encode(builder.build());
- } catch (CborException e) {
- throw new RuntimeException("Error encoding CBOR", e);
- }
- return baos.toByteArray();
- }
-
- static KeyPair createEphemeralKeyPair() {
- try {
- KeyPairGenerator kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC);
- ECGenParameterSpec ecSpec = new ECGenParameterSpec("prime256v1");
- kpg.initialize(ecSpec);
- KeyPair keyPair = kpg.generateKeyPair();
- return keyPair;
- } catch (NoSuchAlgorithmException
- | InvalidAlgorithmParameterException e) {
- throw new RuntimeException("Error generating ephemeral key-pair", e);
- }
- }
-
- // Returns true if, and only if, the Identity Credential HAL (and credstore) is implemented
- // on the device under test.
- static boolean isHalImplemented() {
- Context appContext = InstrumentationRegistry.getTargetContext();
- IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
- if (store != null) {
- return true;
- }
- return false;
- }
-
- // Returns true if, and only if, the Direct Access Identity Credential HAL (and credstore) is
- // implemented on the device under test.
- static boolean isDirectAccessHalImplemented() {
- Context appContext = InstrumentationRegistry.getTargetContext();
- IdentityCredentialStore store = IdentityCredentialStore.getDirectAccessInstance(appContext);
- if (store != null) {
- return true;
- }
- return false;
- }
-
- static byte[] getPopSha256FromAuthKeyCert(X509Certificate cert) {
- byte[] octetString = cert.getExtensionValue("1.3.6.1.4.1.11129.2.1.26");
- if (octetString == null) {
- return null;
- }
- Util.hexdump("octetString", octetString);
-
- try {
- ASN1InputStream asn1InputStream = new ASN1InputStream(octetString);
- byte[] cborBytes = ((ASN1OctetString) asn1InputStream.readObject()).getOctets();
- Util.hexdump("cborBytes", cborBytes);
-
- ByteArrayInputStream bais = new ByteArrayInputStream(cborBytes);
- List<DataItem> dataItems = new CborDecoder(bais).decode();
- if (dataItems.size() != 1) {
- throw new RuntimeException("Expected 1 item, found " + dataItems.size());
- }
- if (!(dataItems.get(0) instanceof co.nstant.in.cbor.model.Array)) {
- throw new RuntimeException("Item is not a map");
- }
- co.nstant.in.cbor.model.Array array = (co.nstant.in.cbor.model.Array) dataItems.get(0);
- List<DataItem> items = array.getDataItems();
- if (items.size() < 2) {
- throw new RuntimeException("Expected at least 2 array items, found " + items.size());
- }
- if (!(items.get(0) instanceof UnicodeString)) {
- throw new RuntimeException("First array item is not a string");
- }
- String id = ((UnicodeString) items.get(0)).getString();
- if (!id.equals("ProofOfBinding")) {
- throw new RuntimeException("Expected ProofOfBinding, got " + id);
- }
- if (!(items.get(1) instanceof ByteString)) {
- throw new RuntimeException("Second array item is not a bytestring");
- }
- byte[] popSha256 = ((ByteString) items.get(1)).getBytes();
- if (popSha256.length != 32) {
- throw new RuntimeException("Expected bstr to be 32 bytes, it is " + popSha256.length);
- }
- return popSha256;
- } catch (IOException e) {
- throw new RuntimeException("Error decoding extension data", e);
- } catch (CborException e) {
- throw new RuntimeException("Error decoding data", e);
- }
- }
-
-}
diff --git a/tests/tests/identity/src/android/security/identity/cts/UtilUnitTests.java b/tests/tests/identity/src/android/security/identity/cts/UtilUnitTests.java
deleted file mode 100644
index c77de79..0000000
--- a/tests/tests/identity/src/android/security/identity/cts/UtilUnitTests.java
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.identity.cts;
-
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyProperties;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-
-import java.security.cert.X509Certificate;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-
-import co.nstant.in.cbor.CborBuilder;
-import co.nstant.in.cbor.CborEncoder;
-import co.nstant.in.cbor.CborException;
-import co.nstant.in.cbor.builder.ArrayBuilder;
-import co.nstant.in.cbor.model.ByteString;
-import co.nstant.in.cbor.model.DoublePrecisionFloat;
-import co.nstant.in.cbor.model.HalfPrecisionFloat;
-import co.nstant.in.cbor.model.NegativeInteger;
-import co.nstant.in.cbor.model.SimpleValue;
-import co.nstant.in.cbor.model.SimpleValueType;
-import co.nstant.in.cbor.model.SinglePrecisionFloat;
-import co.nstant.in.cbor.model.UnicodeString;
-import co.nstant.in.cbor.model.UnsignedInteger;
-
-public class UtilUnitTests {
- @Test
- public void prettyPrintMultipleCompleteTypes() throws CborException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new CborBuilder()
- .add("text") // add string
- .add(1234) // add integer
- .add(new byte[]{0x10}) // add byte array
- .addArray() // add array
- .add(1)
- .add("text")
- .end()
- .build());
- assertEquals("'text',\n"
- + "1234,\n"
- + "[0x10],\n"
- + "[1, 'text']", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintString() throws CborException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new UnicodeString("foobar"));
- assertEquals("'foobar'", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintBytestring() throws CborException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new ByteString(new byte[]{1, 2, 33, (byte) 254}));
- assertEquals("[0x01, 0x02, 0x21, 0xfe]", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintUnsignedInteger() throws CborException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new UnsignedInteger(42));
- assertEquals("42", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintNegativeInteger() throws CborException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new NegativeInteger(-42));
- assertEquals("-42", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintDouble() throws CborException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new DoublePrecisionFloat(1.1));
- assertEquals("1.1", Util.cborPrettyPrint(baos.toByteArray()));
-
- baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new DoublePrecisionFloat(-42.0000000001));
- assertEquals("-42.0000000001", Util.cborPrettyPrint(baos.toByteArray()));
-
- baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new DoublePrecisionFloat(-5));
- assertEquals("-5", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintFloat() throws CborException {
- ByteArrayOutputStream baos;
-
- // TODO: These two tests yield different results on different devices, disable for now
- /*
- baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new SinglePrecisionFloat(1.1f));
- assertEquals("1.100000023841858", Util.cborPrettyPrint(baos.toByteArray()));
-
- baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new SinglePrecisionFloat(-42.0001f));
- assertEquals("-42.000099182128906", Util.cborPrettyPrint(baos.toByteArray()));
- */
-
- baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new SinglePrecisionFloat(-5f));
- assertEquals("-5", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintHalfFloat() throws CborException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new HalfPrecisionFloat(1.1f));
- assertEquals("1.099609375", Util.cborPrettyPrint(baos.toByteArray()));
-
- baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new HalfPrecisionFloat(-42.0001f));
- assertEquals("-42", Util.cborPrettyPrint(baos.toByteArray()));
-
- baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new HalfPrecisionFloat(-5f));
- assertEquals("-5", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintFalse() throws CborException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new SimpleValue(SimpleValueType.FALSE));
- assertEquals("false", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintTrue() throws CborException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new SimpleValue(SimpleValueType.TRUE));
- assertEquals("true", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintNull() throws CborException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new SimpleValue(SimpleValueType.NULL));
- assertEquals("null", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintUndefined() throws CborException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new SimpleValue(SimpleValueType.UNDEFINED));
- assertEquals("undefined", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintTag() throws CborException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new CborBuilder()
- .addTag(0)
- .add("ABC")
- .build());
- byte[] data = baos.toByteArray();
- assertEquals("tag 0 'ABC'", Util.cborPrettyPrint(data));
- }
-
- @Test
- public void prettyPrintArrayNoCompounds() throws CborException {
- // If an array has no compound elements, no newlines are used.
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new CborBuilder()
- .addArray() // add array
- .add(1)
- .add("text")
- .add(new ByteString(new byte[]{1, 2, 3}))
- .end()
- .build());
- assertEquals("[1, 'text', [0x01, 0x02, 0x03]]", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintArray() throws CborException {
- // This array contains a compound value so will use newlines
- CborBuilder array = new CborBuilder();
- ArrayBuilder<CborBuilder> arrayBuilder = array.addArray();
- arrayBuilder.add(2);
- arrayBuilder.add(3);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new CborBuilder()
- .addArray() // add array
- .add(1)
- .add("text")
- .add(new ByteString(new byte[]{1, 2, 3}))
- .add(array.build().get(0))
- .end()
- .build());
- assertEquals("[\n"
- + " 1,\n"
- + " 'text',\n"
- + " [0x01, 0x02, 0x03],\n"
- + " [2, 3]\n"
- + "]", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void prettyPrintMap() throws CborException {
- // If an array has no compound elements, no newlines are used.
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- new CborEncoder(baos).encode(new CborBuilder()
- .addMap()
- .put("Foo", 42)
- .put("Bar", "baz")
- .put(43, 44)
- .put(new UnicodeString("bstr"), new ByteString(new byte[]{1, 2, 3}))
- .put(new ByteString(new byte[]{1, 2, 3}), new UnicodeString("other way"))
- .end()
- .build());
- assertEquals("{\n"
- + " 43 : 44,\n"
- + " [0x01, 0x02, 0x03] : 'other way',\n"
- + " 'Bar' : 'baz',\n"
- + " 'Foo' : 42,\n"
- + " 'bstr' : [0x01, 0x02, 0x03]\n"
- + "}", Util.cborPrettyPrint(baos.toByteArray()));
- }
-
- @Test
- public void cborEncodeDecode() {
- // TODO: add better coverage and check specific encoding etc.
- assertEquals(42, Util.cborDecodeInt(Util.cborEncodeInt(42)));
- assertEquals(123456, Util.cborDecodeInt(Util.cborEncodeInt(123456)));
- assertFalse(Util.cborDecodeBoolean(Util.cborEncodeBoolean(false)));
- assertTrue(Util.cborDecodeBoolean(Util.cborEncodeBoolean(true)));
- }
-
- private KeyPair coseGenerateKeyPair() throws Exception {
- KeyPairGenerator kpg = KeyPairGenerator.getInstance(
- KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
- KeyGenParameterSpec.Builder builder =
- new KeyGenParameterSpec.Builder(
- "coseTestKeyPair",
- KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
- .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512);
- kpg.initialize(builder.build());
- return kpg.generateKeyPair();
- }
-
- @Test
- public void coseSignAndVerify() throws Exception {
- KeyPair keyPair = coseGenerateKeyPair();
- byte[] data = new byte[] {0x10, 0x11, 0x12, 0x13};
- byte[] detachedContent = new byte[] {};
- byte[] sig = Util.coseSign1Sign(keyPair.getPrivate(), data, detachedContent, null);
- assertTrue(Util.coseSign1CheckSignature(sig, detachedContent, keyPair.getPublic()));
- assertArrayEquals(data, Util.coseSign1GetData(sig));
- assertEquals(new ArrayList() {}, Util.coseSign1GetX5Chain(sig));
- }
-
- @Test
- public void coseSignAndVerifyDetachedContent() throws Exception {
- KeyPair keyPair = coseGenerateKeyPair();
- byte[] data = new byte[] {};
- byte[] detachedContent = new byte[] {0x20, 0x21, 0x22, 0x23, 0x24};
- byte[] sig = Util.coseSign1Sign(keyPair.getPrivate(), data, detachedContent, null);
- assertTrue(Util.coseSign1CheckSignature(sig, detachedContent, keyPair.getPublic()));
- assertArrayEquals(data, Util.coseSign1GetData(sig));
- assertEquals(new ArrayList() {}, Util.coseSign1GetX5Chain(sig));
- }
-
- @Test
- public void coseSignAndVerifySingleCertificate() throws Exception {
- KeyPair keyPair = coseGenerateKeyPair();
- byte[] data = new byte[] {};
- byte[] detachedContent = new byte[] {0x20, 0x21, 0x22, 0x23, 0x24};
- ArrayList<X509Certificate> certs = new ArrayList() {};
- certs.add(Util.signPublicKeyWithPrivateKey("coseTestKeyPair", "coseTestKeyPair"));
- byte[] sig = Util.coseSign1Sign(keyPair.getPrivate(), data, detachedContent, certs);
- assertTrue(Util.coseSign1CheckSignature(sig, detachedContent, keyPair.getPublic()));
- assertArrayEquals(data, Util.coseSign1GetData(sig));
- assertEquals(certs, Util.coseSign1GetX5Chain(sig));
- }
-
- @Test
- public void coseSignAndVerifyMultipleCertificates() throws Exception {
- KeyPair keyPair = coseGenerateKeyPair();
- byte[] data = new byte[] {};
- byte[] detachedContent = new byte[] {0x20, 0x21, 0x22, 0x23, 0x24};
- ArrayList<X509Certificate> certs = new ArrayList() {};
- certs.add(Util.signPublicKeyWithPrivateKey("coseTestKeyPair", "coseTestKeyPair"));
- certs.add(Util.signPublicKeyWithPrivateKey("coseTestKeyPair", "coseTestKeyPair"));
- certs.add(Util.signPublicKeyWithPrivateKey("coseTestKeyPair", "coseTestKeyPair"));
- byte[] sig = Util.coseSign1Sign(keyPair.getPrivate(), data, detachedContent, certs);
- assertTrue(Util.coseSign1CheckSignature(sig, detachedContent, keyPair.getPublic()));
- assertArrayEquals(data, Util.coseSign1GetData(sig));
- assertEquals(certs, Util.coseSign1GetX5Chain(sig));
- }
-
- @Test
- public void coseMac0() throws Exception {
- SecretKey secretKey = new SecretKeySpec(new byte[32], "");
- byte[] data = new byte[] {0x10, 0x11, 0x12, 0x13};
- byte[] detachedContent = new byte[] {};
- byte[] mac = Util.coseMac0(secretKey, data, detachedContent);
- assertEquals("[\n"
- + " [0xa1, 0x01, 0x05],\n"
- + " {},\n"
- + " [0x10, 0x11, 0x12, 0x13],\n"
- + " [0x6c, 0xec, 0xb5, 0x6a, 0xc9, 0x5c, 0xae, 0x3b, 0x41, 0x13, 0xde, 0xa4, "
- + "0xd8, 0x86, 0x5c, 0x28, 0x2c, 0xd5, 0xa5, 0x13, 0xff, 0x3b, 0xd1, 0xde, 0x70, "
- + "0x5e, 0xbb, 0xe2, 0x2d, 0x42, 0xbe, 0x53]\n"
- + "]", Util.cborPrettyPrint(mac));
- }
-
- @Test
- public void coseMac0DetachedContent() throws Exception {
- SecretKey secretKey = new SecretKeySpec(new byte[32], "");
- byte[] data = new byte[] {};
- byte[] detachedContent = new byte[] {0x10, 0x11, 0x12, 0x13};
- byte[] mac = Util.coseMac0(secretKey, data, detachedContent);
- // Same HMAC as in coseMac0 test, only difference is that payload is null.
- assertEquals("[\n"
- + " [0xa1, 0x01, 0x05],\n"
- + " {},\n"
- + " null,\n"
- + " [0x6c, 0xec, 0xb5, 0x6a, 0xc9, 0x5c, 0xae, 0x3b, 0x41, 0x13, 0xde, 0xa4, "
- + "0xd8, 0x86, 0x5c, 0x28, 0x2c, 0xd5, 0xa5, 0x13, 0xff, 0x3b, 0xd1, 0xde, 0x70, "
- + "0x5e, 0xbb, 0xe2, 0x2d, 0x42, 0xbe, 0x53]\n"
- + "]", Util.cborPrettyPrint(mac));
- }
-
- @Test
- public void replaceLineTest() {
- assertEquals("foo",
- Util.replaceLine("Hello World", 0, "foo"));
- assertEquals("foo\n",
- Util.replaceLine("Hello World\n", 0, "foo"));
- assertEquals("Hello World",
- Util.replaceLine("Hello World", 1, "foo"));
- assertEquals("Hello World\n",
- Util.replaceLine("Hello World\n", 1, "foo"));
- assertEquals("foo\ntwo\nthree",
- Util.replaceLine("one\ntwo\nthree", 0, "foo"));
- assertEquals("one\nfoo\nthree",
- Util.replaceLine("one\ntwo\nthree", 1, "foo"));
- assertEquals("one\ntwo\nfoo",
- Util.replaceLine("one\ntwo\nthree", 2, "foo"));
- assertEquals("one\ntwo\nfoo",
- Util.replaceLine("one\ntwo\nthree", -1, "foo"));
- assertEquals("one\ntwo\nthree\nfoo",
- Util.replaceLine("one\ntwo\nthree\nfour", -1, "foo"));
- assertEquals("one\ntwo\nfoo\nfour",
- Util.replaceLine("one\ntwo\nthree\nfour", -2, "foo"));
- }
-
-}
diff --git a/tests/tests/identity/src/android/security/identity/cts/X509CertificateSigningTest.java b/tests/tests/identity/src/android/security/identity/cts/X509CertificateSigningTest.java
index 7153982..0fe6e2f 100644
--- a/tests/tests/identity/src/android/security/identity/cts/X509CertificateSigningTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/X509CertificateSigningTest.java
@@ -27,6 +27,7 @@
import android.security.keystore.KeyProperties;
import android.util.AtomicFile;
import android.util.Log;
+import com.android.security.identity.internal.Util;
import androidx.test.InstrumentationRegistry;
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index b86302c..e12ee51 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -2859,8 +2859,8 @@
if (audioCaps != null) {
format = MediaFormat.createAudioFormat(
type,
- audioCaps.getMaxInputChannelCount(),
- audioCaps.getSupportedSampleRateRanges()[0].getLower());
+ audioCaps.getSupportedSampleRateRanges()[0].getLower(),
+ audioCaps.getMaxInputChannelCount());
if (info.isEncoder()) {
format.setInteger(MediaFormat.KEY_BIT_RATE, AUDIO_BIT_RATE);
}
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
deleted file mode 100644
index 582419f..0000000
--- a/tests/tests/os/Android.mk
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# platform version check (b/32056228)
-# ============================================================
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := cts-platform-version-check
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-cts_platform_version_path := cts/tests/tests/os/assets/platform_versions.txt
-cts_platform_version_string := $(shell cat $(cts_platform_version_path))
-cts_platform_release_path := cts/tests/tests/os/assets/platform_releases.txt
-cts_platform_release_string := $(shell cat $(cts_platform_release_path))
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE) : $(cts_platform_version_path) build/core/version_defaults.mk
- $(hide) if [ -z "$(findstring $(PLATFORM_VERSION),$(cts_platform_version_string))" ]; then \
- echo "============================================================" 1>&2; \
- echo "Could not find version \"$(PLATFORM_VERSION)\" in CTS platform version file:" 1>&2; \
- echo "" 1>&2; \
- echo " $(cts_platform_version_path)" 1>&2; \
- echo "" 1>&2; \
- echo "Most likely PLATFORM_VERSION in build/core/version_defaults.mk" 1>&2; \
- echo "has changed and a new version must be added to this CTS file." 1>&2; \
- echo "============================================================" 1>&2; \
- exit 1; \
- fi
- $(hide) if [ -z "$(findstring $(PLATFORM_VERSION_LAST_STABLE),$(cts_platform_release_string))" ]; then \
- echo "============================================================" 1>&2; \
- echo "Could not find version \"$(PLATFORM_VERSION_LAST_STABLE)\" in CTS platform release file:" 1>&2; \
- echo "" 1>&2; \
- echo " $(cts_platform_release_path)" 1>&2; \
- echo "" 1>&2; \
- echo "Most likely PLATFORM_VERSION_LAST_STABLE in build/core/version_defaults.mk" 1>&2; \
- echo "has changed and a new version must be added to this CTS file." 1>&2; \
- echo "============================================================" 1>&2; \
- exit 1; \
- fi
- @mkdir -p $(dir $@)
- echo $(cts_platform_version_string) > $@
diff --git a/tests/tests/os/src/android/os/cts/EnvironmentTest.java b/tests/tests/os/src/android/os/cts/EnvironmentTest.java
index 2ce40fe..9252f6ba 100644
--- a/tests/tests/os/src/android/os/cts/EnvironmentTest.java
+++ b/tests/tests/os/src/android/os/cts/EnvironmentTest.java
@@ -43,14 +43,11 @@
}
/**
- * TMPDIR being set prevents apps from asking to have temporary files
- * placed in their own storage, instead forcing their location to
- * something OS-defined. If TMPDIR points to a global shared directory,
+ * If TMPDIR points to a global shared directory,
* this could compromise the security of the files.
*/
public void testNoTmpDir() {
- assertNull("environment variable TMPDIR should not be set",
- System.getenv("TMPDIR"));
+ assertTrue(System.getenv("TMPDIR").endsWith("android.os.cts/cache"));
}
/**
diff --git a/tests/tests/os/src/android/os/cts/StrictModeTest.java b/tests/tests/os/src/android/os/cts/StrictModeTest.java
index f0358bd..92f5dc4 100644
--- a/tests/tests/os/src/android/os/cts/StrictModeTest.java
+++ b/tests/tests/os/src/android/os/cts/StrictModeTest.java
@@ -37,6 +37,7 @@
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.strictmode.UnbufferedIoViolation;
import android.os.StrictMode;
import android.os.StrictMode.ThreadPolicy.Builder;
import android.os.StrictMode.ViolationInfo;
@@ -88,6 +89,9 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
+import java.util.Random;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
/** Tests for {@link StrictMode} */
@RunWith(AndroidJUnit4.class)
@@ -479,6 +483,55 @@
}
@Test
+ public void testUnbufferedIoGZipInput() throws Exception {
+ StrictMode.setThreadPolicy(
+ new StrictMode.ThreadPolicy.Builder().detectUnbufferedIo().penaltyLog().build());
+
+ inspectViolation(
+ () -> {
+ File tmp = File.createTempFile("StrictModeTest", "tmp");
+ try (FileOutputStream fos = new FileOutputStream(tmp);
+ GZIPOutputStream gzippedOut = new GZIPOutputStream(fos)) {
+ byte[] data = new byte[10240];
+ new Random().nextBytes(data);
+ gzippedOut.write(data);
+ }
+
+ try (FileInputStream fileInputStream = new FileInputStream(tmp);
+ GZIPInputStream in = new GZIPInputStream(fileInputStream)) {
+
+ byte[] buffer = new byte[1024];
+ while (in.read(buffer) != -1) {}
+ }
+ },
+ info -> assertThat(info.getViolationClass())
+ .isAssignableTo(UnbufferedIoViolation.class));
+ }
+
+ @Test
+ public void testUnbufferedIoGZipOutput() throws Exception {
+ StrictMode.setThreadPolicy(
+ new StrictMode.ThreadPolicy.Builder().detectUnbufferedIo().penaltyLog().build());
+
+ inspectViolation(
+ () -> {
+ byte[] data = new byte[512];
+ Random random = new Random(0);
+ try (FileOutputStream ostream = new FileOutputStream(
+ File.createTempFile("StrictModeTest","testUnbufferedIo.dat"));
+ GZIPOutputStream gzippedOut = new GZIPOutputStream(ostream)) {
+ for (int i = 0; i < 9; i++) {
+ random.nextBytes(data);
+ gzippedOut.write(data, 0, data.length);
+ }
+ }
+ },
+ info -> assertThat(info.getViolationClass())
+ .isAssignableTo(UnbufferedIoViolation.class));
+ }
+
+
+ @Test
public void testViolationAcrossBinder() throws Exception {
runWithRemoteServiceBound(
getContext(),
diff --git a/tests/tests/os/src/android/os/image/cts/DynamicSystemClientTest.java b/tests/tests/os/src/android/os/image/cts/DynamicSystemClientTest.java
index fed6b44..b961efb 100644
--- a/tests/tests/os/src/android/os/image/cts/DynamicSystemClientTest.java
+++ b/tests/tests/os/src/android/os/image/cts/DynamicSystemClientTest.java
@@ -20,6 +20,8 @@
import static org.junit.Assert.fail;
import android.app.Instrumentation;
+import android.content.ActivityNotFoundException;
+import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.image.DynamicSystemClient;
import android.platform.test.annotations.AppModeFull;
@@ -29,6 +31,7 @@
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,6 +43,12 @@
private boolean mUpdated;
private Instrumentation mInstrumentation;
+ private static final String DSU_PACKAGE_NAME = "com.android.dynsystem";
+
+ private PackageManager getPackageManager() {
+ return mInstrumentation.getContext().getPackageManager();
+ }
+
public void onStatusChanged(int status, int cause, long progress, Throwable detail) {
mUpdated = true;
}
@@ -63,6 +72,13 @@
mUpdated = false;
try {
dSClient.start(uri, 1024L << 10);
+ } catch (ActivityNotFoundException e) {
+ try {
+ getPackageManager().getPackageInfo(DSU_PACKAGE_NAME, 0);
+ } catch (PackageManager.NameNotFoundException ignore) {
+ Assume.assumeNoException(ignore);
+ }
+ throw e;
} catch (SecurityException e) {
fail();
}
@@ -90,6 +106,13 @@
Uri uri = Uri.parse("https://www.google.com/").buildUpon().build();
try {
dSClient.start(uri, 1024L << 10);
+ } catch (ActivityNotFoundException e) {
+ try {
+ getPackageManager().getPackageInfo(DSU_PACKAGE_NAME, 0);
+ } catch (PackageManager.NameNotFoundException ignore) {
+ Assume.assumeNoException(ignore);
+ }
+ throw e;
} catch (SecurityException e) {
fail();
}
diff --git a/tests/tests/permission3/res/values/strings.xml b/tests/tests/permission3/res/values/strings.xml
index d6d368b..194f203 100755
--- a/tests/tests/permission3/res/values/strings.xml
+++ b/tests/tests/permission3/res/values/strings.xml
@@ -18,9 +18,6 @@
<resources>
<string name="permissions">Permissions</string>
- <string name="deny">Don\u2019t allow</string>
- <string name="ask">Ask every time</string>
- <string name="allow">Allow</string>
<string name="allow_foreground">Allow only while using the app</string>
<string name="allow_media_storage">Allow access to media only</string>
<string name="allow_external_storage">Allow management of all files</string>
diff --git a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
index 70f73b7..867cbf0 100644
--- a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
@@ -72,6 +72,12 @@
"com.android.permissioncontroller:" +
"id/permission_no_upgrade_and_dont_ask_again_button"
+ const val ALLOW_RADIO_BUTTON = "com.android.permissioncontroller:id/allow_radio_button"
+ const val ALLOW_FOREGROUND_RADIO_BUTTON =
+ "com.android.permissioncontroller:id/allow_foreground_only_radio_button"
+ const val ASK_RADIO_BUTTON = "com.android.permissioncontroller:id/ask_radio_button"
+ const val DENY_RADIO_BUTTON = "com.android.permissioncontroller:id/deny_radio_button"
+
const val ALLOW_BUTTON_TEXT = "grant_dialog_button_allow"
const val ALLOW_FOREGROUND_BUTTON_TEXT = "grant_dialog_button_allow_foreground"
const val DENY_BUTTON_TEXT = "grant_dialog_button_deny"
@@ -420,45 +426,45 @@
val wasGranted = if (isAutomotive) {
// Automotive doesn't support one time permissions, and thus
// won't show an "Ask every time" message
- !waitFindObject(byTextRes(R.string.deny)).isChecked
+ !waitFindObject(By.res(DENY_RADIO_BUTTON)).isChecked
} else {
- !(waitFindObject(byTextRes(R.string.deny)).isChecked ||
+ !(waitFindObject(By.res(DENY_RADIO_BUTTON)).isChecked ||
(!isLegacyApp && hasAskButton(permission) &&
- waitFindObject(byTextRes(R.string.ask)).isChecked))
+ waitFindObject(By.res(ASK_RADIO_BUTTON)).isChecked))
}
var alreadyChecked = false
val button = waitFindObject(
- byTextRes(
- if (isAutomotive) {
- // Automotive doesn't support one time permissions, and thus
- // won't show an "Ask every time" message
- when (state) {
- PermissionState.ALLOWED -> R.string.allow
- PermissionState.DENIED -> R.string.deny
- PermissionState.DENIED_WITH_PREJUDICE -> R.string.deny
- }
- } else {
- when (state) {
- PermissionState.ALLOWED ->
- if (showsForegroundOnlyButton(permission)) {
- R.string.allow_foreground
- } else if (isMediaStorageButton(permission, targetSdk)) {
- R.string.allow_media_storage
- } else if (isAllStorageButton(permission, targetSdk)) {
- R.string.allow_external_storage
- } else {
- R.string.allow
- }
- PermissionState.DENIED ->
- if (!isLegacyApp && hasAskButton(permission)) {
- R.string.ask
- } else {
- R.string.deny
- }
- PermissionState.DENIED_WITH_PREJUDICE -> R.string.deny
- }
+ if (isAutomotive) {
+ // Automotive doesn't support one time permissions, and thus
+ // won't show an "Ask every time" message
+ when (state) {
+ PermissionState.ALLOWED -> By.res(ALLOW_RADIO_BUTTON)
+ PermissionState.DENIED -> By.res(DENY_RADIO_BUTTON)
+ PermissionState.DENIED_WITH_PREJUDICE -> By.res(DENY_RADIO_BUTTON)
}
- )
+ } else {
+ when (state) {
+ PermissionState.ALLOWED ->
+ if (showsForegroundOnlyButton(permission)) {
+ By.res(ALLOW_FOREGROUND_RADIO_BUTTON)
+ } else if (isMediaStorageButton(permission, targetSdk)) {
+ // Uses "allow_foreground_only_radio_button" as id
+ byTextRes(R.string.allow_media_storage)
+ } else if (isAllStorageButton(permission, targetSdk)) {
+ // Uses "allow_always_radio_button" as id
+ byTextRes(R.string.allow_external_storage)
+ } else {
+ By.res(ALLOW_RADIO_BUTTON)
+ }
+ PermissionState.DENIED ->
+ if (!isLegacyApp && hasAskButton(permission)) {
+ By.res(ASK_RADIO_BUTTON)
+ } else {
+ By.res(DENY_RADIO_BUTTON)
+ }
+ PermissionState.DENIED_WITH_PREJUDICE -> By.res(DENY_RADIO_BUTTON)
+ }
+ }
)
alreadyChecked = button.isChecked
if (!alreadyChecked) {
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/AllocationTest.java b/tests/tests/renderscript/src/android/renderscript/cts/AllocationTest.java
index 84ebee7..a3a58e5 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/AllocationTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/AllocationTest.java
@@ -219,7 +219,10 @@
Allocation.createFromBitmap(mRS, B).destroy();
Allocation.createCubemapFromBitmap(mRS, B).destroy();
for (Allocation.MipmapControl mc : Allocation.MipmapControl.values()) {
- helperCreateFromBitmap(B, mc);
+ if (mc != Allocation.MipmapControl.MIPMAP_FULL) {
+ // MIPMAP_FULL is not tested because of http://b/184904346
+ helperCreateFromBitmap(B, mc);
+ }
}
try {
@@ -883,5 +886,3 @@
a.destroy();
}
}
-
-
diff --git a/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp b/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
index 824cb50..23ae5b0 100644
--- a/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
+++ b/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
@@ -180,6 +180,7 @@
// https://source.android.com/security/encryption/file-based.html
TEST(FileBasedEncryptionPolicyTest, allowedPolicy) {
int first_api_level = getFirstApiLevel();
+ char crypto_type[PROPERTY_VALUE_MAX];
struct fscrypt_get_policy_ex_arg arg;
int res;
int contents_mode;
@@ -191,6 +192,8 @@
FAIL() << "Failed to open " DIR_TO_CHECK ": " << strerror(errno);
}
+ property_get("ro.crypto.type", crypto_type, "");
+ GTEST_LOG_(INFO) << "ro.crypto.type is '" << crypto_type << "'";
GTEST_LOG_(INFO) << "First API level is " << first_api_level;
// Note: SELinux policy allows the shell domain to use these ioctls, but not
@@ -216,6 +219,15 @@
<< "Exempt from file-based encryption due to old starting API level";
return;
}
+ if (strcmp(crypto_type, "managed") == 0) {
+ // Android is running in a virtualized environment and the file system is encrypted
+ // by the host system.
+ GTEST_LOG_(INFO) << "Exempt from file-based encryption because the file system is "
+ << "encrypted by the host system";
+ // Note: All encryption-related CDD requirements still must be met,
+ // but they can't be tested directly in this case.
+ return;
+ }
FAIL() << "Device isn't using file-based encryption";
} else {
FAIL() << "Failed to get encryption policy of " DIR_TO_CHECK ": " << strerror(errno);
diff --git a/tests/tests/selinux/common/jni/android_security_SELinuxTargetSdkTest.cpp b/tests/tests/selinux/common/jni/android_security_SELinuxTargetSdkTest.cpp
index 9dc0d97..4570f46 100644
--- a/tests/tests/selinux/common/jni/android_security_SELinuxTargetSdkTest.cpp
+++ b/tests/tests/selinux/common/jni/android_security_SELinuxTargetSdkTest.cpp
@@ -26,7 +26,7 @@
#include <memory>
struct SecurityContext_Delete {
- void operator()(security_context_t p) const {
+ void operator()(char* p) const {
freecon(p);
}
};
@@ -151,7 +151,7 @@
return NULL;
}
- security_context_t tmp = NULL;
+ char* tmp = NULL;
int ret = getfilecon(path.c_str(), &tmp);
Unique_SecurityContext context(tmp);
diff --git a/tests/tests/wrap/Android.bp b/tests/tests/wrap/Android.bp
index 27ffc21..a94a5db0 100644
--- a/tests/tests/wrap/Android.bp
+++ b/tests/tests/wrap/Android.bp
@@ -25,3 +25,11 @@
"android.test.base.stubs",
],
}
+
+filegroup {
+ name: "wrap.sh",
+ srcs: [
+ "wrap.sh",
+ ],
+ path: ".",
+}
diff --git a/tests/tests/wrap/wrap_debug/Android.bp b/tests/tests/wrap/wrap_debug/Android.bp
new file mode 100644
index 0000000..5f50d5e
--- /dev/null
+++ b/tests/tests/wrap/wrap_debug/Android.bp
@@ -0,0 +1,66 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsWrapWrapDebugTestCases",
+ compile_multilib: "both",
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+ static_libs: [
+ "compatibility-device-util-axt",
+ "androidx.test.rules",
+ "wrap_debug_lib"
+ ],
+ libs: [
+ "android.test.runner.stubs",
+ "android.test.base.stubs",
+ ],
+ srcs: [":cts_tests_tests_wrap_src"],
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ sdk_version: "current",
+ manifest: "AndroidManifest.xml",
+ // Jarjar to make WrapTest unique.
+ jarjar_rules: "jarjar-rules.txt",
+ use_embedded_native_libs: false,
+}
+
+java_genrule {
+ name: "wrap_debug_lib",
+ srcs: [":wrap.sh"],
+ tools: ["soong_zip"],
+ out: ["wrap_debug_abi.jar"],
+ cmd: "mkdir -p $(genDir)/lib/armeabi-v7a/ && " +
+ "mkdir -p $(genDir)/lib/arm64-v8a/ && " +
+ "mkdir -p $(genDir)/lib/x86/ && " +
+ "mkdir -p $(genDir)/lib/x86_64/ && " +
+ "cp $(in) $(genDir)/lib/armeabi-v7a/ && " +
+ "cp $(in) $(genDir)/lib/arm64-v8a/ && " +
+ "cp $(in) $(genDir)/lib/x86/ && " +
+ "cp $(in) $(genDir)/lib/x86_64/ && " +
+ "$(location soong_zip) -o $(out) -C $(genDir) " +
+ "-D $(genDir)/lib/armeabi-v7a/ -D $(genDir)/lib/arm64-v8a/ " +
+ "-D $(genDir)/lib/x86/ -D $(genDir)/lib/x86_64/",
+}
diff --git a/tests/tests/wrap/wrap_debug/Android.mk b/tests/tests/wrap/wrap_debug/Android.mk
deleted file mode 100644
index 8743cc4..0000000
--- a/tests/tests/wrap/wrap_debug/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MULTILIB := both
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_DEX_PREOPT := false
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_STATIC_JAVA_LIBRARIES := \
- compatibility-device-util-axt \
- androidx.test.rules
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-LOCAL_SDK_VERSION := current
-
-LOCAL_PREBUILT_JNI_LIBS_arm := ../wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_arm64 := ../wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_mips := ../wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_mips64 := ../wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_x86 := ../wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_x86_64 := ../wrap.sh
-
-LOCAL_PACKAGE_NAME := CtsWrapWrapDebugTestCases
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_MANIFEST_FILE := AndroidManifest.xml
-
-# Jarjar to make WrapTest unique.
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
-
-LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
-
-include $(BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/Android.bp b/tests/tests/wrap/wrap_debug_malloc_debug/Android.bp
new file mode 100644
index 0000000..9f152f7
--- /dev/null
+++ b/tests/tests/wrap/wrap_debug_malloc_debug/Android.bp
@@ -0,0 +1,68 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsWrapWrapDebugMallocDebugTestCases",
+ compile_multilib: "both",
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+ static_libs: [
+ "compatibility-device-util-axt",
+ "androidx.test.rules",
+ // this is for the src files
+ "cts_tests_tests_wrap_src",
+ "wrap_debug_malloc_debug_lib",
+ ],
+ libs: [
+ "android.test.runner.stubs",
+ "android.test.base.stubs",
+ "android.test.mock.stubs",
+ ],
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ sdk_version: "current",
+ manifest: "AndroidManifest.xml",
+ // Jarjar to make WrapTest unique.
+ jarjar_rules: "jarjar-rules.txt",
+ use_embedded_native_libs: false,
+}
+
+java_genrule {
+ name: "wrap_debug_malloc_debug_lib",
+ srcs: ["wrap.sh"],
+ tools: ["soong_zip"],
+ out: ["wrap_debug_malloc_debug_abi.jar"],
+ cmd: "mkdir -p $(genDir)/lib/armeabi-v7a/ && " +
+ "mkdir -p $(genDir)/lib/arm64-v8a/ && " +
+ "mkdir -p $(genDir)/lib/x86/ && " +
+ "mkdir -p $(genDir)/lib/x86_64/ && " +
+ "cp $(in) $(genDir)/lib/armeabi-v7a/ && " +
+ "cp $(in) $(genDir)/lib/arm64-v8a/ && " +
+ "cp $(in) $(genDir)/lib/x86/ && " +
+ "cp $(in) $(genDir)/lib/x86_64/ && " +
+ "$(location soong_zip) -o $(out) -C $(genDir) " +
+ "-D $(genDir)/lib/armeabi-v7a/ -D $(genDir)/lib/arm64-v8a/ " +
+ "-D $(genDir)/lib/x86/ -D $(genDir)/lib/x86_64/",
+}
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk b/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
deleted file mode 100644
index 06d1d5c..0000000
--- a/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MULTILIB := both
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_DEX_PREOPT := false
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_STATIC_JAVA_LIBRARIES := \
- compatibility-device-util-axt \
- androidx.test.rules
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-LOCAL_SDK_VERSION := current
-
-LOCAL_PREBUILT_JNI_LIBS_arm := wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_arm64 := wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_mips := wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_mips64 := wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_x86 := wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_x86_64 := wrap.sh
-
-LOCAL_PACKAGE_NAME := CtsWrapWrapDebugMallocDebugTestCases
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_MANIFEST_FILE := AndroidManifest.xml
-
-# Jarjar to make WrapTest unique.
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
-
-LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
-
-include $(BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
diff --git a/tests/tests/wrap/wrap_nodebug/Android.bp b/tests/tests/wrap/wrap_nodebug/Android.bp
new file mode 100644
index 0000000..34f0a5c
--- /dev/null
+++ b/tests/tests/wrap/wrap_nodebug/Android.bp
@@ -0,0 +1,48 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsWrapWrapNoDebugTestCases",
+ compile_multilib: "both",
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+ static_libs: [
+ "compatibility-device-util-axt",
+ "androidx.test.rules",
+ "wrap_debug_lib"
+ ],
+ libs: [
+ "android.test.runner.stubs",
+ "android.test.base.stubs",
+ ],
+ srcs: [":cts_tests_tests_wrap_src"],
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ sdk_version: "current",
+ manifest: "AndroidManifest.xml",
+ // Jarjar to make WrapTest unique.
+ jarjar_rules: "jarjar-rules.txt",
+ use_embedded_native_libs: false,
+}
diff --git a/tests/tests/wrap/wrap_nodebug/Android.mk b/tests/tests/wrap/wrap_nodebug/Android.mk
deleted file mode 100644
index f7823c5..0000000
--- a/tests/tests/wrap/wrap_nodebug/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MULTILIB := both
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_DEX_PREOPT := false
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_STATIC_JAVA_LIBRARIES := \
- compatibility-device-util-axt \
- androidx.test.rules
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-LOCAL_SDK_VERSION := current
-
-LOCAL_PREBUILT_JNI_LIBS_arm := ../wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_arm64 := ../wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_mips := ../wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_mips64 := ../wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_x86 := ../wrap.sh
-LOCAL_PREBUILT_JNI_LIBS_x86_64 := ../wrap.sh
-
-LOCAL_PACKAGE_NAME := CtsWrapWrapNoDebugTestCases
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_MANIFEST_FILE := AndroidManifest.xml
-
-# Jarjar to make WrapTest unique.
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
-
-LOCAL_USE_EMBEDDED_NATIVE_LIBS := false
-
-include $(BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
index 096db55..50e69f4 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
@@ -168,15 +168,22 @@
List<String> supportedAbiApk = result.getNativeCode();
Set<String> buildTarget = AbiUtils.getAbisForArch(
TestSuiteInfo.getInstance().getTargetArchs().get(0));
- // first check, all the abis are supported
- for (String abi : supportedAbiApk) {
- if (!buildTarget.contains(abi)) {
+ // first check, all the abis in the buildTarget are supported
+ for (String abiBT : buildTarget) {
+ Boolean findMatch = false;
+ for (String abiApk : supportedAbiApk) {
+ if (abiApk.equals(abiBT)) {
+ findMatch = true;
+ break;
+ }
+ }
+ if (!findMatch) {
fail(String.format("apk %s %s does not support our abis [%s]",
testApk.getName(), supportedAbiApk, buildTarget));
}
}
apkToAbi.put(testApk.getName(), supportedAbiApk.size());
- maxAbi = Math.max(maxAbi, supportedAbiApk.size());
+ maxAbi = Math.max(maxAbi, buildTarget.size());
}
}