Snap for 8820681 from 65867ee55adf92723851186b9f88dc9e6847aa9b to mainline-go-appsearch-release

Change-Id: I78e7f808d34b7727d4977343ca6a75987b02c7e4
diff --git a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
index 820fd95..24d1249 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -83,6 +83,7 @@
     private static ImmutableList<String> sSystemserverclasspathJars;
     private static ImmutableList<String> sSharedLibJars;
     private static ImmutableList<SharedLibraryInfo> sSharedLibs;
+    private static ImmutableMultimap<String, String> sSharedLibsPathsToName;
     private static ImmutableMultimap<String, String> sJarsToClasses;
     private static ImmutableMultimap<String, String> sJarsToFiles;
 
@@ -795,6 +796,13 @@
                 .filter(file -> !file.contains("GmsCore"))
                 .filter(file -> !file.contains("com.google.android.gms"))
                 .collect(ImmutableList.toImmutableList());
+        final ImmutableSetMultimap.Builder<String, String> sharedLibsPathsToName =
+                ImmutableSetMultimap.builder();
+        sSharedLibs.forEach(sharedLibraryInfo -> {
+                sharedLibraryInfo.paths.forEach(path ->
+                        sharedLibsPathsToName.putAll(path, sharedLibraryInfo.name));
+        });
+        sSharedLibsPathsToName = sharedLibsPathsToName.build();
 
         final ImmutableSetMultimap.Builder<String, String> jarsToFiles =
                 ImmutableSetMultimap.builder();
@@ -1038,17 +1046,17 @@
         // WARNING: Do not add more exceptions here, no androidx should be in bootclasspath.
         // See go/androidx-api-guidelines#module-naming for more details.
         final ImmutableMap<String, ImmutableSet<String>>
-                LegacyExemptAndroidxSharedLibsJarToClasses =
+                LegacyExemptAndroidxSharedLibsNamesToClasses =
                 new ImmutableMap.Builder<String, ImmutableSet<String>>()
