Snap for 9573585 from fb15ea3e529c370e0bb160cc7de508015e3c180d to mainline-art-release
Change-Id: I614dd69ef6ce3c3c915f09a6d143db87c21dfd62
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
index c3b6900..e8ed8c7 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
@@ -1479,6 +1479,14 @@
if (screenSize < (FIRST_SDK_IS_AT_LEAST_R ? 3.3 : 2.5)) return false;
if (screenSize > 8.0) return false;
if (!hasDeviceGotBattery()) return false;
+ // handheld nature is not exposed to package manager, so for now,
+ // in addition to physical screen size, the following checks are
+ // also required:
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) return false;
+ if (isWatch()) return false;
+ if (isTv()) return false;
+ if (isAutomotive()) return false;
+ if (isPc()) return false;
return true;
}
@@ -1487,6 +1495,14 @@
if (screenSize < 7.0) return false;
if (screenSize > 18.0) return false;
if (!hasDeviceGotBattery()) return false;
+ // tablet nature is not exposed to package manager, so for now,
+ // in addition to physical screen size, the following checks are
+ // also required:
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) return false;
+ if (isWatch()) return false;
+ if (isTv()) return false;
+ if (isAutomotive()) return false;
+ if (isPc()) return false;
return true;
}
diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
index c0dfae1..5d792d9 100644
--- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
@@ -29,6 +29,7 @@
import org.w3c.dom.NodeList;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -37,6 +38,9 @@
public final class CompatChangesValidConfigTest extends CompatChangeGatingTestCase {
+ private static final long RESTRICT_STORAGE_ACCESS_FRAMEWORK = 141600225L;
+ private static final String FEATURE_WATCH = "android.hardware.type.watch";
+
private static final Set<String> OVERRIDES_ALLOWLIST = ImmutableSet.of(
// This change id will sometimes remain enabled if an instrumentation test fails.
"ALLOW_TEST_API_ACCESS"
@@ -114,6 +118,15 @@
changes.add(change);
}
}
+
+ // RESTRICT_STORAGE_ACCESS_FRAMEWORK not supported on wear
+ if (getDevice().hasFeature(FEATURE_WATCH)) {
+ for (Iterator<Change> it = changes.iterator(); it.hasNext();) {
+ if (it.next().changeId == RESTRICT_STORAGE_ACCESS_FRAMEWORK) {
+ it.remove();
+ }
+ }
+ }
return changes;
}
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 7627600..5487fb4 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -27,6 +27,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
@@ -217,6 +218,11 @@
<activity android:name="android.security.cts.ActivityManagerTest$ActivityOptionsActivity" />
<activity android:name="android.security.cts.ActivityManagerTest$BaseActivity" />
+ <activity android:name="android.security.cts.PackageInstallerTest$BackgroundLaunchActivity"
+ android:exported="true" />
+ <service android:name="android.security.cts.TestForegroundService"
+ android:exported="true" />
+
<provider android:name="android.security.cts.CVE_2022_20358.PocContentProvider"
android:authorities="android.security.cts.CVE_2022_20358.provider"
android:enabled="true"
diff --git a/tests/tests/security/src/android/security/cts/PackageInstallerTest.java b/tests/tests/security/src/android/security/cts/PackageInstallerTest.java
index ddea213..43124ec 100644
--- a/tests/tests/security/src/android/security/cts/PackageInstallerTest.java
+++ b/tests/tests/security/src/android/security/cts/PackageInstallerTest.java
@@ -16,25 +16,46 @@
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.app.Service;
+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 +63,41 @@
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";
+ private static final String ACTION_COMMIT_WITH_FG_SERVICE_INTENT_SENDER = TEST_APP_NAME
+ + ".action.COMMIT_WITH_FG_SERVICE_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);
+ private static final ComponentName FOREGROUND_SERVICE_COMPONENT_NAME =
+ new ComponentName(sContext, TestForegroundService.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 +126,87 @@
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);
+ }
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 243377226)
+ public void commitSessionInBackground_withForegroundServiceIntentSender_doesNotStartService()
+ throws Exception {
+ Install.single(TEST_APP).commit();
+ // An activity with the system uid in the foreground is necessary to this test.
+ goToSettings();
+
+ sendActionToBackgroundReceiver(
+ ACTION_COMMIT_WITH_FG_SERVICE_INTENT_SENDER, FOREGROUND_SERVICE_COMPONENT_NAME);
+
+ final Service service =
+ TestForegroundService.waitFor(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ if (service != null) {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(
+ () -> service.stopSelf());
+ }
+ Assert.assertNull(service);
+ }
+
+ 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(bundle.getSerializable(KEY_ERROR, Exception.class));
+ }
+ 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/TestForegroundService.java b/tests/tests/security/src/android/security/cts/TestForegroundService.java
new file mode 100644
index 0000000..b09a925
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/TestForegroundService.java
@@ -0,0 +1,86 @@
+/*
+ * 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 android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+
+import org.junit.Assert;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class TestForegroundService extends Service {
+ private static BlockingQueue<Service> sQueue = new LinkedBlockingQueue<>();
+
+ private static final int FGS_NOTIFICATION_ID = 1;
+ private static final String NOTIFICATION_CHANNEL_ID =
+ TestForegroundService.class.getSimpleName();
+
+ @Override
+ public void onCreate() {
+ createNotificationChannelId(this, NOTIFICATION_CHANNEL_ID);
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ // When this service is started, make it a foreground service
+ final Notification.Builder builder =
+ new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(android.R.drawable.btn_star)
+ .setContentTitle(NOTIFICATION_CHANNEL_ID)
+ .setContentText(TestForegroundService.class.getName());
+ startForeground(FGS_NOTIFICATION_ID, builder.build());
+
+ try {
+ sQueue.put(this);
+ } catch (InterruptedException e) {
+ Assert.fail(e.toString());
+ }
+ return Service.START_NOT_STICKY;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ /** Create a notification channel. */
+ private static void createNotificationChannelId(Context context, String id) {
+ final NotificationManager nm =
+ context.getSystemService(NotificationManager.class);
+ final CharSequence name = id;
+ final String description = TestForegroundService.class.getName();
+ final int importance = NotificationManager.IMPORTANCE_DEFAULT;
+ final NotificationChannel channel = new NotificationChannel(
+ NOTIFICATION_CHANNEL_ID, name, importance);
+ channel.setDescription(description);
+ nm.createNotificationChannel(channel);
+ }
+
+ /** Wait until the service is started */
+ public static Service waitFor(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return sQueue.poll(timeout, unit);
+ }
+}
diff --git a/tests/tests/security/testdata/packageinstallertestapp.xml b/tests/tests/security/testdata/packageinstallertestapp.xml
index 5e6e066..ad39db5 100644
--- a/tests/tests/security/testdata/packageinstallertestapp.xml
+++ b/tests/tests/security/testdata/packageinstallertestapp.xml
@@ -34,5 +34,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..8997082
--- /dev/null
+++ b/tests/tests/security/testdata/src/android/security/cts/packageinstallertestapp/BackgroundReceiver.java
@@ -0,0 +1,123 @@
+/*
+ * 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";
+ private static final String ACTION_COMMIT_WITH_FG_SERVICE_INTENT_SENDER = PKG_NAME
+ + ".action.COMMIT_WITH_FG_SERVICE_INTENT_SENDER";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final RemoteCallback remoteCallback = intent.getParcelableExtra(EXTRA_REMOTE_CALLBACK,
+ RemoteCallback.class);
+ final ComponentName statusReceiver = intent.getParcelableExtra(
+ EXTRA_COMPONENT_NAME, ComponentName.class);
+ 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 if (action.equals(ACTION_COMMIT_WITH_FG_SERVICE_INTENT_SENDER)) {
+ final IntentSender intentSender = PendingIntent.getForegroundService(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/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java
index 767143c..5c1e926 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java
@@ -434,6 +434,8 @@
// TODO ntmyren: test TV indicator
} else if (sPkgMgr.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
// TODO ntmyren: test Auto indicator
+ } else if (sPkgMgr.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ // The privacy chips/indicators are not implemented on Wear
} else {
verifyMicrophoneChipHandheld(shouldBePresent);
}