diff options
88 files changed, 1344 insertions, 684 deletions
diff --git a/apps/CameraITS/tests/scene2_a/test_autoframing.py b/apps/CameraITS/tests/scene2_d/test_autoframing.py index c048d99fbad..db0fa3ae530 100644 --- a/apps/CameraITS/tests/scene2_a/test_autoframing.py +++ b/apps/CameraITS/tests/scene2_d/test_autoframing.py @@ -27,9 +27,10 @@ import image_processing_utils import its_session_utils import opencv_processing_utils +_AUTOFRAMING_CONVERGED = 2 _CV2_FACE_SCALE_FACTOR = 1.05 # 5% step for resizing image to find face _CV2_FACE_MIN_NEIGHBORS = 4 # recommended 3-6: higher for less faces -_NUM_TEST_FRAMES = 20 +_NUM_TEST_FRAMES = 150 _NUM_FACES = 3 _W, _H = 640, 480 @@ -67,8 +68,7 @@ class AutoframingTest(its_base_test.ItsBaseTest): # zooms into the scene so that none of the faces are in the view # initially - which gives room for autoframing to take place. max_zoom_ratio = camera_properties_utils.get_max_digital_zoom(props) - cam.do_3a(do_af=False, zoom_ratio=max_zoom_ratio) - cam.do_autoframing(zoom_ratio=max_zoom_ratio) + cam.do_3a(zoom_ratio=max_zoom_ratio) req = capture_request_utils.auto_capture_request( do_autoframing=True, zoom_ratio=max_zoom_ratio) @@ -77,16 +77,20 @@ class AutoframingTest(its_base_test.ItsBaseTest): caps = cam.do_capture([req]*_NUM_TEST_FRAMES, fmt) for i, cap in enumerate(caps): faces = cap['metadata']['android.statistics.faces'] + autoframing_state = cap['metadata']['android.control.autoframingState'] + logging.debug('Frame %d faces: %d, autoframingState: %d', i, len(faces), + autoframing_state) + # Face detection and autoframing could take several frames to warm up, - # but should detect the correct number of faces in last frame - if i == _NUM_TEST_FRAMES - 1: + # but should detect the correct number of faces before the last frame + if autoframing_state == _AUTOFRAMING_CONVERGED: num_faces_found = len(faces) if num_faces_found != _NUM_FACES: raise AssertionError('Wrong num of faces found! Found: ' f'{num_faces_found}, expected: {_NUM_FACES}') # Also check the faces with open cv to make sure the scene is not - # distored or anything. + # distorted or anything. img = image_processing_utils.convert_capture_to_rgb_image( cap, props=props) opencv_faces = opencv_processing_utils.find_opencv_faces( @@ -95,10 +99,12 @@ class AutoframingTest(its_base_test.ItsBaseTest): if num_opencv_faces != _NUM_FACES: raise AssertionError('Wrong num of faces found with OpenCV! Found: ' f'{num_opencv_faces}, expected: {_NUM_FACES}') + break + + # Autoframing didn't converge till the last frame + elif i == _NUM_TEST_FRAMES - 1: + raise AssertionError('Autoframing failed to converge') - if not faces: - continue - logging.debug('Frame %d face metadata:', i) logging.debug('Faces: %s', str(faces)) diff --git a/apps/CameraITS/tests/scene6/test_zoom.py b/apps/CameraITS/tests/scene6/test_zoom.py index 2e34320bc5f..c451575fd55 100644 --- a/apps/CameraITS/tests/scene6/test_zoom.py +++ b/apps/CameraITS/tests/scene6/test_zoom.py @@ -112,6 +112,7 @@ class ZoomTest(its_base_test.ItsBaseTest): logging.debug('testing %s format', fmt) test_data = {} for i, z in enumerate(z_list): + logging.debug('zoom ratio: %.3f', z) req['android.control.zoomRatio'] = z cam.do_3a(zoom_ratio=z) cap = cam.do_capture( @@ -124,7 +125,10 @@ class ZoomTest(its_base_test.ItsBaseTest): # determine radius tolerance of capture cap_fl = cap['metadata']['android.lens.focalLength'] - radius_tol, offset_tol = test_tols[cap_fl] + radius_tol, offset_tol = test_tols.get( + cap_fl, + (zoom_capture_utils.RADIUS_RTOL, zoom_capture_utils.OFFSET_RTOL) + ) # Find the center circle in img circle = zoom_capture_utils.get_center_circle(img, img_name, size, z, diff --git a/apps/CameraITS/tests/scene_extensions/scene_hdr/test_hdr_extension.py b/apps/CameraITS/tests/scene_extensions/scene_hdr/test_hdr_extension.py index a481a10edc5..9710a275052 100644 --- a/apps/CameraITS/tests/scene_extensions/scene_hdr/test_hdr_extension.py +++ b/apps/CameraITS/tests/scene_extensions/scene_hdr/test_hdr_extension.py @@ -209,7 +209,8 @@ class HdrExtensionTest(its_base_test.ItsBaseTest): capture_request_utils.auto_capture_request(), cam.CAP_YUV) y_plane, _, _ = image_processing_utils.convert_capture_to_planes(cap) its_session_utils.validate_lighting( - y_plane, self.scene, state='OFF', log_path=self.log_path) + y_plane, self.scene, state='OFF', log_path=self.log_path, + tablet_state='OFF') self.setup_tablet() self.set_screen_brightness(_TABLET_BRIGHTNESS) diff --git a/apps/CameraITS/tests/scene_extensions/scene_night/test_night_extension.py b/apps/CameraITS/tests/scene_extensions/scene_night/test_night_extension.py index eba69295fb9..376b47b89f3 100644 --- a/apps/CameraITS/tests/scene_extensions/scene_night/test_night_extension.py +++ b/apps/CameraITS/tests/scene_extensions/scene_night/test_night_extension.py @@ -263,7 +263,8 @@ class NightExtensionTest(its_base_test.ItsBaseTest): capture_request_utils.auto_capture_request(), cam.CAP_YUV) y_plane, _, _ = image_processing_utils.convert_capture_to_planes(cap) its_session_utils.validate_lighting( - y_plane, self.scene, state='OFF', log_path=self.log_path) + y_plane, self.scene, state='OFF', log_path=self.log_path, + tablet_state='OFF') self.setup_tablet() its_session_utils.load_scene( diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py index b55e61d117d..0df3fd0d701 100755 --- a/apps/CameraITS/tools/run_all_tests.py +++ b/apps/CameraITS/tools/run_all_tests.py @@ -89,6 +89,12 @@ _GROUPED_SCENES = { 'scene2_f'] } +# Scene extensions +_EXTENSIONS_SCENES = ( + os.path.join('scene_extensions', 'scene_hdr'), + os.path.join('scene_extensions', 'scene_night'), +) + # Scenes that have to be run manually regardless of configuration _MANUAL_SCENES = ['scene5'] @@ -642,6 +648,13 @@ def main(): if (not s.startswith('scene') and not s.startswith(('sensor_fusion', '<scene-name>'))): scenes[i] = f'scene{s}' + # Handle scene_extensions + if s.startswith('extensions'): + scenes[i] = f'scene_{s}' + if s.startswith('hdr') or s.startswith('night'): + scenes[i] = f'scene_extensions/scene_{s}' + if s.startswith('scene_hdr') or s.startswith('scene_night'): + scenes[i] = f'scene_extensions/{s}' # Expand GROUPED_SCENES and remove any duplicates scenes = [_GROUPED_SCENES[s] if s in _GROUPED_SCENES else s for s in scenes] @@ -714,9 +727,12 @@ def main(): if auto_scene_switch: possible_scenes.remove('sensor_fusion') else: - possible_scenes = _AUTO_SCENES if auto_scene_switch else _ALL_SCENES + if 'scene_extensions' in scenes: + possible_scenes = _EXTENSIONS_SCENES + else: + possible_scenes = _AUTO_SCENES if auto_scene_switch else _ALL_SCENES - if '<scene-name>' in scenes: + if '<scene-name>' in scenes or 'scene_extensions' in scenes: per_camera_scenes = possible_scenes else: # Validate user input scene names diff --git a/apps/CameraITS/utils/its_session_utils.py b/apps/CameraITS/utils/its_session_utils.py index 0ccbcdbf31d..af76b75e31a 100644 --- a/apps/CameraITS/utils/its_session_utils.py +++ b/apps/CameraITS/utils/its_session_utils.py @@ -60,6 +60,7 @@ _VALIDATE_LIGHTING_REGIONS = { 1-_VALIDATE_LIGHTING_PATCH_H), } _VALIDATE_LIGHTING_THRESH = 0.05 # Determined empirically from scene[1:6] tests +_VALIDATE_LIGHTING_THRESH_DARK = 0.15 # Determined empirically for night test _CMD_NAME_STR = 'cmdName' _OBJ_VALUE_STR = 'objValue' _STR_VALUE = 'strValue' @@ -1624,34 +1625,6 @@ class ItsSession(object): raise error_util.CameraItsError('3A failed to converge') return ae_sens, ae_exp, awb_gains, awb_transform, af_dist - def do_autoframing(self, zoom_ratio=None): - """Perform autoframing on the device. - - Args: - zoom_ratio: Zoom ratio. None if default zoom. - """ - cmd = {} - cmd[_CMD_NAME_STR] = 'doAutoframing' - if zoom_ratio: - if self.zoom_ratio_within_range(zoom_ratio): - cmd['zoomRatio'] = zoom_ratio - else: - raise AssertionError(f'Zoom ratio {zoom_ratio} out of range') - converged = False - self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) - - while True: - data, _ = self.__read_response_from_socket() - if data[_TAG_STR] == 'autoframingConverged': - converged = True - elif data[_TAG_STR] == 'autoframingDone': - break - else: - raise error_util.CameraItsError('Invalid command response') - - if not converged: - raise error_util.CameraItsError('Autoframing failed to converge') - def calc_camera_fov(self, props): """Determine the camera field of view from internal params. @@ -2011,7 +1984,8 @@ def load_scene(cam, props, scene, tablet, chart_distance, lighting_check=True, validate_lighting(y_plane, scene, log_path=log_path) -def validate_lighting(y_plane, scene, state='ON', log_path=None): +def validate_lighting(y_plane, scene, state='ON', log_path=None, + tablet_state='ON'): """Validates the lighting level in scene corners based on empirical values. Args: @@ -2019,6 +1993,7 @@ def validate_lighting(y_plane, scene, state='ON', log_path=None): scene: scene name state: string 'ON' or 'OFF' log_path: [Optional] path to store artifacts + tablet_state: string 'ON' or 'OFF' Returns: boolean True if lighting validated, else raise AssertionError @@ -2028,6 +2003,11 @@ def validate_lighting(y_plane, scene, state='ON', log_path=None): if log_path: file_name = os.path.join(log_path, f'validate_lighting_{scene}.jpg') + if tablet_state == 'OFF': + validate_lighting_thresh = _VALIDATE_LIGHTING_THRESH_DARK + else: + validate_lighting_thresh = _VALIDATE_LIGHTING_THRESH + # Test patches from each corner. for location, coordinates in _VALIDATE_LIGHTING_REGIONS.items(): patch = image_processing_utils.get_image_patch( @@ -2036,14 +2016,14 @@ def validate_lighting(y_plane, scene, state='ON', log_path=None): y_mean = image_processing_utils.compute_image_means(patch)[0] logging.debug('%s corner Y mean: %.3f', location, y_mean) if state == 'ON': - if y_mean > _VALIDATE_LIGHTING_THRESH: + if y_mean > validate_lighting_thresh: logging.debug('Lights ON in test rig.') return True else: image_processing_utils.write_image(y_plane, file_name) raise AssertionError('Lights OFF in test rig. Turn ON and retry.') elif state == 'OFF': - if y_mean < _VALIDATE_LIGHTING_THRESH: + if y_mean < validate_lighting_thresh: logging.debug('Lights OFF in test rig.') return True else: diff --git a/apps/CameraITS/utils/opencv_processing_utils.py b/apps/CameraITS/utils/opencv_processing_utils.py index bd9b8a8431c..63ca2af10bc 100644 --- a/apps/CameraITS/utils/opencv_processing_utils.py +++ b/apps/CameraITS/utils/opencv_processing_utils.py @@ -640,6 +640,8 @@ def find_center_circle(img, img_name, color, circle_ar_rtol, circlish_rtol, # check contours and find the best circle candidates circles = [] img_ctr = [gray.shape[1] // 2, gray.shape[0] // 2] + logging.debug('img center x,y: %d, %d', img_ctr[0], img_ctr[1]) + logging.debug('min area: %d, min circle pts: %d', min_area, min_circle_pts) for contour in contours: area = cv2.contourArea(contour) if area > min_area and len(contour) >= min_circle_pts: @@ -656,6 +658,8 @@ def find_center_circle(img, img_name, color, circle_ar_rtol, circlish_rtol, if not circles: raise AssertionError('No circle was detected. Please take pictures ' 'according to instructions carefully!') + else: + logging.debug('num of circles found: %s', len(circles)) if debug: logging.debug('circles [x, y, r, pi*r**2/area, area]: %s', str(circles)) diff --git a/apps/CameraITS/utils/zoom_capture_utils.py b/apps/CameraITS/utils/zoom_capture_utils.py index b6ff3ca61db..1d6ddd48bf7 100644 --- a/apps/CameraITS/utils/zoom_capture_utils.py +++ b/apps/CameraITS/utils/zoom_capture_utils.py @@ -114,11 +114,18 @@ def get_center_circle(img, img_name, size, zoom_ratio, min_zoom_ratio, debug): # convert [0, 1] image to [0, 255] and cast as uint8 imgc = image_processing_utils.convert_image_to_uint8(imgc) + # Scale circlish RTOL for low zoom ratios + if zoom_ratio < 1: + circlish_rtol = _CIRCLISH_RTOL / zoom_ratio + else: + circlish_rtol = _CIRCLISH_RTOL + logging.debug('circlish_rtol: %.3f', circlish_rtol) + # Find the center circle in img try: circle = opencv_processing_utils.find_center_circle( imgc, img_name, _CIRCLE_COLOR, circle_ar_rtol=_CIRCLE_AR_RTOL, - circlish_rtol=_CIRCLISH_RTOL, + circlish_rtol=circlish_rtol, min_area=_MIN_AREA_RATIO * size[0] * size[1] * zoom_ratio * zoom_ratio, min_circle_pts=_MIN_CIRCLE_PTS, debug=debug) if opencv_processing_utils.is_circle_cropped(circle, size): diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java index 17485e1ac83..0f6d391473b 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java @@ -160,7 +160,9 @@ public class AnalogHeadsetAudioActivity mHeadsetVolUpText = (TextView)findViewById(R.id.headset_keycode_volume_up); mHeadsetVolDownText = (TextView)findViewById(R.id.headset_keycode_volume_down); - if (isTelevision()) { + mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); + + if (isTelevisionOrFixedVolume()) { mButtonsPromptTxt.setVisibility(View.GONE); mHeadsetHookText.setVisibility(View.GONE); mHeadsetVolUpText.setVisibility(View.GONE); @@ -170,8 +172,6 @@ public class AnalogHeadsetAudioActivity mResultsTxt = (TextView)findViewById(R.id.headset_results); - mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE); - setupPlayer(); mAudioManager.registerAudioDeviceCallback(new ConnectListener(), new Handler()); @@ -183,7 +183,7 @@ public class AnalogHeadsetAudioActivity showKeyMessagesState(); - setInfoResources(R.string.analog_headset_test, isTelevision() + setInfoResources(R.string.analog_headset_test, isTelevisionOrFixedVolume() ? R.string.analog_headset_test_info_tv : R.string.analog_headset_test_info, -1); setPassFailButtonClickListeners(); @@ -219,7 +219,7 @@ public class AnalogHeadsetAudioActivity mPlugIntentReceived && mHeadsetDeviceInfo != null && mPlaybackSuccess && - (isTelevision() + (isTelevisionOrFixedVolume() || ((mHasHeadsetHook || mHasPlayPause) && mHasVolUp && mHasVolDown)); if (pass) { mResultsTxt.setText(getResources().getString(R.string.analog_headset_pass)); @@ -560,7 +560,8 @@ public class AnalogHeadsetAudioActivity return super.onKeyDown(keyCode, event); } - private boolean isTelevision() { - return getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); + private boolean isTelevisionOrFixedVolume() { + return getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK) + || mAudioManager.isVolumeFixed(); } } 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 3eeadac3873..0d0d423baa7 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 @@ -101,7 +101,6 @@ import com.android.compatibility.common.util.ReportLog.Metric; import com.android.cts.verifier.R; import com.android.cts.verifier.camera.performance.CameraTestInstrumentation; import com.android.cts.verifier.camera.performance.CameraTestInstrumentation.MetricListener; -import com.android.ex.camera2.blocking.BlockingCameraManager; import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException; import com.android.ex.camera2.blocking.BlockingExtensionSessionCallback; import com.android.ex.camera2.blocking.BlockingSessionCallback; @@ -906,8 +905,6 @@ public class ItsService extends Service implements SensorEventListener { doGetSensorEvents(); } else if ("do3A".equals(cmdObj.getString("cmdName"))) { do3A(cmdObj); - } else if ("doAutoframing".equals(cmdObj.getString("cmdName"))) { - doAutoframing(cmdObj); } else if ("doCapture".equals(cmdObj.getString("cmdName"))) { doCapture(cmdObj); } else if ("doVibrate".equals(cmdObj.getString("cmdName"))) { @@ -2021,87 +2018,6 @@ public class ItsService extends Service implements SensorEventListener { } } - private void doAutoframing(JSONObject params) throws ItsException { - AutoframingResultListener autoframingListener = new AutoframingResultListener(); - try { - CameraCharacteristics c = mCameraCharacteristics; - Size[] sizes = ItsUtils.getYuvOutputSizes(c); - int[] outputFormats = new int[1]; - outputFormats[0] = ImageFormat.YUV_420_888; - Size[] outputSizes = new Size[1]; - outputSizes[0] = sizes[0]; - int width = outputSizes[0].getWidth(); - int height = outputSizes[0].getHeight(); - - prepareImageReaders(outputSizes, outputFormats, /*inputSize*/null, /*inputFormat*/0, - /*maxInputBuffers*/0); - - List<OutputConfiguration> outputConfigs = new ArrayList<OutputConfiguration>(1); - OutputConfiguration config = - new OutputConfiguration(mOutputImageReaders[0].getSurface()); - outputConfigs.add(config); - BlockingSessionCallback sessionListener = new BlockingSessionCallback(); - mCamera.createCaptureSessionByOutputConfigurations( - outputConfigs, sessionListener, mCameraHandler); - mSession = sessionListener.waitAndGetSession(TIMEOUT_IDLE_MS); - - // Add a listener that just recycles buffers; they aren't saved anywhere. - ImageReader.OnImageAvailableListener readerListener = - createAvailableListenerDropper(); - mOutputImageReaders[0].setOnImageAvailableListener(readerListener, mSaveHandlers[0]); - - double zoomRatio = params.optDouble(ZOOM_RATIO_KEY); - - mInterlockAutoframing.open(); - synchronized (mAutoframingStateLock) { - mConvergedAutoframing = false; - } - - long tstart = System.currentTimeMillis(); - - // Keep issuing capture requests until autoframing has converged. - while (true) { - // Block until the next autoframing frame. - if (!mInterlockAutoframing.block(TIMEOUT_AUTOFRAMING * 1000) - || System.currentTimeMillis() - tstart > TIMEOUT_AUTOFRAMING * 1000) { - throw new ItsException( - "Autoframing failed to converge after " + TIMEOUT_AUTOFRAMING - + " seconds.\n" - + "Autoframing converge state: " + mConvergedAutoframing + "."); - } - mInterlockAutoframing.close(); - - synchronized (mAutoframingStateLock) { - if (!mConvergedAutoframing) { - CaptureRequest.Builder req = mCamera.createCaptureRequest( - CameraDevice.TEMPLATE_PREVIEW); - req.set(CaptureRequest.CONTROL_AUTOFRAMING, - CaptureRequest.CONTROL_AUTOFRAMING_ON); - if (!Double.isNaN(zoomRatio)) { - req.set(CaptureRequest.CONTROL_ZOOM_RATIO, (float) zoomRatio); - } - req.addTarget(mOutputImageReaders[0].getSurface()); - - mSession.setRepeatingRequest(req.build(), autoframingListener, - mResultHandler); - } else { - mSocketRunnableObj.sendResponse("autoframingConverged", ""); - Logt.i(TAG, "Autoframing converged"); - break; - } - } - } - } catch (android.hardware.camera2.CameraAccessException e) { - throw new ItsException("Access error: ", e); - } finally { - mSocketRunnableObj.sendResponse("autoframingDone", ""); - autoframingListener.stop(); - if (mSession != null) { - mSession.close(); - } - } - } - private void doVibrate(JSONObject params) throws ItsException { try { if (mVibrator == null) { diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/EnsureHasNoAccounts.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/EnsureHasNoAccounts.java index 49889940770..c420c4a4f6f 100644 --- a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/EnsureHasNoAccounts.java +++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/EnsureHasNoAccounts.java @@ -39,6 +39,14 @@ public @interface EnsureHasNoAccounts { /** Which user type the account must not be present added on. */ UserType onUser() default ANY; + /** Exclude pre created accounts. */ + boolean allowPreCreatedAccounts() default true; + + /** Behaviour if there are some accounts for the user. */ + com.android.bedstead.harrier.annotations.FailureMode failureMode() + default com.android.bedstead.harrier.annotations.FailureMode.SKIP; + + /** * Weight sets the order that annotations will be resolved. * diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java index 87df143fe33..ddfc0cd303c 100644 --- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java +++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java @@ -44,6 +44,7 @@ import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import android.app.ActivityManager; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -1261,7 +1262,9 @@ public final class DeviceState extends HarrierRule { if (annotation instanceof EnsureHasNoAccounts) { EnsureHasNoAccounts ensureHasNoAccountsAnnotation = (EnsureHasNoAccounts) annotation; - ensureHasNoAccounts(ensureHasNoAccountsAnnotation.onUser()); + ensureHasNoAccounts(ensureHasNoAccountsAnnotation.onUser(), + ensureHasNoAccountsAnnotation.allowPreCreatedAccounts(), + ensureHasNoAccountsAnnotation.failureMode()); continue; } @@ -2835,7 +2838,8 @@ public final class DeviceState extends HarrierRule { ensureCanGetPermission(INTERACT_ACROSS_USERS_FULL); } - ensureHasNoAccounts(UserType.ANY); + ensureHasNoAccounts(UserType.ANY, /* allowPreCreatedAccounts= */ true, + FailureMode.FAIL); ensureTestAppInstalled(RemoteDevicePolicyManagerRoleHolder.sTestApp, user); TestApis.devicePolicy().setDevicePolicyManagementRoleHolder( RemoteDevicePolicyManagerRoleHolder.sTestApp.pkg(), user); @@ -3135,10 +3139,12 @@ public final class DeviceState extends HarrierRule { } if (Versions.meetsMinimumSdkVersionRequirement(Versions.U)) { - ensureHasNoAccounts(UserType.ANY); + ensureHasNoAccounts(UserType.ANY, /* allowPreCreatedAccounts= */ true, + FailureMode.FAIL); } else { // Prior to U this only checked the system user - ensureHasNoAccounts(UserType.SYSTEM_USER); + ensureHasNoAccounts(UserType.SYSTEM_USER, /* allowPreCreatedAccounts= */ true, + FailureMode.FAIL); } ensureHasNoProfileOwner(userReference); @@ -3252,7 +3258,8 @@ public final class DeviceState extends HarrierRule { mChangedProfileOwners.put(user, currentProfileOwner); } - ensureHasNoAccounts(user); + ensureHasNoAccounts(user, /* allowPreCreatedAccounts= */ true, + FailureMode.FAIL); if (resolvedDpcTestApp != null) { mProfileOwners.put(user, @@ -3265,10 +3272,12 @@ public final class DeviceState extends HarrierRule { } if (Versions.meetsMinimumSdkVersionRequirement(Versions.U)) { - ensureHasNoAccounts(user); + ensureHasNoAccounts(user, /* allowPreCreatedAccounts= */ true, + FailureMode.FAIL); } else { // Prior to U this incorrectly checked the system user - ensureHasNoAccounts(UserType.SYSTEM_USER); + ensureHasNoAccounts(UserType.SYSTEM_USER, /* allowPreCreatedAccounts= */ true, + FailureMode.FAIL); } if (isPrimary) { @@ -4045,15 +4054,19 @@ public final class DeviceState extends HarrierRule { } } - private void ensureHasNoAccounts(UserType userType) { + private void ensureHasNoAccounts(UserType userType, boolean allowPreCreatedAccounts, + FailureMode failureMode) { if (userType == UserType.ANY) { - TestApis.users().all().forEach(this::ensureHasNoAccounts); + TestApis.users().all().forEach(user -> ensureHasNoAccounts(user, + allowPreCreatedAccounts, failureMode)); } else { - ensureHasNoAccounts(resolveUserTypeToUser(userType)); + ensureHasNoAccounts(resolveUserTypeToUser(userType), + allowPreCreatedAccounts, failureMode); } } - private void ensureHasNoAccounts(UserReference user) { + private void ensureHasNoAccounts(UserReference user, boolean allowPreCreatedAccounts, + FailureMode failureMode) { if (REMOTE_ACCOUNT_AUTHENTICATOR_TEST_APP.pkg().installedOnUser(user)) { user.start(); // The user has to be started to remove accounts @@ -4061,9 +4074,25 @@ public final class DeviceState extends HarrierRule { .forEach(AccountReference::remove); } - if (!TestApis.accounts().all(user).isEmpty()) { - throw new NeneException("Expected no accounts on user " + user - + " but there was some that could not be removed"); + Set<AccountReference> accounts = TestApis.accounts().all(user); + + // If allowPreCreatedAccounts is enabled, that means it's okay to have + // pre created accounts on the device. + // Now to EnsureHasNoAccounts we will only check that there are no non-pre created accounts. + // Non pre created accounts either have ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED + // or do not have ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED + if (allowPreCreatedAccounts) { + accounts = accounts.stream() + .filter(accountReference -> !accountReference.hasFeature( + DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED) + || accountReference.hasFeature( + DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED)) + .collect(Collectors.toSet()); + } + + if (!accounts.isEmpty()) { + failOrSkip("Expected no user created accounts on user " + user + + " but there was some that could not be removed.", failureMode); } TestApis.devicePolicy().calculateHasIncompatibleAccounts(); diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java index af59d7f552d..3722dd2867b 100644 --- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java +++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java @@ -51,6 +51,7 @@ public class AppDataIsolationTests extends BaseAppSecurityTest { private static final String APPA_CLASS = "com.android.cts.appdataisolation.appa.AppATests"; private static final String APPA_METHOD_CREATE_CE_DE_DATA = "testCreateCeDeAppData"; + private static final String APPA_METHOD_DELETE_EXTERNAL_DIRS = "testDeleteExternalDirs"; private static final String APPA_METHOD_CHECK_CE_DATA_EXISTS = "testAppACeDataExists"; private static final String APPA_METHOD_CHECK_CE_DATA_DOES_NOT_EXIST = "testAppACeDataDoesNotExist"; @@ -248,6 +249,10 @@ public class AppDataIsolationTests extends BaseAppSecurityTest { try { runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_TEST_UNLOCK_DEVICE); } catch (Exception e) {} + try { + runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_DELETE_EXTERNAL_DIRS); + } catch (Exception e) {} + getDevice().executeShellCommand("locksettings clear --old 1234"); getDevice().executeShellCommand("locksettings set-disabled true"); } finally { diff --git a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java index fbc0860c214..904842815f0 100644 --- a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java +++ b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java @@ -28,6 +28,7 @@ import static com.android.cts.appdataisolation.common.FileUtils.assertDirIsAcces import static com.android.cts.appdataisolation.common.FileUtils.assertDirIsNotAccessible; import static com.android.cts.appdataisolation.common.FileUtils.assertFileDoesNotExist; import static com.android.cts.appdataisolation.common.FileUtils.assertFileExists; +import static com.android.cts.appdataisolation.common.FileUtils.deleteFile; import static com.android.cts.appdataisolation.common.FileUtils.touchFile; import static com.android.cts.appdataisolation.common.UserUtils.getCurrentUserId; @@ -45,6 +46,7 @@ import android.content.pm.ApplicationInfo; import android.os.Build; import android.os.Bundle; import android.os.IBinder; +import android.os.SystemClock; import android.os.SystemProperties; import android.support.test.uiautomator.UiDevice; import android.view.KeyEvent; @@ -69,6 +71,7 @@ import java.util.concurrent.TimeUnit; public class AppATests { private static final long BIND_SERVICE_TIMEOUT_MS = 5000; + private static final int MAX_VOLD_QUERY_RETRIES = 20; private Context mContext; private UiDevice mDevice; @@ -111,7 +114,7 @@ public class AppATests { private void setUpExternalStoragePaths() { File externalFilesDir = mContext.getExternalFilesDir(""); if (externalFilesDir != null) { - mExternalDataPath = mContext.getExternalFilesDir("").getAbsolutePath(); + mExternalDataPath = externalFilesDir.getAbsolutePath(); } File obbDir = mContext.getObbDir(); if (obbDir != null) { @@ -148,6 +151,15 @@ public class AppATests { } @Test + public void testDeleteExternalDirs() throws Exception { + deleteFile(mExternalDataPath, EXTERNAL_DATA_FILE_NAME); + deleteFile(mObbPath, OBB_FILE_NAME); + + assertFileDoesNotExist(mExternalDataPath, EXTERNAL_DATA_FILE_NAME); + assertFileDoesNotExist(mObbPath, OBB_FILE_NAME); + } + + @Test public void testAppACeDataExists() { assertFileExists(mCePath, CE_DATA_FILE_NAME); } @@ -263,7 +275,16 @@ public class AppATests { assertTrue("User not unlocked", unlocked.await(1, TimeUnit.MINUTES)); assertTrue("No locked boot complete", bootCompleted.await(2, TimeUnit.MINUTES)); - setUpExternalStoragePaths(); + // TODO(b/302586971): Remove this when the vold resets are resolved. + // vold can reset on an HSUM configuration during the user unlock flow; wait until valid + // values are returned for the external and obb directories before continuing with the test. + int numRetries = 0; + do { + numRetries++; + SystemClock.sleep(3000); + setUpExternalStoragePaths(); + } while ((mExternalDataPath == null || mObbPath == null) + && numRetries <= MAX_VOLD_QUERY_RETRIES); // The test app process should be still running, make sure CE DE now is available testAppACeDataExists(); diff --git a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/common/src/com/android/cts/appdataisolation/common/FileUtils.java b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/common/src/com/android/cts/appdataisolation/common/FileUtils.java index 15450f934d8..bda7f239b0c 100644 --- a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/common/src/com/android/cts/appdataisolation/common/FileUtils.java +++ b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/common/src/com/android/cts/appdataisolation/common/FileUtils.java @@ -130,6 +130,11 @@ public class FileUtils { file.createNewFile(); } + public static void deleteFile(String path, String name) throws IOException { + File file = new File(path, name); + file.delete(); + } + public static String replacePackageAWithPackageB(String path) { return path.replace(APPA_PKG, APPB_PKG); } diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp index b73b888b697..fa396ae1de0 100644 --- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp +++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp @@ -36,6 +36,7 @@ android_test_helper_app { "ShortcutManagerTestUtils", "MetricsRecorder", "statsdprotolite", + "cts-keystore-test-util", ], resource_dirs: ["res"], asset_dirs: ["assets"], @@ -70,6 +71,7 @@ android_test_helper_app { "ShortcutManagerTestUtils", "MetricsRecorder", "statsdprotolite", + "cts-keystore-test-util", ], resource_dirs: ["res"], asset_dirs: ["assets"], @@ -103,6 +105,7 @@ android_test_helper_app { "ShortcutManagerTestUtils", "MetricsRecorder", "statsdprotolite", + "cts-keystore-test-util", ], resource_dirs: ["res"], asset_dirs: ["assets"], @@ -140,6 +143,7 @@ android_test_helper_app { "ShortcutManagerTestUtils", "MetricsRecorder", "statsdprotolite", + "cts-keystore-test-util", ], resource_dirs: ["res"], asset_dirs: ["assets"], diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java index 8c08811ef4c..2d361b26b06 100755 --- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java +++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java @@ -33,6 +33,7 @@ import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.keystore.cts.Attestation; import android.keystore.cts.AuthorizationList; +import android.keystore.cts.util.TestUtils; import android.net.Uri; import android.os.Build; import android.os.Process; @@ -293,11 +294,26 @@ public class KeyManagementTest extends BaseDeviceAdminTest { Attestation attestationRecord = Attestation.loadFromCertificate((X509Certificate) leaf); AuthorizationList teeAttestation = attestationRecord.getTeeEnforced(); assertThat(teeAttestation).isNotNull(); - assertThat(teeAttestation.getBrand()).isEqualTo(Build.BRAND); - assertThat(teeAttestation.getDevice()).isEqualTo(Build.DEVICE); - assertThat(teeAttestation.getProduct()).isEqualTo(Build.PRODUCT); - assertThat(teeAttestation.getManufacturer()).isEqualTo(Build.MANUFACTURER); - assertThat(teeAttestation.getModel()).isEqualTo(Build.MODEL); + final String platformReportedBrand = + TestUtils.isPropertyEmptyOrUnknown(Build.BRAND_FOR_ATTESTATION) + ? Build.BRAND : Build.BRAND_FOR_ATTESTATION; + assertThat(teeAttestation.getBrand()).isEqualTo(platformReportedBrand); + final String platformReportedDevice = + TestUtils.isPropertyEmptyOrUnknown(Build.DEVICE_FOR_ATTESTATION) + ? Build.DEVICE : Build.DEVICE_FOR_ATTESTATION; + assertThat(teeAttestation.getDevice()).isEqualTo(platformReportedDevice); + final String platformReportedProduct = + TestUtils.isPropertyEmptyOrUnknown(Build.PRODUCT_FOR_ATTESTATION) + ? Build.PRODUCT : Build.PRODUCT_FOR_ATTESTATION; + assertThat(teeAttestation.getProduct()).isEqualTo(platformReportedProduct); + final String platformReportedManufacturer = + TestUtils.isPropertyEmptyOrUnknown(Build.MANUFACTURER_FOR_ATTESTATION) + ? Build.MANUFACTURER : Build.MANUFACTURER_FOR_ATTESTATION; + assertThat(teeAttestation.getManufacturer()).isEqualTo(platformReportedManufacturer); + final String platformReportedModel = + TestUtils.isPropertyEmptyOrUnknown(Build.MODEL_FOR_ATTESTATION) + ? Build.MODEL : Build.MODEL_FOR_ATTESTATION; + assertThat(teeAttestation.getModel()).isEqualTo(platformReportedModel); assertThat(teeAttestation.getSerialNumber()).isEqualTo(expectedSerial); assertThat(teeAttestation.getImei()).isEqualTo(expectedImei); assertThat(teeAttestation.getMeid()).isEqualTo(expectedMeid); diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java index 5799abd579a..bc40dbd3afd 100644 --- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java +++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java @@ -529,6 +529,7 @@ public final class ManagedProfileTest extends BaseManagedProfileTest { installAppAsUser(SHARING_APP_2_APK, mPrimaryUserId); installAppAsUser(SHARING_APP_1_APK, mProfileUserId); installAppAsUser(SHARING_APP_2_APK, mProfileUserId); + RunUtil.getDefault().sleep(3000); try { runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileSharingTest", "addCrossProfileIntents", mProfileUserId); diff --git a/hostsidetests/multiuser/app/src/com/android/cts/multiuser/AccountCreator.java b/hostsidetests/multiuser/app/src/com/android/cts/multiuser/AccountCreator.java index 408eb5733fa..63fc6bf6199 100644 --- a/hostsidetests/multiuser/app/src/com/android/cts/multiuser/AccountCreator.java +++ b/hostsidetests/multiuser/app/src/com/android/cts/multiuser/AccountCreator.java @@ -31,10 +31,18 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + @RunWith(JUnit4.class) public class AccountCreator { private static final String TAG = "MultiuserAccountCreator"; + private static final int ACCOUNT_AUTHENTICATOR_TIMEOUT_MILLISECONDS = 180000; // 180 seconds + + private static final int ACCOUNT_AUTHENTICATOR_WAIT_TIME_MILLISECONDS = 5000; // 5 seconds + private Context mContext; @Before @@ -48,6 +56,9 @@ public class AccountCreator { final AccountManager accountManager = mContext.getSystemService(AccountManager.class); Log.i(TAG, "Adding account"); + + waitForAccountAuthenticator(MockAuthenticator.ACCOUNT_TYPE, accountManager); + final AccountManagerFuture<Bundle> future = accountManager.addAccount( MockAuthenticator.ACCOUNT_TYPE, null, null, null, null, null, null); @@ -65,4 +76,33 @@ public class AccountCreator { Log.i(TAG, "Successfully added account; all is good"); } + + + private void waitForAccountAuthenticator(String accountType, AccountManager am) { + long startTime = System.currentTimeMillis(); + + while (System.currentTimeMillis() - startTime < ACCOUNT_AUTHENTICATOR_TIMEOUT_MILLISECONDS + && !accountAuthenticatorExists(accountType, am)) { + Log.w(TAG, "Account authenticator not found for accountType: " + accountType); + sleep(ACCOUNT_AUTHENTICATOR_WAIT_TIME_MILLISECONDS); + } + + Log.i(TAG, "Account authenticator found for accountType: " + accountType); + } + + + private boolean accountAuthenticatorExists(String accountType, AccountManager am) { + + Set<String> authenticatorTypes = Arrays.stream(am.getAuthenticatorTypes()) + .map(authenticatorDescription -> authenticatorDescription.type) + .collect(Collectors.toSet()); + + return authenticatorTypes.contains(accountType); + } + + private void sleep(int timeout) { + try { + Thread.sleep(timeout); + } catch (InterruptedException ex) { } + } } diff --git a/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/PackageInstallationSessionReportedStatsTests.java b/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/PackageInstallationSessionReportedStatsTests.java index 3c76407ff3f..4ee5e37f6bb 100644 --- a/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/PackageInstallationSessionReportedStatsTests.java +++ b/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/PackageInstallationSessionReportedStatsTests.java @@ -65,6 +65,9 @@ public class PackageInstallationSessionReportedStatsTests extends PackageManager } public void testPackageInstallationSessionReportedForApkSuccessWithReplace() throws Exception { + if (!Utils.hasIncrementalFeature(getDevice())) { + return; + } ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, AtomsProto.Atom.PACKAGE_INSTALLATION_SESSION_REPORTED_FIELD_NUMBER); RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); diff --git a/hostsidetests/security/Android.bp b/hostsidetests/security/Android.bp index 4798f0c04de..4ca90cca077 100644 --- a/hostsidetests/security/Android.bp +++ b/hostsidetests/security/Android.bp @@ -81,27 +81,19 @@ java_genrule_host { "checkfc", "property_info_checker", "searchpolicy", - "seamendc", "secilc", "sepolicy-analyze", "sepolicy_tests", "treble_sepolicy_tests", ], - tool_files: [ - ":apex_sepolicy-33.cil", - ":apex_sepolicy-33.decompiled.cil", - ], out: ["CtsSecurityHostTestCases_StaticLibs.jar"], cmd: "$(location soong_zip) -jar -o $(location CtsSecurityHostTestCases_StaticLibs.jar) -j " + "-f $(location checkseapp) " + "-f $(location checkfc) " + "-f $(location property_info_checker) " + "-f $(location searchpolicy) " + - "-f $(location seamendc) " + "-f $(location secilc) " + "-f $(location sepolicy-analyze) " + "-f $(location sepolicy_tests) " + - "-f $(location treble_sepolicy_tests) " + - "-f $(location :apex_sepolicy-33.cil) " + - "-f $(location :apex_sepolicy-33.decompiled.cil)", + "-f $(location treble_sepolicy_tests)", } diff --git a/hostsidetests/security/src/android/security/cts/SeamendcHostTest.java b/hostsidetests/security/src/android/security/cts/SeamendcHostTest.java deleted file mode 100644 index d0e337301af..00000000000 --- a/hostsidetests/security/src/android/security/cts/SeamendcHostTest.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * 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 com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; -import com.android.tradefed.device.ITestDevice; -import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; - -@RunWith(DeviceJUnit4ClassRunner.class) -public class SeamendcHostTest extends BaseHostJUnit4Test { - - private ITestDevice mDevice; - - // executable binaries - private File seamendc; - private File secilc; - private File searchpolicy; - private File libsepolwrap; - - // CIL policies - private File mPlatPolicyCil; - private File mPlatCompatCil; - private File mSystemExtPolicyCil; - private File mSystemExtMappingCil; - private File mSystemExtCompatCil; - private File mProductPolicyCil; - private File mProductMappingCil; - private File mVendorPolicyCil; - private File mPlatPubVersionedCil; - private File mOdmPolicyCil; - private File mApexSepolicyCil; - private File mApexSepolicyDecompiledCil; - - @Before - public void setUp() throws Exception { - mDevice = getDevice(); - - seamendc = copyResToTempFile("/seamendc"); - seamendc.setExecutable(true); - secilc = copyResToTempFile("/secilc"); - secilc.setExecutable(true); - searchpolicy = copyResToTempFile("/searchpolicy"); - searchpolicy.setExecutable(true); - libsepolwrap = new CompatibilityBuildHelper(getBuild()).getTestFile("libsepolwrap.so"); - libsepolwrap.deleteOnExit(); - - // Pull CIL files for policy compilation, using selinux.cpp as reference - // https://cs.android.com/android/platform/superproject/+/master:system/core/init/selinux.cpp;l=378-453;drc=2d579af880afae96239c80765b11c7dbc2c1b264 - mPlatPolicyCil = getPlatPolicyFromDevice(); - String vendorMappingVersion = - readFirstLine("/vendor/etc/selinux/", "plat_sepolicy_vers.txt"); - mPlatCompatCil = - getDeviceFile("/system/etc/selinux/mapping/", vendorMappingVersion + ".cil"); - mSystemExtPolicyCil = getDeviceFile("/system_ext/etc/selinux/", "system_ext_sepolicy.cil"); - mSystemExtMappingCil = - getDeviceFile("/system_ext/etc/selinux/mapping/", vendorMappingVersion + ".cil"); - mSystemExtCompatCil = - getDeviceFile( - "/system_ext/etc/selinux/mapping/", vendorMappingVersion + ".compat.cil"); - mProductPolicyCil = getDeviceFile("/product/etc/selinux/", "product_sepolicy.cil"); - mProductMappingCil = - getDeviceFile("/product/etc/selinux/mapping", vendorMappingVersion + ".cil"); - mVendorPolicyCil = getDeviceFile("/vendor/etc/selinux/", "vendor_sepolicy.cil"); - mPlatPubVersionedCil = getDeviceFile("/vendor/etc/selinux/", "plat_pub_versioned.cil"); - mOdmPolicyCil = getDeviceFile("/odm/etc/selinux/", "odm_sepolicy.cil"); - mApexSepolicyCil = copyResToTempFile("/apex_sepolicy.cil"); - - mApexSepolicyDecompiledCil = copyResToTempFile("/apex_sepolicy.decompiled.cil"); - } - - /** - * Verifies that the files necessary for policy compilation exist. - * - * @throws Exception - */ - @Test - public void testRequiredDeviceFilesArePresent() throws Exception { - assertTrue(mPlatPolicyCil.getName() + " is missing", mPlatPolicyCil != null); - assertTrue(mPlatCompatCil.getName() + " is missing", mPlatCompatCil != null); - assertTrue(mVendorPolicyCil.getName() + " is missing", mVendorPolicyCil != null); - assertTrue(mPlatPubVersionedCil.getName() + " is missing", mPlatPubVersionedCil != null); - } - - private File getPlatPolicyFromDevice() throws Exception { - File policyFile = getDeviceFile("/system_ext/etc/selinux/", "userdebug_plat_sepolicy.cil"); - if (policyFile == null) { - policyFile = getDeviceFile("/debug_ramdisk/", "userdebug_plat_sepolicy.cil"); - } - if (policyFile == null) { - policyFile = getDeviceFile("/system/etc/selinux/", "plat_sepolicy.cil"); - } - return policyFile; - } - - private String readFirstLine(String filePath, String fileName) throws Exception { - try (BufferedReader brTest = - new BufferedReader(new FileReader(getDeviceFile(filePath, fileName)))) { - return brTest.readLine(); - } - } - - private File getDeviceFile(String filePath, String fileName) throws Exception { - String deviceFile = filePath + fileName; - File file = File.createTempFile(fileName, ".tmp"); - file.deleteOnExit(); - return mDevice.pullFile(deviceFile, file) ? file : null; - } - - private static File copyResToTempFile(String resName) throws IOException { - InputStream is = SeamendcHostTest.class.getResourceAsStream(resName); - File tempFile = File.createTempFile(resName, ".tmp"); - FileOutputStream os = new FileOutputStream(tempFile); - byte[] buf = new byte[1024]; - int len; - while ((len = is.read(buf)) != -1) { - os.write(buf, 0, len); - } - os.flush(); - os.close(); - tempFile.deleteOnExit(); - return tempFile; - } - - private static String runProcess(String... args) throws Exception { - ProcessBuilder pb = new ProcessBuilder(args); - pb.redirectOutput(ProcessBuilder.Redirect.PIPE); - pb.redirectErrorStream(true); - Process p = pb.start(); - BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream())); - String line; - StringBuilder errorString = new StringBuilder(); - while ((line = result.readLine()) != null) { - errorString.append(line); - errorString.append("\n"); - } - p.waitFor(); - return errorString.toString(); - } - - private String searchpolicySource(File policy, String name) throws Exception { - return runProcess( - searchpolicy.getAbsolutePath(), - "--allow", - "-s", - name, - "--libpath", - libsepolwrap.getAbsolutePath(), - policy.getAbsolutePath()); - } - - private String searchpolicyTarget(File policy, String name) throws Exception { - return runProcess( - searchpolicy.getAbsolutePath(), - "--allow", - "-t", - name, - "--libpath", - libsepolwrap.getAbsolutePath(), - policy.getAbsolutePath()); - } - - /** Uses searchpolicy to verify the two policies wrt the provided source type. */ - private void assertSource(File left, File right, String type, boolean equal) throws Exception { - String diff = diff(searchpolicySource(left, type), searchpolicySource(right, type)); - if (equal) { - assertTrue("Policy sources are not equal:\n" + diff, diff.length() == 0); - } else { - assertTrue("Policy sources should be different.", diff.length() != 0); - } - } - - private void assertSourceEqual(File left, File right, String type) throws Exception { - assertSource(left, right, type, /* equal= */ true); - } - - private void assertSourceNotEqual(File left, File right, String type) throws Exception { - assertSource(left, right, type, /* equal= */ false); - } - - /** Uses searchpolicy to verify the two policies wrt the provided target type. */ - private void assertTarget(File left, File right, String type, boolean equal) throws Exception { - String diff = diff(searchpolicyTarget(left, type), searchpolicyTarget(right, type)); - if (equal) { - assertTrue("Policies are not equal:\n" + diff, diff.length() == 0); - } else { - assertTrue("Policies should be different.", diff.length() != 0); - } - } - - private void assertTargetEqual(File left, File right, String type) throws Exception { - assertTarget(left, right, type, /* equal= */ true); - } - - private void assertTargetNotEqual(File left, File right, String type) throws Exception { - assertTarget(left, right, type, /* equal= */ false); - } - - private File runSeamendc(File basePolicy, File... cilFiles) throws Exception { - File output = File.createTempFile("seamendc-out", ".binary"); - output.deleteOnExit(); - String errorString = - runProcess( - Stream.concat( - Stream.of( - seamendc.getAbsolutePath(), - "-b", - basePolicy.getAbsolutePath(), - "-o", - output.getAbsolutePath()), - Stream.of(cilFiles).map(File::getAbsolutePath)) - .toArray(String[]::new)); - assertTrue(errorString, errorString.length() == 0); - return output; - } - - private File runSecilc(File... cilFiles) throws Exception { - File fileContexts = File.createTempFile("file_contexts", ".txt"); - fileContexts.deleteOnExit(); - File output = File.createTempFile("secilc-out", ".binary"); - output.deleteOnExit(); - String errorString = - runProcess( - Stream.concat( - Stream.of( - secilc.getAbsolutePath(), - "-m", - "-M", - "true", - "-G", - "-N", - "-c", - "30", - "-f", - fileContexts.getAbsolutePath(), - "-o", - output.getAbsolutePath()), - Stream.of(cilFiles) - .filter(Objects::nonNull) - .map(File::getAbsolutePath)) - .toArray(String[]::new)); - assertTrue(errorString, errorString.length() == 0); - return output; - } - - private static String diff(String left, String right) { - List<String> leftLines = Arrays.asList(left.split("\\r?\\n")); - List<String> rightLines = Arrays.asList(right.split("\\r?\\n")); - - // Generate diff information. - List<String> unifiedDiff = - difflib.DiffUtils.generateUnifiedDiff( - "original", - "diff", - leftLines, - difflib.DiffUtils.diff(leftLines, rightLines), - /* contextSize= */ 0); - StringBuilder stringBuilder = new StringBuilder(); - for (String delta : unifiedDiff) { - stringBuilder.append(delta); - stringBuilder.append("\n"); - } - - return stringBuilder.toString(); - } - - /** - * Verifies the output of seamendc against the binary policy obtained by secilc-compiling the - * CIL policies on the device. The binary policies must be the same. - * - * @throws Exception - */ - @Test - public void testSeamendcAgainstSecilc() throws Exception { - File secilcOutWithApex = - runSecilc( - mPlatPolicyCil, - mPlatCompatCil, - mSystemExtPolicyCil, - mSystemExtMappingCil, - mSystemExtCompatCil, - mProductPolicyCil, - mProductMappingCil, - mVendorPolicyCil, - mPlatPubVersionedCil, - mOdmPolicyCil, - mApexSepolicyCil); - File secilcOutWithoutApex = - runSecilc( - mPlatPolicyCil, - mPlatCompatCil, - mSystemExtPolicyCil, - mSystemExtMappingCil, - mSystemExtCompatCil, - mProductPolicyCil, - mProductMappingCil, - mVendorPolicyCil, - mPlatPubVersionedCil, - mOdmPolicyCil); - File seamendcOutWithApex = runSeamendc(secilcOutWithoutApex, mApexSepolicyDecompiledCil); - - // system/sepolicy/com.android.sepolicy/33/shell.te - assertSourceNotEqual(secilcOutWithoutApex, seamendcOutWithApex, "shell"); - assertTargetEqual(secilcOutWithoutApex, seamendcOutWithApex, "shell"); - assertSourceEqual(secilcOutWithApex, seamendcOutWithApex, "shell"); - assertTargetEqual(secilcOutWithApex, seamendcOutWithApex, "shell"); - } -} diff --git a/hostsidetests/securitybulletin/res/cve_2023_21118.bin b/hostsidetests/securitybulletin/res/cve_2023_21118.bin Binary files differnew file mode 100644 index 00000000000..6dc2aaab8d2 --- /dev/null +++ b/hostsidetests/securitybulletin/res/cve_2023_21118.bin diff --git a/hostsidetests/securitybulletin/res/v1-only-10-signers.apk b/hostsidetests/securitybulletin/res/v1-only-10-signers.apk Binary files differnew file mode 100644 index 00000000000..198beeb6510 --- /dev/null +++ b/hostsidetests/securitybulletin/res/v1-only-10-signers.apk diff --git a/hostsidetests/securitybulletin/res/v1-only-11-signers.apk b/hostsidetests/securitybulletin/res/v1-only-11-signers.apk Binary files differnew file mode 100644 index 00000000000..95e6c61e2f6 --- /dev/null +++ b/hostsidetests/securitybulletin/res/v1-only-11-signers.apk diff --git a/hostsidetests/securitybulletin/res/v2-only-10-signers.apk b/hostsidetests/securitybulletin/res/v2-only-10-signers.apk Binary files differnew file mode 100644 index 00000000000..ad34c14ced8 --- /dev/null +++ b/hostsidetests/securitybulletin/res/v2-only-10-signers.apk diff --git a/hostsidetests/securitybulletin/res/v2-only-11-signers.apk b/hostsidetests/securitybulletin/res/v2-only-11-signers.apk Binary files differnew file mode 100644 index 00000000000..674b6e4d7d6 --- /dev/null +++ b/hostsidetests/securitybulletin/res/v2-only-11-signers.apk diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2023-21118/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2023-21118/Android.bp new file mode 100644 index 00000000000..e235d48c482 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2023-21118/Android.bp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_test { + name: "CVE-2023-21118", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ":cts_hostsidetests_securitybulletin_memutils", + ], + shared_libs: [ + "libsensor", + "libbinder", + ], + cflags: [ + "-DCHECK_OVERFLOW", + "-DENABLE_SELECTIVE_OVERLOADING", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2023-21118/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2023-21118/poc.cpp new file mode 100644 index 00000000000..e79dc696f96 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2023-21118/poc.cpp @@ -0,0 +1,55 @@ +/** + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <binder/Parcel.h> +#include <sensor/Sensor.h> + +#include <fstream> + +#include "../includes/common.h" +#include "../includes/memutils.h" + +using namespace android; +using namespace std; + +char enable_selective_overload = ENABLE_NONE; + +void fillParcel(Parcel &reply) { + ifstream inputFile("cve_2023_21118.bin", ios::binary); + FAIL_CHECK(inputFile.is_open()); + + // Compute size of file + inputFile.seekg(0, std::ios::end); + std::streampos fileSize = inputFile.tellg(); + inputFile.seekg(0, std::ios::beg); + + // Fill parcel with file data + vector<uint8_t> fileData(fileSize); + inputFile.read(reinterpret_cast<char *>(fileData.data()), fileSize); + inputFile.close(); + reply.write(fileData.data(), fileSize); + reply.setDataPosition(25044 /* Set data position to required position */); +} + +int main() { + Parcel reply; + Sensor s; + fillParcel(reply); + enable_selective_overload = ENABLE_ALL; + reply.read(s); + enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK; + return 0; +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_21118.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_21118.java new file mode 100644 index 00000000000..b0eb7c61760 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_21118.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import static com.android.sts.common.NativePocCrashAsserter.assertNoCrash; + +import static org.junit.Assume.assumeNoException; + +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.sts.common.NativePoc; +import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase; +import com.android.sts.common.util.TombstoneUtils; +import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2023_21118 extends NonRootSecurityTestCase { + + @AsbSecurityTest(cveBugId = 269014004) + @Test + public void testPocCVE_2023_21118() { + try { + String binaryName = "CVE-2023-21118"; + String inputFile = "cve_2023_21118.bin"; + + String[] signals = {TombstoneUtils.Signals.SIGSEGV}; + TombstoneUtils.Config crashConfig = + new TombstoneUtils.Config() + .setProcessPatterns(binaryName) + .setBacktraceIncludes( + new BacktraceFilterPattern( + "libsensor.so", "android::Sensor::unflatten")) + .setSignals(signals); + + // Running the PoC for CVE-2023-21118 + NativePoc.builder() + .pocName(binaryName) + .resources(inputFile) + .asserter(assertNoCrash(crashConfig)) + .build() + .run(this); + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_21253.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_21253.java new file mode 100644 index 00000000000..957c459a9b9 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_21253.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import static com.android.tradefed.util.CommandStatus.SUCCESS; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import static java.lang.String.format; + +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.util.CommandResult; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2023_21253 extends NonRootSecurityTestCase { + private final List<String> mAssumptionFailureList = new ArrayList<String>(); + private final List<String> mFailureList = new ArrayList<String>(); + + @AsbSecurityTest(cveBugId = 266580022) + @Test + public void testPocCVE_2023_21253() { + try { + // Prebuilt apks used in this test are same as used in ApkVerifierTest.java. Dependence + // on prebuilt apks cannot be removed because with fix, apks with more than 10 signers + // cannot be built due to changes done in 'apksigner'. + final String v1Only10SignersApk = "v1-only-10-signers.apk"; + final String v1Only11SignersApk = "v1-only-11-signers.apk"; + final String v2Only10SignersApk = "v2-only-10-signers.apk"; + final String v2Only11SignersApk = "v2-only-11-signers.apk"; + + // Check V1 apk signature scheme + checkApkSignerScheme(v1Only10SignersApk, v1Only11SignersApk, "V1 apk signature"); + + // Check V2 apk signature scheme + checkApkSignerScheme(v2Only10SignersApk, v2Only11SignersApk, "V2 apk signature"); + + // Fail the test if any failure strings are present in mFailureList + assertTrue( + format( + "Vulnerable to b/266580022! Failures are :- %s", + mFailureList.toString()), + mFailureList.isEmpty()); + + // Assumption failure if any exception messages are present in mAssumptionFailureList + assumeTrue( + format("Exceptions occurred :- %s", mAssumptionFailureList.toString()), + mAssumptionFailureList.isEmpty()); + } catch (Exception e) { + assumeNoException(e); + } + } + + private void checkApkSignerScheme( + String apkWith10Signers, String apkWith11Signers, String apkSignerScheme) { + try { + final CommandResult outputV1Only10 = installAndCheck(apkWith10Signers); + final CommandResult outputV1Only11 = installAndCheck(apkWith11Signers); + if (outputV1Only10.getStatus() != SUCCESS) { + // outputV1Only10 should be successful as it is expected that installation of an apk + // with 10 signers should be allowed + mAssumptionFailureList.add( + format("Unable to install app %s with 10 signatures", apkWith10Signers)); + return; + } + if (outputV1Only11.getStatus() == SUCCESS) { + // Add scheme to mFailureList if installation of an apk with 11 signers is + // successful + mFailureList.add( + format( + "%s scheme allows installation of apk %s with more than 10 signers", + apkSignerScheme, apkWith11Signers)); + } + } catch (Exception e) { + // Add exception occurred in mAssumptionFailureList. This is done to avoid test + // termination midway and ensure that both the schemes are checked + mAssumptionFailureList.add( + format( + "Exception %s occurred while checking %s apk signer scheme", + e.getMessage(), apkSignerScheme)); + } + } + + private CommandResult installAndCheck(String apkName) throws Exception { + final ITestDevice device = getDevice(); + final String apkPath = AdbUtils.TMP_PATH + apkName; + try { + // Push apk file to /data/local/tmp + AdbUtils.pushResource(AdbUtils.RESOURCE_ROOT + apkName, apkPath, device); + + // Install apk + return device.executeShellV2Command("pm install " + apkPath); + } finally { + // Uninstall apk + device.executeShellV2Command("pm uninstall android.appsecurity.cts.tinyapp"); + + // Remove apk file from /data/local/tmp + AdbUtils.removeResources(new String[] {apkName}, AdbUtils.TMP_PATH, device); + } + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_21261.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_21261.java index 68babce9570..d2c57f89a23 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_21261.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_21261.java @@ -32,9 +32,7 @@ import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import org.junit.Test; import org.junit.runner.RunWith; -// CVE-2023-21261 includes fix for 2 vulnerabilities. -// 1.CVE-2022-27405 -// 2.CVE-2022-27406 +// CVE-2023-21261 includes fix for CVE-2022-27406. // Hence checking for both the vulnerabilties @RunWith(DeviceJUnit4ClassRunner.class) public class CVE_2023_21261 extends NonRootSecurityTestCase { @@ -51,14 +49,6 @@ public class CVE_2023_21261 extends NonRootSecurityTestCase { String binaryName = "CVE-2023-21261"; String inputFile = "cve_2023_21261.ttf"; - // Running the PoC for CVE-2022-27405 - NativePoc.builder() - .pocName(binaryName) - .args("CVE-2022-27405", inputFile) - .resources(inputFile) - .asserter(assertNotVulnerableExitCode()) - .build() - .run(this); TombstoneUtils.Config crashConfig = new TombstoneUtils.Config() .setProcessPatterns(binaryName) diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_40120.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_40120.java new file mode 100644 index 00000000000..a489cea954e --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_40120.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import static org.junit.Assume.assumeNoException; + +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2023_40120 extends NonRootSecurityTestCase { + + @AsbSecurityTest(cveBugId = 274775190) + @Test + public void testPocCVE_2023_40120() { + try { + final String testPkg = "android.security.cts.CVE_2023_40120"; + installPackage("CVE-2023-40120.apk"); + + // Run DeviceTest + runDeviceTests(testPkg, testPkg + ".DeviceTest", "testPocCVE_2023_40120"); + } catch (Exception e) { + assumeNoException(e); + } finally { + try { + // To exit test gracefully + getDevice().executeShellV2Command("input keyevent KEYCODE_HOME"); + } catch (Exception e) { + // ignore the exceptions + } + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0595/test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0595/test-app/res/values/strings.xml index faf549e4171..b0493f1d681 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0595/test-app/res/values/strings.xml +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0595/test-app/res/values/strings.xml @@ -16,6 +16,7 @@ --> <resources> + <string name="deviceLockFailMessage">Device is not Locked!</string> <string name="helperAppPackage">android.security.cts.CVE_2021_0595_helper</string> <string name="launchSecondPocActivityAction">launchSecondPocActivity</string> <string name="testFailMessage">Vulnerable to b/177457096</string> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0595/test-app/src/android/security/cts/CVE_2021_0595_test/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0595/test-app/src/android/security/cts/CVE_2021_0595_test/DeviceTest.java index 431d44519e6..b3784f5199b 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0595/test-app/src/android/security/cts/CVE_2021_0595_test/DeviceTest.java +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0595/test-app/src/android/security/cts/CVE_2021_0595_test/DeviceTest.java @@ -19,10 +19,11 @@ package android.security.cts.CVE_2021_0595_test; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static org.junit.Assert.assertFalse; -import static org.junit.Assume.assumeTrue; import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; import android.app.Instrumentation; +import android.app.KeyguardManager; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; @@ -72,6 +73,9 @@ public class DeviceTest { // Swipe/Remove Lock Screen device.pressMenu(); + assumeTrue( + context.getString(R.string.deviceLockFailMessage), + context.getSystemService(KeyguardManager.class).isDeviceLocked()); assertFalse( context.getString(R.string.testFailMessage), context.getString(R.string.helperAppPackage) diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-40120/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2023-40120/Android.bp new file mode 100644 index 00000000000..2015242f475 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-40120/Android.bp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2023-40120", + defaults: [ + "cts_defaults", + ], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + "sts-device-util", + "truth-prebuilt", + ], +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-40120/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-40120/AndroidManifest.xml new file mode 100644 index 00000000000..020a20f5a09 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-40120/AndroidManifest.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.security.cts.CVE_2023_40120"> + <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2023_40120" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-40120/src/android/security/cts/CVE_2023_40120/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-40120/src/android/security/cts/CVE_2023_40120/DeviceTest.java new file mode 100644 index 00000000000..c399df5708d --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-40120/src/android/security/cts/CVE_2023_40120/DeviceTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts.CVE_2023_40120; + +import static android.provider.Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static com.android.sts.common.SystemUtil.poll; + +import static com.google.common.truth.Truth.assertWithMessage; +import static com.google.common.truth.TruthJUnit.assume; + +import static org.junit.Assume.assumeNoException; + +import android.app.Instrumentation; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.graphics.drawable.Icon; +import android.media.MediaMetadata; +import android.media.session.MediaSession; +import android.service.notification.StatusBarNotification; + +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 org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + + @Test + public void testPocCVE_2023_40120() { + try { + Instrumentation instrumentation = getInstrumentation(); + Context context = instrumentation.getContext(); + + // Create a MediaSession + MediaSession session = + new MediaSession(context, "cve_2023_40120_session" /* session name */); + + // Create a MediaMetadata object, pass an empty 'METADATA_KEY_TITLE' and set metadata + // for session + String artistName = "testArtist"; + session.setMetadata( + new MediaMetadata.Builder() + .putString(MediaMetadata.METADATA_KEY_TITLE, "") + .putString(MediaMetadata.METADATA_KEY_ARTIST, artistName) + .build()); + + // Create notificationManager + NotificationManager notificationManager = + context.getSystemService(NotificationManager.class); + + // Create notificationChannel + String channelId = "cve_2023_40120_channel_id"; + notificationManager.createNotificationChannel( + new NotificationChannel( + channelId, + "cve_2023_40120_channel_name" /* notification channel name */, + NotificationManager.IMPORTANCE_DEFAULT)); + + // Post the Notification and check if any security exception is caught + notificationManager.notify( + 0 /* notification id */, + new Notification.Builder(context) + .setChannelId(channelId) + .setStyle( + new Notification.DecoratedMediaCustomViewStyle() + .setMediaSession(session.getSessionToken())) + .setSmallIcon( + Icon.createWithData( + new byte[0] /* data */, 0 /* offset */, 0 /* length */)) + .build()); + + // Check if notification gets posted or not + assume().withMessage("Notification was not posted") + .that( + poll( + () -> { + StatusBarNotification[] activeNotifications = + notificationManager.getActiveNotifications(); + for (StatusBarNotification notification : + activeNotifications) { + if (notification + .getPackageName() + .equals(context.getPackageName())) { + return true; + } + } + return false; + })) + .isTrue(); + + // Launch notification shade + UiDevice uiDevice = UiDevice.getInstance(instrumentation); + assume().withMessage("Unable to launch notification shade") + .that(uiDevice.openNotification()) + .isTrue(); + + // Wait for 'qs_media_controls' resource id to appear + String systemuiPackage = "com.android.systemui"; + UiObject2 resIdObj = + uiDevice.wait( + Until.findObject(By.res(systemuiPackage, SHOW_MEDIA_ON_QUICK_SETTINGS)), + 3000); + + // Assumption failure if 'resIdObj' is null + assume().withMessage("resource id qs_media_controls not found") + .that(resIdObj) + .isNotNull(); + + // Assumption failure if 'testArtist' text is not present in notification + assume().withMessage("testArtist text not found") + .that(resIdObj.getContentDescription().contains(artistName)) + .isTrue(); + + // Fail the test if either notification title is not present or notification title text + // is null + UiObject2 headerTitleObj = + resIdObj.getParent().findObject(By.res(systemuiPackage, "header_title")); + assertWithMessage("Device is vulnerable to b/274775190 hence foreground services can be" + + " started with an empty notification") + .that(headerTitleObj == null || headerTitleObj.getText() == null) + .isFalse(); + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java b/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java index 3ef7a4dfdf9..76ff2175e9f 100644 --- a/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java +++ b/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java @@ -25,7 +25,6 @@ import static android.photopicker.cts.util.PhotoPickerUiUtils.findItemList; import static android.photopicker.cts.util.ResultsAssertionsUtils.assertPersistedGrant; import static android.photopicker.cts.util.ResultsAssertionsUtils.assertPickerUriFormat; import static android.photopicker.cts.util.ResultsAssertionsUtils.assertRedactedReadOnlyAccess; -import static android.provider.MediaStore.ACTION_PICK_IMAGES; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -75,7 +74,7 @@ public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest { @Test public void testPhotoPickerIntentDelegation() throws Exception { - final Intent intent = new Intent(ACTION_PICK_IMAGES); + final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES); for (String mimeType: new String[] { null, @@ -94,7 +93,7 @@ public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest { @Test public void testMultiSelect_invalidParam() throws Exception { - final Intent intent = new Intent(ACTION_PICK_IMAGES); + final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES); intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit() + 1); mActivity.startActivityForResult(intent, REQUEST_CODE); final GetResultActivity.Result res = mActivity.getResult(); @@ -103,7 +102,7 @@ public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest { @Test public void testMultiSelect_invalidNegativeParam() throws Exception { - final Intent intent = new Intent(ACTION_PICK_IMAGES); + final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES); intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, -1); mActivity.startActivityForResult(intent, REQUEST_CODE); final GetResultActivity.Result res = mActivity.getResult(); @@ -116,7 +115,7 @@ public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest { final int imageCount = maxCount + 1; mUriList.addAll(createImagesAndGetUris(imageCount, mContext.getUserId())); - final Intent intent = new Intent(ACTION_PICK_IMAGES); + final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES); intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, maxCount); mActivity.startActivityForResult(intent, REQUEST_CODE); @@ -147,7 +146,7 @@ public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest { public void testDoesNotRespectExtraAllowMultiple() throws Exception { final int imageCount = 2; mUriList.addAll(createImagesAndGetUris(imageCount, mContext.getUserId())); - final Intent intent = new Intent(ACTION_PICK_IMAGES); + final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES); intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); mActivity.startActivityForResult(intent, REQUEST_CODE); @@ -158,14 +157,14 @@ public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest { clickAndWait(sDevice, itemList.get(0)); final Uri uri = mActivity.getResult().data.getData(); - assertPickerUriFormat(ACTION_PICK_IMAGES, uri, mContext.getUserId()); + assertPickerUriFormat(uri, mContext.getUserId()); assertPersistedGrant(uri, mContext.getContentResolver()); assertRedactedReadOnlyAccess(uri); } @Test public void testMimeTypeFilter() throws Exception { - final Intent intent = new Intent(ACTION_PICK_IMAGES); + final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES); intent.setType("audio/*"); assertThrows(ActivityNotFoundException.class, () -> mActivity.startActivityForResult(intent, REQUEST_CODE)); @@ -173,7 +172,7 @@ public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest { @Test public void testExtraMimeTypeFilter() throws Exception { - final Intent intent = new Intent(ACTION_PICK_IMAGES); + final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES); intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"audio/*"}); mActivity.startActivityForResult(intent, REQUEST_CODE); final GetResultActivity.Result res = mActivity.getResult(); diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java index 98d1df02d8f..a4f7b902a9e 100644 --- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java +++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java @@ -24,7 +24,6 @@ import static android.photopicker.cts.util.PhotoPickerUiUtils.findItemList; import static android.photopicker.cts.util.PhotoPickerUiUtils.findProfileButton; import static android.photopicker.cts.util.ResultsAssertionsUtils.assertPickerUriFormat; import static android.photopicker.cts.util.ResultsAssertionsUtils.assertRedactedReadOnlyAccess; -import static android.provider.MediaStore.ACTION_PICK_IMAGES; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -94,7 +93,7 @@ public class PhotoPickerCrossProfileTest extends PhotoPickerBaseTest { final int imageCount = 2; mUriList.addAll(createImagesAndGetUris(imageCount, primaryUserId)); - Intent intent = new Intent(ACTION_PICK_IMAGES); + Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES); intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, imageCount); mActivity.startActivityForResult(intent, REQUEST_CODE); @@ -121,7 +120,7 @@ public class PhotoPickerCrossProfileTest extends PhotoPickerBaseTest { assertThat(count).isEqualTo(imageCount); for (int i = 0; i < count; i++) { Uri uri = clipData.getItemAt(i).getUri(); - assertPickerUriFormat(ACTION_PICK_IMAGES, uri, primaryUserId); + assertPickerUriFormat(uri, primaryUserId); assertRedactedReadOnlyAccess(uri); } } @@ -148,7 +147,7 @@ public class PhotoPickerCrossProfileTest extends PhotoPickerBaseTest { } private void assertBlockedByAdmin(boolean isInvokedFromWorkProfile) throws Exception { - Intent intent = new Intent(ACTION_PICK_IMAGES); + Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES); intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit()); mActivity.startActivityForResult(intent, REQUEST_CODE); diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java index 3b144105f7f..08639ae26e8 100644 --- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java +++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java @@ -20,6 +20,8 @@ import static android.photopicker.cts.PhotoPickerCloudUtils.disableCloudMediaAnd import static android.photopicker.cts.PhotoPickerCloudUtils.enableCloudMediaAndSetAllowedCloudProviders; import static android.photopicker.cts.PhotoPickerCloudUtils.getAllowedProvidersDeviceConfig; import static android.photopicker.cts.PhotoPickerCloudUtils.isCloudMediaEnabled; +import static android.photopicker.cts.util.PhotoPickerUiUtils.REGEX_PACKAGE_NAME; +import static android.photopicker.cts.util.PhotoPickerUiUtils.SHORT_TIMEOUT; import static android.photopicker.cts.util.PhotoPickerUiUtils.isPhotoPickerVisible; import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsActionBarIsVisible; import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsActivityIsVisible; @@ -27,15 +29,25 @@ import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsDesc import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsFragmentContainerExists; import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsTitleIsVisible; +import static com.google.common.truth.Truth.assertWithMessage; + import android.content.Intent; import android.os.Build; +import android.os.UserHandle; import android.photopicker.cts.util.PhotoPickerUiUtils; import android.provider.MediaStore; +import androidx.annotation.NonNull; +import androidx.test.filters.LargeTest; import androidx.test.filters.SdkSuppress; -import androidx.test.runner.AndroidJUnit4; import androidx.test.uiautomator.UiObject; +import androidx.test.uiautomator.UiObjectNotFoundException; +import androidx.test.uiautomator.UiSelector; + +import com.android.bedstead.harrier.BedsteadJUnit4; +import com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile; +import org.junit.After; import org.junit.AfterClass; import org.junit.Assume; import org.junit.BeforeClass; @@ -48,12 +60,18 @@ import org.junit.runner.RunWith; */ // TODO(b/195009187): Enabling settings page requires setting allowed_cloud_providers device config. // We currently can't do this in R. -@RunWith(AndroidJUnit4.class) +@RunWith(BedsteadJUnit4.class) @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public class PhotoPickerSettingsTest extends PhotoPickerBaseTest { private static boolean sCloudMediaPreviouslyEnabled; private static String sPreviouslyAllowedCloudProviders; + private static final String EXTRA_TAB_USER_ID = "user_id"; + private static final String TAB_CONTAINER_RESOURCE_ID = + REGEX_PACKAGE_NAME + ":id/tab_container"; + private static final String TAB_LAYOUT_RESOURCE_ID = REGEX_PACKAGE_NAME + ":id/tabs"; + private static final String PERSONAL_TAB_TITLE_ENGLISH = "Personal"; + private static final String WORK_TAB_TITLE_ENGLISH = "Work"; @BeforeClass public static void setUpBeforeClass() { @@ -78,8 +96,15 @@ public class PhotoPickerSettingsTest extends PhotoPickerBaseTest { } } + @After + public void tearDown() { + if (mActivity != null) { + mActivity.finish(); + } + } + @Test - public void testSettingsLaunchFromOverflowMenu() throws Exception { + public void testSettingsLaunchFromOverflowMenu_WorkDisabled() throws Exception { // Launch PhotoPickerActivity. final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES); mActivity.startActivityForResult(intent, REQUEST_CODE); @@ -96,5 +121,62 @@ public class PhotoPickerSettingsTest extends PhotoPickerBaseTest { verifySettingsTitleIsVisible(); verifySettingsDescriptionIsVisible(); verifySettingsFragmentContainerExists(); + + // Verify Tab container (to switch profiles) is not visible since Work profile is disabled. + verifySettingsTabContainerIsNotVisible(); + } + + @Test + @LargeTest + @RequireRunOnWorkProfile + public void testSettingsLaunchedInPersonalProfile_WorkEnabled() throws Exception { + final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES_SETTINGS); + + mActivity.startActivityForResult(intent, REQUEST_CODE); + sDevice.waitForIdle(); + verifySettingsActivityIsVisible(); + + verifySettingsTabContainerIsVisible(); + assertWithMessage("Personal tab is not selected") + .that(isSelectedTabTitle(PERSONAL_TAB_TITLE_ENGLISH)).isTrue(); + } + + @Test + @LargeTest + @RequireRunOnWorkProfile + public void testSettingsLaunchedInWorkProfile() throws Exception { + final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES_SETTINGS); + intent.putExtra(EXTRA_TAB_USER_ID, UserHandle.myUserId()); + + mActivity.startActivityForResult(intent, REQUEST_CODE); + sDevice.waitForIdle(); + verifySettingsActivityIsVisible(); + + verifySettingsTabContainerIsVisible(); + assertWithMessage("Work tab is not selected") + .that(isSelectedTabTitle(WORK_TAB_TITLE_ENGLISH)).isTrue(); + } + + private static void verifySettingsTabContainerIsVisible() { + assertWithMessage("Timed out waiting for settings profile select tab container to appear") + .that(findObject(TAB_CONTAINER_RESOURCE_ID).waitForExists(SHORT_TIMEOUT)) + .isTrue(); + } + + private static void verifySettingsTabContainerIsNotVisible() { + assertWithMessage("Found the settings profile select tab container") + .that(findObject(TAB_CONTAINER_RESOURCE_ID).waitForExists(SHORT_TIMEOUT)) + .isFalse(); + } + + private static boolean isSelectedTabTitle(@NonNull String tabTitle) + throws UiObjectNotFoundException { + final UiObject tabLayout = findObject(TAB_LAYOUT_RESOURCE_ID); + final UiObject tab = tabLayout.getChild(new UiSelector().textContains(tabTitle)); + return tab.isSelected(); + } + + private static UiObject findObject(@NonNull String resourceId) { + return sDevice.findObject(new UiSelector().resourceIdMatches(resourceId)); } } diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java index d166c359268..293cbacd05c 100644 --- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java +++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java @@ -39,7 +39,6 @@ import static android.photopicker.cts.util.ResultsAssertionsUtils.assertMimeType import static android.photopicker.cts.util.ResultsAssertionsUtils.assertPersistedGrant; import static android.photopicker.cts.util.ResultsAssertionsUtils.assertPickerUriFormat; import static android.photopicker.cts.util.ResultsAssertionsUtils.assertRedactedReadOnlyAccess; -import static android.provider.MediaStore.ACTION_PICK_IMAGES; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -123,7 +122,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { clickAndWait(sDevice, item); final Uri uri = mActivity.getResult().data.getData(); - assertPickerUriFormat(mAction, uri, mContext.getUserId()); + assertPickerUriFormat(uri, mContext.getUserId()); assertPersistedGrant(uri, mContext.getContentResolver()); assertRedactedReadOnlyAccess(uri); } @@ -147,7 +146,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { clickAndWait(sDevice, item); final Uri uri = mActivity.getResult().data.getData(); - assertPickerUriFormat(mAction, uri, mContext.getUserId()); + assertPickerUriFormat(uri, mContext.getUserId()); assertRedactedReadOnlyAccess(uri); } @@ -201,7 +200,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { clickAndWait(sDevice, addButton); final Uri uri = mActivity.getResult().data.getData(); - assertPickerUriFormat(mAction, uri, mContext.getUserId()); + assertPickerUriFormat(uri, mContext.getUserId()); assertRedactedReadOnlyAccess(uri); } @@ -227,7 +226,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { assertThat(count).isEqualTo(itemCount); for (int i = 0; i < count; i++) { final Uri uri = clipData.getItemAt(i).getUri(); - assertPickerUriFormat(mAction, uri, mContext.getUserId()); + assertPickerUriFormat(uri, mContext.getUserId()); assertPersistedGrant(uri, mContext.getContentResolver()); assertRedactedReadOnlyAccess(uri); } @@ -275,7 +274,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { assertThat(count).isEqualTo(3); for (int i = 0; i < count; i++) { final Uri uri = clipData.getItemAt(i).getUri(); - assertPickerUriFormat(mAction, uri, mContext.getUserId()); + assertPickerUriFormat(uri, mContext.getUserId()); assertPersistedGrant(uri, mContext.getContentResolver()); assertRedactedReadOnlyAccess(uri); } @@ -315,7 +314,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { assertThat(count).isEqualTo(itemCount - 1); for (int i = 0; i < count; i++) { final Uri uri = clipData.getItemAt(i).getUri(); - assertPickerUriFormat(mAction, uri, mContext.getUserId()); + assertPickerUriFormat(uri, mContext.getUserId()); assertPersistedGrant(uri, mContext.getContentResolver()); assertRedactedReadOnlyAccess(uri); } @@ -577,7 +576,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { assertThat(count).isEqualTo(itemCount); for (int i = 0; i < count; i++) { final Uri uri = clipData.getItemAt(i).getUri(); - assertPickerUriFormat(mAction, uri, mContext.getUserId()); + assertPickerUriFormat(uri, mContext.getUserId()); assertPersistedGrant(uri, mContext.getContentResolver()); assertRedactedReadOnlyAccess(uri); assertMimeType(uri, mimeType); @@ -623,7 +622,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { .that(clipData.getItemCount()).isEqualTo(itemCount); for (int i = 0; i < itemCount; i++) { final Uri uri = clipData.getItemAt(i).getUri(); - assertPickerUriFormat(mAction, uri, mContext.getUserId()); + assertPickerUriFormat(uri, mContext.getUserId()); assertPersistedGrant(uri, mContext.getContentResolver()); assertRedactedReadOnlyAccess(uri); assertContainsMimeType(uri, mimeTypes); @@ -660,7 +659,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { .that(clipData.getItemCount()).isEqualTo(itemCount); for (int i = 0; i < itemCount; i++) { final Uri uri = clipData.getItemAt(i).getUri(); - assertPickerUriFormat(mAction, uri, mContext.getUserId()); + assertPickerUriFormat(uri, mContext.getUserId()); assertPersistedGrant(uri, mContext.getContentResolver()); assertRedactedReadOnlyAccess(uri); assertMimeType(uri, mimeType); @@ -871,14 +870,14 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { private static List<String> getTestParameters() { return Arrays.asList( - ACTION_PICK_IMAGES, + MediaStore.ACTION_PICK_IMAGES, Intent.ACTION_GET_CONTENT ); } private void addMultipleSelectionFlag(Intent intent) { switch (intent.getAction()) { - case ACTION_PICK_IMAGES: + case MediaStore.ACTION_PICK_IMAGES: intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit()); break; diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/ResultsAssertionsUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/ResultsAssertionsUtils.java index 9c14650a43f..2f346770215 100644 --- a/tests/PhotoPicker/src/android/photopicker/cts/util/ResultsAssertionsUtils.java +++ b/tests/PhotoPicker/src/android/photopicker/cts/util/ResultsAssertionsUtils.java @@ -53,17 +53,13 @@ import java.util.Map; public class ResultsAssertionsUtils { private static final String TAG = "PhotoPickerTestAssertions"; - public static void assertPickerUriFormat(String action, Uri uri, int expectedUserId) { + public static void assertPickerUriFormat(Uri uri, int expectedUserId) { // content://media/picker/<user-id>/<media-id> final int userId = Integer.parseInt(uri.getPathSegments().get(1)); assertThat(userId).isEqualTo(expectedUserId); final String auth = uri.getPathSegments().get(0); - if (action.equalsIgnoreCase(Intent.ACTION_GET_CONTENT)) { - assertThat(auth).isEqualTo("picker_get_content"); - } else { - assertThat(auth).isEqualTo("picker"); - } + assertThat(auth).isEqualTo("picker"); } public static void assertPersistedGrant(Uri uri, ContentResolver resolver) { diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityInputConnectionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityInputConnectionTest.java index 5ce7582dd4e..29388b32525 100644 --- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityInputConnectionTest.java +++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityInputConnectionTest.java @@ -127,7 +127,9 @@ public final class AccessibilityInputConnectionTest { // For some reasons, Mockito.spy() for real Framework classes did not work... // Use NoOpInputConnection/InputConnectionSplitter instead. final InputConnection spy = Mockito.spy(new NoOpInputConnection()); - mLastInputConnectionSpy.set(spy); + if (mLastInputConnectionSpy.get() == null) { + mLastInputConnectionSpy.set(spy); + } return new InputConnectionSplitter(ic, spy); } }; diff --git a/tests/app/WallpaperTest/src/android/app/cts/wallpapers/WallpaperManagerTest.java b/tests/app/WallpaperTest/src/android/app/cts/wallpapers/WallpaperManagerTest.java index c7ea05a23dd..d41303a7c99 100644 --- a/tests/app/WallpaperTest/src/android/app/cts/wallpapers/WallpaperManagerTest.java +++ b/tests/app/WallpaperTest/src/android/app/cts/wallpapers/WallpaperManagerTest.java @@ -696,6 +696,10 @@ public class WallpaperManagerTest { @Test public void invokeOnColorsChangedListenerTest_systemOnly() { + if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) { + verifyColorListenerInvoked(FLAG_SYSTEM, FLAG_SYSTEM); + return; + } int both = FLAG_LOCK | FLAG_SYSTEM; // Expect both since the first step is to migrate the current wallpaper // to the lock screen. diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java index e254cee00b3..2b8402aba92 100644 --- a/tests/app/src/android/app/cts/ActivityManagerTest.java +++ b/tests/app/src/android/app/cts/ActivityManagerTest.java @@ -107,6 +107,7 @@ import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RestrictedBuildTest; import android.provider.DeviceConfig; import android.provider.Settings; +import android.server.wm.WindowManagerStateHelper; import android.server.wm.settings.SettingsSession; import android.util.ArrayMap; import android.util.ArraySet; @@ -1722,8 +1723,11 @@ public final class ActivityManagerTest { } })); + final WindowManagerStateHelper wms = new WindowManagerStateHelper(); mTargetContext.startActivity(intent); watcher3.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP, null); + wms.waitForValidState(new ComponentName(CANT_SAVE_STATE_1_PACKAGE_NAME, + "CantSave1Activity")); heavyLatchHolder[0] = new CountDownLatch(1); testFunc[0] = level -> TRIM_MEMORY_RUNNING_MODERATE <= (int) level @@ -1742,6 +1746,7 @@ public final class ActivityManagerTest { heavyLatchHolder[0] = new CountDownLatch(1); testFunc[0] = level -> TRIM_MEMORY_BACKGROUND == (int) level; mTargetContext.startActivity(homeIntent); + wms.waitForHomeActivityVisible(); assertTrue("Failed to wait for the trim memory event", heavyLatchHolder[0].await(waitForSec, TimeUnit.MILLISECONDS)); diff --git a/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java index 311095e5749..a5314a3dabb 100644 --- a/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java +++ b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java @@ -2025,7 +2025,7 @@ public class ImageReaderTest extends Camera2AndroidTestCase { if (VERBOSE) Log.v(TAG, "Waiting for an Image"); mListener.waitForAnyImageAvailable(CAPTURE_WAIT_TIMEOUT_MS); if (repeating) { - img = mReader.acquireLatestImage(); + img = mReader.acquireNextImage(); if (img == null && retryCount < MAX_RETRY_COUNT) { retryCount++; continue; diff --git a/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java b/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java index e37e3117521..a9e0a58fa64 100644 --- a/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java +++ b/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java @@ -1035,9 +1035,16 @@ public final class LogicalCameraDeviceTest extends Camera2SurfaceViewTestCase { Rect activeArraySize = mStaticInfo.getActiveArraySizeChecked(); SizeF sensorSize = mStaticInfo.getValueFromKeyNonNull( CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE); + Size logicalPixelArraySize = mStaticInfo.getValueFromKeyNonNull( + CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); + Rect logicalPreCorrActiveArraySize = mStaticInfo.getValueFromKeyNonNull( + CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); + Float fovTransferRatio = logicalPreCorrActiveArraySize.width() * 1f / + logicalPixelArraySize.getWidth(); + Float logicalSensorWidth = sensorSize.getWidth() * fovTransferRatio; // Assume subject distance >> focal length, and subject distance >> camera baseline. - double fov = 2 * Math.toDegrees(Math.atan2(sensorSize.getWidth() * cropRegion.width() / + double fov = 2 * Math.toDegrees(Math.atan2(logicalSensorWidth * cropRegion.width() / (2 * zoomRatio * activeArraySize.width()), focalLength)); Map<String, CaptureResult> physicalResultsDual = @@ -1052,15 +1059,23 @@ public final class LogicalCameraDeviceTest extends Camera2SurfaceViewTestCase { SizeF physicalSensorSize = physicalStaticInfo.getValueFromKeyNonNull( CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE); + Size physicalPixelArraySize = physicalStaticInfo.getValueFromKeyNonNull( + CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); + Rect physicalPreCorrActiveArraySize = physicalStaticInfo.getValueFromKeyNonNull( + CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); + Float transferRatio = physicalPreCorrActiveArraySize.width() * 1f / + physicalPixelArraySize.getWidth(); + Float physicalSensorWidth = physicalSensorSize.getWidth() * transferRatio; + // Physical result metadata's ZOOM_RATIO is 1.0f. assertTrue("Physical result metadata ZOOM_RATIO should be 1.0f, but is " + physicalZoomRatio, Math.abs(physicalZoomRatio - 1.0f) < ZOOM_RATIO_THRESHOLD); double physicalFov = 2 * Math.toDegrees(Math.atan2( - physicalSensorSize.getWidth() * physicalCropRegion.width() / + physicalSensorWidth * physicalCropRegion.width() / (2 * physicalZoomRatio * physicalActiveArraySize.width()), physicalFocalLength)); - double maxPhysicalFov = 2 * Math.toDegrees(Math.atan2(physicalSensorSize.getWidth() / 2, + double maxPhysicalFov = 2 * Math.toDegrees(Math.atan2(physicalSensorWidth / 2, physicalFocalLength)); double expectedPhysicalFov = Math.min(maxPhysicalFov, fov); diff --git a/tests/camera/src/android/hardware/cts/CameraTest.java b/tests/camera/src/android/hardware/cts/CameraTest.java index a6d4131dc6d..ff0b1ede465 100644 --- a/tests/camera/src/android/hardware/cts/CameraTest.java +++ b/tests/camera/src/android/hardware/cts/CameraTest.java @@ -1986,7 +1986,7 @@ public class CameraTest extends Assert { } @UiThreadTest - @Test(timeout=60*60*1000) // timeout = 60 mins for long running tests + @Test(timeout=120*60*1000) // timeout = 120 mins for long running tests public void testPreviewPictureSizesCombination() throws Exception { for (int id : mCameraIds) { Log.v(TAG, "Camera id=" + id); diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerTest.java index 9f4b3b70b76..00d3da65572 100644 --- a/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerTest.java +++ b/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerTest.java @@ -25,16 +25,15 @@ import static org.junit.Assert.assertThrows; import android.app.admin.DevicePolicyManager; import android.content.Context; -import android.util.Log; import com.android.bedstead.harrier.BedsteadJUnit4; import com.android.bedstead.harrier.DeviceState; import com.android.bedstead.harrier.UserType; import com.android.bedstead.harrier.annotations.EnsureHasAccount; -import com.android.bedstead.harrier.annotations.EnsureHasAccountAuthenticator; import com.android.bedstead.harrier.annotations.EnsureHasAdditionalUser; import com.android.bedstead.harrier.annotations.EnsureHasNoAccounts; import com.android.bedstead.harrier.annotations.EnsureHasPermission; +import com.android.bedstead.harrier.annotations.FailureMode; import com.android.bedstead.harrier.annotations.Postsubmit; import com.android.bedstead.harrier.annotations.RequireNotHeadlessSystemUserMode; import com.android.bedstead.harrier.annotations.RequireRunOnSystemUser; @@ -42,7 +41,6 @@ import com.android.bedstead.harrier.annotations.UserTest; import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner; import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc; import com.android.bedstead.nene.TestApis; -import com.android.bedstead.nene.accounts.AccountReference; import com.android.bedstead.nene.devicepolicy.DeviceOwner; import com.android.bedstead.nene.exceptions.AdbException; import com.android.bedstead.nene.packages.ComponentReference; @@ -155,7 +153,8 @@ public final class DeviceOwnerTest { @EnsureHasAdditionalUser @EnsureHasNoDpc - @EnsureHasNoAccounts(onUser = UserType.ANY) + @EnsureHasNoAccounts(onUser = UserType.ANY, allowPreCreatedAccounts = false, + failureMode = FailureMode.SKIP) @RequireNotHeadlessSystemUserMode(reason = "No non-testonly dpc which supports headless") @Test public void setDeviceOwnerViaAdb_noAccounts_notTestOnly_sets() throws Exception { diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ProfileOwnerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ProfileOwnerTest.java index 0fb1b8a8b79..04c84d7f141 100644 --- a/tests/devicepolicy/src/android/devicepolicy/cts/ProfileOwnerTest.java +++ b/tests/devicepolicy/src/android/devicepolicy/cts/ProfileOwnerTest.java @@ -27,11 +27,10 @@ import static org.junit.Assert.assertThrows; import com.android.bedstead.harrier.BedsteadJUnit4; import com.android.bedstead.harrier.DeviceState; import com.android.bedstead.harrier.annotations.EnsureHasAccount; -import com.android.bedstead.harrier.annotations.EnsureHasAccountAuthenticator; import com.android.bedstead.harrier.annotations.EnsureHasNoAccounts; +import com.android.bedstead.harrier.annotations.FailureMode; import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc; import com.android.bedstead.nene.TestApis; -import com.android.bedstead.nene.accounts.AccountReference; import com.android.bedstead.nene.devicepolicy.ProfileOwner; import com.android.bedstead.nene.exceptions.AdbException; import com.android.bedstead.nene.packages.ComponentReference; @@ -103,7 +102,8 @@ public final class ProfileOwnerTest { } @EnsureHasNoDpc - @EnsureHasNoAccounts(onUser = ANY) + @EnsureHasNoAccounts(onUser = ANY, allowPreCreatedAccounts = false, + failureMode = FailureMode.SKIP) @Test public void setProfileOwnerViaAdb_noAccounts_notTestOnly_sets() throws Exception { try (TestAppInstance dpcApp = NOT_TEST_ONLY_DPC.install()) { diff --git a/tests/framework/base/windowmanager/src/android/server/wm/BackGestureInvokedTest.java b/tests/framework/base/windowmanager/src/android/server/wm/BackGestureInvokedTest.java index 104c07a1978..e13157c23d1 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/BackGestureInvokedTest.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/BackGestureInvokedTest.java @@ -77,13 +77,17 @@ public class BackGestureInvokedTest extends ActivityManagerTestBase { @Test public void popupWindowDismissedOnBackGesture() { mActivitySession.runOnMainSyncAndWait(mActivity::addPopupWindow); - mWmState.waitAndAssertWindowShown(TYPE_APPLICATION_PANEL, true); + final int taskId = mWmState.getTaskByActivity(mActivity.getComponentName()).getTaskId(); + assertTrue("Popup window must show", mWmState.waitFor(state -> + mWmState.getMatchingWindows(ws -> ws.getType() == TYPE_APPLICATION_PANEL + && ws.getStackId() == taskId && ws.isSurfaceShown()) + .findAny().isPresent(), "popup window show")); triggerBackEventByGesture(DEFAULT_DISPLAY); - assertTrue("Popup window must be removed", - mWmState.waitForWithAmState( - state -> state.getMatchingWindowType(TYPE_APPLICATION_PANEL).isEmpty(), - "popup window to dismiss")); + assertTrue("Popup window must be removed", mWmState.waitFor(state -> + mWmState.getMatchingWindows(ws -> ws.getType() == TYPE_APPLICATION_PANEL + && ws.getStackId() == taskId).findAny().isEmpty(), + "popup window removed")); // activity remain focused mWmState.assertFocusedActivity("Top activity must be focused", 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 b94e0d35f72..cfbdeef61f7 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java @@ -88,6 +88,7 @@ import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; @@ -335,6 +336,7 @@ public final class CompatChangeTests extends MultiDisplayTestBase { } @Test + @Ignore("b/295873734 flaky") public void testOverrideIgnoreRequestedOrientation_propertyIsFalse_overrideNotApplied() { assumeTrue("Skipping test: " + "config_letterboxIsPolicyForIgnoringRequestedOrientationEnabled not enabled", diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayHashManagerTest.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayHashManagerTest.java index 590dd45e1bc..09b253c51b6 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayHashManagerTest.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayHashManagerTest.java @@ -289,6 +289,8 @@ public class DisplayHashManagerTest { } catch (InterruptedException e) { } + waitForAllActivitiesResumed(); + generateDisplayHash(null); mInstrumentation.runOnMainSync(() -> { @@ -414,6 +416,7 @@ public class DisplayHashManagerTest { committedCallbackLatch.await(WAIT_TIME_S, TimeUnit.SECONDS); } catch (InterruptedException e) { } + waitForAllActivitiesResumed(); byte[] expectedImageHash = new byte[]{-1, -1, 127, -1, -1, -1, 127, 127}; @@ -472,6 +475,7 @@ public class DisplayHashManagerTest { committedCallbackLatch.await(WAIT_TIME_S, TimeUnit.SECONDS); } catch (InterruptedException e) { } + waitForAllActivitiesResumed(); } public static class TestActivity extends Activity { @@ -539,4 +543,13 @@ public class DisplayHashManagerTest { mCountDownLatch.countDown(); } } + + /** + * Waits for all activities to be resumed since image hash could be calculated before the + * activity is resumed due to slower activity transitions. + */ + private void waitForAllActivitiesResumed() { + mWmState.waitForWithAmState(WindowManagerState::allActivitiesResumed, + "All activities should be resumed"); + } } diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java index e17c7ec826d..ab34530b804 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java @@ -53,6 +53,7 @@ import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; +import android.graphics.Point; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -614,7 +615,7 @@ public class SurfaceControlViewHostTests extends ActivityManagerTestBase impleme assertTrue("Failed to tap on embedded parent", tapOnWindow(mInstrumentation, () -> mEmbeddedView.getWindowToken(), - null /* offset */)); + new Point(1, 1) /* offset */)); // When tapping on the parent embedded window, it should gain focus. assertWindowFocused(mEmbeddedView, true); // assert child embedded window does not have focus. 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 7d8098210a1..fdcd640585d 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 @@ -1743,6 +1743,11 @@ public abstract class ActivityManagerTestBase { } LockScreenSession disableLockScreen() { + // Lock credentials need to be cleared before disabling the lock. + if (mLockCredentialSet) { + removeLockCredential(); + mLockCredentialSet = false; + } setLockDisabled(true); return this; } @@ -1866,7 +1871,7 @@ public abstract class ActivityManagerTestBase { * @param lockDisabled true if should disable, false otherwise. */ protected void setLockDisabled(boolean lockDisabled) { - runCommandAndPrintOutput("locksettings set-disabled " + oldIfNeeded() + lockDisabled); + runCommandAndPrintOutput("locksettings set-disabled " + lockDisabled); } @NonNull diff --git a/tests/input/src/android/input/cts/UinputTouchDevice.kt b/tests/input/src/android/input/cts/UinputTouchDevice.kt index 709c922f43e..ceb4506a5db 100644 --- a/tests/input/src/android/input/cts/UinputTouchDevice.kt +++ b/tests/input/src/android/input/cts/UinputTouchDevice.kt @@ -20,6 +20,7 @@ import android.app.Instrumentation import android.content.Context import android.graphics.Point import android.hardware.input.InputManager +import android.server.wm.WindowManagerStateHelper import android.util.Size import android.view.Display import android.view.InputDevice @@ -45,6 +46,8 @@ class UinputTouchDevice( uinputDevice = createDevice(instrumentation, size) inputManager = instrumentation.targetContext.getSystemService(InputManager::class.java)!! associateWith(display) + WindowManagerStateHelper().waitForAppTransitionIdleOnDisplay(display.displayId) + instrumentation.uiAutomation.syncInputTransactions() } private fun injectEvent(events: IntArray) { diff --git a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java index cb611332925..b35128ca9b6 100644 --- a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java +++ b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java @@ -18,7 +18,6 @@ package android.location.cts.fine; import static org.junit.Assert.assertThrows; import static org.junit.Assume.assumeTrue; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; @@ -55,10 +54,11 @@ public class GeocoderTest { private Geocoder mGeocoder; private @Mock Runnable mCallbackRunnable; - private GeocodeListener mListener = new TestGeocodeListener(); + private GeocodeListener mListener; @Before public void setUp() { + mListener = new TestGeocodeListener(mCallbackRunnable); mContext = ApplicationProvider.getApplicationContext(); mGeocoder = new Geocoder(mContext, Locale.US); @@ -69,10 +69,16 @@ public class GeocoderTest { /** * GeocodeListener for tests. For the purposes of this test class, we don't care whether the - * request succeeds or fails. Invokes the mocked runnable so we can verify that that the - * callback is invoked in either case. + * request succeeds or fails. Invokes the runnable so we can verify that the callback is invoked + * in either case. */ - private class TestGeocodeListener implements GeocodeListener { + private static class TestGeocodeListener implements GeocodeListener { + private Runnable mCallbackRunnable; + + TestGeocodeListener(Runnable callbackRunnable) { + this.mCallbackRunnable = callbackRunnable; + } + @Override public void onGeocode(List<Address> addresses) { mCallbackRunnable.run(); @@ -104,7 +110,6 @@ public class GeocoderTest { @ApiTest(apis = "android.location.Geocoder#getFromLocation") @Test public void testGetFromLocation_badInput() { - GeocodeListener listener = mock(GeocodeListener.class); assertThrows( IllegalArgumentException.class, () -> mGeocoder.getFromLocation(-91, 30, 5, mListener)); @@ -139,7 +144,6 @@ public class GeocoderTest { @ApiTest(apis = "android.location.Geocoder#getFromLocationName") @Test public void testGetFromLocationName_badInput() { - GeocodeListener listener = mock(GeocodeListener.class); assertThrows( IllegalArgumentException.class, () -> mGeocoder.getFromLocationName(null, 5, mListener)); @@ -164,8 +168,7 @@ public class GeocoderTest { }) @Test public void testGeocodeListener() { - GeocodeListener listener = mock(GeocodeListener.class); - listener.onGeocode(new ArrayList<>()); - listener.onError(null); + mListener.onGeocode(new ArrayList<>()); + mListener.onError(null); } } diff --git a/tests/media/common/src/android/mediav2/common/cts/CompareStreams.java b/tests/media/common/src/android/mediav2/common/cts/CompareStreams.java index 76745363f67..b6b906864a8 100644 --- a/tests/media/common/src/android/mediav2/common/cts/CompareStreams.java +++ b/tests/media/common/src/android/mediav2/common/cts/CompareStreams.java @@ -16,7 +16,9 @@ package android.mediav2.common.cts; +import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010; import static android.mediav2.common.cts.DecodeStreamToYuv.findDecoderForStream; +import static android.mediav2.common.cts.DecodeStreamToYuv.getFormatInStream; import static android.mediav2.common.cts.DecodeStreamToYuv.getImage; import static android.mediav2.common.cts.VideoErrorManager.computeMSE; import static android.mediav2.common.cts.VideoErrorManager.computePSNR; @@ -31,6 +33,10 @@ import android.media.MediaExtractor; import android.media.MediaFormat; import android.util.Log; +import com.android.compatibility.common.util.MediaUtils; + +import org.junit.Assume; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -260,6 +266,21 @@ public class CompareStreams extends CodecDecoderTestBase { private void generateErrorStats() throws IOException, InterruptedException { if (!mGenerateStats) { + if (MediaUtils.isTv()) { + // Some TV devices support HDR10 display with VO instead of GPU. In this case, + // COLOR_FormatYUVP010 may not be supported. + MediaFormat format = mStreamFormat != null ? mStreamFormat : + getFormatInStream(mMediaType, mTestFile); + ArrayList<MediaFormat> formatList = new ArrayList<>(); + formatList.add(format); + boolean isHBD = doesAnyFormatHaveHDRProfile(mMediaType, formatList); + if (isHBD || mTestFile.contains("10bit")) { + if (!hasSupportForColorFormat(mCodecName, mMediaType, COLOR_FormatYUVP010)) { + Assume.assumeTrue("Could not validate the encoded output as" + + " COLOR_FormatYUVP010 is not supported by the decoder", false); + } + } + } if (mStreamFormat != null) { decodeToMemory(mStreamBuffer, mStreamBufferInfos, mStreamFormat, mCodecName); } else { diff --git a/tests/media/common/src/android/mediav2/common/cts/DecodeStreamToYuv.java b/tests/media/common/src/android/mediav2/common/cts/DecodeStreamToYuv.java index 97bcf73e316..5c3b741f1da 100644 --- a/tests/media/common/src/android/mediav2/common/cts/DecodeStreamToYuv.java +++ b/tests/media/common/src/android/mediav2/common/cts/DecodeStreamToYuv.java @@ -108,7 +108,7 @@ public class DecodeStreamToYuv extends CodecDecoderTestBase { .build(); } - static String findDecoderForStream(String mediaType, String file) throws IOException { + static MediaFormat getFormatInStream(String mediaType, String file) throws IOException { File tmp = new File(file); if (!tmp.exists()) { throw new FileNotFoundException("Test Setup Error, missing file: " + file); @@ -128,7 +128,11 @@ public class DecodeStreamToYuv extends CodecDecoderTestBase { throw new IllegalArgumentException( "No track with mediaType: " + mediaType + " found in file: " + file); } - return findDecoderForFormat(format); + return format; + } + + static String findDecoderForStream(String mediaType, String file) throws IOException { + return findDecoderForFormat(getFormatInStream(mediaType, file)); } static String findDecoderForFormat(MediaFormat format) { diff --git a/tests/surfacecontrol/src/android/view/surfacecontrol/cts/AttachedSurfaceControlTest.java b/tests/surfacecontrol/src/android/view/surfacecontrol/cts/AttachedSurfaceControlTest.java index edfd5ff9737..c34a344aa03 100644 --- a/tests/surfacecontrol/src/android/view/surfacecontrol/cts/AttachedSurfaceControlTest.java +++ b/tests/surfacecontrol/src/android/view/surfacecontrol/cts/AttachedSurfaceControlTest.java @@ -41,6 +41,7 @@ import android.view.Gravity; import android.view.Surface; import android.view.SurfaceControl; import android.view.View; +import android.view.ViewTreeObserver; import android.view.cts.surfacevalidator.BitmapPixelChecker; import android.widget.FrameLayout; @@ -234,7 +235,7 @@ public class AttachedSurfaceControlTest { if (firstCallback[0] != null) { Assert.assertTrue(firstCallback[0].await(3, TimeUnit.SECONDS)); scenario.onActivity(activity -> Assert.assertEquals(transformHintResult[0], - activity.getWindow().getRootSurfaceControl().getBufferTransformHint())); + activity.getWindow().getRootSurfaceControl().getBufferTransformHint())); } scenario.onActivity(activity -> { @@ -266,6 +267,8 @@ public class AttachedSurfaceControlTest { private final CountDownLatch mDrawCompleteLatch = new CountDownLatch(1); + private boolean mChildScAttached; + GreenAnchorViewWithInsets(Context c, Rect insets) { super(c, null, 0, 0); mSurfaceControl = new SurfaceControl.Builder() @@ -277,21 +280,46 @@ public class AttachedSurfaceControlTest { canvas.drawColor(Color.GREEN); mSurface.unlockCanvasAndPost(canvas); mChildBoundingInsets = insets; + + getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + attachChildSc(); + getViewTreeObserver().removeOnPreDrawListener(this); + return true; + } + }); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); + attachChildSc(); + } + + private void attachChildSc() { + if (mChildScAttached) { + return; + } + // This should be called even if buildReparentTransaction fails the first time since + // the second call will come from preDrawListener which is called after bounding insets + // are updated in VRI. + getRootSurfaceControl().setChildBoundingInsets(mChildBoundingInsets); + SurfaceControl.Transaction t = getRootSurfaceControl().buildReparentTransaction(mSurfaceControl); - getRootSurfaceControl().setChildBoundingInsets(mChildBoundingInsets); - t.setLayer(mSurfaceControl, 1) - .setVisibility(mSurfaceControl, true) - .apply(); + if (t == null) { + // TODO (b/286406553) SurfaceControl was not yet setup. Wait until the draw request + // to attach since the SurfaceControl will be created by that point. This can be + // cleaned up when the bug is fixed. + return; + } + t.setLayer(mSurfaceControl, 1).setVisibility(mSurfaceControl, true); t.addTransactionCommittedListener(Runnable::run, mDrawCompleteLatch::countDown); getRootSurfaceControl().applyTransactionOnDraw(t); + mChildScAttached = true; } @Override @@ -299,6 +327,7 @@ public class AttachedSurfaceControlTest { new SurfaceControl.Transaction().reparent(mSurfaceControl, null).apply(); mSurfaceControl.release(); mSurface.release(); + mChildScAttached = false; super.onDetachedFromWindow(); } @@ -335,7 +364,7 @@ public class AttachedSurfaceControlTest { countDownLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS)); view[0].waitForDrawn(); - // Do not include system insets because the child SC is not layed out in the system + // Do not include system insets because the child SC is not laid out in the system // insets validateScreenshot(mName, activity[0], new BitmapPixelChecker(Color.GREEN, new Rect(0, 10, 100, 100)), diff --git a/tests/surfacecontrol/src/android/view/surfacecontrol/cts/SurfaceViewSyncTest.java b/tests/surfacecontrol/src/android/view/surfacecontrol/cts/SurfaceViewSyncTest.java index 0c80ed506f6..ad28177b4a9 100644 --- a/tests/surfacecontrol/src/android/view/surfacecontrol/cts/SurfaceViewSyncTest.java +++ b/tests/surfacecontrol/src/android/view/surfacecontrol/cts/SurfaceViewSyncTest.java @@ -39,7 +39,6 @@ import android.view.cts.surfacevalidator.ViewFactory; import android.widget.FrameLayout; import androidx.test.filters.LargeTest; -import androidx.test.filters.RequiresDevice; import androidx.test.rule.ActivityTestRule; import androidx.test.runner.AndroidJUnit4; @@ -52,7 +51,6 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @LargeTest @SuppressLint("RtlHardcoded") -@RequiresDevice public class SurfaceViewSyncTest { private static final String TAG = "SurfaceViewSyncTests"; diff --git a/tests/tests/database/src/android/database/sqlite/cts/SQLiteDatabaseTest.java b/tests/tests/database/src/android/database/sqlite/cts/SQLiteDatabaseTest.java index 14df6139415..11f739f377c 100644 --- a/tests/tests/database/src/android/database/sqlite/cts/SQLiteDatabaseTest.java +++ b/tests/tests/database/src/android/database/sqlite/cts/SQLiteDatabaseTest.java @@ -2015,10 +2015,15 @@ public class SQLiteDatabaseTest extends AndroidTestCase { "Unexpected version format, expected MAJOR.MINOR.PATCH but was " + fullVersionStr, lastDot > 0); String majorMinor = fullVersionStr.substring(0, lastDot); + int patchLevel = Integer.valueOf(fullVersionStr.substring(lastDot + 1)); + // Temporarily allow 3.42.0. + if (majorMinor.equals("3.42") && patchLevel >= 0) { + // Okay. No further testing required. + return; + } assertEquals( "Expected SQLite library version " + EXPECTED_MAJOR_MINOR_VERSION + ", but was " + fullVersionStr, EXPECTED_MAJOR_MINOR_VERSION, majorMinor); - int patchLevel = Integer.valueOf(fullVersionStr.substring(lastDot + 1)); assertTrue("Expected minimum patch level " + EXPECTED_MIN_PATCH_LEVEL + ", but was " + patchLevel, patchLevel >= EXPECTED_MIN_PATCH_LEVEL); } diff --git a/tests/tests/media/audio/Android.bp b/tests/tests/media/audio/Android.bp index 66e2ff6714d..abe42eebb60 100644 --- a/tests/tests/media/audio/Android.bp +++ b/tests/tests/media/audio/Android.bp @@ -101,8 +101,6 @@ android_test { test_suites: [ "cts", "general-tests", - "mts-media", ], - min_sdk_version: "29", target_sdk_version: "31", } diff --git a/tests/tests/media/audio/src/android/media/audio/cts/AudioCommunicationDeviceTest.java b/tests/tests/media/audio/src/android/media/audio/cts/AudioCommunicationDeviceTest.java index 26edb47634e..aa40d3852c0 100644 --- a/tests/tests/media/audio/src/android/media/audio/cts/AudioCommunicationDeviceTest.java +++ b/tests/tests/media/audio/src/android/media/audio/cts/AudioCommunicationDeviceTest.java @@ -21,6 +21,7 @@ import android.content.pm.PackageManager; import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.os.SystemClock; +import android.platform.test.annotations.AppModeFull; import android.util.Log; import androidx.test.filters.SdkSuppress; @@ -97,6 +98,7 @@ public class AudioCommunicationDeviceTest extends CtsAndroidTestCase { } } + @AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS") public void testSetCommunicationDeviceSuccessModeOwner() { if (!isValidPlatform("testSetValidCommunicationDevice")) return; @@ -141,6 +143,8 @@ public class AudioCommunicationDeviceTest extends CtsAndroidTestCase { } public void testSetCommunicationDeviceDeniedNotModeOwnerNotPrivileged() { + final long kDeviceListenerIdleWaitTimeoutMs = 10000; + if (!isValidPlatform("testSetValidCommunicationDevice")) return; AudioDeviceInfo originalCommDevice = mAudioManager.getCommunicationDevice(); @@ -151,23 +155,38 @@ public class AudioCommunicationDeviceTest extends CtsAndroidTestCase { if (device.getType() == originalCommDevice.getType()) { continue; } - + MyOnCommunicationDeviceChangedListener listener = + new MyOnCommunicationDeviceChangedListener(mAudioManager); try { - mAudioManager.setCommunicationDevice(device); - AudioDeviceInfo commDevice = null; - try { - commDevice = mAudioManager.getCommunicationDevice(); - assertNotNull("Platform has no default communication device", commDevice); - } catch (Exception e) { - fail("getCommunicationDevice failed with exception: " + e); - } - - if (commDevice.getType() != originalCommDevice.getType()) { - fail("setCommunicationDevice not denied, expected device: " - + originalCommDevice.getType() + " but got: " + commDevice.getType()); + mAudioManager.addOnCommunicationDeviceChangedListener( + Executors.newSingleThreadExecutor(), listener); + + listener.setCommunicationDevice(device); + // The following behaviors are acceptable: + // - U: the communication device changes: log a warning to + // track migration to post U QPR1 behavior + // - U QPR1 and after: + // - the communication device does not change OR + // - the communication device changes temporarily and comes back to + // the initial device after the inactivity grace period. + AudioDeviceInfo listenerDevice = listener.getDevice(); + if (listenerDevice != null + && listenerDevice.getType() != originalCommDevice.getType()) { + listener.waitForDeviceUpdate( + originalCommDevice, kDeviceListenerIdleWaitTimeoutMs); + listenerDevice = listener.getDevice(); + if (listenerDevice == null + || listenerDevice.getType() != originalCommDevice.getType()) { + Log.w(TAG, "setCommunicationDevice not denied, expected device: " + + originalCommDevice.getType() + + " but got: " + (listenerDevice == null + ? AudioDeviceInfo.TYPE_UNKNOWN : listenerDevice.getType())); + } } } catch (Exception e) { - fail("setCommunicationDevice failed with exception: " + e); + fail("AudioManager call failed with exception: " + e); + } finally { + mAudioManager.removeOnCommunicationDeviceChangedListener(listener); } } } @@ -193,6 +212,8 @@ public class AudioCommunicationDeviceTest extends CtsAndroidTestCase { static class MyOnCommunicationDeviceChangedListener implements AudioManager.OnCommunicationDeviceChangedListener { + private static final long LISTENER_WAIT_TIMEOUT_MS = 3000; + private final Object mCbLock = new Object(); @GuardedBy("mCbLock") private boolean mCalled; @@ -201,7 +222,6 @@ public class AudioCommunicationDeviceTest extends CtsAndroidTestCase { private final AudioManager mAudioManager; - private static final long LISTENER_WAIT_TIMEOUT_MS = 3000; void reset() { synchronized (mCbLock) { mCalled = false; @@ -210,14 +230,23 @@ public class AudioCommunicationDeviceTest extends CtsAndroidTestCase { } AudioDeviceInfo waitForDeviceUpdate() { - return waitForDeviceUpdateTo(null); + return waitForDeviceUpdateTo(null, LISTENER_WAIT_TIMEOUT_MS); + } + + AudioDeviceInfo waitForDeviceUpdate(AudioDeviceInfo device) { + return waitForDeviceUpdateTo(device, LISTENER_WAIT_TIMEOUT_MS); + } + + AudioDeviceInfo waitForDeviceUpdate(AudioDeviceInfo device, long timeoutMs) { + return waitForDeviceUpdateTo(device, timeoutMs); } // Waits for the communication device to be the one passed as argument. - // If the device passed is null, it will wait unconditionnaly for the listener to be called - private AudioDeviceInfo waitForDeviceUpdateTo(AudioDeviceInfo device) { + // If the device passed is null, it will wait unconditionally for the listener to be called + private AudioDeviceInfo waitForDeviceUpdateTo(AudioDeviceInfo device, + long timeoutMs) { synchronized (mCbLock) { - long endTimeMillis = SystemClock.uptimeMillis() + LISTENER_WAIT_TIMEOUT_MS; + long endTimeMillis = SystemClock.uptimeMillis() + timeoutMs; long waiTimeMillis = endTimeMillis - SystemClock.uptimeMillis(); while (((device != null && !device.equals(mAudioManager.getCommunicationDevice())) || !mCalled) && (waiTimeMillis > 0)) { @@ -233,7 +262,7 @@ public class AudioCommunicationDeviceTest extends CtsAndroidTestCase { void setCommunicationDevice(AudioDeviceInfo device) { mAudioManager.setCommunicationDevice(device); - waitForDeviceUpdateTo(device); + waitForDeviceUpdateTo(device, LISTENER_WAIT_TIMEOUT_MS); } AudioDeviceInfo getDevice() { @@ -257,6 +286,7 @@ public class AudioCommunicationDeviceTest extends CtsAndroidTestCase { } } + @AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS") public void testCommunicationDeviceListener() { if (!isValidPlatform("testCommunicationDeviceListener")) return; diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeOnlyTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeOnlyTest.java index 8b25bcde25e..93ab0d1c8bd 100644 --- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeOnlyTest.java +++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeOnlyTest.java @@ -37,6 +37,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; +import android.os.SystemProperties; import android.platform.test.annotations.AppModeFull; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -72,6 +73,10 @@ import java.util.function.Supplier; @RunWith(AndroidJUnit4.class) @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public class DecodeOnlyTest extends MediaTestBase { + public static final boolean IS_BOARD_AT_LEAST_U = + SystemProperties.getInt("ro.board.api_level", Build.VERSION_CODES.CUR_DEVELOPMENT) + >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE; + private static final String MEDIA_DIR_STRING = WorkDir.getMediaDirString(); private static final String HEVC_VIDEO = "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv"; @@ -102,36 +107,48 @@ public class DecodeOnlyTest extends MediaTestBase { @Test @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledPerfectSeekInitialPeekOnAvc() throws Exception { + // Tunnel mode requires vendor support of the DECODE_ONLY feature + Assume.assumeTrue("Board API level is not Android 14 or later.", IS_BOARD_AT_LEAST_U); testTunneledPerfectSeek(AVC_VIDEO, true); } @Test @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledPerfectSeekInitialPeekOnVp9() throws Exception { + // Tunnel mode requires vendor support of the DECODE_ONLY feature + Assume.assumeTrue("Board API level is not Android 14 or later.", IS_BOARD_AT_LEAST_U); testTunneledPerfectSeek(VP9_VIDEO, true); } @Test @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledPerfectSeekInitialPeekOnHevc() throws Exception { + // Tunnel mode requires vendor support of the DECODE_ONLY feature + Assume.assumeTrue("Board API level is not Android 14 or later.", IS_BOARD_AT_LEAST_U); testTunneledPerfectSeek(HEVC_VIDEO, true); } @Test @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledPerfectSeekInitialPeekOffAvc() throws Exception { + // Tunnel mode requires vendor support of the DECODE_ONLY feature + Assume.assumeTrue("Board API level is not Android 14 or later.", IS_BOARD_AT_LEAST_U); testTunneledPerfectSeek(AVC_VIDEO, false); } @Test @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledPerfectSeekInitialPeekOffVp9() throws Exception { + // Tunnel mode requires vendor support of the DECODE_ONLY feature + Assume.assumeTrue("Board API level is not Android 14 or later.", IS_BOARD_AT_LEAST_U); testTunneledPerfectSeek(VP9_VIDEO, false); } @Test @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledPerfectSeekInitialPeekOffHevc() throws Exception { + // Tunnel mode requires vendor support of the DECODE_ONLY feature + Assume.assumeTrue("Board API level is not Android 14 or later.", IS_BOARD_AT_LEAST_U); testTunneledPerfectSeek(HEVC_VIDEO, false); } @@ -141,18 +158,24 @@ public class DecodeOnlyTest extends MediaTestBase { @Test @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledTrickPlayHevc() throws Exception { + // Tunnel mode requires vendor support of the DECODE_ONLY feature + Assume.assumeTrue("Board API level is not Android 14 or later.", IS_BOARD_AT_LEAST_U); testTunneledTrickPlay(HEVC_VIDEO); } @Test @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledTrickPlayAvc() throws Exception { + // Tunnel mode requires vendor support of the DECODE_ONLY feature + Assume.assumeTrue("Board API level is not Android 14 or later.", IS_BOARD_AT_LEAST_U); testTunneledTrickPlay(AVC_VIDEO); } @Test @ApiTest(apis = {"android.media.MediaCodec#BUFFER_FLAG_DECODE_ONLY"}) public void testTunneledTrickPlayVp9() throws Exception { + // Tunnel mode requires vendor support of the DECODE_ONLY feature + Assume.assumeTrue("Board API level is not Android 14 or later.", IS_BOARD_AT_LEAST_U); testTunneledTrickPlay(VP9_VIDEO); } diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java index ee4e37b6e41..b6d428327f8 100644 --- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java +++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java @@ -59,6 +59,7 @@ import android.media.cts.TestUtils; import android.net.Uri; import android.os.Build; import android.os.ParcelFileDescriptor; +import android.os.SystemProperties; import android.platform.test.annotations.AppModeFull; import android.util.Log; import android.view.Surface; @@ -107,10 +108,14 @@ import java.util.zip.CRC32; public class DecoderTest extends MediaTestBase { private static final String TAG = "DecoderTest"; private static final String REPORT_LOG_NAME = "CtsMediaDecoderTestCases"; - private static boolean mIsAtLeastR = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R); - private static boolean sIsBeforeS = ApiLevelUtil.isBefore(Build.VERSION_CODES.S); - private static boolean sIsAfterT = ApiLevelUtil.isAfter(Build.VERSION_CODES.TIRAMISU) - || ApiLevelUtil.codenameEquals("UpsideDownCake"); + + private static final int BOARD_SDK_LEVEL = + SystemProperties.getInt("ro.board.api_level", Build.VERSION_CODES.CUR_DEVELOPMENT); + public static final boolean IS_BOARD_AT_LEAST_S = BOARD_SDK_LEVEL >= Build.VERSION_CODES.S; + + private static boolean IS_AT_LEAST_R = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R); + private static boolean IS_BEFORE_S = ApiLevelUtil.isBefore(Build.VERSION_CODES.S); + private static boolean IS_AFTER_T = ApiLevelUtil.isAfter(Build.VERSION_CODES.TIRAMISU); private static final int RESET_MODE_NONE = 0; private static final int RESET_MODE_RECONFIGURE = 1; @@ -369,7 +374,7 @@ public class DecoderTest extends MediaTestBase { private void verifyChannelsAndRates(String[] mimetypes, int[] sampleRates, int[] channelMasks) throws Exception { - if (!MediaUtils.check(mIsAtLeastR, "test invalid before Android 11")) return; + if (!MediaUtils.check(IS_AT_LEAST_R, "test invalid before Android 11")) return; for (String mimetype : mimetypes) { // ensure we find a codec for all listed mime/channel/rate combinations @@ -1487,7 +1492,7 @@ public class DecoderTest extends MediaTestBase { throws IOException { // CODEC_DEFAULT behaviors started with S - if (sIsBeforeS) { + if (IS_BEFORE_S) { codecSupportMode = CODEC_ALL; } MediaExtractor ex = new MediaExtractor(); @@ -1515,7 +1520,7 @@ public class DecoderTest extends MediaTestBase { continue; } if (codecSupportMode == CODEC_ALL) { - if (sIsAfterT) { + if (IS_AFTER_T) { // This is an extractor failure as often as it is a codec failure assertTrue(info.getName() + " does not declare support for " + format.toString(), @@ -3525,6 +3530,8 @@ public class DecoderTest extends MediaTestBase { @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"}) @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testTunneledVideoPeekOnHevc() throws Exception { + // Requires vendor support of the TUNNEL_PEEK feature + Assume.assumeTrue("Board API level is not Android 12 or later.", IS_BOARD_AT_LEAST_S); testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_HEVC, "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv", 25); } @@ -3536,6 +3543,8 @@ public class DecoderTest extends MediaTestBase { @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"}) @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testTunneledVideoPeekOnAvc() throws Exception { + // Requires vendor support of the TUNNEL_PEEK feature + Assume.assumeTrue("Board API level is not Android 12 or later.", IS_BOARD_AT_LEAST_S); testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_AVC, "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4", 25); } @@ -3547,12 +3556,13 @@ public class DecoderTest extends MediaTestBase { @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"}) @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testTunneledVideoPeekOnVp9() throws Exception { + // Requires vendor support of the TUNNEL_PEEK feature + Assume.assumeTrue("Board API level is not Android 12 or later.", IS_BOARD_AT_LEAST_S); testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm", 30); } - /** * Test that peek off doesn't render the first frame until turned on in tunneled mode. * @@ -3618,6 +3628,8 @@ public class DecoderTest extends MediaTestBase { @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"}) @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testTunneledVideoPeekOffHevc() throws Exception { + // Requires vendor support of the TUNNEL_PEEK feature + Assume.assumeTrue("Board API level is not Android 12 or later.", IS_BOARD_AT_LEAST_S); testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_HEVC, "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv", 25); } @@ -3629,6 +3641,8 @@ public class DecoderTest extends MediaTestBase { @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"}) @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testTunneledVideoPeekOffAvc() throws Exception { + // Requires vendor support of the TUNNEL_PEEK feature + Assume.assumeTrue("Board API level is not Android 12 or later.", IS_BOARD_AT_LEAST_S); testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_AVC, "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4", 25); } @@ -3640,6 +3654,8 @@ public class DecoderTest extends MediaTestBase { @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"}) @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public void testTunneledVideoPeekOffVp9() throws Exception { + // Requires vendor support of the TUNNEL_PEEK feature + Assume.assumeTrue("Board API level is not Android 12 or later.", IS_BOARD_AT_LEAST_S); testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm", 30); diff --git a/tests/tests/media/encoder/src/android/media/encoder/cts/EncoderTest.java b/tests/tests/media/encoder/src/android/media/encoder/cts/EncoderTest.java index cbfb26d00fd..0a4d19ee337 100644 --- a/tests/tests/media/encoder/src/android/media/encoder/cts/EncoderTest.java +++ b/tests/tests/media/encoder/src/android/media/encoder/cts/EncoderTest.java @@ -69,7 +69,7 @@ public class EncoderTest { static final String mInpPrefix = WorkDir.getMediaDirString(); private static final int kNumInputBytes = 512 * 1024; private static final long kTimeoutUs = 100; - public static final int PER_TEST_TIMEOUT_SMALL_TEST_MS = 60000; + public static final int PER_TEST_TIMEOUT_SMALL_TEST_MS = 120000; // not all combinations are valid private static final int MODE_SILENT = 0; diff --git a/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivityBase.java b/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivityBase.java index 110ad390870..e20cc3306ac 100644 --- a/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivityBase.java +++ b/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivityBase.java @@ -135,6 +135,7 @@ public class ResourceManagerTestActivityBase extends Activity { Bundle extras = getIntent().getExtras(); int type = TYPE_NONSECURE; boolean highResolution = false; + boolean isResolutionSet = true; if (extras != null) { type = extras.getInt("test-type", type); // Check if mime has been passed. @@ -144,7 +145,8 @@ public class ResourceManagerTestActivityBase extends Activity { mHeight = extras.getInt("height"); if (mWidth == 0 || mHeight == 0) { // Either no resolution has been passed or its invalid. - // So, look for high-resolution flag. + isResolutionSet = false; + // See if the high-resolution flag has been set. highResolution = extras.getBoolean("high-resolution", highResolution); } else if (mHeight >= 1080) { highResolution = true; @@ -167,6 +169,12 @@ public class ResourceManagerTestActivityBase extends Activity { if (!shouldSkip) { if (type == TYPE_SECURE || type == TYPE_MIX) { + if (!isResolutionSet && type == TYPE_MIX) { + // clear previously set resolutions by the unsecure codecs, + // so that we read the secure codec resolutions again. + mWidth = 0; + mHeight = 0; + } securePlayback = true; MediaCodecInfo info = getTestCodecInfo(securePlayback); if (info != null) { diff --git a/tests/tests/notification/src/android/app/notification/current/cts/NotificationManagerTest.java b/tests/tests/notification/src/android/app/notification/current/cts/NotificationManagerTest.java index e1cfbca5636..c56fadd878b 100755 --- a/tests/tests/notification/src/android/app/notification/current/cts/NotificationManagerTest.java +++ b/tests/tests/notification/src/android/app/notification/current/cts/NotificationManagerTest.java @@ -2413,16 +2413,20 @@ public class NotificationManagerTest extends BaseNotificationManagerTest { List<String> allowedPackages = Arrays.asList( mPackageManager.getPermissionControllerPackageName(), "com.android.shell"); + StringBuilder sb = new StringBuilder(); for (PackageInfo pkg : allPackages) { if (!pkg.applicationInfo.isSystemApp() && mPackageManager.checkPermission( Manifest.permission.MANAGE_NOTIFICATION_LISTENERS, pkg.packageName) == PackageManager.PERMISSION_GRANTED && !allowedPackages.contains(pkg.packageName)) { - fail(pkg.packageName + " can't hold " - + Manifest.permission.MANAGE_NOTIFICATION_LISTENERS); + sb.append(pkg.packageName + " can't hold " + + Manifest.permission.MANAGE_NOTIFICATION_LISTENERS + "\n"); } } + if (sb.length() > 0) { + fail(sb.toString()); + } } public void testChannelDeletion_cancelReason() throws Exception { diff --git a/tests/tests/permission/src/android/permission/cts/ShellCommandPermissionTest.java b/tests/tests/permission/src/android/permission/cts/ShellCommandPermissionTest.java index e70f07bcea0..54562d5ee3a 100644 --- a/tests/tests/permission/src/android/permission/cts/ShellCommandPermissionTest.java +++ b/tests/tests/permission/src/android/permission/cts/ShellCommandPermissionTest.java @@ -16,7 +16,8 @@ package android.permission.cts; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.fail; import androidx.test.runner.AndroidJUnit4; @@ -24,36 +25,23 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import java.io.BufferedReader; -import java.io.InputStreamReader; - /** * Test shell command capability enforcement */ @RunWith(AndroidJUnit4.class) public class ShellCommandPermissionTest { - private void executeShellCommandAndRequireError(String command, String required) + static final int EXPECTED_ERROR_CODE = 255; + + /** + * Runs the given command, waits for it to exit, and verifies the return + * code indicates failure. + */ + private void executeShellCommandAndWaitForError(String command) throws Exception { try { java.lang.Process proc = Runtime.getRuntime().exec(command); - - // read output of command - BufferedReader reader = - new BufferedReader(new InputStreamReader(proc.getErrorStream())); - StringBuilder stderr = new StringBuilder(); - String line = reader.readLine(); - while (line != null) { - stderr.append(line); - line = reader.readLine(); - } - reader.close(); - proc.waitFor(); - - String stderrString = stderr.toString(); - assertTrue("Expected command stderr '" + stderrString - + " to contain '" + required + "'", - stderrString.contains(required)); + assertThat(proc.waitFor()).isEqualTo(EXPECTED_ERROR_CODE); } catch (InterruptedException e) { fail("Unsuccessful shell command"); } @@ -61,15 +49,13 @@ public class ShellCommandPermissionTest { @Test public void testTraceIpc() throws Exception { - executeShellCommandAndRequireError( - "cmd activity trace-ipc stop --dump-file /data/system/last-fstrim", - "Error:"); + executeShellCommandAndWaitForError( + "cmd activity trace-ipc stop --dump-file /data/system/last-fstrim"); } @Test public void testDumpheap() throws Exception { - executeShellCommandAndRequireError( - "cmd activity dumpheap system_server /data/system/last-fstrim", - "Error:"); + executeShellCommandAndWaitForError( + "cmd activity dumpheap system_server /data/system/last-fstrim"); } } diff --git a/tests/tests/permission3/src/android/permission3/cts/ReviewAccessibilityServicesTest.kt b/tests/tests/permission3/src/android/permission3/cts/ReviewAccessibilityServicesTest.kt index e42cc748912..c1fe8671833 100644 --- a/tests/tests/permission3/src/android/permission3/cts/ReviewAccessibilityServicesTest.kt +++ b/tests/tests/permission3/src/android/permission3/cts/ReviewAccessibilityServicesTest.kt @@ -51,6 +51,7 @@ class ReviewAccessibilityServicesTest { private val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) private val testService1String = context.getString(R.string.test_accessibility_service) private val testService2String = context.getString(R.string.test_accessibility_service_2) + private val packageName = context.packageManager.permissionControllerPackageName companion object { private const val EXPECTED_TIMEOUT_MS = 500L @@ -171,7 +172,10 @@ class ReviewAccessibilityServicesTest { private fun waitForSettingsButtonToDisappear() { SystemUtil.eventually { - findObjectByText(false, "Settings") + findPCObjectByClassAndText(false, + "android.widget.Button", + "Settings" + ) } } @@ -196,6 +200,21 @@ class ReviewAccessibilityServicesTest { return findObjectByTextWithoutRetry(expected, text) } } + + private fun findPCObjectByClassAndText( + shouldBePresent: Boolean, + className: String, + text: String + ): UiObject2? { + val selector = By.pkg(packageName) + .clazz(className) + .text(text) + val view = waitFindObjectOrNull(selector) + assertEquals( + "Expected to find view with packageName '$packageName' className '$className' " + + "text '$text' : $shouldBePresent", shouldBePresent, view != null) + return view + } } /** Test Accessibility Services */ diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_39738.java b/tests/tests/security/src/android/security/cts/CVE_2021_39738.java new file mode 100644 index 00000000000..7d8daea9f89 --- /dev/null +++ b/tests/tests/security/src/android/security/cts/CVE_2021_39738.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +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_39738 extends StsExtraBusinessLogicTestCase { + + @AsbSecurityTest(cveBugId = 216190509) + @Test + public void testPocCVE_2021_39738() { + try { + Context context = getApplicationContext(); + PackageManager pm = context.getPackageManager(); + + // Skip test for non-automotive builds + assumeTrue( + "Skipping test: " + PackageManager.FEATURE_AUTOMOTIVE + " missing", + pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)); + + // BluetoothPairingDialog activity should require BLUETOOTH_PRIVILEGED permission + final String pkgName = "com.android.car.settings"; + ComponentName component = + new ComponentName(pkgName, pkgName + ".bluetooth.BluetoothPairingDialog"); + String permission = pm.getActivityInfo(component, 0 /* flags */).permission; + assertTrue( + "Vulnerable to b/216190509", + permission.contains(android.Manifest.permission.BLUETOOTH_PRIVILEGED)); + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/tests/tests/telephony/current/AndroidTest.xml b/tests/tests/telephony/current/AndroidTest.xml index 8fcbc6098e1..947443bb32d 100644 --- a/tests/tests/telephony/current/AndroidTest.xml +++ b/tests/tests/telephony/current/AndroidTest.xml @@ -65,4 +65,8 @@ <option name="run-command" value="setprop persist.radio.allow_mock_modem true" /> <option name="teardown-command" value="setprop persist.radio.allow_mock_modem false" /> </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer" > + <option name="flag-value" value="telephony/com.android.internal.telephony.flags.oem_enabled_satellite_flag=true" /> + <option name="flag-value" value="telephony/com.android.internal.telephony.flags.carrier_enabled_satellite_flag=true" /> + </target_preparer> </configuration> diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigBase.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigBase.java index 5642a5fbe16..7a462d17538 100644 --- a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigBase.java +++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigBase.java @@ -227,6 +227,9 @@ public class MockModemConfigBase implements MockModemConfigInterface { case 1: imei = new String(MockModemConfigInterface.DEFAULT_PHONE2_IMEI); break; + case 2: + imei = new String(MockModemConfigInterface.DEFAULT_PHONE3_IMEI); + break; default: imei = new String(MockModemConfigInterface.DEFAULT_PHONE1_IMEI); break; @@ -243,6 +246,9 @@ public class MockModemConfigBase implements MockModemConfigInterface { case 1: imeisv = new String(MockModemConfigInterface.DEFAULT_PHONE2_IMEISV); break; + case 2: + imeisv = new String(MockModemConfigInterface.DEFAULT_PHONE3_IMEISV); + break; default: imeisv = new String(MockModemConfigInterface.DEFAULT_PHONE1_IMEISV); break; @@ -259,6 +265,9 @@ public class MockModemConfigBase implements MockModemConfigInterface { case 1: esn = new String(MockModemConfigInterface.DEFAULT_PHONE2_ESN); break; + case 2: + esn = new String(MockModemConfigInterface.DEFAULT_PHONE3_ESN); + break; default: esn = new String(MockModemConfigInterface.DEFAULT_PHONE1_ESN); break; @@ -275,6 +284,9 @@ public class MockModemConfigBase implements MockModemConfigInterface { case 1: meid = new String(MockModemConfigInterface.DEFAULT_PHONE2_MEID); break; + case 2: + meid = new String(MockModemConfigInterface.DEFAULT_PHONE3_MEID); + break; default: meid = new String(MockModemConfigInterface.DEFAULT_PHONE1_MEID); break; @@ -523,6 +535,13 @@ public class MockModemConfigBase implements MockModemConfigInterface { mMeid[i] = MockModemConfigInterface.DEFAULT_PHONE2_MEID; mImeiType[i] = MockModemConfigInterface.DEFAULT_PHONE2_IMEITYPE; break; + case 2: + mImei[i] = MockModemConfigInterface.DEFAULT_PHONE3_IMEI; + mImeiSv[i] = MockModemConfigInterface.DEFAULT_PHONE3_IMEISV; + mEsn[i] = MockModemConfigInterface.DEFAULT_PHONE3_ESN; + mMeid[i] = MockModemConfigInterface.DEFAULT_PHONE3_MEID; + mImeiType[i] = MockModemConfigInterface.DEFAULT_PHONE3_IMEITYPE; + break; default: mImei[i] = MockModemConfigInterface.DEFAULT_PHONE1_IMEI; mImeiSv[i] = MockModemConfigInterface.DEFAULT_PHONE1_IMEISV; @@ -554,6 +573,7 @@ public class MockModemConfigBase implements MockModemConfigInterface { MockModemConfigInterface.DEFAULT_IS_INTERNAL_LINGERING_SUPPORTED; phoneCapability.logicalModemIds[0] = MockModemConfigInterface.DEFAULT_LOGICAL_MODEM1_ID; phoneCapability.logicalModemIds[1] = MockModemConfigInterface.DEFAULT_LOGICAL_MODEM2_ID; + phoneCapability.logicalModemIds[2] = MockModemConfigInterface.DEFAULT_LOGICAL_MODEM3_ID; } private void updateSimSlotStatus() { diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigInterface.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigInterface.java index afead886278..cd76dc1d77c 100644 --- a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigInterface.java +++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigInterface.java @@ -27,7 +27,7 @@ public interface MockModemConfigInterface { // ***** Constants int MAX_NUM_OF_SIM_SLOT = 3; // Change this needs to add more SIM SLOT NVs. - int MAX_NUM_OF_LOGICAL_MODEM = 2; // Change this needs to add more MODEM NVs. + int MAX_NUM_OF_LOGICAL_MODEM = 3; // Change this needs to add more MODEM NVs. int RADIO_STATE_UNAVAILABLE = 0; int RADIO_STATE_OFF = 1; int RADIO_STATE_ON = 2; @@ -46,6 +46,12 @@ public interface MockModemConfigInterface { String DEFAULT_PHONE2_ESN = "987654321"; String DEFAULT_PHONE2_MEID = "987654321543210"; int DEFAULT_PHONE2_IMEITYPE = ImeiInfo.ImeiType.SECONDARY; + // PHONE3 + String DEFAULT_PHONE3_IMEI = "987654321012345"; + String DEFAULT_PHONE3_IMEISV = "03"; + String DEFAULT_PHONE3_ESN = "192837465"; + String DEFAULT_PHONE3_MEID = "987654321012345"; + int DEFAULT_PHONE3_IMEITYPE = ImeiInfo.ImeiType.SECONDARY; int DEFAULT_RADIO_STATE = RADIO_STATE_UNAVAILABLE; int DEFAULT_NUM_OF_LIVE_MODEM = 1; // Should <= MAX_NUM_OF_MODEM @@ -54,6 +60,7 @@ public interface MockModemConfigInterface { boolean DEFAULT_IS_INTERNAL_LINGERING_SUPPORTED = false; int DEFAULT_LOGICAL_MODEM1_ID = 0; int DEFAULT_LOGICAL_MODEM2_ID = 1; + int DEFAULT_LOGICAL_MODEM3_ID = 2; // ***** Methods void destroy(); diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java index b11003292d7..caa9224238f 100644 --- a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java +++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java @@ -64,6 +64,8 @@ public class MockModemService extends Service { public static final byte PHONE_ID_0 = 0x00; public static final byte PHONE_ID_1 = 0x01; + public static final byte PHONE_ID_2 = 0x02; + public static final byte MAX_PHONE_NUM = 3; public static final int LATCH_MOCK_MODEM_SERVICE_READY = 0; public static final int LATCH_RADIO_INTERFACES_READY = 1; @@ -99,6 +101,10 @@ public class MockModemService extends Service { mNumOfPhone = mTelephonyManager.getActiveModemCount(); Log.d(TAG, "Support number of phone = " + mNumOfPhone + ", number of SIM = " + mNumOfSim); + if (mNumOfPhone > MAX_PHONE_NUM) { + mNumOfPhone = MAX_PHONE_NUM; + } + // Number of physical Sim slot should be equals to or greater than number of phone. if (mNumOfSim < mNumOfPhone) { mNumOfSim = mNumOfPhone; @@ -181,7 +187,7 @@ public class MockModemService extends Service { byte phoneId = intent.getByteExtra(PHONE_ID, PHONE_ID_0); - if (phoneId > PHONE_ID_1) { + if (phoneId >= MAX_PHONE_NUM) { Log.e(TAG, "Not suuport for phone " + phoneId); return null; } diff --git a/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java b/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java index 77e1c969df3..e22db02e333 100644 --- a/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java +++ b/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java @@ -27,8 +27,10 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; + import android.Manifest; import android.app.Instrumentation; import android.content.BroadcastReceiver; @@ -44,6 +46,7 @@ import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.ParcelFileDescriptor; +import android.os.SystemProperties; import android.provider.Telephony.Sms; import android.provider.Telephony.Sms.Intents; import android.telecom.PhoneAccount; @@ -105,7 +108,8 @@ public class VisualVoicemailServiceTest { public void setUp() throws Exception { mContext = getInstrumentation().getContext(); assumeTrue(hasFeatureSupported(mContext)); - + // The tests run on real modem with visual voicemail SMS. + assumeFalse(isEmulator()); mPreviousDefaultDialer = getDefaultDialer(getInstrumentation()); setDefaultDialer(getInstrumentation(), PACKAGE); @@ -714,4 +718,9 @@ public class VisualVoicemailServiceTest { } } } + + private static boolean isEmulator() { + return SystemProperties.getBoolean("ro.boot.qemu", false) + || SystemProperties.getBoolean("ro.kernel.qemu", false); + } } diff --git a/tests/tests/text/src/android/text/method/cts/TouchTest.java b/tests/tests/text/src/android/text/method/cts/TouchTest.java index 127b87cb72b..8e80d42a7f6 100644 --- a/tests/tests/text/src/android/text/method/cts/TouchTest.java +++ b/tests/tests/text/src/android/text/method/cts/TouchTest.java @@ -26,7 +26,6 @@ import android.text.Layout; import android.text.SpannableString; import android.text.TextPaint; import android.text.method.Touch; -import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.MotionEvent; import android.view.ViewGroup; @@ -115,19 +114,17 @@ public class TouchTest { @Test public void testOnTouchEvent() throws Throwable { // Create a string that is wider than the screen. - DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics(); - int screenWidth = metrics.widthPixels; + int rootViewWidth = mActivity.getWindow().getDecorView().getWidth(); TextPaint paint = mTextView.getPaint(); String text = LONG_TEXT; int textWidth = Math.round(paint.measureText(text)); - while (textWidth < screenWidth) { + while (textWidth < rootViewWidth) { text += LONG_TEXT; textWidth = Math.round(paint.measureText(text)); } // Drag the difference between the text width and the screen width. - int dragAmount = Math.min(screenWidth, textWidth - screenWidth); - assertTrue(dragAmount > 0); + int dragAmount = Math.min(rootViewWidth, textWidth - rootViewWidth); final String finalText = text; final SpannableString spannable = new SpannableString(finalText); mActivityRule.runOnUiThread(() -> { diff --git a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java index c30f9ca1027..38516f07d06 100644 --- a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java +++ b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java @@ -633,7 +633,7 @@ public class LinkifyTest { @Test public void testAddLinks_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld() { - String url = "thank.you"; + String url = "thank.unknowntld"; verifyAddLinksWithWebUrlFails("Should not match URL that does not start with a protocol " + "and does not contain a known TLD", url); } @@ -647,7 +647,7 @@ public class LinkifyTest { @Test public void testAddLinks_doesNotMatchUrlsWithEmojiWithoutProtocolAndWithoutKnownTld() { - String url = "Thank\u263A.you"; + String url = "Thank\u263A.unknowntld"; verifyAddLinksWithWebUrlFails("Should not match URLs containing emoji and with unknown " + "TLD", url); } diff --git a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerFrontendTest.java b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerFrontendTest.java index 1a65c659d6c..6644d1f20f8 100644 --- a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerFrontendTest.java +++ b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerFrontendTest.java @@ -644,7 +644,6 @@ public class TunerFrontendTest { assertEquals(1, settings.getFrequencyLong()); assertEquals(AnalogFrontendSettings.SIGNAL_TYPE_NTSC, settings.getSignalType()); assertEquals(AnalogFrontendSettings.SIF_BG_NICAM, settings.getSifStandard()); - assertEquals(AnalogFrontendSettings.AFT_FLAG_TRUE, settings.getAftFlag()); if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) { assertEquals(AnalogFrontendSettings.AFT_FLAG_TRUE, settings.getAftFlag()); assertEquals(FrontendSettings.FRONTEND_SPECTRAL_INVERSION_NORMAL, @@ -776,11 +775,11 @@ public class TunerFrontendTest { assertEquals(3, settings.getSymbolRate()); assertEquals(DvbcFrontendSettings.OUTER_FEC_OUTER_FEC_RS, settings.getOuterFec()); assertEquals(DvbcFrontendSettings.ANNEX_B, settings.getAnnex()); - assertEquals(DvbcFrontendSettings.TIME_INTERLEAVE_MODE_AUTO, - settings.getTimeInterleaveMode()); assertEquals(FrontendSettings.FRONTEND_SPECTRAL_INVERSION_NORMAL, settings.getSpectralInversion()); if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) { + assertEquals(DvbcFrontendSettings.TIME_INTERLEAVE_MODE_AUTO, + settings.getTimeInterleaveMode()); assertEquals(100, settings.getEndFrequencyLong()); assertEquals(DvbcFrontendSettings.BANDWIDTH_5MHZ, settings.getBandwidth()); } else { diff --git a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java index 353c5a4263e..72093a961de 100644 --- a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java +++ b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java @@ -1159,6 +1159,7 @@ public class TunerTest { // TODO: get real CiCam id from MediaCas res = mTuner.connectFrontendToCiCam(0); } else { + res = mTuner.connectFrontendToCiCam(0); assertEquals(Tuner.INVALID_LTS_ID, mTuner.connectFrontendToCiCam(0)); } @@ -1403,12 +1404,12 @@ public class TunerTest { assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId()); DownloadSettings.Builder builder = DownloadSettings.builder(Filter.TYPE_MMTP); - if (!TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) { + if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_2_0)) { builder.setUseDownloadId(true); } builder.setDownloadId(2); DownloadSettings settings = builder.build(); - if (!TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) { + if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_2_0)) { assertEquals(settings.useDownloadId(), true); } else { assertEquals(settings.useDownloadId(), false); diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt index 08666e20809..110061d5cad 100644 --- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt +++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt @@ -26,6 +26,7 @@ import android.uirendering.cts.R import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.WindowManager import androidx.annotation.Nullable import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue @@ -88,6 +89,8 @@ class DrawActivity : Activity() { mHandler = RenderSpecHandler() setContentView(R.layout.test_container) + window.attributes.layoutInDisplayCutoutMode = + WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS mTestContainer = findViewById(R.id.test_content_wrapper) } diff --git a/tests/tests/voiceinteraction/AndroidTest.xml b/tests/tests/voiceinteraction/AndroidTest.xml index 6191ac9a462..a69379fb04f 100644 --- a/tests/tests/voiceinteraction/AndroidTest.xml +++ b/tests/tests/voiceinteraction/AndroidTest.xml @@ -49,4 +49,11 @@ <option name="package" value="android.voiceinteraction.cts" /> <option name="runtime-hint" value="11m" /> </test> + + <!-- This test is included as part of GTS 11 but is built against U SDK. + Skip on non-U devices. --> + <object type="module_controller" + class="com.android.tradefed.testtype.suite.module.MinApiLevelModuleController"> + <option name="min-api-level" value="34" /> + </object> </configuration> diff --git a/tools/cts-device-info/Android.bp b/tools/cts-device-info/Android.bp index e7cf2f95ec3..b1287827b34 100644 --- a/tools/cts-device-info/Android.bp +++ b/tools/cts-device-info/Android.bp @@ -96,7 +96,5 @@ genrule { " -lo androidx.window.sidecar " + " -p com.android.compatibility.common.deviceinfo " + " -i androidx.test.runner.AndroidJUnitRunner " + - " -s 23 " + - " -t 23 " + " -o $(out)", } diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml index 31e7af0a43c..0ad645eab21 100644 --- a/tools/cts-tradefed/res/config/cts-known-failures.xml +++ b/tools/cts-tradefed/res/config/cts-known-failures.xml @@ -111,9 +111,6 @@ <!-- b/64221494 --> <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testAospSeappContexts" /> - <!-- b/63378294 b/64382381 --> - <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxNeverallowRulesTest#testNeverallowRules440" /> - <!-- b/36686383 --> <option name="compatibility:exclude-filter" value="CtsIncidentHostTestCases com.android.server.cts.ErrorsTest#testANR" /> @@ -307,4 +304,8 @@ <!-- b/296988493 --> <option name="compatibility:exclude-filter" value="CtsFrameRateOverrideTestCases com.android.cts.graphics.framerateoverride.FrameRateOverrideHostTest" /> <option name="compatibility:exclude-filter" value="CtsFrameRateOverrideTestCases[instant] com.android.cts.graphics.framerateoverride.FrameRateOverrideHostTest" /> + + <!-- b/303631162 --> + <option name="compatibility:exclude-filter" value="CtsTelephonyTestCases android.telephony.ims.cts.ImsCallingTest#testCallJoinExistingConferenceCallAfterCallSwap" /> + <option name="compatibility:exclude-filter" value="CtsTelephonyTestCases android.telephony.ims.cts.ImsCallingTest#testCallJoinExistingConferenceCallAfterCallSwapFail" /> </configuration> diff --git a/tools/cts-tradefed/res/config/cts-on-aosp-exclude.xml b/tools/cts-tradefed/res/config/cts-on-aosp-exclude.xml index fad97b9aa54..dc5bb27e5cc 100644 --- a/tools/cts-tradefed/res/config/cts-on-aosp-exclude.xml +++ b/tools/cts-tradefed/res/config/cts-on-aosp-exclude.xml @@ -36,13 +36,13 @@ <option name="compatibility:exclude-filter" value="CtsNetTestCasesLegacyApi22 android.net.cts.legacy.api22.ConnectivityManagerLegacyTest#testStartUsingNetworkFeature_enableHipri" /> <option name="compatibility:exclude-filter" value="CtsPermissionPolicyTestCases android.permissionpolicy.cts.NoReceiveSmsPermissionTest#testAppSpecificSmsToken" /> <option name="compatibility:exclude-filter" value="CtsPermissionPolicyTestCases android.permissionpolicy.cts.NoReceiveSmsPermissionTest#testReceiveTextMessage" /> - <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testAppDetails" /> - <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testAppSummary" /> - <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testCallback" /> - <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testDeviceSummary" /> - <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testTagDetails" /> - <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testUidDetails" /> - <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testUserSummary" /> + <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.NetworkStatsManagerTest#testAppDetails" /> + <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.NetworkStatsManagerTest#testAppSummary" /> + <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.NetworkStatsManagerTest#testCallback" /> + <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.NetworkStatsManagerTest#testDeviceSummary" /> + <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.NetworkStatsManagerTest#testTagDetails" /> + <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.NetworkStatsManagerTest#testUidDetails" /> + <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.NetworkStatsManagerTest#testUserSummary" /> <!-- Exclude testcases failing on Pixel devices diff --git a/tools/cts-tradefed/res/config/cts-validation-exclude.xml b/tools/cts-tradefed/res/config/cts-validation-exclude.xml index edc29af288d..1da87f4c7f4 100644 --- a/tools/cts-tradefed/res/config/cts-validation-exclude.xml +++ b/tools/cts-tradefed/res/config/cts-validation-exclude.xml @@ -510,4 +510,12 @@ <option name="compatibility:exclude-filter" value="CtsCredentialManagerTestCases android.credentials.cts.CtsDevicePolicyTest#setCredentialManagerPolicy_policyIsSet[IncludeRunOnDeviceOwnerUser]" /> <option name="compatibility:exclude-filter" value="CtsCredentialManagerTestCases android.credentials.cts.CtsDevicePolicyTest#setCredentialManagerPolicy_allowlistAndSystemPolicy_allowsAllowlistedAndSystemProviders_SDK[IncludeRunOnDeviceOwnerUser]" /> + <!-- b/302404278 --> + <option name="compatibility:exclude-filter" value="CtsDomainVerificationDeviceMultiUserTestCases com.android.cts.packagemanager.verify.domain.device.multiuser.DomainVerificationWorkProfileCrossProfileIntentTests#inPersonal_unverified" /> + <option name="compatibility:exclude-filter" value="CtsDomainVerificationDeviceMultiUserTestCases com.android.cts.packagemanager.verify.domain.device.multiuser.DomainVerificationWorkProfileCrossProfileIntentTests#inPersonal_verifiedInOtherProfile" /> + <option name="compatibility:exclude-filter" value="CtsDomainVerificationDeviceMultiUserTestCases CtsDomainVerificationDeviceMultiUserTestCases com.android.cts.packagemanager.verify.domain.device.multiuser.DomainVerificationWorkProfileCrossProfileIntentTests#inPersonal_verifiedInBothProfiles" /> + <option name="compatibility:exclude-filter" value="CtsDomainVerificationDeviceMultiUserTestCases com.android.cts.packagemanager.verify.domain.device.multiuser.DomainVerificationWorkProfileAllowParentLinkingTests#inPersonal_verifiedInOtherProfile" /> + <option name="compatibility:exclude-filter" value="CtsDomainVerificationDeviceMultiUserTestCases com.android.cts.packagemanager.verify.domain.device.multiuser.DomainVerificationWorkProfileAllowParentLinkingTests#inPersonal_verifiedInBothProfiles" /> + <option name="compatibility:exclude-filter" value="CtsDomainVerificationDeviceMultiUserTestCases com.android.cts.packagemanager.verify.domain.device.multiuser.DomainVerificationWorkProfileAllowParentLinkingTests#inPersonal_verifiedInCurrentProfile" /> + </configuration> |