-                .put("/vendor/framework/androidx.camera.extensions.impl.jar",
+                .put("androidx.camera.extensions.impl",
                     ImmutableSet.of("Landroidx/camera/extensions/impl/"))
-                .put("/system_ext/framework/androidx.window.extensions.jar",
+                .put("androidx.window.extensions",
                     ImmutableSet.of("Landroidx/window/common/", "Landroidx/window/extensions/",
                         "Landroidx/window/util/"))
-                .put("/system_ext/framework/androidx.window.sidecar.jar",
+                .put("androidx.window.sidecar",
                     ImmutableSet.of("Landroidx/window/common/", "Landroidx/window/sidecar",
                         "Landroidx/window/util"))
-                .put("/vendor/framework/com.google.android.camera.experimental2020_midyear.jar",
+                .put("com.google.android.camera.experimental2020_midyear",
                     ImmutableSet.of("Landroidx/annotation"))
                 .build();
         assertWithMessage("There must not be any androidx classes on the "
@@ -1057,7 +1065,7 @@
                 .that(sJarsToClasses.entries().stream()
                         .filter(e -> e.getValue().startsWith("Landroidx/"))
                         .filter(e -> !isLegacyAndroidxDependency(
-                            LegacyExemptAndroidxSharedLibsJarToClasses, e.getKey(), e.getValue()))
+                            LegacyExemptAndroidxSharedLibsNamesToClasses, e.getKey(), e.getValue()))
                         .collect(Collectors.toList())
                 ).isEmpty();
     }
@@ -1103,11 +1111,12 @@
     }
 
     private boolean isLegacyAndroidxDependency(
-            ImmutableMap<String, ImmutableSet<String>> legacyExemptAndroidxSharedLibsJarToClasses,
-            String jar, String className) {
-        return legacyExemptAndroidxSharedLibsJarToClasses.containsKey(jar)
-                && legacyExemptAndroidxSharedLibsJarToClasses.get(jar).stream().anyMatch(
-                        v -> className.startsWith(v));
+            ImmutableMap<String, ImmutableSet<String>> legacyExemptAndroidxSharedLibsNamesToClasses,
+            String path, String className) {
+        return sSharedLibsPathsToName.get(path).stream()
+                .filter(legacyExemptAndroidxSharedLibsNamesToClasses::containsKey)
+                .flatMap(name -> legacyExemptAndroidxSharedLibsNamesToClasses.get(name).stream())
+                .anyMatch(className::startsWith);
     }
 
     private String[] collectApkInApexPaths() {
diff --git a/hostsidetests/securitybulletin/res/cve_2021_39623.ogg b/hostsidetests/securitybulletin/res/cve_2021_39623.ogg
new file mode 100644
index 0000000..1992a17
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2021_39623.ogg
Binary files differ
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/Android.bp
new file mode 100644
index 0000000..50662fd
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/Android.bp
@@ -0,0 +1,36 @@
+/*
+ * 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"],
+}
+
+cc_test {
+    name: "CVE-2021-39623",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+    ],
+    header_libs: [
+        "libmediametrics_headers",
+    ],
+    shared_libs: [
+        "libstagefright",
+        "libdatasource",
+        "libutils",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/poc.cpp
new file mode 100644
index 0000000..d9e38ba
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/poc.cpp
@@ -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.
+ */
+
+#include "../includes/common.h"
+#include <datasource/DataSourceFactory.h>
+#include <dlfcn.h>
+#include <gui/SurfaceComposerClient.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaExtractorFactory.h>
+#include <media/stagefright/SimpleDecodingSource.h>
+#include <sys/mman.h>
+
+typedef void *(*mmap_t)(void *, size_t, int, int, int, off_t);
+mmap_t real_mmap = nullptr;
+
+using namespace android;
+
+bool testInProgress = false;
+constexpr size_t kTargetBufferSize = 32768;
+struct sigaction new_action, old_action;
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+  if (testInProgress && info->si_signo == SIGSEGV) {
+    (*old_action.sa_sigaction)(signum, info, context);
+    return;
+  }
+  exit(EXIT_FAILURE);
+}
+
+void *mmap(void *addr, size_t length, int prot, int flags, int fd,
+           off_t offset) {
+  real_mmap = (mmap_t)dlsym(RTLD_NEXT, "mmap");
+  if (!real_mmap) {
+    exit(EXIT_FAILURE);
+  }
+  if (length == kTargetBufferSize) {
+    char *tmp_ptr = (char *)real_mmap(addr, length + PAGE_SIZE, prot,
+                                      flags | MAP_ANONYMOUS, -1, offset);
+    mprotect(tmp_ptr + length, PAGE_SIZE, PROT_NONE);
+    return tmp_ptr;
+  }
+  return real_mmap(addr, length, prot, flags, fd, offset);
+}
+
+int main(int argc, char **argv) {
+  FAIL_CHECK(argc > 1);
+  sigemptyset(&new_action.sa_mask);
+  new_action.sa_flags = SA_SIGINFO;
+  new_action.sa_sigaction = sigsegv_handler;
+  sigaction(SIGSEGV, &new_action, &old_action);
+
+  sp<DataSource> dataSource = DataSourceFactory::getInstance()->CreateFromURI(
+      nullptr /* httpService */, argv[1]);
+  FAIL_CHECK(dataSource);
+
+  sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
+  FAIL_CHECK(extractor);
+
+  sp<MediaSource> mediaSource =
+      CreateMediaSourceFromIMediaSource(extractor->getTrack(0));
+  FAIL_CHECK(mediaSource);
+
+  sp<MediaSource> rawSource = SimpleDecodingSource::Create(
+      mediaSource, MediaCodecList::kPreferSoftwareCodecs, nullptr, nullptr,
+      false);
+  FAIL_CHECK(rawSource);
+
+  status_t err = rawSource->start();
+  FAIL_CHECK(err == OK);
+
+  MediaSource::ReadOptions options = {};
+  MediaBufferBase *buffer = nullptr;
+
+  testInProgress = true;
+  rawSource->read(&buffer, &options);
+  testInProgress = false;
+  if (buffer) {
+    buffer->release();
+    buffer = nullptr;
+  }
+  options.clearSeekTo();
+  options.setSeekTo(0);
+  rawSource->stop();
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
new file mode 100644
index 0000000..9ab3f08
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
@@ -0,0 +1,55 @@
+/*
+ * 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.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39623 extends SecurityTestCase {
+
+    /**
+     * b/194105348
+     * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libstagefright (As per AOSP code)
+     * Vulnerable Function: doRead (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 194105348)
+    @Test
+    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)
+                .setBacktraceIncludes(new BacktraceFilterPattern("libstagefright",
+                        "android::SimpleDecodingSource::doRead"));
+        String signals[] = {CrashUtils.SIGSEGV};
+        testConfig.config.setSignals(signals);
+        testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+        String inputFiles[] = {"cve_2021_39623.ogg"};
+        testConfig.inputFiles = Arrays.asList(inputFiles);
+        testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSessionCtsTestBase.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSessionCtsTestBase.java
index 70b68b4..affdaa8 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSessionCtsTestBase.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSessionCtsTestBase.java
@@ -676,6 +676,7 @@
                                         .build())
                         .build();
         mDb1.setSchemaAsync(new SetSchemaRequest.Builder().addSchemas(schema).build()).get();
+
         // Creates a large batch of Documents, since we have max document size in Framework which is
         // 512KiB, we will create 1KiB * 4000 docs = 4MiB total size > 1MiB binder transaction limit
         char[] chars = new char[1024]; // 1KiB
@@ -3851,4 +3852,104 @@
         documents = convertSearchResultsToDocuments(searchResults);
         assertThat(documents).containsExactly(inEmail1);
     }
+
+    @Test
+    public void testSetSchemaWithIncompatibleNestedSchema() throws Exception {
+        // 1. Set the original schema. This should succeed without any problems.
+        AppSearchSchema originalNestedSchema =
+                new AppSearchSchema.Builder("TypeA")
+                        .addProperty(
+                                new StringPropertyConfig.Builder("prop1")
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .build())
+                        .build();
+        SetSchemaRequest originalRequest =
+                new SetSchemaRequest.Builder().addSchemas(originalNestedSchema).build();
+        mDb1.setSchemaAsync(originalRequest).get();
+
+        // 2. Set a new schema with a new type that refers to "TypeA" and an incompatible change to
+        // "TypeA". This should fail.
+        AppSearchSchema newNestedSchema =
+                new AppSearchSchema.Builder("TypeA")
+                        .addProperty(
+                                new StringPropertyConfig.Builder("prop1")
+                                        .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+                                        .build())
+                        .build();
+        AppSearchSchema newSchema =
+                new AppSearchSchema.Builder("TypeB")
+                        .addProperty(
+                                new AppSearchSchema.DocumentPropertyConfig.Builder("prop2", "TypeA")
+                                        .build())
+                        .build();
+        final SetSchemaRequest newRequest =
+                new SetSchemaRequest.Builder().addSchemas(newNestedSchema, newSchema).build();
+        Throwable throwable =
+                assertThrows(ExecutionException.class, () -> mDb1.setSchemaAsync(newRequest).get())
+                        .getCause();
+        assertThat(throwable).isInstanceOf(AppSearchException.class);
+        AppSearchException exception = (AppSearchException) throwable;
+        assertThat(exception.getResultCode()).isEqualTo(RESULT_INVALID_SCHEMA);
+        assertThat(exception).hasMessageThat().contains("Schema is incompatible.");
+        assertThat(exception).hasMessageThat().contains("Incompatible types: {TypeA}");
+
+        // 3. Now set that same set of schemas but with forceOverride=true. This should succeed.
+        SetSchemaRequest newRequestForced =
+                new SetSchemaRequest.Builder()
+                        .addSchemas(newNestedSchema, newSchema)
+                        .setForceOverride(true)
+                        .build();
+        mDb1.setSchemaAsync(newRequestForced).get();
+    }
+
+    @Test
+    public void testEmojiSnippet() throws Exception {
+        // Schema registration
+        mDb1.setSchemaAsync(
+                        new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // String:     "Luca Brasi sleeps with the 🐟🐟🐟."
+        //              ^    ^     ^      ^    ^   ^ ^  ^ ^
+        // UTF8 idx:    0    5     11     18   23 27 3135 39
+        // UTF16 idx:   0    5     11     18   23 27 2931 33
+        // Breaks into segments: "Luca", "Brasi", "sleeps", "with", "the", "🐟", "🐟"
+        // and "🐟".
+        // Index a document to instance 1.
+        String sicilianMessage = "Luca Brasi sleeps with the 🐟🐟🐟.";
+        AppSearchEmail inEmail1 =
+                new AppSearchEmail.Builder("namespace", "uri1").setBody(sicilianMessage).build();
+        checkIsBatchResultSuccess(
+                mDb1.putAsync(
+                        new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1).build()));
+
+        AppSearchEmail inEmail2 =
+                new AppSearchEmail.Builder("namespace", "uri2")
+                        .setBody("Some other content.")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.putAsync(
+                        new PutDocumentsRequest.Builder().addGenericDocuments(inEmail2).build()));
+
+        // Query for "🐟"
+        SearchResultsShim searchResults =
+                mDb1.search(
+                        "🐟",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+                                .setSnippetCount(1)
+                                .setSnippetCountPerProperty(1)
+                                .build());
+        List<SearchResult> page = searchResults.getNextPageAsync().get();
+        assertThat(page).hasSize(1);
+        assertThat(page.get(0).getGenericDocument()).isEqualTo(inEmail1);
+        List<SearchResult.MatchInfo> matches = page.get(0).getMatchInfos();
+        assertThat(matches).hasSize(1);
+        assertThat(matches.get(0).getPropertyPath()).isEqualTo("body");
+        assertThat(matches.get(0).getFullText()).isEqualTo(sicilianMessage);
+        assertThat(matches.get(0).getExactMatch()).isEqualTo("🐟");
+        if (mDb1.getFeatures().isFeatureSupported(Features.SEARCH_RESULT_MATCH_INFO_SUBMATCH)) {
+            assertThat(matches.get(0).getSubmatch()).isEqualTo("🐟");
+        }
+    }
 }
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java
index 5dd2eac..0bfa693 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java
@@ -576,6 +576,30 @@
     }
 
     @Test
+    public void testNestedProperties_buildBlankPaths() {
+        Exception e =
+                assertThrows(
+                        IllegalArgumentException.class,
+                        () ->
+                                new GenericDocument.Builder<>("namespace", "id1", "schema1")
+                                        .setPropertyString("", "foo"));
+        assertThat(e.getMessage()).isEqualTo("Property name cannot be blank.");
+
+        e =
+                assertThrows(
+                        IllegalArgumentException.class,
+                        () ->
+                                new GenericDocument.Builder<>("namespace", "id1", "schema1")
+                                        .setPropertyDocument(
+                                                "propDoc",
+                                                new GenericDocument.Builder<>(
+                                                                "namespace", "id2", "schema1")
+                                                        .setPropertyString("", "Bat", "Hawk")
+                                                        .build()));
+        assertThat(e.getMessage()).isEqualTo("Property name cannot be blank.");
+    }
+
+    @Test
     public void testNestedProperties_invalidPaths() {
         GenericDocument doc =
                 new GenericDocument.Builder<>("namespace", "id1", "schema1")
@@ -592,25 +616,28 @@
                                         .build())
                         .build();
 
-        // Some paths are invalid because they don't apply to the given document --- these should
+        // These paths are invalid because they don't apply to the given document --- these should
         // return null. It's not the querier's fault.
         assertThat(doc.getPropertyStringArray("propString.propInts")).isNull();
         assertThat(doc.getPropertyStringArray("propDocs.propFoo")).isNull();
         assertThat(doc.getPropertyStringArray("propDocs.propNestedString.propFoo")).isNull();
+    }
 
-        // Some paths are invalid because they are malformed. These throw an exception --- the
-        // querier shouldn't provide such paths.
-        assertThrows(
-                IllegalArgumentException.class, () -> doc.getPropertyStringArray("propString[0"));
-        assertThrows(
-                IllegalArgumentException.class, () -> doc.getPropertyStringArray("propString[0.]"));
-        assertThrows(
-                IllegalArgumentException.class,
-                () -> doc.getPropertyStringArray("propString[banana]"));
-        assertThrows(
-                IllegalArgumentException.class, () -> doc.getPropertyStringArray("propString[-1]"));
-        assertThrows(
-                IllegalArgumentException.class, () -> doc.getPropertyStringArray("propDocs[0]cat"));
+    @Test
+    public void testNestedProperties_arrayTypesInvalidPath() {
+        GenericDocument doc = new GenericDocument.Builder<>("namespace", "id1", "schema1").build();
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyString("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyDocument("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyBoolean("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyDouble("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyLong("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyBytes("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyStringArray("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyDocumentArray("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyBooleanArray("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyDoubleArray("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyLongArray("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyBytesArray("."));
     }
 
     @Test
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java
index 71822ca..47337ca 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java
@@ -1641,6 +1641,11 @@
 
     @Test
     public void testAddObserver_schemaChange_added() throws Exception {
+        assumeTrue(
+                mDb1.getFeatures()
+                        .isFeatureSupported(
+                                Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK));
+
         // Register an observer
         TestObserverCallback observer = new TestObserverCallback();
         mGlobalSearchSession.registerObserverCallback(
@@ -1688,6 +1693,11 @@
 
     @Test
     public void testAddObserver_schemaChange_removed() throws Exception {
+        assumeTrue(
+                mDb1.getFeatures()
+                        .isFeatureSupported(
+                                Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK));
+
         // Add a schema type
         mDb1.setSchemaAsync(
                         new SetSchemaRequest.Builder()
@@ -1723,6 +1733,11 @@
 
     @Test
     public void testAddObserver_schemaChange_contents() throws Exception {
+        assumeTrue(
+                mDb1.getFeatures()
+                        .isFeatureSupported(
+                                Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK));
+
         // Add a schema
         mDb1.setSchemaAsync(
                         new SetSchemaRequest.Builder()
@@ -1794,6 +1809,11 @@
 
     @Test
     public void testAddObserver_schemaChange_contents_skipBySpec() throws Exception {
+        assumeTrue(
+                mDb1.getFeatures()
+                        .isFeatureSupported(
+                                Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK));
+
         // Add a schema
         mDb1.setSchemaAsync(
                         new SetSchemaRequest.Builder()
@@ -1862,6 +1882,11 @@
 
     @Test
     public void testRegisterObserver_schemaMigration() throws Exception {
+        assumeTrue(
+                mDb1.getFeatures()
+                        .isFeatureSupported(
+                                Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK));
+
         // Add a schema with two types
         mDb1.setSchemaAsync(
                         new SetSchemaRequest.Builder()
diff --git a/tests/framework/base/windowmanager/Android.bp b/tests/framework/base/windowmanager/Android.bp
index 168ee3f..b786d83 100644
--- a/tests/framework/base/windowmanager/Android.bp
+++ b/tests/framework/base/windowmanager/Android.bp
@@ -67,6 +67,7 @@
         "cts-wm-overlayapp-base",
         "cts-wm-shared",
         "platform-compat-test-rules",
+        "cts_window_jetpack_utils",
     ],
 
     test_suites: [
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index 39c3d3e..1a86422 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -38,6 +38,8 @@
                  android:enableOnBackInvokedCallback="true"
                  android:testOnly="true">
         <uses-library android:name="android.test.runner"/>
+        <uses-library android:name="androidx.window.extensions"
+            android:required="false" />
 
         <activity android:name="android.server.wm.ActivityManagerTestBase$ConfigChangeHandlingActivity"
              android:resizeableActivity="true"
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
index d12b7c1d..477cc8d 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
@@ -16,6 +16,7 @@
 
 package android.server.wm.jetpack.utils;
 
+import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
 import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
 import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
 import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getMaximumActivityBounds;
@@ -28,6 +29,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.Activity;
 import android.content.ComponentName;
@@ -51,6 +53,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.Predicate;
 
 /**
@@ -447,6 +450,13 @@
         }
     }
 
+    public static void assumeActivityEmbeddingSupportedDevice() {
+        assumeExtensionSupportedDevice();
+        assumeTrue("Device does not support ActivityEmbedding",
+                Objects.requireNonNull(getWindowExtensions())
+                        .getActivityEmbeddingComponent() != null);
+    }
+
     private static void assertSplitInfoTopSplitIsCorrect(@NonNull List<SplitInfo> splitInfoList,
             @NonNull Activity primaryActivity, @NonNull Activity secondaryActivity) {
         assertFalse("Split info callback should not be empty", splitInfoList.isEmpty());
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
index 385a5af..c13c4ee 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
@@ -18,6 +18,7 @@
 
 import static android.server.wm.WindowManagerState.STATE_RESUMED;
 import static android.server.wm.jetpack.second.Components.SECOND_UNTRUSTED_EMBEDDING_ACTIVITY;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.assumeActivityEmbeddingSupportedDevice;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -39,6 +40,7 @@
 
 import androidx.annotation.NonNull;
 
+import org.junit.Before;
 import org.junit.Test;
 
 /**
@@ -52,6 +54,13 @@
     private final ComponentName mTranslucentActivity = new ComponentName(mContext,
             TranslucentActivity.class);
 
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        assumeActivityEmbeddingSupportedDevice();
+    }
+
     /**
      * Verifies the visibility of a task fragment that has overlays on top of activities embedded
      * in untrusted mode when there is an overlay over the task fragment.
diff --git a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
index 2508845..8da22f3 100644
--- a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
@@ -41,6 +41,7 @@
 import java.util.List;
 import java.util.UUID;
 import org.junit.Assume;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
@@ -58,6 +59,11 @@
     @Rule
     public final TestName mTestName = new TestName();
 
+    @Before
+    public void isPerformanceClassCandidate() {
+        Utils.assumeDeviceMeetsPerformanceClassPreconditions();
+    }
+
     static {
         mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_AVC);
         mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
diff --git a/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
index bbe26dc..2ee8b3b 100644
--- a/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
@@ -21,12 +21,14 @@
 import static android.mediapc.cts.CodecTestBase.SELECT_VIDEO;
 import static android.mediapc.cts.CodecTestBase.getMimesOfAvailableCodecs;
 import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
+import static org.junit.Assert.assertTrue;
 
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
 import android.media.MediaFormat;
 import android.mediapc.cts.common.PerformanceClassEvaluator;
+import android.mediapc.cts.common.Utils;
 import android.util.Log;
 import androidx.test.filters.LargeTest;
 import com.android.compatibility.common.util.CddTest;
@@ -35,6 +37,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
@@ -47,6 +50,11 @@
     @Rule
     public final TestName mTestName = new TestName();
 
+    @Before
+    public void isPerformanceClassCandidate() {
+        Utils.assumeDeviceMeetsPerformanceClassPreconditions();
+    }
+
     private Set<String> get4k60HwCodecSet(boolean isEncoder) throws IOException {
         Set<String> codecSet = new HashSet<>();
         Set<String> codecMediaTypes = getMimesOfAvailableCodecs(SELECT_VIDEO, SELECT_HARDWARE);
@@ -60,6 +68,7 @@
                         codec.getCodecInfo().getCapabilitiesForType(codecMediaType);
                 List<PerformancePoint> pps =
                         capabilities.getVideoCapabilities().getSupportedPerformancePoints();
+                assertTrue(hwVideoCodec + " doesn't advertise performance points", pps.size() > 0);
                 for (PerformancePoint pp : pps) {
                     if (pp.covers(PP4k60)) {
                         codecSet.add(hwVideoCodec);
diff --git a/tests/tests/media/common/src/android/media/cts/CodecState.java b/tests/tests/media/common/src/android/media/cts/CodecState.java
index 13e56f8..3565fc8 100644
--- a/tests/tests/media/common/src/android/media/cts/CodecState.java
+++ b/tests/tests/media/common/src/android/media/cts/CodecState.java
@@ -358,7 +358,7 @@
                 return null;
             }
 
-            if (mIsTunneled && !mIsAudio) {
+            if (mIsTunneled) {
                 if (mFirstSampleTimeUs == -1) {
                     mFirstSampleTimeUs = sampleTime;
                 }
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index dfc8031..d785d96 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -284,5 +284,6 @@
 
     <!-- b/237035040 -->
     <option name="compatibility:exclude-filter" value="CtsGraphicsTestCases android.graphics.cts.ImageDecoderTest#testDecode10BitHeifWithLowRam" />
+    <option name="compatibility:exclude-filter" value="CtsGraphicsTestCases[instant] android.graphics.cts.ImageDecoderTest#testDecode10BitHeifWithLowRam" />
 
 </configuration>