diff options
Diffstat (limited to 'hostsidetests')
39 files changed, 1085 insertions, 565 deletions
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java index 71c8bc19b6a..a3d7e6ea431 100644 --- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java +++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java @@ -51,6 +51,7 @@ import java.util.concurrent.TimeUnit; public class AdoptableHostTest extends BaseHostJUnit4Test { public static final String FEATURE_ADOPTABLE_STORAGE = "feature:android.software.adoptable_storage"; + private static final int ANDROID_API_LEVEL_R = 30; private String mListVolumesInitialState; @@ -400,7 +401,11 @@ public class AdoptableHostTest extends BaseHostJUnit4Test { } private boolean isSupportedDevice() throws Exception { - return hasFeature() || hasFstab(); + return hasCasefoldSupport() && (hasFeature() || hasFstab()); + } + + private boolean hasCasefoldSupport() throws Exception { + return getDevice().getLaunchApiLevel() >= ANDROID_API_LEVEL_R; } private boolean hasFeature() throws Exception { diff --git a/hostsidetests/compilation/Android.bp b/hostsidetests/compilation/Android.bp index b80a17dfe80..bac1ac298ba 100644 --- a/hostsidetests/compilation/Android.bp +++ b/hostsidetests/compilation/Android.bp @@ -14,6 +14,7 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], + default_team: "trendy_team_art_mainline", } java_defaults { @@ -25,15 +26,18 @@ java_defaults { java_resource_dirs: ["assets/"], java_resources: [ ":AppUsedByOtherApp", + ":AppUsedByOtherApp_1_disable_embedded_profile_dm", ":AppUsedByOtherApp_1_dm", ":AppUsedByOtherApp_2_prof", ":AppUsingOtherApp", - ":CompilationTestCases_package-dex-usage", + ":CompilationTestCases-package-dex-usage", ":CtsCompilationApp", ":CtsCompilationApp_profile", ":CtsCompilationApp_dm", ":CtsCompilationApp_with_bad_profile", ":CtsCompilationApp_with_good_profile", + ":disable_embedded_profile_dm", + ":empty_config_dm", ], libs: [ "cts-tradefed", @@ -78,15 +82,22 @@ genrule_defaults { "--reference-profile-file=$(out)", } -// Generates a DM file from a binary profile. -// The input must be the binary profile. +sh_binary { + name: "generate_dm", + host_supported: true, + src: "scripts/generate_dm.sh", +} + +// Generates a DM file. +// Each input must be a binary profile or a config file in binary protobuf +// format. genrule_defaults { name: "dm_defaults", - tools: ["soong_zip"], - cmd: "cp $(in) $(genDir)/primary.prof && " + - "$(location soong_zip) " + - "-j -f $(genDir)/primary.prof " + - "-o $(out)", + tools: [ + "generate_dm", + "soong_zip", + ], + cmd: "$(location generate_dm) $(location soong_zip) $(out) $(in)", } genrule { @@ -138,15 +149,69 @@ genrule { } genrule { - name: "CompilationTestCases_package-dex-usage", + name: "CompilationTestCases-package-dex-usage", + srcs: [ + ":libartservice_protos", + "assets/package-dex-usage.textproto", + ], tools: ["aprotoc"], cmd: "$(location aprotoc) " + "--encode=com.android.server.art.proto.DexUseProto " + "$(locations :libartservice_protos) " + "< $(location assets/package-dex-usage.textproto) > $(out)", + out: ["package-dex-usage.pb"], +} + +genrule { + name: "CompilationTestCases-config-empty", srcs: [ ":libartservice_protos", - "assets/package-dex-usage.textproto", ], - out: ["package-dex-usage.pb"], + tools: ["aprotoc"], + cmd: "$(location aprotoc) " + + "--encode=com.android.server.art.proto.DexMetadataConfig " + + "$(locations :libartservice_protos) " + + "<<<'' > $(out)", + out: ["config-empty.pb"], +} + +genrule { + name: "empty_config_dm", + defaults: ["dm_defaults"], + srcs: [ + ":CompilationTestCases-config-empty", + ], + out: ["empty_config.dm"], +} + +genrule { + name: "CompilationTestCases-config-disable_embedded_profile", + srcs: [ + ":libartservice_protos", + ], + tools: ["aprotoc"], + cmd: "$(location aprotoc) " + + "--encode=com.android.server.art.proto.DexMetadataConfig " + + "$(locations :libartservice_protos) " + + "<<<'enable_embedded_profile: false' > $(out)", + out: ["config-disable_embedded_profile.pb"], +} + +genrule { + name: "disable_embedded_profile_dm", + defaults: ["dm_defaults"], + srcs: [ + ":CompilationTestCases-config-disable_embedded_profile", + ], + out: ["disable_embedded_profile.dm"], +} + +genrule { + name: "AppUsedByOtherApp_1_disable_embedded_profile_dm", + defaults: ["dm_defaults"], + srcs: [ + ":AppUsedByOtherApp_1_prof", + ":CompilationTestCases-config-disable_embedded_profile", + ], + out: ["AppUsedByOtherApp_1_disable_embedded_profile.dm"], } diff --git a/hostsidetests/compilation/scripts/generate_dm.sh b/hostsidetests/compilation/scripts/generate_dm.sh new file mode 100644 index 00000000000..7be9bfdcbea --- /dev/null +++ b/hostsidetests/compilation/scripts/generate_dm.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# +# Copyright 2024 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A tool to generate a dm file from inputs. +# Usage: SCRIPT SOONG_ZIP OUTPUT INPUTS... + +soong_zip=$1 +output=$2 +shift 2 + +args="${soong_zip} -o ${output}" +for input in $@; do + if [[ $input =~ \.prof$ ]]; then + args+=" -e primary.prof -f $input" + fi + if [[ $input =~ \.pb$ ]]; then + args+=" -e config.pb -f $input" + fi +done + +$args diff --git a/hostsidetests/compilation/src/android/compilation/cts/CompilationTest.java b/hostsidetests/compilation/src/android/compilation/cts/CompilationTest.java index 1f7dfb04fbe..c01dec9588b 100644 --- a/hostsidetests/compilation/src/android/compilation/cts/CompilationTest.java +++ b/hostsidetests/compilation/src/android/compilation/cts/CompilationTest.java @@ -56,6 +56,10 @@ public class CompilationTest extends BaseHostJUnit4Test { private static final String TEST_APP_2_PKG = "android.compilation.cts.appusedbyotherapp"; private static final String TEST_APP_2_APK_RES = "/AppUsedByOtherApp.apk"; private static final String TEST_APP_2_DM_RES = "/AppUsedByOtherApp_1.dm"; + private static final String TEST_APP_2_DISABLE_EMBEDDED_PROFILE_DM_RES = + "/AppUsedByOtherApp_1_disable_embedded_profile.dm"; + private static final String DISABLE_EMBEDDED_PROFILE_DM_RES = "/disable_embedded_profile.dm"; + private static final String EMPTY_CONFIG_DM_RES = "/empty_config.dm"; private Utils mUtils; @@ -269,6 +273,24 @@ public class CompilationTest extends BaseHostJUnit4Test { "Error occurred during dexopt when processing external profiles:"); } + @Test + public void testEmbeddedProfileEmptyConfig() throws Exception { + // A DM with a config file is provided, but it's empty, so it should have no impact on the + // embedded profile. + mUtils.installFromResources(getAbi(), TEST_APP_WITH_GOOD_PROFILE_RES, EMPTY_CONFIG_DM_RES); + String dump = mUtils.assertCommandSucceeds("pm art dump " + TEST_APP_PKG); + checkDexoptStatus(dump, Pattern.quote("base.apk"), "speed-profile"); + } + + @Test + public void testEmbeddedProfileConfigDisabledByConfig() throws Exception { + // A DM with a config file is provided, and it disables embedded profile. + mUtils.installFromResources( + getAbi(), TEST_APP_WITH_GOOD_PROFILE_RES, DISABLE_EMBEDDED_PROFILE_DM_RES); + String dump = mUtils.assertCommandSucceeds("pm art dump " + TEST_APP_PKG); + checkDexoptStatus(dump, Pattern.quote("base.apk"), "verify"); + } + /** * Verifies that adb install-multi-package fails with multiple error messages when multiple * APK-DM mismatches happen. @@ -304,6 +326,29 @@ public class CompilationTest extends BaseHostJUnit4Test { checkDexoptStatus(dump, Pattern.quote("base.apk"), "verify"); } + @Test + public void testFallBackToEmbeddedProfile() throws Exception { + // The DM has a bad profile, so ART Service should fall back to the embedded profile. + assertThrows(Throwable.class, () -> { + mUtils.installFromResources( + getAbi(), TEST_APP_WITH_GOOD_PROFILE_RES, TEST_APP_2_DM_RES); + }); + String dump = mUtils.assertCommandSucceeds("pm art dump " + TEST_APP_PKG); + checkDexoptStatus(dump, Pattern.quote("base.apk"), "speed-profile"); + } + + @Test + public void testNoFallBackToEmbeddedProfile() throws Exception { + // The DM has a bad profile, but it also has a config that disables embedded profile, so ART + // Service should not fall back to the embedded profile. + assertThrows(Throwable.class, () -> { + mUtils.installFromResources(getAbi(), TEST_APP_WITH_GOOD_PROFILE_RES, + TEST_APP_2_DISABLE_EMBEDDED_PROFILE_DM_RES); + }); + String dump = mUtils.assertCommandSucceeds("pm art dump " + TEST_APP_PKG); + checkDexoptStatus(dump, Pattern.quote("base.apk"), "verify"); + } + private void checkDexoptStatus(String dump, String dexfilePattern, String statusPattern) { // Matches the dump output typically being: // /data/user/0/android.compilation.cts.statuscheckerapp/secondary.jar diff --git a/hostsidetests/devicepolicy/Android.bp b/hostsidetests/devicepolicy/Android.bp index 1efdf960622..eb0eb3d8916 100644 --- a/hostsidetests/devicepolicy/Android.bp +++ b/hostsidetests/devicepolicy/Android.bp @@ -13,6 +13,7 @@ // limitations under the License. package { + default_team: "trendy_team_enterprise", default_applicable_licenses: ["Android-Apache-2.0"], } @@ -33,6 +34,7 @@ java_test_host { "cts", "general-tests", "mts-permission", + "mcts-permission", ], static_libs: [ "cts-statsd-atom-host-test-utils", @@ -99,3 +101,44 @@ java_test_host { ], per_testcase_directory: true, } + +test_module_config_host { + name: "CtsDevicePolicyManagerTestCases_Permissions", + base: "CtsDevicePolicyManagerTestCases", + test_suites: ["general-tests"], + include_annotations: ["com.android.cts.devicepolicy.annotations.PermissionsTest"], +} + +test_module_config_host { + name: "CtsDevicePolicyManagerTestCases_Permissions_NoFlakes", + base: "CtsDevicePolicyManagerTestCases", + test_suites: ["general-tests"], + include_annotations: ["com.android.cts.devicepolicy.annotations.PermissionsTest"], + exclude_annotations: ["android.platform.test.annotations.FlakyTest"], +} + +// Currently, there are no tests marked flaky or large in CtsDevicePolicyManagerTestCases +test_module_config_host { + name: "CtsDevicePolicyManagerTestCases_NoFlakes_NoLarge", + base: "CtsDevicePolicyManagerTestCases", + test_suites: ["general-tests"], + exclude_annotations: [ + "android.platform.test.annotations.FlakyTest", + "android.platform.test.annotations.LargeTest", + ], +} + +test_module_config_host { + name: "CtsDevicePolicyManagerTestCases_LockSettings_NoFlakes", + base: "CtsDevicePolicyManagerTestCases", + test_suites: ["general-tests"], + include_annotations: ["com.android.cts.devicepolicy.annotations.LockSettingsTest"], + exclude_annotations: ["android.platform.test.annotations.FlakyTest"], +} + +test_module_config_host { + name: "CtsDevicePolicyManagerTestCases_ParentProfileApiDisabled", + base: "CtsDevicePolicyManagerTestCases", + test_suites: ["general-tests"], + include_filters: ["com.android.cts.devicepolicy.ManagedProfileTest#testParentProfileApiDisabled"], +} diff --git a/hostsidetests/devicepolicy/TEST_MAPPING b/hostsidetests/devicepolicy/TEST_MAPPING index 7275f80ee70..189a2244011 100644 --- a/hostsidetests/devicepolicy/TEST_MAPPING +++ b/hostsidetests/devicepolicy/TEST_MAPPING @@ -27,5 +27,11 @@ { "name": "CtsDevicePolicyManagerTestCases" } + ], + "postsubmit": [ + { + "name": "CtsDevicePolicyManagerTestCases_Permissions_NoFlakes", + "name": "CtsDevicePolicyManagerTestCases_LockSettings_NoFlakes" + } ] } diff --git a/hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp b/hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp index 05c8016dc0e..04efba21856 100644 --- a/hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp +++ b/hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp @@ -13,6 +13,7 @@ // limitations under the License. package { + default_team: "trendy_team_enterprise", default_applicable_licenses: ["Android-Apache-2.0"], } diff --git a/hostsidetests/devicepolicy/app/StartInfoApp/OWNERS b/hostsidetests/devicepolicy/app/StartInfoApp/OWNERS new file mode 100644 index 00000000000..24bb8f97b2f --- /dev/null +++ b/hostsidetests/devicepolicy/app/StartInfoApp/OWNERS @@ -0,0 +1,5 @@ +carmenjackson@google.com +edgararriaga@google.com +haiping@google.com +steventerrell@google.com +yforta@google.com diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java index 2c6332e727f..d2a075abaaf 100644 --- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java +++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java @@ -124,15 +124,9 @@ public abstract class BaseDevicePolicyTest extends BaseHostJUnit4Test { private static final long DEFAULT_TEST_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(10); /** - * The amount of milliseconds to wait for the remove user calls in {@link #tearDown}. - * This is a temporary measure until b/114057686 is fixed. - */ - private static final long USER_REMOVE_WAIT = TimeUnit.SECONDS.toMillis(5); - - /** * The amount of milliseconds to wait for the switch user calls in {@link #tearDown}. */ - private static final long USER_SWITCH_WAIT = TimeUnit.SECONDS.toMillis(5); + private static final long USER_SWITCH_WAIT = TimeUnit.SECONDS.toMillis(1); // From the UserInfo class protected static final int FLAG_GUEST = 0x00000004; @@ -426,7 +420,7 @@ public abstract class BaseDevicePolicyTest extends BaseHostJUnit4Test { */ protected void switchUser(int userId) throws Exception { // TODO Move this logic to ITestDevice - int retries = 10; + int retries = 15; CLog.i("switching to user %d", userId); executeShellCommand("am switch-user " + userId); RunUtil.getDefault().sleep(USER_SWITCH_WAIT); @@ -527,12 +521,9 @@ public abstract class BaseDevicePolicyTest extends BaseHostJUnit4Test { String stopUserCommand = "am stop-user -w -f " + userId; CLog.d("stopping and removing user " + userId); getDevice().executeShellCommand(stopUserCommand); - // TODO: Remove both sleeps and USER_REMOVE_WAIT constant when b/114057686 is fixed. - RunUtil.getDefault().sleep(USER_REMOVE_WAIT); // Ephemeral users may have already been removed after being stopped. if (listUsers().contains(userId)) { assertTrue("Couldn't remove user", getDevice().removeUser(userId)); - RunUtil.getDefault().sleep(USER_REMOVE_WAIT); } } } diff --git a/hostsidetests/gwp_asan/Android.bp b/hostsidetests/gwp_asan/Android.bp index 1ed34b94a0b..81932b420e5 100644 --- a/hostsidetests/gwp_asan/Android.bp +++ b/hostsidetests/gwp_asan/Android.bp @@ -30,7 +30,7 @@ java_test_host { ], data: [ ":CtsGwpAsanEnabled", - ":CtsGwpAsanRecoverable", + ":CtsGwpAsanDefault", ], } diff --git a/hostsidetests/gwp_asan/common/android/cts/gwp_asan/GwpAsanActivityTest.java b/hostsidetests/gwp_asan/common/android/cts/gwp_asan/GwpAsanActivityTest.java index 609af0df575..e6029185feb 100644 --- a/hostsidetests/gwp_asan/common/android/cts/gwp_asan/GwpAsanActivityTest.java +++ b/hostsidetests/gwp_asan/common/android/cts/gwp_asan/GwpAsanActivityTest.java @@ -59,42 +59,40 @@ public class GwpAsanActivityTest { GwpAsanDisabledActivity.class, Utils.TEST_IS_GWP_ASAN_DISABLED); } - @Test - public void testCrashToDropboxRecoverableEnabled() throws Exception { + public void testCrash(Class<?> cls, String processNameSuffix, String crashTag, + boolean shouldRecover) throws Exception { TestActivityLauncher activity = mTestActivityRule.launchActivity(null); - DropBoxReceiver receiver = Utils.getDropboxReceiver(mContext, "gwp_asan_enabled"); - activity.callActivity(GwpAsanEnabledActivity.class, Utils.TEST_USE_AFTER_FREE); + DropBoxReceiver receiver = Utils.getDropboxReceiver(mContext, processNameSuffix, crashTag); + if (shouldRecover) { + activity.callActivityAndCheckSuccess(cls, Utils.TEST_USE_AFTER_FREE); + } else { + activity.callActivity(cls, Utils.TEST_USE_AFTER_FREE); + } Assert.assertTrue(receiver.await()); } @Test + public void testCrashToDropboxRecoverableEnabled() throws Exception { + testCrash(GwpAsanEnabledActivity.class, "gwp_asan_enabled", Utils.DROPBOX_RECOVERABLE_TAG, + /*shouldRecover=*/true); + } + + @Test public void testCrashToDropboxRecoverableDefault() throws Exception { - TestActivityLauncher activity = mTestActivityRule.launchActivity(null); - DropBoxReceiver receiver = - Utils.getDropboxReceiver( - mContext, "gwp_asan_default", Utils.DROPBOX_RECOVERABLE_TAG); - // Ensure the recoverable mode recovers, and returns success. - activity.callActivityAndCheckSuccess( - GwpAsanDefaultActivity.class, Utils.TEST_USE_AFTER_FREE); - Assert.assertTrue(receiver.await()); + testCrash(GwpAsanDefaultActivity.class, "gwp_asan_default", Utils.DROPBOX_RECOVERABLE_TAG, + /*shouldRecover=*/true); } @Test - public void testCrashToDropboxEnabled() throws Exception { - TestActivityLauncher activity = mTestActivityRule.launchActivity(null); - DropBoxReceiver receiver = Utils.getDropboxReceiver(mContext, "gwp_asan_enabled"); - activity.callActivity(GwpAsanEnabledActivity.class, Utils.TEST_USE_AFTER_FREE); - Assert.assertTrue(receiver.await()); + public void testCrashToDropboxNonRecoverableEnabled() throws Exception { + testCrash(GwpAsanEnabledActivity.class, "gwp_asan_enabled", + Utils.DROPBOX_NON_RECOVERABLE_TAG, /*shouldRecover=*/false); } @Test - public void testCrashToDropboxDefault() throws Exception { - TestActivityLauncher activity = mTestActivityRule.launchActivity(null); - DropBoxReceiver receiver = Utils.getDropboxReceiver(mContext, "gwp_asan_default"); - // Inherits from the app-wide property, which was `gwpAsanMode=always`. So, this should - // crash. - activity.callActivity(GwpAsanDefaultActivity.class, Utils.TEST_USE_AFTER_FREE); - Assert.assertTrue(receiver.await()); + public void testCrashToDropboxNonRecoverableDefault() throws Exception { + testCrash(GwpAsanDefaultActivity.class, "gwp_asan_default", + Utils.DROPBOX_NON_RECOVERABLE_TAG, /*shouldRecover=*/false); } @Test diff --git a/hostsidetests/gwp_asan/common/android/cts/gwp_asan/GwpAsanServiceTest.java b/hostsidetests/gwp_asan/common/android/cts/gwp_asan/GwpAsanServiceTest.java index 4a6236cade5..add3ad3108b 100644 --- a/hostsidetests/gwp_asan/common/android/cts/gwp_asan/GwpAsanServiceTest.java +++ b/hostsidetests/gwp_asan/common/android/cts/gwp_asan/GwpAsanServiceTest.java @@ -73,33 +73,38 @@ public class GwpAsanServiceTest { runServiceAndCheckSuccess(GwpAsanDisabledService.class, Utils.TEST_IS_GWP_ASAN_DISABLED); } - @Test - public void testCrashToDropboxEnabled() throws Exception { - DropBoxReceiver receiver = Utils.getDropboxReceiver(mContext, "gwp_asan_enabled"); - runService(GwpAsanEnabledService.class, Utils.TEST_USE_AFTER_FREE); + public void testCrash(Class<?> cls, String processNameSuffix, String crashTag, + boolean shouldRecover) throws Exception { + DropBoxReceiver receiver = Utils.getDropboxReceiver(mContext, processNameSuffix, crashTag); + if (shouldRecover) { + runServiceAndCheckSuccess(cls, Utils.TEST_USE_AFTER_FREE); + } else { + runService(cls, Utils.TEST_USE_AFTER_FREE); + } assertTrue(receiver.await()); } @Test - public void testCrashToDropboxDefault() throws Exception { - DropBoxReceiver receiver = Utils.getDropboxReceiver(mContext, "gwp_asan_default"); - runService(GwpAsanDefaultService.class, Utils.TEST_USE_AFTER_FREE); - assertTrue(receiver.await()); + public void testCrashToDropboxNonRecoverableEnabled() throws Exception { + testCrash(GwpAsanEnabledService.class, "gwp_asan_enabled", + Utils.DROPBOX_NON_RECOVERABLE_TAG, /*shouldRecover=*/false); + } + + @Test + public void testCrashToDropboxNonRecoverableDefault() throws Exception { + testCrash(GwpAsanDefaultService.class, "gwp_asan_default", + Utils.DROPBOX_NON_RECOVERABLE_TAG, /*shouldRecover=*/false); } @Test public void testCrashToDropboxRecoverableEnabled() throws Exception { - DropBoxReceiver receiver = Utils.getDropboxReceiver(mContext, "gwp_asan_enabled"); - runService(GwpAsanEnabledService.class, Utils.TEST_USE_AFTER_FREE); - assertTrue(receiver.await()); + testCrash(GwpAsanEnabledService.class, "gwp_asan_enabled", Utils.DROPBOX_RECOVERABLE_TAG, + /*shouldRecover=*/true); } @Test public void testCrashToDropboxRecoverableDefault() throws Exception { - DropBoxReceiver receiver = - Utils.getDropboxReceiver( - mContext, "gwp_asan_default", Utils.DROPBOX_RECOVERABLE_TAG); - runServiceAndCheckSuccess(GwpAsanDefaultService.class, Utils.TEST_USE_AFTER_FREE); - assertTrue(receiver.await()); + testCrash(GwpAsanDefaultService.class, "gwp_asan_default", Utils.DROPBOX_RECOVERABLE_TAG, + /*shouldRecover=*/true); } } diff --git a/hostsidetests/gwp_asan/common/android/cts/gwp_asan/Utils.java b/hostsidetests/gwp_asan/common/android/cts/gwp_asan/Utils.java index eee4a83c0d3..2a1e0e4d220 100644 --- a/hostsidetests/gwp_asan/common/android/cts/gwp_asan/Utils.java +++ b/hostsidetests/gwp_asan/common/android/cts/gwp_asan/Utils.java @@ -44,7 +44,7 @@ public class Utils { public static final int TEST_IS_GWP_ASAN_DISABLED = 43; public static final int TEST_USE_AFTER_FREE = 44; - public static final String DROPBOX_TAG = "data_app_native_crash"; + public static final String DROPBOX_NON_RECOVERABLE_TAG = "data_app_native_crash"; public static final String DROPBOX_RECOVERABLE_TAG = "data_app_native_recoverable_crash"; // Check that GWP-ASan is enabled by allocating a whole bunch of heap pointers and making sure @@ -102,10 +102,6 @@ public class Utils { "backtrace:"); } - public static DropBoxReceiver getDropboxReceiver(Context context, String processNameSuffix) { - return getDropboxReceiver(context, processNameSuffix, DROPBOX_TAG); - } - public static boolean appExitInfoHasReport(Context context, String processNameSuffix) throws Exception { ActivityManager am = context.getSystemService(ActivityManager.class); diff --git a/hostsidetests/gwp_asan/recoverable/Android.bp b/hostsidetests/gwp_asan/default/Android.bp index 466944f9a23..e0a25a76bc6 100644 --- a/hostsidetests/gwp_asan/recoverable/Android.bp +++ b/hostsidetests/gwp_asan/default/Android.bp @@ -17,7 +17,7 @@ package { } android_test_helper_app { - name: "CtsGwpAsanRecoverable", + name: "CtsGwpAsanDefault", defaults: ["cts_gwp_asan_app_defaults"], use_embedded_native_libs: false, } diff --git a/hostsidetests/gwp_asan/recoverable/AndroidManifest.xml b/hostsidetests/gwp_asan/default/AndroidManifest.xml index ab0c632cf79..ab0c632cf79 100644 --- a/hostsidetests/gwp_asan/recoverable/AndroidManifest.xml +++ b/hostsidetests/gwp_asan/default/AndroidManifest.xml diff --git a/hostsidetests/gwp_asan/src/android/cts/gwp_asan/EnabledTest.java b/hostsidetests/gwp_asan/src/android/cts/gwp_asan/EnabledTest.java deleted file mode 100644 index 8fa57a7311a..00000000000 --- a/hostsidetests/gwp_asan/src/android/cts/gwp_asan/EnabledTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.cts.gwp_asan; - -import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(DeviceJUnit4ClassRunner.class) -public class EnabledTest extends GwpAsanBaseTest { - protected String getTestApk() { - return "CtsGwpAsanEnabled.apk"; - } - - @Test - public void testGwpAsanEnabled() throws Exception { - runTest(".GwpAsanActivityTest", "testEnablement"); - runTest(".GwpAsanServiceTest", "testEnablement"); - } - - @Test - public void testCrashToDropbox() throws Exception { - runTest(".GwpAsanActivityTest", "testCrashToDropboxEnabled"); - runTest(".GwpAsanActivityTest", "testCrashToDropboxDefault"); - runTest(".GwpAsanServiceTest", "testCrashToDropboxEnabled"); - runTest(".GwpAsanServiceTest", "testCrashToDropboxDefault"); - } - - @Test - public void testAppExitInfo() throws Exception { - resetAppExitInfo(); - runTest(".GwpAsanActivityTest", "testCrashToDropboxDefault"); - runTest(".GwpAsanActivityTest", "checkAppExitInfo"); - } -} diff --git a/hostsidetests/gwp_asan/src/android/cts/gwp_asan/NonRecoverableTest.java b/hostsidetests/gwp_asan/src/android/cts/gwp_asan/NonRecoverableTest.java new file mode 100644 index 00000000000..47f8784265e --- /dev/null +++ b/hostsidetests/gwp_asan/src/android/cts/gwp_asan/NonRecoverableTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.cts.gwp_asan; + +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class NonRecoverableTest extends GwpAsanBaseTest { + private static final String RECOVERABLE_SYSPROP = "libc.debug.gwp_asan.recoverable."; + + protected String getTestApk() { + return "CtsGwpAsanEnabled.apk"; + } + + @Before + public void setUp() throws Exception { + super.setUp(); + // Android 15+ uses recoverable GWP-ASan for all apps. This test suite expects crashes, so + // let's disable the recovery. + mDevice.setProperty(RECOVERABLE_SYSPROP + TEST_PKG, "false"); + mDevice.setProperty(RECOVERABLE_SYSPROP + TEST_PKG + ":gwp_asan_enabled", "false"); + mDevice.setProperty(RECOVERABLE_SYSPROP + TEST_PKG + ":gwp_asan_default", "false"); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + mDevice.setProperty(RECOVERABLE_SYSPROP + TEST_PKG, ""); + mDevice.setProperty(RECOVERABLE_SYSPROP + TEST_PKG + ":gwp_asan_enabled", ""); + mDevice.setProperty(RECOVERABLE_SYSPROP + TEST_PKG + ":gwp_asan_default", ""); + } + + @Test + public void testGwpAsanEnabled() throws Exception { + runTest(".GwpAsanActivityTest", "testEnablement"); + runTest(".GwpAsanServiceTest", "testEnablement"); + } + + @Test + public void testCrashToDropbox() throws Exception { + runTest(".GwpAsanActivityTest", "testCrashToDropboxNonRecoverableEnabled"); + runTest(".GwpAsanActivityTest", "testCrashToDropboxNonRecoverableDefault"); + runTest(".GwpAsanServiceTest", "testCrashToDropboxNonRecoverableEnabled"); + runTest(".GwpAsanServiceTest", "testCrashToDropboxNonRecoverableDefault"); + } + + @Test + public void testAppExitInfo() throws Exception { + resetAppExitInfo(); + runTest(".GwpAsanActivityTest", "testCrashToDropboxNonRecoverableDefault"); + runTest(".GwpAsanActivityTest", "checkAppExitInfo"); + } +} diff --git a/hostsidetests/gwp_asan/src/android/cts/gwp_asan/RecoverableTest.java b/hostsidetests/gwp_asan/src/android/cts/gwp_asan/RecoverableTest.java deleted file mode 100644 index e6cadfec82f..00000000000 --- a/hostsidetests/gwp_asan/src/android/cts/gwp_asan/RecoverableTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.cts.gwp_asan; - -import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(DeviceJUnit4ClassRunner.class) -public class RecoverableTest extends GwpAsanBaseTest { - private static final String PROCESS_SAMPLING_SYSPROP = "libc.debug.gwp_asan.process_sampling."; - - protected String getTestApk() { - return "CtsGwpAsanRecoverable.apk"; - } - - @Before - public void setUp() throws Exception { - super.setUp(); - // Recoverable mode uses process sampling, which only enables GWP-ASan a fraction of the - // time (to preserve system-wide memory overhead). Make sure that our test app doesn't use - // process sampling, and enables GWP-ASan, when requested, every time. Note: We don't set - // the property on the ":gwp_asan_disabled" subprocess, because libc will enable GWP-ASan - // because a GWP-ASan property was overwritten. - mDevice.setProperty(PROCESS_SAMPLING_SYSPROP + TEST_PKG, "1"); - mDevice.setProperty(PROCESS_SAMPLING_SYSPROP + TEST_PKG + ":gwp_asan_enabled", "1"); - mDevice.setProperty(PROCESS_SAMPLING_SYSPROP + TEST_PKG + ":gwp_asan_default", "1"); - } - - @After - public void tearDown() throws Exception { - super.tearDown(); - mDevice.setProperty(PROCESS_SAMPLING_SYSPROP + TEST_PKG, ""); - mDevice.setProperty(PROCESS_SAMPLING_SYSPROP + TEST_PKG + ":gwp_asan_enabled", ""); - mDevice.setProperty(PROCESS_SAMPLING_SYSPROP + TEST_PKG + ":gwp_asan_default", ""); - } - - @Test - public void testGwpAsanRecoverable() throws Exception { - runTest(".GwpAsanActivityTest", "testEnablement"); - runTest(".GwpAsanServiceTest", "testEnablement"); - } - - @Test - public void testCrashToDropboxRecoverable() throws Exception { - runTest(".GwpAsanActivityTest", "testCrashToDropboxRecoverableEnabled"); - runTest(".GwpAsanActivityTest", "testCrashToDropboxRecoverableDefault"); - runTest(".GwpAsanServiceTest", "testCrashToDropboxRecoverableEnabled"); - runTest(".GwpAsanServiceTest", "testCrashToDropboxRecoverableDefault"); - } - - @Test - public void testAppExitInfo() throws Exception { - resetAppExitInfo(); - runTest(".GwpAsanActivityTest", "testCrashToDropboxRecoverableDefault"); - runTest(".GwpAsanActivityTest", "checkAppExitInfo"); - } -} diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/RemoteControlPassthrough.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/RemoteControlPassthrough.java index 296284bfcd9..eb25c1b73b1 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/RemoteControlPassthrough.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/RemoteControlPassthrough.java @@ -342,6 +342,19 @@ public final class RemoteControlPassthrough { hdmiCecClient.sendUserControlPressAndRelease( sourceDevice, dutLogicalAddress, cecKeycode, false); + // KEYCODE_SETUP_MENU might trigger the notification panel quitting the activity + // HdmiCecKeyEventCapture. + if (cecKeycode == HdmiCecConstants.CEC_KEYCODE_SETUP_MENU) { + try { + LogHelper.waitForLog(device, "ActivityTaskManager", 5, + "TOGGLE_NOTIFICATION_HANDLER_PANEL"); + return; + } catch (Exception e) { + // We have to send the key again since logcat was cleared. + hdmiCecClient.sendUserControlPressAndRelease( + sourceDevice, dutLogicalAddress, cecKeycode, false); + } + } LogHelper.assertLog(device, CLASS, "Short press KEYCODE_" + androidKeycode); } } diff --git a/hostsidetests/incrementalinstall/OWNERS b/hostsidetests/incrementalinstall/OWNERS index 9a71abdce8a..8031a5dee1b 100644 --- a/hostsidetests/incrementalinstall/OWNERS +++ b/hostsidetests/incrementalinstall/OWNERS @@ -1,7 +1,6 @@ # Bug component: 554432 dimuthu@google.com -alexbuy@google.com schfan@google.com patb@google.com -zyy@google.com
\ No newline at end of file +zyy@google.com diff --git a/hostsidetests/jdwptunnel/src/android/jdwptunnel/cts/JdwpTunnelTest.java b/hostsidetests/jdwptunnel/src/android/jdwptunnel/cts/JdwpTunnelTest.java index 66e4953b03d..9961273349c 100644 --- a/hostsidetests/jdwptunnel/src/android/jdwptunnel/cts/JdwpTunnelTest.java +++ b/hostsidetests/jdwptunnel/src/android/jdwptunnel/cts/JdwpTunnelTest.java @@ -32,6 +32,7 @@ import com.android.tradefed.util.RunUtil; import com.sun.jdi.Bootstrap; import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; import com.sun.jdi.VirtualMachine; import com.sun.jdi.VirtualMachineManager; import com.sun.jdi.connect.AttachingConnector; @@ -70,13 +71,13 @@ import java.util.Map; @RunWith(DeviceJUnit4ClassRunner.class) public class JdwpTunnelTest extends BaseHostJUnit4Test { private static final String DEBUGGABLE_TEST_APP_PACKAGE_NAME = - "android.jdwptunnel.sampleapp.debuggable"; + "android.jdwptunnel.sampleapp.debuggable"; private static final String DEBUGGABLE_TEST_APP_ACTIVITY_CLASS_NAME = - "DebuggableSampleDeviceActivity"; + "DebuggableSampleDeviceActivity"; private static final String PROFILEABLE_TEST_APP_PACKAGE_NAME = - "android.jdwptunnel.sampleapp.profileable"; + "android.jdwptunnel.sampleapp.profileable"; private static final String PROFILEABLE_TEST_APP_ACTIVITY_CLASS_NAME = - "ProfileableSampleDeviceActivity"; + "ProfileableSampleDeviceActivity"; private static final String DDMS_TEST_APP_PACKAGE_NAME = "android.jdwptunnel.sampleapp.ddms"; private static final String DDMS_TEST_APP_ACTIVITY_CLASS_NAME = "DdmsSampleDeviceActivity"; @@ -100,11 +101,11 @@ public class JdwpTunnelTest extends BaseHostJUnit4Test { private VirtualMachine getDebuggerConnection(String port) throws Exception { VirtualMachineManager vmm = Bootstrap.virtualMachineManager(); AttachingConnector conn = - vmm.attachingConnectors().stream() + vmm.attachingConnectors() + .stream() .filter((x) -> x.transport().name().equals("dt_socket")) .findFirst() - .orElseThrow( - () -> new Error("Could not find dt_socket connector!")); + .orElseThrow(() -> new Error("Could not find dt_socket connector!")); Map<String, Connector.Argument> params = conn.defaultArguments(); params.get("port").setValue(port); params.get("hostname").setValue("localhost"); @@ -129,17 +130,20 @@ public class JdwpTunnelTest extends BaseHostJUnit4Test { } private String startupForwarding(String packageName, String shortClassName, boolean debug) - throws Exception { + throws Exception { + return startupForwarding(packageName, shortClassName, debug, false); + } + + private String startupForwarding(String packageName, String shortClassName, boolean debug, + boolean startSuspended) throws Exception { moveToHomeScreen(); new Thread(() -> { try { - mDevice.executeShellCommand( - "cmd activity start-activity " - + (debug ? "-D" : "") - + " -W -n " - + packageName - + "/." - + shortClassName); + String cmd = "cmd activity start-activity " + (debug ? "-D" : "") + + (startSuspended ? " --suspend" : "") + " -W -n " + packageName + "/." + + shortClassName; + CLog.i(cmd); + mDevice.executeShellCommand(cmd); } catch (DeviceNotAvailableException e) { CLog.i("Failed to start activity for package: " + packageName, e); } @@ -148,8 +152,7 @@ public class JdwpTunnelTest extends BaseHostJUnit4Test { // Don't keep trying after a minute. final Instant deadline = Instant.now().plusSeconds(60); String pid = ""; - while ((pid = mDevice.executeShellCommand( - "pidof " + packageName).trim()).equals("")) { + while ((pid = mDevice.executeShellCommand("pidof " + packageName).trim()).equals("")) { if (Instant.now().isAfter(deadline)) { fail("Unable to find PID of " + packageName + " process!"); } @@ -162,7 +165,13 @@ public class JdwpTunnelTest extends BaseHostJUnit4Test { } private VirtualMachine startupTest(String packageName, String shortClassName) throws Exception { - return getDebuggerConnection(startupForwarding(packageName, shortClassName, true)); + return getDebuggerConnection(startupForwarding(packageName, shortClassName, true, false)); + } + + private VirtualMachine startupTest(String packageName, String shortClassName, boolean debug, + boolean startSuspended) throws Exception { + return getDebuggerConnection( + startupForwarding(packageName, shortClassName, debug, startSuspended)); } /** @@ -174,7 +183,7 @@ public class JdwpTunnelTest extends BaseHostJUnit4Test { * TODO: We should expand this to more functions. */ private void testAttachDebugger(String packageName, String shortClassName) - throws DeviceNotAvailableException, Exception { + throws DeviceNotAvailableException, Exception { String fullClassName = packageName + "." + shortClassName; VirtualMachine vm = startupTest(packageName, shortClassName); @@ -186,8 +195,7 @@ public class JdwpTunnelTest extends BaseHostJUnit4Test { final Instant deadline = Instant.now().plusSeconds(120); // Check the test-activity class is not already loaded. assertTrue(shortClassName + " is not yet loaded!", - vm.allClasses().stream() - .noneMatch(x -> x.name().equals(fullClassName))); + vm.allClasses().stream().noneMatch(x -> x.name().equals(fullClassName))); // Wait for the class to load. ClassPrepareRequest cpr = erm.createClassPrepareRequest(); @@ -200,11 +208,13 @@ public class JdwpTunnelTest extends BaseHostJUnit4Test { if (Instant.now().isAfter(deadline)) { fail(fullClassName + " did not load within timeout!"); } - activityType = vm.eventQueue().remove().stream() - .filter(e -> cpr == e.request()) - .findFirst() - .map(e -> ((ClassPrepareEvent) e).referenceType()) - .orElse(null); + activityType = vm.eventQueue() + .remove() + .stream() + .filter(e -> cpr == e.request()) + .findFirst() + .map(e -> ((ClassPrepareEvent) e).referenceType()) + .orElse(null); } cpr.disable(); // Set a breakpoint on the onCreate method at the first line. @@ -237,8 +247,8 @@ public class JdwpTunnelTest extends BaseHostJUnit4Test { */ @Test public void testAttachDebuggerToDebuggableApp() throws DeviceNotAvailableException, Exception { - testAttachDebugger(DEBUGGABLE_TEST_APP_PACKAGE_NAME, - DEBUGGABLE_TEST_APP_ACTIVITY_CLASS_NAME); + testAttachDebugger( + DEBUGGABLE_TEST_APP_PACKAGE_NAME, DEBUGGABLE_TEST_APP_ACTIVITY_CLASS_NAME); } /** @@ -251,8 +261,8 @@ public class JdwpTunnelTest extends BaseHostJUnit4Test { public void testAttachDebuggerToProfileableApp() throws DeviceNotAvailableException, Exception { java.io.IOException thrownException = null; try { - testAttachDebugger(PROFILEABLE_TEST_APP_PACKAGE_NAME, - PROFILEABLE_TEST_APP_ACTIVITY_CLASS_NAME); + testAttachDebugger( + PROFILEABLE_TEST_APP_PACKAGE_NAME, PROFILEABLE_TEST_APP_ACTIVITY_CLASS_NAME); } catch (java.io.IOException e) { thrownException = e; } @@ -271,13 +281,17 @@ public class JdwpTunnelTest extends BaseHostJUnit4Test { // when it calls the "attach" method from class AttachingConnector or its subclass. // In other words, the callstack is expected to look like // - // at jdk.jdi/com.sun.tools.jdi.SocketAttachingConnector.attach(SocketAttachingConnector.java:83) - // at android.jdwptunnel.cts.JdwpTunnelTest.getDebuggerConnection(JdwpTunnelTest.java:96) + // at + // jdk.jdi/com.sun.tools.jdi.SocketAttachingConnector.attach + // (SocketAttachingConnector.java:83) + // at + // android.jdwptunnel.cts.JdwpTunnelTest.getDebuggerConnection + // (JdwpTunnelTest.java:96) boolean thrownByGetDebuggerConnection = false; StackTraceElement[] stack = thrownException.getStackTrace(); for (int i = 0; i < stack.length; i++) { - if (stack[i].getClassName().equals("android.jdwptunnel.cts.JdwpTunnelTest") && - stack[i].getMethodName().equals("getDebuggerConnection")) { + if (stack[i].getClassName().equals("android.jdwptunnel.cts.JdwpTunnelTest") + && stack[i].getMethodName().equals("getDebuggerConnection")) { thrownByGetDebuggerConnection = true; assertTrue(i > 0); assertEquals("attach", stack[i - 1].getMethodName()); @@ -306,8 +320,8 @@ public class JdwpTunnelTest extends BaseHostJUnit4Test { String deviceArch = getDeviceBaseArch(); Assume.assumeTrue(testingArch.equals(deviceArch)); - String port = - startupForwarding(DDMS_TEST_APP_PACKAGE_NAME, DDMS_TEST_APP_ACTIVITY_CLASS_NAME, false); + String port = startupForwarding( + DDMS_TEST_APP_PACKAGE_NAME, DDMS_TEST_APP_ACTIVITY_CLASS_NAME, false); Socket sock = new Socket("localhost", Integer.decode(port).intValue()); OutputStream os = sock.getOutputStream(); // Let the test spin a bit. Try to lose any race with the app. @@ -330,4 +344,33 @@ public class JdwpTunnelTest extends BaseHostJUnit4Test { // Data sent big-endian so first byte has sign bit. assertTrue((is.read() & 0x80) == 0x80); } + + private void assertThreadSuspensionState(VirtualMachine vm, boolean expected) { + for (ThreadReference tr : vm.allThreads()) { + boolean isSuspended = tr.isSuspended(); + if (isSuspended != expected) { + fail("Thread in unexpected state '" + tr.name() + "' isSuspended=" + isSuspended); + } + } + } + + // App can be started "suspended" which means all its threads will be suspended shorty after + // zygote specializes. + @Test + public void testSuspendStartup() throws DeviceNotAvailableException, Exception { + + VirtualMachine vm = startupTest(DEBUGGABLE_TEST_APP_PACKAGE_NAME, + DEBUGGABLE_TEST_APP_ACTIVITY_CLASS_NAME, true, true); + + try { + // The VM was started in suspended mode. + assertThreadSuspensionState(vm, true); + + // Let's go! + vm.resume(); + assertThreadSuspensionState(vm, false); + } finally { + vm.dispose(); + } + } } diff --git a/hostsidetests/media/src/android/media/cts/BaseMultiUserTest.java b/hostsidetests/media/src/android/media/cts/BaseMultiUserTest.java index c4ed6bdfbe0..689a93d19dc 100644 --- a/hostsidetests/media/src/android/media/cts/BaseMultiUserTest.java +++ b/hostsidetests/media/src/android/media/cts/BaseMultiUserTest.java @@ -52,6 +52,7 @@ public class BaseMultiUserTest extends BaseMediaHostSideTest { private String mPackageVerifier; + private int mInitialUserId; private Set<String> mExistingPackages; private List<Integer> mExistingUsers; private HashSet<String> mAvailableFeatures; @@ -75,9 +76,17 @@ public class BaseMultiUserTest extends BaseMediaHostSideTest { "0", USER_ALL); + mInitialUserId = getDevice().getCurrentUser(); mExistingUsers = getDevice().listUsers(); + Integer mainUserId = getDevice().getMainUserId(); Integer primaryUserId = getDevice().getPrimaryUserId(); - executeShellCommand("am switch-user " + primaryUserId); + if (primaryUserId != null) { + getDevice().switchUser(primaryUserId); + } else if (mainUserId != null) { + getDevice().switchUser(mainUserId); + } else { + // Neither a primary nor a main user exists. Just use the current one. + } executeShellCommand("wm dismiss-keyguard"); } @@ -117,6 +126,9 @@ public class BaseMultiUserTest extends BaseMediaHostSideTest { lastTearDownError = t; } } + if (getDevice().getCurrentUser() != mInitialUserId) { + getDevice().switchUser(mInitialUserId); + } super.tearDown(); if (lastTearDownError != null) { throw new AssertionError("Something went wrong while cleaning up.", lastTearDownError); diff --git a/hostsidetests/mediapc/videoencodingquality/src/CtsVideoEncodingQualityHostTest.java b/hostsidetests/mediapc/videoencodingquality/src/CtsVideoEncodingQualityHostTest.java index 5c30bf97333..df220112773 100644 --- a/hostsidetests/mediapc/videoencodingquality/src/CtsVideoEncodingQualityHostTest.java +++ b/hostsidetests/mediapc/videoencodingquality/src/CtsVideoEncodingQualityHostTest.java @@ -22,6 +22,7 @@ import android.platform.test.annotations.AppModeFull; import com.android.compatibility.common.util.CddTest; import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; +import com.android.ddmlib.testrunner.TestResult.TestStatus; import com.android.tradefed.config.Option; import com.android.tradefed.config.OptionClass; import com.android.tradefed.device.DeviceNotAvailableException; @@ -498,17 +499,24 @@ public class CtsVideoEncodingQualityHostTest implements IDeviceTest { + testRunResult.getName() + ": " + testRunResult.getRunFailureMessage()); } if (testRunResult.getNumTests() != testRunResult.getPassedTests().size()) { - StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n"); for (Map.Entry<TestDescription, TestResult> resultEntry : testRunResult.getTestResults().entrySet()) { - if (!resultEntry.getValue().getStatus() - .equals(com.android.ddmlib.testrunner.TestResult.TestStatus.PASSED)) { + if (resultEntry.getValue().getStatus().equals(TestStatus.FAILURE)) { + StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n"); errorBuilder.append(resultEntry.getKey().toString()); errorBuilder.append(":\n"); errorBuilder.append(resultEntry.getValue().getStackTrace()); + throw new AssertionError(errorBuilder.toString()); + } + if (resultEntry.getValue().getStatus().equals(TestStatus.ASSUMPTION_FAILURE)) { + StringBuilder errorBuilder = + new StringBuilder("On-device tests assumption failed:\n"); + errorBuilder.append(resultEntry.getKey().toString()); + errorBuilder.append(":\n"); + errorBuilder.append(resultEntry.getValue().getStackTrace()); + Assume.assumeTrue(errorBuilder.toString(), false); } } - throw new AssertionError(errorBuilder.toString()); } } } diff --git a/hostsidetests/rollback/OWNERS b/hostsidetests/rollback/OWNERS index b8578eb6794..ca6897c0d60 100644 --- a/hostsidetests/rollback/OWNERS +++ b/hostsidetests/rollback/OWNERS @@ -1,5 +1,3 @@ # Bug component: 557916 -olilan@google.com -wangchun@google.com -gavincorkery@google.com -* +ancr@google.com +harshitmahajan@google.com diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java index e0dc9463ee1..fb7fd3f236a 100644 --- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java +++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java @@ -18,6 +18,8 @@ package android.scopedstorage.cts.host; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assume.assumeFalse; + import android.platform.test.annotations.AppModeFull; import com.android.tradefed.device.contentprovider.ContentProviderHandler; @@ -40,7 +42,7 @@ public class LegacyStorageHostTest extends BaseHostTestCase { private ContentProviderHandler mContentProviderHandler; /** - * Runs the given phase of LegacyFileAccessTest by calling into the device. + * Runs the given phase of LegacyStorageTest by calling into the device. * Throws an exception if the test phase fails. */ void runDeviceTest(String phase) throws Exception { @@ -86,6 +88,9 @@ public class LegacyStorageHostTest extends BaseHostTestCase { @Before public void setup() throws Exception { + // Ignore tests on automotive devices b/319785789 + assumeFalse(hasDeviceFeature("android.hardware.type.automotive")); + mContentProviderHandler = new ContentProviderHandler(getDevice()); mContentProviderHandler.setUp(); setupExternalStorage(); @@ -98,7 +103,9 @@ public class LegacyStorageHostTest extends BaseHostTestCase { @After public void tearDown() throws Exception { - mContentProviderHandler.tearDown(); + if (mContentProviderHandler != null) { + mContentProviderHandler.tearDown(); + } revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.READ_EXTERNAL_STORAGE"); } @@ -260,7 +267,7 @@ public class LegacyStorageHostTest extends BaseHostTestCase { } /** - * (b/205673506): Test that legacy System Gallery can update() media file's releative_path to a + * (b/205673506): Test that legacy System Gallery can update() media file's relative_path to a * non default top level directory. */ @Test diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java index 37f8ee7faf3..6c2b836b98f 100644 --- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java +++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java @@ -18,6 +18,8 @@ package android.scopedstorage.cts.host; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assume.assumeFalse; + import android.platform.test.annotations.AppModeFull; import com.android.modules.utils.build.testing.DeviceSdkLevel; @@ -71,6 +73,9 @@ public class ScopedStorageHostTest extends BaseHostTestCase { @Before public void setup() throws Exception { + // Ignore tests on automotive devices b/319785789 + assumeFalse(hasDeviceFeature("android.hardware.type.automotive")); + setupExternalStorage(); executeShellCommand("mkdir /sdcard/Android/data/com.android.shell -m 2770"); executeShellCommand("mkdir /sdcard/Android/data/com.android.shell/files -m 2770"); diff --git a/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java b/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java index 33a838ed42d..4517e646b1f 100644 --- a/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java +++ b/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java @@ -64,8 +64,6 @@ import static android.scopedstorage.cts.lib.TestUtils.verifyInsertFromExternalPr import static android.scopedstorage.cts.lib.TestUtils.verifyUpdateToExternalMediaDirViaRelativePath_allowed; import static android.scopedstorage.cts.lib.TestUtils.verifyUpdateToExternalPrivateDirsViaRelativePath_denied; -import static androidx.test.InstrumentationRegistry.getContext; - import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -93,8 +91,8 @@ import android.system.OsConstants; import android.text.TextUtils; import android.util.Log; -import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.cts.install.lib.TestApp; @@ -116,7 +114,7 @@ import java.util.Arrays; /** * Test app targeting Q and requesting legacy storage - tests legacy file path access. - * Designed to be run by LegacyAccessHostTest. + * Designed to be run by LegacyStorageHostTest. * * <p> Test cases that assume we have WRITE_EXTERNAL_STORAGE only are appended with hasW, * those that assume we have READ_EXTERNAL_STORAGE only are appended with hasR, those who assume we @@ -126,22 +124,23 @@ import java.util.Arrays; */ @RunWith(AndroidJUnit4.class) public class LegacyStorageTest { - private static final String TAG = "LegacyFileAccessTest"; - static final String THIS_PACKAGE_NAME = InstrumentationRegistry.getContext().getPackageName(); + private static final String TAG = "LegacyStorageTest"; + private static final String THIS_PACKAGE_NAME = + InstrumentationRegistry.getInstrumentation().getContext().getPackageName(); /** * To help avoid flaky tests, give ourselves a unique nonce to be used for * all filesystem paths, so that we don't risk conflicting with previous * test runs. */ - static final String NONCE = String.valueOf(System.nanoTime()); - static final String TEST_DIRECTORY_NAME = "ScopedStorageTestDirectory" + NONCE; + private static final String NONCE = String.valueOf(System.nanoTime()); + private static final String TEST_DIRECTORY_NAME = "LegacyStorageTestDirectory" + NONCE; - static final String IMAGE_FILE_NAME = "LegacyStorageTest_file_" + NONCE + ".jpg"; - static final String VIDEO_FILE_NAME = "LegacyStorageTest_file_" + NONCE + ".mp4"; - static final String NONMEDIA_FILE_NAME = "LegacyStorageTest_file_" + NONCE + ".pdf"; + private static final String IMAGE_FILE_NAME = "LegacyStorageTest_file_" + NONCE + ".jpg"; + private static final String VIDEO_FILE_NAME = "LegacyStorageTest_file_" + NONCE + ".mp4"; + private static final String NONMEDIA_FILE_NAME = "LegacyStorageTest_file_" + NONCE + ".pdf"; - static final String CONTENT_PROVIDER_URL = "content://android.tradefed.contentprovider"; + private static final String CONTENT_PROVIDER_URL = "content://android.tradefed.contentprovider"; // The following apps are installed before the tests are run via a target_preparer. // See test config for details. @@ -194,18 +193,18 @@ public class LegacyStorageTest { pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /*granted*/ false); pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ true); // Can create file under root dir - assertCanCreateFile(new File(TestUtils.getExternalStorageDir(), "LegacyFileAccessTest.txt")); + assertCanCreateFile(new File(TestUtils.getExternalStorageDir(), "LegacyStorageTest.txt")); // Can create music file under DCIM - assertCanCreateFile(new File(TestUtils.getDcimDir(), "LegacyFileAccessTest.mp3")); + assertCanCreateFile(new File(TestUtils.getDcimDir(), "LegacyStorageTest.mp3")); // Can create random file under external files dir assertCanCreateFile(new File(TestUtils.getExternalFilesDir(), - "LegacyFileAccessTest")); + "LegacyStorageTest")); // However, even legacy apps can't create files under other app's directories final File otherAppDir = new File(TestUtils.getAndroidDataDir(), "com.android.shell"); - final File file = new File(otherAppDir, "LegacyFileAccessTest.txt"); + final File file = new File(otherAppDir, "LegacyStorageTest.txt"); // otherAppDir was already created by the host test try { @@ -223,14 +222,14 @@ public class LegacyStorageTest { public void testMkdirInRandomPlaces_hasW() throws Exception { pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /*granted*/ false); pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ true); - // Can create a top-level direcotry - final File topLevelDir = new File(TestUtils.getExternalStorageDir(), "LegacyFileAccessTest"); + // Can create a top-level directory + final File topLevelDir = new File(TestUtils.getExternalStorageDir(), "LegacyStorageTest"); assertCanCreateDir(topLevelDir); final File otherAppDir = new File(TestUtils.getAndroidDataDir(), "com.android.shell"); // However, even legacy apps can't create dirs under other app's directories - final File subDir = new File(otherAppDir, "LegacyFileAccessTest"); + final File subDir = new File(otherAppDir, "LegacyStorageTest"); // otherAppDir was already created by the host test assertThat(subDir.mkdir()).isFalse(); @@ -247,7 +246,7 @@ public class LegacyStorageTest { pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ false); // Can't create file under root dir final File newTxtFile = new File(TestUtils.getExternalStorageDir(), - "LegacyFileAccessTest.txt"); + "LegacyStorageTest.txt"); try { newTxtFile.createNewFile(); fail("File creation expected to fail: " + newTxtFile); @@ -255,15 +254,15 @@ public class LegacyStorageTest { } // Can't create music file under /MUSIC - final File newMusicFile = new File(TestUtils.getMusicDir(), "LegacyFileAccessTest.mp3"); + final File newMusicFile = new File(TestUtils.getMusicDir(), "LegacyStorageTest.mp3"); try { newMusicFile.createNewFile(); fail("File creation expected to fail: " + newMusicFile); } catch (IOException expected) { } - // Can't create a top-level direcotry - final File topLevelDir = new File(TestUtils.getExternalStorageDir(), "LegacyFileAccessTest"); + // Can't create a top-level directory + final File topLevelDir = new File(TestUtils.getExternalStorageDir(), "LegacyStorageTest"); assertThat(topLevelDir.mkdir()).isFalse(); // Can't read existing file @@ -287,11 +286,11 @@ public class LegacyStorageTest { // However, even without permissions, we can access our own external dir final File fileInDataDir = new File(TestUtils.getExternalFilesDir(), - "LegacyFileAccessTest"); + "LegacyStorageTest"); try { assertThat(fileInDataDir.createNewFile()).isTrue(); assertThat(Arrays.asList(fileInDataDir.getParentFile().list())) - .contains("LegacyFileAccessTest"); + .contains("LegacyStorageTest"); } finally { fileInDataDir.delete(); } @@ -299,11 +298,11 @@ public class LegacyStorageTest { // we can access our own external media directory without permissions. final File fileInMediaDir = new File(TestUtils.getExternalMediaDir(), - "LegacyFileAccessTest"); + "LegacyStorageTest"); try { assertThat(fileInMediaDir.createNewFile()).isTrue(); assertThat(Arrays.asList(fileInMediaDir.getParentFile().list())) - .contains("LegacyFileAccessTest"); + .contains("LegacyStorageTest"); } finally { fileInMediaDir.delete(); } @@ -340,7 +339,7 @@ public class LegacyStorageTest { } // try to create file and fail, because it requires WRITE - final File newFile = new File(TestUtils.getMusicDir(), "LegacyFileAccessTest.mp3"); + final File newFile = new File(TestUtils.getMusicDir(), "LegacyStorageTest.mp3"); try { newFile.createNewFile(); fail("Creating file expected to fail: " + newFile); @@ -348,7 +347,7 @@ public class LegacyStorageTest { } // try to mkdir and fail, because it requires WRITE - final File newDir = new File(TestUtils.getExternalStorageDir(), "LegacyFileAccessTest"); + final File newDir = new File(TestUtils.getExternalStorageDir(), "LegacyStorageTest"); try { assertThat(newDir.mkdir()).isFalse(); } finally { @@ -408,15 +407,15 @@ public class LegacyStorageTest { pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /*granted*/ true); pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ true); - final File musicFile1 = new File(TestUtils.getDcimDir(), "LegacyFileAccessTest.mp3"); + final File musicFile1 = new File(TestUtils.getDcimDir(), "LegacyStorageTest.mp3"); final File musicFile2 = new File(TestUtils.getExternalStorageDir(), - "LegacyFileAccessTest.mp3"); - final File musicFile3 = new File(TestUtils.getMoviesDir(), "LegacyFileAccessTest.mp3"); - final File nonMediaDir1 = new File(TestUtils.getDcimDir(), "LegacyFileAccessTest"); + "LegacyStorageTest.mp3"); + final File musicFile3 = new File(TestUtils.getMoviesDir(), "LegacyStorageTest.mp3"); + final File nonMediaDir1 = new File(TestUtils.getDcimDir(), "LegacyStorageTest"); final File nonMediaDir2 = new File(TestUtils.getExternalStorageDir(), - "LegacyFileAccessTest"); - final File pdfFile1 = new File(nonMediaDir1, "LegacyFileAccessTest.pdf"); - final File pdfFile2 = new File(nonMediaDir2, "LegacyFileAccessTest.pdf"); + "LegacyStorageTest"); + final File pdfFile1 = new File(nonMediaDir1, "LegacyStorageTest.pdf"); + final File pdfFile2 = new File(nonMediaDir2, "LegacyStorageTest.pdf"); try { // can rename a file to root directory. assertThat(musicFile1.createNewFile()).isTrue(); @@ -429,7 +428,7 @@ public class LegacyStorageTest { assertThat(pdfFile1.createNewFile()).isTrue(); // can rename directory to root directory. assertCanRenameDirectory( - nonMediaDir1, nonMediaDir2, new File[] {pdfFile1}, new File[] {pdfFile2}); + nonMediaDir1, nonMediaDir2, new File[]{pdfFile1}, new File[]{pdfFile2}); } finally { musicFile1.delete(); musicFile2.delete(); @@ -469,13 +468,13 @@ public class LegacyStorageTest { pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ false); final File shellFile1 = getShellFile(); - final File shellFile2 = new File(TestUtils.getDownloadDir(), "LegacyFileAccessTest_shell"); + final File shellFile2 = new File(TestUtils.getDownloadDir(), "LegacyStorageTest_shell"); final File mediaFile1 = new File(TestUtils.getExternalMediaDir(), - "LegacyFileAccessTest1"); + "LegacyStorageTest1"); final File mediaFile2 = new File(TestUtils.getExternalMediaDir(), - "LegacyFileAccessTest2"); + "LegacyStorageTest2"); try { createFileInExternalDir(shellFile1); MediaStore.scanFile(getContentResolver(), shellFile1); @@ -504,13 +503,13 @@ public class LegacyStorageTest { pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ false); final File shellFile1 = getShellFile(); - final File shellFile2 = new File(TestUtils.getDownloadDir(), "LegacyFileAccessTest_shell"); + final File shellFile2 = new File(TestUtils.getDownloadDir(), "LegacyStorageTest_shell"); final File mediaFile1 = new File(TestUtils.getExternalMediaDir(), - "LegacyFileAccessTest1"); + "LegacyStorageTest1"); final File mediaFile2 = new File(TestUtils.getExternalMediaDir(), - "LegacyFileAccessTest2"); + "LegacyStorageTest2"); try { createFileInExternalDir(shellFile1); MediaStore.scanFile(getContentResolver(), shellFile1); @@ -535,7 +534,7 @@ public class LegacyStorageTest { */ @Test public void testRenameDirectoryAndUpdateDB_hasW() throws Exception { - final String testDirectoryName = "LegacyFileAccessTestDirectory"; + final String testDirectoryName = "LegacyStorageTestDirectory"; File directoryOldPath = new File(TestUtils.getDcimDir(), testDirectoryName); File directoryNewPath = new File(TestUtils.getMoviesDir(), testDirectoryName); try { @@ -625,7 +624,8 @@ public class LegacyStorageTest { pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ true); final File videoFile = new File(TestUtils.getDcimDir(), VIDEO_FILE_NAME); - final File renamedVideoFile = new File(TestUtils.getDcimDir(), "Renamed_" + VIDEO_FILE_NAME); + final File renamedVideoFile = new File(TestUtils.getDcimDir(), + "Renamed_" + VIDEO_FILE_NAME); final ContentResolver cr = getContentResolver(); try { @@ -747,7 +747,7 @@ public class LegacyStorageTest { assertTrue(file.createNewFile()); try (Cursor c = TestUtils.queryFile(file, - new String[] {MediaStore.MediaColumns.IS_PENDING})) { + new String[]{MediaStore.MediaColumns.IS_PENDING})) { // This file will not have IS_PENDING=1 because create didn't set IS_PENDING. assertTrue(c.moveToFirst()); assertEquals(c.getInt(0), 0); @@ -809,45 +809,49 @@ public class LegacyStorageTest { pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /*granted*/ true); pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ true); - final String IMAGE_FILE_DISPLAY_NAME = "LegacyStorageTest_file_" + NONCE; - final File imageFile = new File(TestUtils.getDcimDir(), IMAGE_FILE_DISPLAY_NAME + ".jpg"); - - for (String mimeType : new String[] { - "image/*", "", null, "foo/bar" - }) { - Uri uri = null; - try { - ContentValues values = new ContentValues(); - values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM); - if (TextUtils.isEmpty(mimeType)) { - values.put(MediaStore.MediaColumns.DISPLAY_NAME, imageFile.getName()); - } else { - values.put(MediaStore.MediaColumns.DISPLAY_NAME, IMAGE_FILE_DISPLAY_NAME); - } - values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType); - - uri = getContentResolver().insert(getImageContentUri(), values, Bundle.EMPTY); - assertNotNull(uri); - - try (final OutputStream fos = getContentResolver().openOutputStream(uri, "rw")) { - fos.write(BYTES_DATA1); - } - - // Closing the file should trigger a scan, we still scan again to ensure MIME type - // is extracted from file extension - assertNotNull(MediaStore.scanFile(getContentResolver(), imageFile)); - - final String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME, - MediaStore.MediaColumns.MIME_TYPE}; - try (Cursor c = getContentResolver().query(uri, projection, null, null, null)) { - assertTrue(c.moveToFirst()); - assertEquals(c.getCount(), 1); - assertEquals(c.getString(0), imageFile.getName()); - assertTrue("image/jpeg".equalsIgnoreCase(c.getString(1))); - } - } finally { - deleteWithMediaProviderNoThrow(uri); + final String imageFileDisplayName = "LegacyStorageTest_file_" + NONCE; + final String[] mimeTypes = {"image/*", "", null, "foo/bar"}; + for (int i = 0; i < mimeTypes.length; i++) { + // b/288337808 Creating files with different names to avoid potential name reassignments + assertFileInsertWithMimeType(imageFileDisplayName + "_" + i, mimeTypes[i]); + } + } + + private void assertFileInsertWithMimeType(String filename, String mimeType) + throws IOException { + Uri uri = null; + final File imageFile = new File(TestUtils.getDcimDir(), filename + ".jpg"); + try { + ContentValues values = new ContentValues(); + values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM); + if (TextUtils.isEmpty(mimeType)) { + values.put(MediaStore.MediaColumns.DISPLAY_NAME, imageFile.getName()); + } else { + values.put(MediaStore.MediaColumns.DISPLAY_NAME, filename); + } + values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType); + + uri = getContentResolver().insert(getImageContentUri(), values, Bundle.EMPTY); + assertNotNull(uri); + + try (OutputStream fos = getContentResolver().openOutputStream(uri, "rw")) { + fos.write(BYTES_DATA1); + } + + // Closing the file should trigger a scan, we still scan again to ensure MIME type + // is extracted from file extension + assertNotNull(MediaStore.scanFile(getContentResolver(), imageFile)); + + final String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME, + MediaStore.MediaColumns.MIME_TYPE}; + try (Cursor c = getContentResolver().query(uri, projection, null, null, null)) { + assertTrue(c.moveToFirst()); + assertEquals(c.getCount(), 1); + assertEquals(c.getString(0), imageFile.getName()); + assertTrue("image/jpeg".equalsIgnoreCase(c.getString(1))); } + } finally { + deleteWithMediaProviderNoThrow(uri); } } @@ -881,7 +885,7 @@ public class LegacyStorageTest { } /** - * (b/205673506): Test that legacy System Gallery can update() media file's releative_path to a + * (b/205673506): Test that legacy System Gallery can update() media file's relative_path to a * non default top level directory. */ @Test @@ -968,8 +972,8 @@ public class LegacyStorageTest { final File jpgFile = new File(getPicturesDir(), IMAGE_FILE_NAME); try { // Copy the image content to jpgFile - try (InputStream in = - getContext().getResources().openRawResource(R.raw.img_with_metadata); + try (InputStream in = InstrumentationRegistry.getInstrumentation().getContext() + .getResources().openRawResource(R.raw.img_with_metadata); FileOutputStream out = new FileOutputStream(jpgFile)) { FileUtils.copy(in, out); out.getFD().sync(); @@ -1208,11 +1212,11 @@ public class LegacyStorageTest { final String selection = "is_pending = 0 AND is_trashed = 0 AND " + "(media_type = ? OR media_type = ?)"; final String[] selectionArgs = - new String[] {String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE), + new String[]{String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE), String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO)}; try (Cursor c = getContentResolver().query(TestUtils.getTestVolumeFileUri(), - /* projection */ new String[] {MediaStore.MediaColumns.DISPLAY_NAME}, + /* projection */ new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, selection, selectionArgs, null)) { while (c.moveToNext()) { mediaFiles.add(c.getString(0)); @@ -1223,7 +1227,7 @@ public class LegacyStorageTest { private File getShellFile() throws Exception { return new File(TestUtils.getExternalStorageDir(), - "LegacyAccessHostTest_shell"); + "LegacyStorageHostTest_shell"); } private void createFileInExternalDir(File file) throws Exception { diff --git a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java index 9c0b577269b..b337265999c 100644 --- a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java +++ b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java @@ -1023,7 +1023,8 @@ public class TestUtils { try { getContentResolver().delete(uri, Bundle.EMPTY); - } catch (Exception ignored) { + } catch (Exception exception) { + Log.e("Exception while deleting files", exception.getMessage()); } } } diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java index 01792e7213c..89b207b52b2 100644 --- a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java +++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java @@ -71,8 +71,6 @@ import static android.scopedstorage.cts.lib.TestUtils.verifyUpdateToExternalDirs import static android.scopedstorage.cts.lib.TestUtils.verifyUpdateToExternalMediaDirViaRelativePath_allowed; import static android.scopedstorage.cts.lib.TestUtils.verifyUpdateToExternalPrivateDirsViaRelativePath_denied; -import static androidx.test.InstrumentationRegistry.getContext; - import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -84,6 +82,7 @@ import static org.junit.Assume.assumeTrue; import android.Manifest; import android.content.ContentValues; +import android.content.Context; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -95,7 +94,8 @@ import android.provider.MediaStore; import android.scopedstorage.cts.lib.RedactionTestHelper; import android.util.Log; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.cts.install.lib.TestApp; import com.android.modules.utils.build.SdkLevel; @@ -117,7 +117,8 @@ import java.io.IOException; @RunWith(AndroidJUnit4.class) public class ScopedStorageTest { static final String TAG = "ScopedStorageTest"; - static final String THIS_PACKAGE_NAME = getContext().getPackageName(); + static final String THIS_PACKAGE_NAME = + InstrumentationRegistry.getInstrumentation().getContext().getPackageName(); static final int USER_SYSTEM = 0; /** @@ -165,11 +166,12 @@ public class ScopedStorageTest { @Before public void setup() throws Exception { - if (!getContext().getPackageManager().isInstantApp()) { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + if (!context.getPackageManager().isInstantApp()) { pollForExternalStorageState(); getExternalFilesDir().mkdirs(); } - MediaStore.waitForIdle(getContext().getContentResolver()); + MediaStore.waitForIdle(context.getContentResolver()); } /** @@ -187,7 +189,8 @@ public class ScopedStorageTest { public void testCheckInstallerAppAccessToObbDirs() throws Exception { assertCanAccessPrivateAppAndroidObbDir(true /*canAccess*/, APP_B_NO_PERMS, THIS_PACKAGE_NAME, NONMEDIA_FILE_NAME); - final int uid = getContext().getPackageManager().getPackageUid(THIS_PACKAGE_NAME, 0); + final int uid = InstrumentationRegistry.getInstrumentation().getContext() + .getPackageManager().getPackageUid(THIS_PACKAGE_NAME, 0); if (isAtLeastS()) { assertMountMode(THIS_PACKAGE_NAME, uid, StorageManager.MOUNT_MODE_EXTERNAL_INSTALLER); } @@ -200,7 +203,8 @@ public class ScopedStorageTest { public void testCheckInstallerAppCannotAccessDataDirs() throws Exception { assertCanAccessPrivateAppAndroidDataDir(false /*canAccess*/, APP_B_NO_PERMS, THIS_PACKAGE_NAME, NONMEDIA_FILE_NAME); - final int uid = getContext().getPackageManager().getPackageUid(THIS_PACKAGE_NAME, 0); + final int uid = InstrumentationRegistry.getInstrumentation().getContext() + .getPackageManager().getPackageUid(THIS_PACKAGE_NAME, 0); if (isAtLeastS()) { assertMountMode(THIS_PACKAGE_NAME, uid, StorageManager.MOUNT_MODE_EXTERNAL_INSTALLER); } @@ -577,7 +581,7 @@ public class ScopedStorageTest { assertAccess(new File("/storage/emulated"), true, false, false); // Verify we can enter "/storage/emulated/<userId>" and read - int userId = getContext().getUserId(); + int userId = InstrumentationRegistry.getInstrumentation().getContext().getUserId(); assertAccess(new File("/storage/emulated/" + userId), true, true, false); // Verify we can't get another userId @@ -1138,9 +1142,10 @@ public class ScopedStorageTest { @Test @AppModeInstant public void testInstantAppsCantAccessExternalStorage() throws Exception { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); assumeTrue("This test requires that the test runs as an Instant app", - getContext().getPackageManager().isInstantApp()); - assertThat(getContext().getPackageManager().isInstantApp()).isTrue(); + context.getPackageManager().isInstantApp()); + assertThat(context.getPackageManager().isInstantApp()).isTrue(); // Check that the app does not have legacy external storage access assertThat(Environment.isExternalStorageLegacy()).isFalse(); diff --git a/hostsidetests/security/Android.bp b/hostsidetests/security/Android.bp index d4e9d215cc2..f42b9b434ed 100644 --- a/hostsidetests/security/Android.bp +++ b/hostsidetests/security/Android.bp @@ -61,6 +61,11 @@ java_test_host { target_required: ["CtsDeviceInfo"], } +filegroup { + name: "prebuilt_sepolicy_cts_data", + srcs: [":202404_sepolicy_cts_data"], +} + java_genrule_host { name: "CtsSecurityHostTestCases_StaticLibs", tools: [ @@ -75,9 +80,11 @@ java_genrule_host { ], tool_files: [ ":general_sepolicy.conf", + ":prebuilt_sepolicy_cts_data", ], out: ["CtsSecurityHostTestCases_StaticLibs.jar"], - cmd: "$(location soong_zip) -jar -o $(location CtsSecurityHostTestCases_StaticLibs.jar) -j " + + cmd: "echo $(locations :prebuilt_sepolicy_cts_data) > $(out).prebuilt_list.txt && " + + "$(location soong_zip) -jar -o $(location CtsSecurityHostTestCases_StaticLibs.jar) -j " + "-f $(location checkseapp) " + "-f $(location checkfc) " + "-f $(location property_info_checker) " + @@ -85,5 +92,6 @@ java_genrule_host { "-f $(location secilc) " + "-f $(location sepolicy-analyze) " + "-f $(location sepolicy_tests) " + - "-f $(location :general_sepolicy.conf)", + "-f $(location :general_sepolicy.conf) " + + "-l $(out).prebuilt_list.txt", } diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java index 341024c5f28..2ffcfce38c6 100644 --- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java +++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java @@ -92,12 +92,13 @@ public class SELinuxHostTest extends BaseHostJUnit4Test { private static final String SEPOLICY_VERSION_JSON_KEY = "sepolicy_version"; private static final String PLATFORM_SEPOLICY_VERSION_JSON_KEY = "platform_sepolicy_version"; - private static final Map<ITestDevice, File> cachedDevicePolicyFiles = new HashMap<>(1); - private static final Map<ITestDevice, File> cachedDevicePlatFcFiles = new HashMap<>(1); - private static final Map<ITestDevice, File> cachedDeviceVendorFcFiles = new HashMap<>(1); - private static final Map<ITestDevice, File> cachedDeviceVendorManifest = new HashMap<>(1); - private static final Map<ITestDevice, File> cachedDeviceVintfJson = new HashMap<>(1); - private static final Map<ITestDevice, File> cachedDeviceSystemPolicy = new HashMap<>(1); + private static final Map<ITestDevice, File> sCachedDevicePolicyFiles = new HashMap<>(1); + private static final Map<ITestDevice, File> sCachedDevicePlatFcFiles = new HashMap<>(1); + private static final Map<ITestDevice, File> sCachedDeviceVendorFcFiles = new HashMap<>(1); + private static final Map<ITestDevice, File> sCachedDeviceVendorManifest = new HashMap<>(1); + private static final Map<ITestDevice, File> sCachedDeviceVendorPolicy = new HashMap<>(1); + private static final Map<ITestDevice, File> sCachedDeviceVintfJson = new HashMap<>(1); + private static final Map<ITestDevice, File> sCachedDeviceSystemPolicy = new HashMap<>(1); private File mSepolicyAnalyze; private File checkSeapp; @@ -163,16 +164,16 @@ public class SELinuxHostTest extends BaseHostJUnit4Test { devicePolicyFile = getDevicePolicyFile(mDevice); if (isSepolicySplit(mDevice)) { - devicePlatFcFile = getDeviceFile(mDevice, cachedDevicePlatFcFiles, + devicePlatFcFile = getDeviceFile(mDevice, sCachedDevicePlatFcFiles, "/system/etc/selinux/plat_file_contexts", "plat_file_contexts"); - deviceVendorFcFile = getDeviceFile(mDevice, cachedDeviceVendorFcFiles, + deviceVendorFcFile = getDeviceFile(mDevice, sCachedDeviceVendorFcFiles, "/vendor/etc/selinux/vendor_file_contexts", "vendor_file_contexts"); deviceSystemPolicyFile = android.security.cts.SELinuxHostTest.getDeviceSystemPolicyFile(mDevice); } else { - devicePlatFcFile = getDeviceFile(mDevice, cachedDevicePlatFcFiles, + devicePlatFcFile = getDeviceFile(mDevice, sCachedDevicePlatFcFiles, "/plat_file_contexts", "plat_file_contexts"); - deviceVendorFcFile = getDeviceFile(mDevice, cachedDeviceVendorFcFiles, + deviceVendorFcFile = getDeviceFile(mDevice, sCachedDeviceVendorFcFiles, "/vendor_file_contexts", "vendor_file_contexts"); } } @@ -204,7 +205,7 @@ public class SELinuxHostTest extends BaseHostJUnit4Test { Map<ITestDevice, File> cache, String deviceFilePath, String tmpFileName) throws Exception { if (!device.doesFileExist(deviceFilePath)){ - throw new Exception(); + throw new Exception("File not found on the device: " + deviceFilePath); } File file; synchronized (cache) { @@ -271,18 +272,86 @@ public class SELinuxHostTest extends BaseHostJUnit4Test { return builtPolicyFile; } + private static File buildVendorPolicy(IBuildInfo build, ITestDevice device, + Map<ITestDevice, File> cache, String tmpFileName) throws Exception { + File builtPolicyFile; + synchronized (cache) { + builtPolicyFile = cache.get(device); + } + if (builtPolicyFile != null) { + return builtPolicyFile; + } + + builtPolicyFile = createTempFile(tmpFileName, ".tmp"); + + File secilc = copyResourceToTempFile("/secilc"); + secilc.setExecutable(true); + + int vendorVersion = getVendorSepolicyVersion(build, device); + + File platSepolicyFile = copyResourceToTempFile("/" + vendorVersion + "_plat_sepolicy.cil"); + File platMappingFile = copyResourceToTempFile("/" + vendorVersion + "_mapping.cil"); + File vendorSepolicyCilFile = createTempFile("vendor_sepolicy", ".cil"); + File platPubVersionedCilFile = createTempFile("plat_pub_versioned", ".cil"); + File odmSepolicyCilFile = createTempFile("odm_sepolicy", ".cil"); + File fileContextsFile = createTempFile("file_contexts", ".txt"); + + assertTrue(device.pullFile("/vendor/etc/selinux/vendor_sepolicy.cil", + vendorSepolicyCilFile)); + assertTrue(device.pullFile("/vendor/etc/selinux/plat_pub_versioned.cil", + platPubVersionedCilFile)); + + List<String> command = new ArrayList<>(Arrays.asList( + secilc.getAbsolutePath(), + "-m", + "-M", + "true", + "-c", + "30", + "-N", + "-o", + builtPolicyFile.getAbsolutePath(), + "-f", + fileContextsFile.getAbsolutePath(), + platSepolicyFile.getAbsolutePath(), + platMappingFile.getAbsolutePath(), + vendorSepolicyCilFile.getAbsolutePath(), + platPubVersionedCilFile.getAbsolutePath())); + + if (device.pullFile("/odm/etc/selinux/odm_sepolicy.cil", odmSepolicyCilFile)) { + command.add(odmSepolicyCilFile.getAbsolutePath()); + } + + String errorString = tryRunCommand(command.toArray(new String[0])); + assertTrue(errorString, errorString.length() == 0); + + synchronized (cache) { + cache.put(device, builtPolicyFile); + } + return builtPolicyFile; + } + /** * Returns the host-side file containing the SELinux policy of the device under test. */ public static File getDevicePolicyFile(ITestDevice device) throws Exception { - return getDeviceFile(device, cachedDevicePolicyFiles, "/sys/fs/selinux/policy", "sepolicy"); + return getDeviceFile(device, sCachedDevicePolicyFiles, "/sys/fs/selinux/policy", + "sepolicy"); } /** * Returns the host-side file containing the system SELinux policy of the device under test. */ public static File getDeviceSystemPolicyFile(ITestDevice device) throws Exception { - return buildSystemPolicy(device, cachedDeviceSystemPolicy, "system_sepolicy"); + return buildSystemPolicy(device, sCachedDeviceSystemPolicy, "system_sepolicy"); + } + + /** + * Returns the host-side file containing the vendor SELinux policy of the device under test. + */ + public static File getDeviceVendorPolicyFile(IBuildInfo build, ITestDevice device) + throws Exception { + return buildVendorPolicy(build, device, sCachedDeviceVendorPolicy, "vendor_sepolicy"); } /** @@ -303,19 +372,20 @@ public class SELinuxHostTest extends BaseHostJUnit4Test { try { return getVendorSepolicyVersionFromBuildInfo(build); } catch (Exception ex) { - CLog.e("getVendorSepolicyVersionFromBuildInfo failed: ", ex); + CLog.e("getVendorSepolicyVersionFromBuildInfo failed: " + ex); buildInfoEx = ex; } try { return getVendorSepolicyVersionFromDeviceJson(device); } catch (Exception ex) { - CLog.e("getVendorSepolicyVersionFromDeviceJson failed: ", ex); + CLog.e("getVendorSepolicyVersionFromDeviceJson failed: " + ex); } try { return getVendorSepolicyVersionFromManifests(device); } catch (Exception ex) { - CLog.e("getVendorSepolicyVersionFromManifests failed: ", ex); - throw buildInfoEx; + CLog.e("getVendorSepolicyVersionFromManifests failed: " + ex); + throw new Exception("Unable to get the vendor policy version from the device:", + buildInfoEx); } } @@ -347,7 +417,7 @@ public class SELinuxHostTest extends BaseHostJUnit4Test { * VintfDeviceInfo. */ private static int getVendorSepolicyVersionFromDeviceJson(ITestDevice device) throws Exception { - File vintfJson = getDeviceFile(device, cachedDeviceVintfJson, + File vintfJson = getDeviceFile(device, sCachedDeviceVintfJson, DEVICE_INFO_DEVICE_DIR + VINTF_DEVICE_JSON, VINTF_DEVICE_JSON); return getVendorSepolicyVersionFromJsonFile(vintfJson); } @@ -374,7 +444,7 @@ public class SELinuxHostTest extends BaseHostJUnit4Test { (device.doesFileExist("/vendor/etc/vintf/manifest.xml")) ? "/vendor/etc/vintf/manifest.xml" : "/vendor/manifest.xml"; - File vendorManifestFile = getDeviceFile(device, cachedDeviceVendorManifest, + File vendorManifestFile = getDeviceFile(device, sCachedDeviceVendorManifest, deviceManifestPath, "manifest.xml"); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); diff --git a/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRule.java b/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRule.java new file mode 100644 index 00000000000..e2335da64c7 --- /dev/null +++ b/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRule.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import static org.junit.Assert.assertTrue; + +import com.android.compatibility.common.util.PropertyUtil; +import com.android.tradefed.device.ITestDevice; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class SELinuxNeverallowRule { + private static String[] sConditions = { + "TREBLE_ONLY", + "COMPATIBLE_PROPERTY_ONLY", + "LAUNCHING_WITH_R_ONLY", + "LAUNCHING_WITH_S_ONLY", + }; + + public String mText; + public boolean fullTrebleOnly; + public boolean launchingWithROnly; + public boolean launchingWithSOnly; + public boolean compatiblePropertyOnly; + + private SELinuxNeverallowRule(String text, Map<String, Integer> conditions) { + mText = text; + if (conditions.getOrDefault("TREBLE_ONLY", 0) > 0) { + fullTrebleOnly = true; + } + if (conditions.getOrDefault("COMPATIBLE_PROPERTY_ONLY", 0) > 0) { + compatiblePropertyOnly = true; + } + if (conditions.getOrDefault("LAUNCHING_WITH_R_ONLY", 0) > 0) { + launchingWithROnly = true; + } + if (conditions.getOrDefault("LAUNCHING_WITH_S_ONLY", 0) > 0) { + launchingWithSOnly = true; + } + } + + public String toString() { + return "Rule [text= " + mText + + ", fullTrebleOnly=" + fullTrebleOnly + + ", compatiblePropertyOnly=" + compatiblePropertyOnly + + ", launchingWithROnly=" + launchingWithROnly + + ", launchingWithSOnly=" + launchingWithSOnly + + "]"; + } + + private boolean isFullTrebleDevice(ITestDevice device) throws Exception { + return SELinuxHostTest.isFullTrebleDevice(device); + } + + private boolean isDeviceLaunchingWithR(ITestDevice device) throws Exception { + return PropertyUtil.getFirstApiLevel(device) > 29; + } + + private boolean isDeviceLaunchingWithS(ITestDevice device) throws Exception { + return PropertyUtil.getFirstApiLevel(device) > 30; + } + + private boolean isCompatiblePropertyEnforcedDevice(ITestDevice device) throws Exception { + return SELinuxHostTest.isCompatiblePropertyEnforcedDevice(device); + } + + public boolean isCompatible(ITestDevice device) throws Exception { + if ((fullTrebleOnly) && (!isFullTrebleDevice(device))) { + // This test applies only to Treble devices but this device isn't one + return false; + } + if ((launchingWithROnly) && (!isDeviceLaunchingWithR(device))) { + // This test applies only to devices launching with R or later but this device isn't one + return false; + } + if ((launchingWithSOnly) && (!isDeviceLaunchingWithS(device))) { + // This test applies only to devices launching with S or later but this device isn't one + return false; + } + if ((compatiblePropertyOnly) && (!isCompatiblePropertyEnforcedDevice(device))) { + // This test applies only to devices on which compatible property is enforced but this + // device isn't one + return false; + } + return true; + } + + public static List<SELinuxNeverallowRule> parsePolicy(String policy) throws Exception { + String patternConditions = Arrays.stream(sConditions) + .flatMap(condition -> Stream.of("BEGIN_" + condition, "END_" + condition)) + .collect(Collectors.joining("|")); + + /* Uncomment conditions delimiter lines. */ + Pattern uncommentConditions = Pattern.compile("^\\s*#\\s*(" + patternConditions + ")\\s*$", + Pattern.MULTILINE); + Matcher matcher = uncommentConditions.matcher(policy); + policy = matcher.replaceAll("$1"); + + /* Remove all comments. */ + Pattern comments = Pattern.compile("#.*?$", Pattern.MULTILINE); + matcher = comments.matcher(policy); + policy = matcher.replaceAll(""); + + /* Use a pattern to match all the neverallow rules or a condition. */ + Pattern neverAllowPattern = Pattern.compile( + "(neverallow\\s[^;]+?;|" + patternConditions + ")", + Pattern.MULTILINE); + + List<SELinuxNeverallowRule> rules = new ArrayList(); + Map<String, Integer> conditions = new HashMap(); + + matcher = neverAllowPattern.matcher(policy); + while (matcher.find()) { + String rule = matcher.group(1).replace("\n", " "); + if (rule.startsWith("BEGIN_")) { + String section = rule.substring(6); + conditions.put(section, conditions.getOrDefault(section, 0) + 1); + } else if (rule.startsWith("END_")) { + String section = rule.substring(4); + Integer v = conditions.getOrDefault(section, 0); + assertTrue("Condition " + rule + " found without BEGIN", v > 0); + conditions.put(section, v - 1); + } else if (rule.startsWith("neverallow")) { + rules.add(new SELinuxNeverallowRule(rule, conditions)); + } else { + throw new Exception("Unknown rule: " + rule); + } + } + + for (Map.Entry<String, Integer> condition : conditions.entrySet()) { + if (condition.getValue() != 0) { + throw new Exception("End of input while inside " + condition.getKey() + " section"); + } + } + + return rules; + } + + public void testNeverallowRule(File sepolicyAnalyze, File policyFile) throws Exception { + /* run sepolicy-analyze neverallow check on policy file using given neverallow rules */ + ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(), + policyFile.getAbsolutePath(), "neverallow", "-n", + mText); + pb.redirectOutput(ProcessBuilder.Redirect.PIPE); + pb.redirectErrorStream(true); + Process p = pb.start(); + BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream())); + String line; + StringBuilder errorString = new StringBuilder(); + while ((line = result.readLine()) != null) { + errorString.append(line); + errorString.append("\n"); + } + p.waitFor(); + assertTrue("The following errors were encountered when validating the SELinux" + + "neverallow rule:\n" + mText + "\n" + errorString, + errorString.length() == 0); + } +} diff --git a/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRulesParserTest.java b/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRulesParserTest.java index b7f5aefbcdf..def1f8182f0 100644 --- a/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRulesParserTest.java +++ b/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRulesParserTest.java @@ -19,15 +19,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; -import android.security.cts.SELinuxNeverallowRulesTest.NeverAllowRule; - import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.ArrayList; +import java.util.List; @RunWith(DeviceJUnit4ClassRunner.class) public class SELinuxNeverallowRulesParserTest extends BaseHostJUnit4Test { @@ -35,7 +33,7 @@ public class SELinuxNeverallowRulesParserTest extends BaseHostJUnit4Test { @Test public void testParsingEmpty() throws Exception { String policy = "allow s t:c p;"; - ArrayList<NeverAllowRule> rules = SELinuxNeverallowRulesTest.parsePolicy(policy); + List<SELinuxNeverallowRule> rules = SELinuxNeverallowRule.parsePolicy(policy); assertTrue(rules.isEmpty()); } @@ -44,7 +42,7 @@ public class SELinuxNeverallowRulesParserTest extends BaseHostJUnit4Test { String policy = "# A comment, no big deal\n" + "neverallow d1 d2:c1 p;\n" + "neverallow d2 d3:c2 p2;\n"; - ArrayList<NeverAllowRule> rules = SELinuxNeverallowRulesTest.parsePolicy(policy); + List<SELinuxNeverallowRule> rules = SELinuxNeverallowRule.parsePolicy(policy); assertEquals(2, rules.size()); assertEquals("neverallow d1 d2:c1 p;", rules.get(0).mText); assertEquals(false, rules.get(0).fullTrebleOnly); @@ -62,7 +60,7 @@ public class SELinuxNeverallowRulesParserTest extends BaseHostJUnit4Test { public void testParsingMultiNeverallowOnOneLine() throws Exception { String policy = "# A comment\n" + "neverallow d1 d2:c1 p; neverallow d2 d3:c2 p2;\n"; - ArrayList<NeverAllowRule> rules = SELinuxNeverallowRulesTest.parsePolicy(policy); + List<SELinuxNeverallowRule> rules = SELinuxNeverallowRule.parsePolicy(policy); assertEquals(2, rules.size()); } @@ -76,7 +74,7 @@ public class SELinuxNeverallowRulesParserTest extends BaseHostJUnit4Test { + " p1\n" + " p2\n" + "};\n"; - ArrayList<NeverAllowRule> rules = SELinuxNeverallowRulesTest.parsePolicy(policy); + List<SELinuxNeverallowRule> rules = SELinuxNeverallowRule.parsePolicy(policy); assertEquals(1, rules.size()); assertEquals(rules.get(0).mText, "neverallow d1 { d2 d3 }:file { p1 p2 };"); } @@ -87,7 +85,7 @@ public class SELinuxNeverallowRulesParserTest extends BaseHostJUnit4Test { + "neverallow d1 d2:c1 p;\n" + "# END_TREBLE_ONLY\n" + "neverallow d2 d3:c2 p2;\n"; - ArrayList<NeverAllowRule> rules = SELinuxNeverallowRulesTest.parsePolicy(policy); + List<SELinuxNeverallowRule> rules = SELinuxNeverallowRule.parsePolicy(policy); assertEquals(2, rules.size()); assertEquals(true, rules.get(0).fullTrebleOnly); assertEquals(false, rules.get(1).fullTrebleOnly); @@ -97,6 +95,6 @@ public class SELinuxNeverallowRulesParserTest extends BaseHostJUnit4Test { public void testParsingMissingConditions() throws Exception { String policy = "# BEGIN_LAUNCHING_WITH_S_ONLY\n" + "neverallow d1 d2:c1 p;\n"; - assertThrows(Exception.class, () -> SELinuxNeverallowRulesTest.parsePolicy(policy)); + assertThrows(Exception.class, () -> SELinuxNeverallowRule.parsePolicy(policy)); } } diff --git a/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRulesTest.java b/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRulesTest.java index 6ea35c0a5e7..10da2544e66 100644 --- a/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRulesTest.java +++ b/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRulesTest.java @@ -17,13 +17,12 @@ package android.security.cts; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters; import android.cts.host.utils.DeviceJUnit4Parameterized; import android.platform.test.annotations.RestrictedBuildTest; -import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; -import com.android.compatibility.common.util.PropertyUtil; import com.android.tradefed.build.IBuildInfo; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; @@ -36,18 +35,9 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; import org.junit.runners.Parameterized.UseParametersRunnerFactory; -import java.io.BufferedReader; import java.io.File; -import java.io.InputStreamReader; import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.util.List; /** * Neverallow Rules SELinux tests. @@ -58,7 +48,8 @@ import java.util.stream.Stream; * policy. * * A set of criteria can be used in the platform policy to skip the test - * depending on the device (e.g., launching version). See sConditions below. + * depending on the device (e.g., launching version). See + * SELinuxNeverallowRule.sConditions. * */ @RunWith(DeviceJUnit4Parameterized.class) @@ -77,106 +68,15 @@ public class SELinuxNeverallowRulesTest extends BaseHostJUnit4Test { */ private ITestDevice mDevice; - private static String[] sConditions = { - "TREBLE_ONLY", - "COMPATIBLE_PROPERTY_ONLY", - "LAUNCHING_WITH_R_ONLY", - "LAUNCHING_WITH_S_ONLY", - }; - - protected static class NeverAllowRule { - public String mText; - public boolean fullTrebleOnly; - public boolean launchingWithROnly; - public boolean launchingWithSOnly; - public boolean compatiblePropertyOnly; - - NeverAllowRule(String text, HashMap<String, Integer> conditions) { - mText = text; - if (conditions.getOrDefault("TREBLE_ONLY", 0) > 0) { - fullTrebleOnly = true; - } - if (conditions.getOrDefault("COMPATIBLE_PROPERTY_ONLY", 0) > 0) { - compatiblePropertyOnly = true; - } - if (conditions.getOrDefault("LAUNCHING_WITH_R_ONLY", 0) > 0) { - launchingWithROnly = true; - } - if (conditions.getOrDefault("LAUNCHING_WITH_S_ONLY", 0) > 0) { - launchingWithSOnly = true; - } - } - - public String toString() { - return "Rule [text= " + mText - + ", fullTrebleOnly=" + fullTrebleOnly - + ", compatiblePropertyOnly=" + compatiblePropertyOnly - + ", launchingWithROnly=" + launchingWithROnly - + ", launchingWithSOnly=" + launchingWithSOnly - + "]"; - } - } - - public static ArrayList<NeverAllowRule> parsePolicy(String policy) throws Exception { - String patternConditions = Arrays.stream(sConditions) - .flatMap(condition -> Stream.of("BEGIN_" + condition, "END_" + condition)) - .collect(Collectors.joining("|")); - - /* Uncomment conditions delimiter lines. */ - Pattern uncommentConditions = Pattern.compile("^\\s*#\\s*(" + patternConditions + ")\\s*$", - Pattern.MULTILINE); - Matcher matcher = uncommentConditions.matcher(policy); - policy = matcher.replaceAll("$1"); - - /* Remove all comments. */ - Pattern comments = Pattern.compile("#.*?$", Pattern.MULTILINE); - matcher = comments.matcher(policy); - policy = matcher.replaceAll(""); - - /* Use a pattern to match all the neverallow rules or a condition. */ - Pattern neverAllowPattern = Pattern.compile( - "(neverallow\\s[^;]+?;|" + patternConditions + ")", - Pattern.MULTILINE); - - ArrayList<NeverAllowRule> rules = new ArrayList(); - HashMap<String, Integer> conditions = new HashMap(); - - matcher = neverAllowPattern.matcher(policy); - while (matcher.find()) { - String rule = matcher.group(1).replace("\n", " "); - if (rule.startsWith("BEGIN_")) { - String section = rule.substring(6); - conditions.put(section, conditions.getOrDefault(section, 0) + 1); - } else if (rule.startsWith("END_")) { - String section = rule.substring(4); - Integer v = conditions.getOrDefault(section, 0); - assertTrue("Condition " + rule + " found without BEGIN", v > 0); - conditions.put(section, v - 1); - } else if (rule.startsWith("neverallow")) { - rules.add(new NeverAllowRule(rule, conditions)); - } else { - throw new Exception("Unknown rule: " + rule); - } - } - - for (Map.Entry<String, Integer> condition : conditions.entrySet()) { - if (condition.getValue() != 0) { - throw new Exception("End of input while inside " + condition.getKey() + " section"); - } - } - - return rules; - } - /** * Generate the test parameters based on the embedded policy (general_sepolicy.conf). */ @Parameters - public static Iterable<NeverAllowRule> generateRules() throws Exception { + public static Iterable<SELinuxNeverallowRule> generateRules() throws Exception { File publicPolicy = SELinuxHostTest.copyResourceToTempFile("/general_sepolicy.conf"); String policy = Files.readString(publicPolicy.toPath()); - ArrayList<NeverAllowRule> rules = parsePolicy(policy); + List<SELinuxNeverallowRule> rules = SELinuxNeverallowRule.parsePolicy(policy); assertTrue("No test generated from the CTS-embedded policy", !rules.isEmpty()); return rules; @@ -184,20 +84,23 @@ public class SELinuxNeverallowRulesTest extends BaseHostJUnit4Test { /* Parameter generated by generateRules() and available to testNeverallowRules */ @Parameter - public NeverAllowRule mRule; + public SELinuxNeverallowRule mRule; @Before public void setUp() throws Exception { mDevice = getDevice(); mBuild = getBuild(); - CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild); - sepolicyAnalyze = SELinuxHostTest.copyResourceToTempFile("/sepolicy-analyze"); - sepolicyAnalyze.setExecutable(true); + assumeTrue("skipping not compatible rule", mRule.isCompatible(mDevice)); + + if (sepolicyAnalyze == null) { + sepolicyAnalyze = SELinuxHostTest.copyResourceToTempFile("/sepolicy-analyze"); + sepolicyAnalyze.setExecutable(true); + } devicePolicyFile = SELinuxHostTest.getDevicePolicyFile(mDevice); - if (isSepolicySplit()) { + if (SELinuxHostTest.isSepolicySplit(mDevice)) { deviceSystemPolicyFile = SELinuxHostTest.getDeviceSystemPolicyFile(mDevice); @@ -215,74 +118,22 @@ public class SELinuxNeverallowRulesTest extends BaseHostJUnit4Test { @After public void tearDown() throws Exception { - sepolicyAnalyze.delete(); - } - - private boolean isFullTrebleDevice() throws Exception { - return SELinuxHostTest.isFullTrebleDevice(mDevice); - } - - private boolean isDeviceLaunchingWithR() throws Exception { - return PropertyUtil.getFirstApiLevel(mDevice) > 29; - } - - private boolean isDeviceLaunchingWithS() throws Exception { - return PropertyUtil.getFirstApiLevel(mDevice) > 30; - } - - private boolean isCompatiblePropertyEnforcedDevice() throws Exception { - return SELinuxHostTest.isCompatiblePropertyEnforcedDevice(mDevice); - } - - private boolean isSepolicySplit() throws Exception { - return SELinuxHostTest.isSepolicySplit(mDevice); + if (sepolicyAnalyze != null) { + sepolicyAnalyze.delete(); + sepolicyAnalyze = null; + } } @Test @RestrictedBuildTest public void testNeverallowRules() throws Exception { - - if ((mRule.fullTrebleOnly) && (!isFullTrebleDevice())) { - // This test applies only to Treble devices but this device isn't one - return; - } - if ((mRule.launchingWithROnly) && (!isDeviceLaunchingWithR())) { - // This test applies only to devices launching with R or later but this device isn't one - return; - } - if ((mRule.launchingWithSOnly) && (!isDeviceLaunchingWithS())) { - // This test applies only to devices launching with S or later but this device isn't one - return; - } - if ((mRule.compatiblePropertyOnly) && (!isCompatiblePropertyEnforcedDevice())) { - // This test applies only to devices on which compatible property is enforced but this - // device isn't one - return; - } - // If sepolicy is split and vendor sepolicy version is behind platform's, // only test against platform policy. File policyFile = - (isSepolicySplit() && mVendorSepolicyVersion < mSystemSepolicyVersion) + (SELinuxHostTest.isSepolicySplit(mDevice) + && mVendorSepolicyVersion < mSystemSepolicyVersion) ? deviceSystemPolicyFile : devicePolicyFile; - /* run sepolicy-analyze neverallow check on policy file using given neverallow rules */ - ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(), - policyFile.getAbsolutePath(), "neverallow", "-n", - mRule.mText); - pb.redirectOutput(ProcessBuilder.Redirect.PIPE); - pb.redirectErrorStream(true); - Process p = pb.start(); - BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream())); - String line; - StringBuilder errorString = new StringBuilder(); - while ((line = result.readLine()) != null) { - errorString.append(line); - errorString.append("\n"); - } - p.waitFor(); - assertTrue("The following errors were encountered when validating the SELinux" - + "neverallow rule:\n" + mRule.mText + "\n" + errorString, - errorString.length() == 0); + mRule.testNeverallowRule(sepolicyAnalyze, policyFile); } } diff --git a/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRulesTestVendor.java b/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRulesTestVendor.java new file mode 100644 index 00000000000..7e4ae2ccbf7 --- /dev/null +++ b/hostsidetests/security/src/android/security/cts/SELinuxNeverallowRulesTestVendor.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters; +import android.cts.host.utils.DeviceJUnit4Parameterized; +import android.platform.test.annotations.RestrictedBuildTest; + +import com.android.tradefed.build.IBuildInfo; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.Parameterized.UseParametersRunnerFactory; + +import java.io.File; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import java.util.jar.JarFile; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Neverallow Rules SELinux tests on vendor. + * + * This is a parametrised test. It extracts the neverallow rules from the + * platform policy which is embedded in the CTS distribution. Each rule + * generates its own test to ensure that it is not violated by the device + * policy. + * + * A set of criteria can be used in the platform policy to skip the test + * depending on the device (e.g., launching version). See + * SELinuxNeverallowRule.sConditions. + * + */ +@RunWith(DeviceJUnit4Parameterized.class) +@UseParametersRunnerFactory(DeviceJUnit4ClassRunnerWithParameters.RunnerFactory.class) +public class SELinuxNeverallowRulesTestVendor extends BaseHostJUnit4Test { + private File mSepolicyAnalyze; + private File mDeviceVendorPolicyFile; + + private IBuildInfo mBuild; + private int mVendorSepolicyVersion = -1; + + /** + * A reference to the device under test. + */ + private ITestDevice mDevice; + + private static final Pattern VENDOR_POLICY_PATTERN = Pattern.compile( + "^([0-9]{6})_general_sepolicy.conf$"); + + /** + * Generate the test parameters based on the embedded policy ({ver}_general_sepolicy.conf). + */ + @Parameters(name = "ver={0,number,#};idx={1,number,#}") + public static Iterable<Object[]> generateRules() throws Exception { + List<Object[]> rules = new ArrayList<>(); + JarFile jarFile = new JarFile(SELinuxHostTest.class + .getProtectionDomain() + .getCodeSource() + .getLocation() + .getPath()); + jarFile.stream().forEach(entry -> { + try { + String name = entry.getName(); + Matcher m = VENDOR_POLICY_PATTERN.matcher(name); + if (m.matches()) { + int ver = Integer.parseInt(m.group(1)); + File publicPolicy = SELinuxHostTest.copyResourceToTempFile("/" + name); + String policy = Files.readString(publicPolicy.toPath()); + List<SELinuxNeverallowRule> parsedRules = + SELinuxNeverallowRule.parsePolicy(policy); + + for (int idx = 0; idx < parsedRules.size(); ++idx) { + rules.add(new Object[]{ver, idx, parsedRules.get(idx)}); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + jarFile.close(); + + assertTrue("No test generated from the CTS-embedded policy", !rules.isEmpty()); + return rules; + } + + @Parameter(0) + public int mVersion; + + @Parameter(1) + public int mIndex; + + /* Parameter generated by generateRules() and available to testNeverallowRules */ + @Parameter(2) + public SELinuxNeverallowRule mRule; + + @Before + public void setUp() throws Exception { + mDevice = getDevice(); + mBuild = getBuild(); + + if (mVendorSepolicyVersion == -1) { + mVendorSepolicyVersion = + SELinuxHostTest.getVendorSepolicyVersion(mBuild, mDevice); + } + + assumeTrue("skipping not matching vendor", mVendorSepolicyVersion == mVersion); + assumeTrue("skipping not compatible rule", mRule.isCompatible(mDevice)); + + if (mSepolicyAnalyze == null) { + mSepolicyAnalyze = SELinuxHostTest.copyResourceToTempFile("/sepolicy-analyze"); + mSepolicyAnalyze.setExecutable(true); + } + mDeviceVendorPolicyFile = SELinuxHostTest.getDeviceVendorPolicyFile(mBuild, mDevice); + } + + @After + public void tearDown() throws Exception { + if (mSepolicyAnalyze != null) { + mSepolicyAnalyze.delete(); + mSepolicyAnalyze = null; + } + } + + @Test + @RestrictedBuildTest + public void testNeverallowRules() throws Exception { + mRule.testNeverallowRule(mSepolicyAnalyze, mDeviceVendorPolicyFile); + } +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/poc.c index 67ed5c7fc14..cb4b3c6c9fe 100755 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/poc.c +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/poc.c @@ -17,16 +17,25 @@ #define LOG_TAG "CVE-2017-0386" -#include <sys/wait.h> -#include <sys/types.h> -#include <stdio.h> #include <log/log.h> +#include <netlink/attr.h> #include <netlink/msg.h> #include <netlink/netlink.h> -#include <netlink-private/object-api.h> -#include <netlink-private/types.h> +#include <netlink/object-api.h> #include <netlink/object.h> -#include <netlink/attr.h> +#include <netlink/types.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/wait.h> + +// These are private headers from libnl and make this code fragile. +#if __has_include(<netlink-private/types.h>) +// Old libnl private header. +#include <netlink-private/types.h> +#else +#include <base/nl-base-utils.h> +#include <nl-priv-dynamic-core/nl-core.h> +#endif #include "../includes/common.h" diff --git a/hostsidetests/shortcuts/hostside/AndroidTest.xml b/hostsidetests/shortcuts/hostside/AndroidTest.xml index 36a08763c15..f7d2931b600 100644 --- a/hostsidetests/shortcuts/hostside/AndroidTest.xml +++ b/hostsidetests/shortcuts/hostside/AndroidTest.xml @@ -16,7 +16,7 @@ <configuration description="Config for the CTS ShortcutManager host 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="all_foldable_states" /> + <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" /> <!-- Instant apps can't access ShortcutManager --> <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" /> <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" /> diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/media/MediaCapabilitiesTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/media/MediaCapabilitiesTests.java index 20d7872783c..5490627d5ff 100644 --- a/hostsidetests/statsdatom/src/android/cts/statsdatom/media/MediaCapabilitiesTests.java +++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/media/MediaCapabilitiesTests.java @@ -80,9 +80,9 @@ public class MediaCapabilitiesTests extends DeviceTestCase implements IBuildRece // Setting the values of audio setting via shell commands getDevice().executeShellCommand( - "cmd audio set-surround-format-enabled 7 true"); + "cmd audio set-surround-format-enabled 5 true"); getDevice().executeShellCommand( - "cmd audio set-surround-format-enabled 14 false"); + "cmd audio set-surround-format-enabled 6 false"); getDevice().executeShellCommand("cmd audio set-encoded-surround-mode 2"); RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); @@ -98,10 +98,10 @@ public class MediaCapabilitiesTests extends DeviceTestCase implements IBuildRece .isAtLeast(1); assertEquals(Mediametrics.EncodedSurroundOutputMode.ENCODED_SURROUND_OUTPUT_NEVER, atom.getMediaCapabilities().getSurroundOutputMode()); - assertThat(Mediametrics.AudioEncoding.ENCODING_DTS).isIn( + assertThat(Mediametrics.AudioEncoding.ENCODING_AC3).isIn( atom.getMediaCapabilities() .getUserEnabledSurroundEncodings().getAudioEncodingsList()); - assertThat(Mediametrics.AudioEncoding.ENCODING_DOLBY_TRUEHD).isNotIn( + assertThat(Mediametrics.AudioEncoding.ENCODING_E_AC3).isNotIn( atom.getMediaCapabilities() .getUserEnabledSurroundEncodings().getAudioEncodingsList()); } diff --git a/hostsidetests/videoencodingminimum/src/android/videoqualityfloor/cts/CtsVideoQualityFloorHostTest.java b/hostsidetests/videoencodingminimum/src/android/videoqualityfloor/cts/CtsVideoQualityFloorHostTest.java index 32107f57bae..ded3568ef08 100644 --- a/hostsidetests/videoencodingminimum/src/android/videoqualityfloor/cts/CtsVideoQualityFloorHostTest.java +++ b/hostsidetests/videoencodingminimum/src/android/videoqualityfloor/cts/CtsVideoQualityFloorHostTest.java @@ -21,6 +21,7 @@ import android.cts.host.utils.DeviceJUnit4Parameterized; import android.platform.test.annotations.AppModeFull; import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; +import com.android.ddmlib.testrunner.TestResult.TestStatus; import com.android.tradefed.config.Option; import com.android.tradefed.config.OptionClass; import com.android.tradefed.device.DeviceNotAvailableException; @@ -230,7 +231,8 @@ public class CtsVideoQualityFloorHostTest implements IDeviceTest { JSONArray codecConfigs = obj.getJSONArray("CodecConfigs"); int th = Runtime.getRuntime().availableProcessors() / 2; th = Math.min(Math.max(1, th), 8); - String filter = "libvmaf=feature=name=psnr:model=version=vmaf_v0.6.1:n_threads=" + th; + String filter = "feature=name=psnr:model=version=vmaf_v0.6.1\\\\:enable_transform=true" + + ":n_threads=" + th; for (int i = 0; i < codecConfigs.length(); i++) { JSONObject codecConfig = codecConfigs.getJSONObject(i); String outputName = codecConfig.getString("EncodedFileName"); @@ -240,7 +242,7 @@ public class CtsVideoQualityFloorHostTest implements IDeviceTest { cmd += " -hide_banner"; cmd += " -i " + outDir + "/" + outputName + ".mp4" + " -an"; cmd += " -i " + "samples/" + refFileName + " -an"; - cmd += " -filter_complex " + "\"" + filter + "\""; + cmd += " -lavfi libvmaf=" + "\'" + filter + "\'"; cmd += " -f null -"; cmd += " > " + outputVmafPath + " 2>&1"; LogUtil.CLog.i("ffmpeg command : " + cmd); @@ -346,17 +348,24 @@ public class CtsVideoQualityFloorHostTest implements IDeviceTest { + testRunResult.getName() + ": " + testRunResult.getRunFailureMessage()); } if (testRunResult.getNumTests() != testRunResult.getPassedTests().size()) { - StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n"); for (Map.Entry<TestDescription, TestResult> resultEntry : testRunResult.getTestResults().entrySet()) { - if (!resultEntry.getValue().getStatus() - .equals(com.android.ddmlib.testrunner.TestResult.TestStatus.PASSED)) { + if (resultEntry.getValue().getStatus().equals(TestStatus.FAILURE)) { + StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n"); errorBuilder.append(resultEntry.getKey().toString()); errorBuilder.append(":\n"); errorBuilder.append(resultEntry.getValue().getStackTrace()); + throw new AssertionError(errorBuilder.toString()); + } + if (resultEntry.getValue().getStatus().equals(TestStatus.ASSUMPTION_FAILURE)) { + StringBuilder errorBuilder = + new StringBuilder("On-device tests assumption failed:\n"); + errorBuilder.append(resultEntry.getKey().toString()); + errorBuilder.append(":\n"); + errorBuilder.append(resultEntry.getValue().getStackTrace()); + Assume.assumeTrue(errorBuilder.toString(), false); } } - throw new AssertionError(errorBuilder.toString()); } } } |