Add a broad try-catch to AppFunctionSchemaParser and attribute parsing for joinableType.

Also update the generated schema's names to be unique for package as in AppFunctionStaticMetadataParserImpl.

Change-Id: I6e011dc0441e2b095d8d3c880405d098b8f9cffa
Flag: EXEMPT Code not used yet
Test: atest AppsIndexerTests
Bug: 380729091
diff --git a/service/java/com/android/server/appsearch/appsindexer/AppFunctionSchemaParser.java b/service/java/com/android/server/appsearch/appsindexer/AppFunctionSchemaParser.java
index 1b7044f..e06414e 100644
--- a/service/java/com/android/server/appsearch/appsindexer/AppFunctionSchemaParser.java
+++ b/service/java/com/android/server/appsearch/appsindexer/AppFunctionSchemaParser.java
@@ -21,16 +21,19 @@
 import android.app.appsearch.AppSearchSchema.LongPropertyConfig;
 import android.app.appsearch.AppSearchSchema.PropertyConfig;
 import android.app.appsearch.AppSearchSchema.StringPropertyConfig;
+import android.app.appsearch.util.LogUtil;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.AssetManager;
 import android.util.ArrayMap;
+import android.util.Log;
 
 import com.android.server.appsearch.appsindexer.appsearchtypes.AppFunctionStaticMetadata;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.util.Collections;
 import java.util.Map;
 import java.util.Objects;
 
@@ -41,23 +44,31 @@
 /**
  * This class parses the XSD file from an app's assets and creates AppSearch schemas from document
  * types.
+ *
+ * <p>The generated {@link AppSearchSchema} objects are used to set the schema under the {@link
+ * AppSearchHelper#APP_DATABASE} database. Within the database, each {@link AppSearchSchema} is
+ * named dynamically to be unique to the app package name.
+ *
+ * <p>Note: The XSD file should be generated by the App Functions SDK and always define
+ * AppFunctionStaticMetadata document type.
  */
 public class AppFunctionSchemaParser {
     private static final String TAG = "AppSearchSchemaParser";
-    private static final String TAG_DOCUMENT_TYPE = "xs:documentType";
-    private static final String TAG_ELEMENT = "xs:element";
-    private static final String APPFN_NAMESPACE_PREFIX = "appfn:";
-    private static final String TAG_STRING_TYPE = "xs:string";
-    private static final String TAG_LONG_TYPE = "xs:long";
-    private static final String TAG_INT_TYPE = "xs:int";
-    private static final String TAG_BOOLEAN_TYPE = "xs:boolean";
-    private static final String ATTRIBUTE_INDEXING_TYPE = "indexingType";
-    private static final String ATTRIBUTE_TOKENIZER_TYPE = "tokenizerType";
-    private static final String ATTRIBUTE_CARDINALITY = "cardinality";
-    private static final String ATTRIBUTE_SHOULD_INDEX_NESTED_PROPERTIES =
+    private static final String XML_TAG_DOCUMENT_TYPE = "xs:documentType";
+    private static final String XML_TAG_ELEMENT = "xs:element";
+    private static final String XML_APPFN_NAMESPACE_PREFIX = "appfn:";
+    private static final String XML_TAG_STRING_TYPE = "xs:string";
+    private static final String XML_TAG_LONG_TYPE = "xs:long";
+    private static final String XML_TAG_INT_TYPE = "xs:int";
+    private static final String XML_TAG_BOOLEAN_TYPE = "xs:boolean";
+    private static final String XML_ATTRIBUTE_INDEXING_TYPE = "indexingType";
+    private static final String XML_ATTRIBUTE_TOKENIZER_TYPE = "tokenizerType";
+    private static final String XML_ATTRIBUTE_JOINABLE_VALUE_TYPE = "joinableValueType";
+    private static final String XML_ATTRIBUTE_CARDINALITY = "cardinality";
+    private static final String XML_ATTRIBUTE_SHOULD_INDEX_NESTED_PROPERTIES =
             "shouldIndexNestedProperties";
-    private static final String ATTRIBUTE_NAME = "name";
-    private static final String ATTRIBUTE_TYPE = "type";
+    private static final String XML_ATTRIBUTE_NAME = "name";
+    private static final String XML_ATTRIBUTE_TYPE = "type";
 
     /**
      * The maximum number of document types allowed in the XSD file. This is to prevent malicious
@@ -79,32 +90,55 @@
      * Parses the XSD and create AppSearch schemas from document types.
      *
      * <p>The schema output isn't guaranteed to have valid dependencies, which can be caught during
-     * a {@link SyncAppSearchSession#setSchema} call, however the parser will throw an exception if
-     * the number of document types exceeds the maximum allowed or illegal types are encountered.
+     * a {@link SyncAppSearchSession#setSchema} call.
      *
      * @param packageManager The PackageManager used to access app resources.
      * @param packageName The package name of the app whose assets contain the XSD file.
      * @param assetFilePath The path to the XSD file within the app's assets.
-     * @return A mapping of schema types to their corresponding {@link AppSearchSchema} objects.
+     * @return A mapping of schema types to their corresponding {@link AppSearchSchema} objects, or
+     *     an empty map if there's an error during parsing or if the AppFunctionStaticMetadata
+     *     document type is not found.
      */
     @NonNull
     public Map<String, AppSearchSchema> parseAndCreateSchemas(
             @NonNull PackageManager packageManager,
             @NonNull String packageName,
-            @NonNull String assetFilePath)
-            throws XmlPullParserException, NameNotFoundException, IOException {
+            @NonNull String assetFilePath) {
         Objects.requireNonNull(packageManager);
         Objects.requireNonNull(packageName);
         Objects.requireNonNull(assetFilePath);
 
-        AssetManager assetManager =
-                packageManager.getResourcesForApplication(packageName).getAssets();
-        InputStream xsdInputStream = assetManager.open(assetFilePath);
-        return parseDocumentTypeAndCreateSchemas(xsdInputStream);
+        try {
+            AssetManager assetManager =
+                    packageManager.getResourcesForApplication(packageName).getAssets();
+            InputStream xsdInputStream = assetManager.open(assetFilePath);
+            String appFunctionStaticMetadataType =
+                    AppFunctionStaticMetadata.getSchemaNameForPackage(
+                            packageName, /* schemaType= */ null);
+            Map<String, AppSearchSchema> schemas =
+                    parseDocumentTypeAndCreateSchemas(packageName, xsdInputStream);
+            if (schemas.containsKey(appFunctionStaticMetadataType)) {
+                return schemas;
+            } else if (LogUtil.DEBUG) {
+                Log.d(TAG, "AppFunctionStaticMetadata schema not found.");
+            }
+        } catch (Exception ex) {
+            // The code parses an XSD file from another app's assets, using a broad try-catch to
+            // handle potential errors since the XML structure might be unpredictable.
+            Log.e(
+                    TAG,
+                    String.format(
+                            "Failed to parse XSD from package '%s', asset file '%s'",
+                            packageName, assetFilePath),
+                    ex);
+        }
+        return Collections.emptyMap();
     }
 
     private Map<String, AppSearchSchema> parseDocumentTypeAndCreateSchemas(
-            @NonNull InputStream xsdInputStream) throws XmlPullParserException, IOException {
+            @NonNull String packageName, @NonNull InputStream xsdInputStream)
+            throws XmlPullParserException, IOException {
+        Objects.requireNonNull(packageName);
         Objects.requireNonNull(xsdInputStream);
 
         Map<String, AppSearchSchema> schemas = new ArrayMap<>();
@@ -117,26 +151,30 @@
         while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
             switch (parser.getEventType()) {
                 case XmlPullParser.START_TAG:
-                    if (TAG_DOCUMENT_TYPE.equals(parser.getName())) {
+                    if (XML_TAG_DOCUMENT_TYPE.equals(parser.getName())) {
                         if (schemas.size() >= mMaxAllowedDocumentType) {
                             throw new IllegalStateException(
                                     "Exceeded max allowed document types: "
                                             + mMaxAllowedDocumentType);
                         }
 
-                        String documentTypeName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
+                        String documentTypeName =
+                                parser.getAttributeValue(null, XML_ATTRIBUTE_NAME);
                         if (documentTypeName != null) {
-                            schemaBuilder = new AppSearchSchema.Builder(documentTypeName);
+                            schemaBuilder =
+                                    new AppSearchSchema.Builder(
+                                            AppFunctionStaticMetadata.getSchemaNameForPackage(
+                                                    packageName, documentTypeName));
                         }
-                    } else if (TAG_ELEMENT.equals(parser.getName()) && schemaBuilder != null) {
+                    } else if (XML_TAG_ELEMENT.equals(parser.getName()) && schemaBuilder != null) {
                         AppSearchSchema.PropertyConfig propertyConfig =
-                                computePropertyConfigFromXsdType(parser);
+                                computePropertyConfigFromXsdType(parser, packageName);
                         if (propertyConfig != null) schemaBuilder.addProperty(propertyConfig);
                     }
                     break;
 
                 case XmlPullParser.END_TAG:
-                    if (TAG_DOCUMENT_TYPE.equals(parser.getName())) {
+                    if (XML_TAG_DOCUMENT_TYPE.equals(parser.getName())) {
                         if (schemaBuilder != null) {
                             AppSearchSchema schema = schemaBuilder.build();
                             schemas.put(schema.getSchemaType(), schema);
@@ -151,54 +189,65 @@
         return schemas;
     }
 
-    private static PropertyConfig computePropertyConfigFromXsdType(@NonNull XmlPullParser parser)
+    private static PropertyConfig computePropertyConfigFromXsdType(
+            @NonNull XmlPullParser parser, @NonNull String packageName)
             throws XmlPullParserException, IOException {
         Objects.requireNonNull(parser);
 
-        String name = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-        String type = parser.getAttributeValue(null, ATTRIBUTE_TYPE);
+        String name = parser.getAttributeValue(null, XML_ATTRIBUTE_NAME);
+        String type = parser.getAttributeValue(null, XML_ATTRIBUTE_TYPE);
 
         if (name == null || type == null) return null;
 
         int cardinality =
                 getAttributeIntOrDefault(
-                        parser, ATTRIBUTE_CARDINALITY, PropertyConfig.CARDINALITY_OPTIONAL);
+                        parser, XML_ATTRIBUTE_CARDINALITY, PropertyConfig.CARDINALITY_OPTIONAL);
 
         switch (type) {
-            case TAG_STRING_TYPE:
+            case XML_TAG_STRING_TYPE:
                 return new StringPropertyConfig.Builder(name)
                         .setCardinality(cardinality)
                         .setIndexingType(
                                 getAttributeIntOrDefault(
                                         parser,
-                                        ATTRIBUTE_INDEXING_TYPE,
+                                        XML_ATTRIBUTE_INDEXING_TYPE,
                                         StringPropertyConfig.INDEXING_TYPE_NONE))
                         .setTokenizerType(
                                 getAttributeIntOrDefault(
                                         parser,
-                                        ATTRIBUTE_TOKENIZER_TYPE,
+                                        XML_ATTRIBUTE_TOKENIZER_TYPE,
                                         StringPropertyConfig.TOKENIZER_TYPE_NONE))
+                        .setJoinableValueType(
+                                getAttributeIntOrDefault(
+                                        parser,
+                                        XML_ATTRIBUTE_JOINABLE_VALUE_TYPE,
+                                        StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE))
                         .build();
-            case TAG_LONG_TYPE:
-            case TAG_INT_TYPE:
+            case XML_TAG_LONG_TYPE:
+            case XML_TAG_INT_TYPE:
                 return new LongPropertyConfig.Builder(name)
                         .setCardinality(cardinality)
                         .setIndexingType(
                                 getAttributeIntOrDefault(
                                         parser,
-                                        ATTRIBUTE_INDEXING_TYPE,
+                                        XML_ATTRIBUTE_INDEXING_TYPE,
                                         LongPropertyConfig.INDEXING_TYPE_NONE))
                         .build();
-            case TAG_BOOLEAN_TYPE:
+            case XML_TAG_BOOLEAN_TYPE:
                 return new BooleanPropertyConfig.Builder(name).setCardinality(cardinality).build();
             default:
-                if (type.contains(APPFN_NAMESPACE_PREFIX)) {
+                if (type.contains(XML_APPFN_NAMESPACE_PREFIX)) {
                     String localType = type.substring(type.indexOf(':') + 1);
-                    return new AppSearchSchema.DocumentPropertyConfig.Builder(name, localType)
+                    return new AppSearchSchema.DocumentPropertyConfig.Builder(
+                                    name,
+                                    AppFunctionStaticMetadata.getSchemaNameForPackage(
+                                            packageName, localType))
                             .setCardinality(cardinality)
                             .setShouldIndexNestedProperties(
                                     getAttributeBoolOrDefault(
-                                            parser, ATTRIBUTE_SHOULD_INDEX_NESTED_PROPERTIES, true))
+                                            parser,
+                                            XML_ATTRIBUTE_SHOULD_INDEX_NESTED_PROPERTIES,
+                                            true))
                             .build();
                 }
                 throw new IllegalArgumentException("Unsupported type: " + type);
diff --git a/service/java/com/android/server/appsearch/appsindexer/AppFunctionStaticMetadataParserImpl.java b/service/java/com/android/server/appsearch/appsindexer/AppFunctionStaticMetadataParserImpl.java
index 27a8867..c6eab15 100644
--- a/service/java/com/android/server/appsearch/appsindexer/AppFunctionStaticMetadataParserImpl.java
+++ b/service/java/com/android/server/appsearch/appsindexer/AppFunctionStaticMetadataParserImpl.java
@@ -328,7 +328,9 @@
 
         while (eventType != XmlPullParser.END_DOCUMENT) {
             String tagName = parser.getName();
-            if (eventType == XmlPullParser.START_TAG && schemas.containsKey(tagName)) {
+            String schemaName =
+                    AppFunctionStaticMetadata.getSchemaNameForPackage(packageName, tagName);
+            if (eventType == XmlPullParser.START_TAG && schemas.containsKey(schemaName)) {
                 GenericDocument appFnMetadata =
                         parseXmlElementToGenericDocument(
                                 parser,
@@ -401,7 +403,9 @@
                                 parseXmlElementToGenericDocument(
                                         parser,
                                         packageName,
-                                        ((DocumentPropertyConfig) propertyConfig).getSchemaType(),
+                                        getSchemaTypeWithoutPackage(
+                                                ((DocumentPropertyConfig) propertyConfig)
+                                                        .getSchemaType()),
                                         qualifiedPropertyNamesToPropertyConfig);
                         nestedDocumentValues
                                 .computeIfAbsent(currentPropertyPath, k -> new ArrayList<>())
@@ -463,7 +467,7 @@
         Map<String, PropertyConfig> propertyMap = new ArrayMap<>();
 
         for (Map.Entry<String, AppSearchSchema> entry : schemaMap.entrySet()) {
-            String schemaType = entry.getKey();
+            String schemaType = getSchemaTypeWithoutPackage(entry.getKey());
             AppSearchSchema schema = entry.getValue();
 
             List<AppSearchSchema.PropertyConfig> properties = schema.getProperties();
@@ -488,6 +492,17 @@
     }
 
     /**
+     * Returns the schema type without the package name suffix.
+     *
+     * <p>For example, if the schema name is "Person-com.example.app", this method will return
+     * "Person".
+     */
+    @NonNull
+    private static String getSchemaTypeWithoutPackage(@NonNull String schemaName) {
+        return Objects.requireNonNull(schemaName).substring(0, schemaName.indexOf('-'));
+    }
+
+    /**
      * Adds primitive property values to the given {@link GenericDocument.Builder} based on the
      * given {@link PropertyConfig}.
      *
diff --git a/service/java/com/android/server/appsearch/appsindexer/package-info.java b/service/java/com/android/server/appsearch/appsindexer/package-info.java
new file mode 100644
index 0000000..a80c504
--- /dev/null
+++ b/service/java/com/android/server/appsearch/appsindexer/package-info.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.server.appsearch.appsindexer;
+
+import android.app.appsearch.AppSearchSession;
+
+/**
+ * The package contains the implementation of the AppsIndexer used to index metadata about apps and
+ * app functions exposed by apps into AppSearch.
+ *
+ * <p>App function documents are indexed into AppSearch via {@link AppsIndexerImpl#doIncrementalUpdate} in a
+ * single {@link AppSearchHelper#APP_DATABASE} database. Within the database, each schema type is
+ * named dynamically to be unique to the app package name to control the schema visibility by the
+ * result of {@link android.content.pm.PackageManager#canPackageQuery}. This was preferred over
+ * defining one database per app because {@link AppSearchSession#setSchema} was a bottleneck for the
+ * inserting schemas into per app database.
+ */
diff --git a/testing/appsindexertests/src/com/android/server/appsearch/appsindexer/AppFunctionSchemaParserTest.java b/testing/appsindexertests/src/com/android/server/appsearch/appsindexer/AppFunctionSchemaParserTest.java
index 91ceccc..8ce59fd 100644
--- a/testing/appsindexertests/src/com/android/server/appsearch/appsindexer/AppFunctionSchemaParserTest.java
+++ b/testing/appsindexertests/src/com/android/server/appsearch/appsindexer/AppFunctionSchemaParserTest.java
@@ -16,7 +16,6 @@
 package com.android.server.appsearch.appsindexer;
 
 import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertThrows;
 
 import static org.mockito.Mockito.when;
 
@@ -67,7 +66,7 @@
     public void parse_singleType_withNoAttributes() throws Exception {
         String xsd =
                 "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
-                        + "    <xs:documentType name=\"TestType\">"
+                        + "    <xs:documentType name=\"AppFunctionStaticMetadata\">"
                         + "        <xs:element name=\"name\" type=\"xs:string\" />"
                         + "        <xs:element name=\"age\" type=\"xs:int\" />"
                         + "        <xs:element name=\"isActive\" type=\"xs:boolean\" />"
@@ -80,9 +79,9 @@
                         mPackageManager, TEST_PACKAGE_NAME, TEST_XML_ASSET_FILE_PATH);
 
         assertThat(schemas).hasSize(1);
-        assertThat(schemas.get("TestType"))
+        assertThat(schemas.get("AppFunctionStaticMetadata-com.example.app"))
                 .isEqualTo(
-                        new AppSearchSchema.Builder("TestType")
+                        new AppSearchSchema.Builder("AppFunctionStaticMetadata-com.example.app")
                                 .addProperty(new StringPropertyConfig.Builder("name").build())
                                 .addProperty(new LongPropertyConfig.Builder("age").build())
                                 .addProperty(new BooleanPropertyConfig.Builder("isActive").build())
@@ -93,11 +92,13 @@
     public void parse_singleType_withAttributes() throws Exception {
         String xsd =
                 "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
-                        + "    <xs:documentType name=\"TestType\">"
+                        + "    <xs:documentType name=\"AppFunctionStaticMetadata\">"
                         + "        <xs:element name=\"name\" type=\"xs:string\" indexingType=\""
                         + StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS
                         + "\" tokenizerType=\""
                         + StringPropertyConfig.TOKENIZER_TYPE_VERBATIM
+                        + "\" joinableValueType=\""
+                        + StringPropertyConfig.JOINABLE_VALUE_TYPE_QUALIFIED_ID
                         + "\" />"
                         + "        <xs:element name=\"age\" type=\"xs:int\" indexingType=\""
                         + LongPropertyConfig.INDEXING_TYPE_RANGE
@@ -114,9 +115,9 @@
                         mPackageManager, TEST_PACKAGE_NAME, TEST_XML_ASSET_FILE_PATH);
 
         assertThat(schemas).hasSize(1);
-        assertThat(schemas.get("TestType"))
+        assertThat(schemas.get("AppFunctionStaticMetadata-com.example.app"))
                 .isEqualTo(
-                        new AppSearchSchema.Builder("TestType")
+                        new AppSearchSchema.Builder("AppFunctionStaticMetadata-com.example.app")
                                 .addProperty(
                                         new StringPropertyConfig.Builder("name")
                                                 .setIndexingType(
@@ -125,6 +126,9 @@
                                                 .setTokenizerType(
                                                         StringPropertyConfig
                                                                 .TOKENIZER_TYPE_VERBATIM)
+                                                .setJoinableValueType(
+                                                        StringPropertyConfig
+                                                                .JOINABLE_VALUE_TYPE_QUALIFIED_ID)
                                                 .build())
                                 .addProperty(
                                         new LongPropertyConfig.Builder("age")
@@ -142,7 +146,7 @@
     public void parse_multipleNestedTypes() throws Exception {
         String xsd =
                 "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
-                        + "    <xs:documentType name=\"OuterType\">"
+                        + "    <xs:documentType name=\"AppFunctionStaticMetadata\">"
                         + "        <xs:element name=\"inner\" type=\"appfn:InnerType\" />"
                         + "    </xs:documentType>"
                         + "    <xs:documentType name=\"InnerType\">"
@@ -156,17 +160,17 @@
                         mPackageManager, TEST_PACKAGE_NAME, TEST_XML_ASSET_FILE_PATH);
 
         assertThat(schemas).hasSize(2);
-        assertThat(schemas.get("InnerType"))
+        assertThat(schemas.get("InnerType-com.example.app"))
                 .isEqualTo(
-                        new AppSearchSchema.Builder("InnerType")
+                        new AppSearchSchema.Builder("InnerType-com.example.app")
                                 .addProperty(new StringPropertyConfig.Builder("value").build())
                                 .build());
-        assertThat(schemas.get("OuterType"))
+        assertThat(schemas.get("AppFunctionStaticMetadata-com.example.app"))
                 .isEqualTo(
-                        new AppSearchSchema.Builder("OuterType")
+                        new AppSearchSchema.Builder("AppFunctionStaticMetadata-com.example.app")
                                 .addProperty(
                                         new AppSearchSchema.DocumentPropertyConfig.Builder(
-                                                        "inner", "InnerType")
+                                                        "inner", "InnerType-com.example.app")
                                                 .setShouldIndexNestedProperties(true)
                                                 .build())
                                 .build());
@@ -188,19 +192,30 @@
                         + "</xs:schema>";
         setXmlInput(xsd);
 
-        Exception e =
-                assertThrows(
-                        IllegalStateException.class,
-                        () ->
-                                mParser.parseAndCreateSchemas(
-                                        mPackageManager,
-                                        TEST_PACKAGE_NAME,
-                                        TEST_XML_ASSET_FILE_PATH));
-        assertThat(e).hasMessageThat().contains("Exceeded max allowed document types: 2");
+        Map<String, AppSearchSchema> schemas =
+                mParser.parseAndCreateSchemas(
+                        mPackageManager, TEST_PACKAGE_NAME, TEST_XML_ASSET_FILE_PATH);
+        assertThat(schemas).isEmpty();
     }
 
     @Test
-    public void parse_unsupportedType_throwsException() throws Exception {
+    public void parse_unsupportedType_returnsEmptyMap() throws Exception {
+        String xsd =
+                "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
+                        + "    <xs:documentType name=\"AppFunctionStaticMetadata\">"
+                        + "        <xs:element name=\"name\" type=\"xs:unsupportedType\" />"
+                        + "    </xs:documentType>"
+                        + "</xs:schema>";
+        setXmlInput(xsd);
+
+        Map<String, AppSearchSchema> schemas =
+                mParser.parseAndCreateSchemas(
+                        mPackageManager, TEST_PACKAGE_NAME, TEST_XML_ASSET_FILE_PATH);
+        assertThat(schemas).isEmpty();
+    }
+
+    @Test
+    public void parse_missingAppFunctionStaticMetadataType_returnsEmptyMap() throws Exception {
         String xsd =
                 "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
                         + "    <xs:documentType name=\"TestType\">"
@@ -209,15 +224,10 @@
                         + "</xs:schema>";
         setXmlInput(xsd);
 
-        Exception e =
-                assertThrows(
-                        IllegalArgumentException.class,
-                        () ->
-                                mParser.parseAndCreateSchemas(
-                                        mPackageManager,
-                                        TEST_PACKAGE_NAME,
-                                        TEST_XML_ASSET_FILE_PATH));
-        assertThat(e).hasMessageThat().contains("Unsupported type: xs:unsupportedType");
+        Map<String, AppSearchSchema> schemas =
+                mParser.parseAndCreateSchemas(
+                        mPackageManager, TEST_PACKAGE_NAME, TEST_XML_ASSET_FILE_PATH);
+        assertThat(schemas).isEmpty();
     }
 
     private void setXmlInput(String xml) throws IOException {
diff --git a/testing/appsindexertests/src/com/android/server/appsearch/appsindexer/AppFunctionStaticMetadataParserImplTest.java b/testing/appsindexertests/src/com/android/server/appsearch/appsindexer/AppFunctionStaticMetadataParserImplTest.java
index e92bd31..05d8b5b 100644
--- a/testing/appsindexertests/src/com/android/server/appsearch/appsindexer/AppFunctionStaticMetadataParserImplTest.java
+++ b/testing/appsindexertests/src/com/android/server/appsearch/appsindexer/AppFunctionStaticMetadataParserImplTest.java
@@ -48,7 +48,7 @@
     private static final String TEST_XML_ASSET_FILE_PATH = "app_functions.xml";
     private static final Map<String, AppSearchSchema> TEST_SCHEMAS =
             Map.of(
-                    "AppFunctionStaticMetadata",
+                    "AppFunctionStaticMetadata-com.example.app",
                     new AppSearchSchema.Builder("AppFunctionStaticMetadata-com.example.app")
                             .addProperty(
                                     new AppSearchSchema.StringPropertyConfig.Builder("functionId")
@@ -63,10 +63,10 @@
                             .addProperty(
                                     new AppSearchSchema.DocumentPropertyConfig.Builder(
                                                     "appFunctionParameterMetadata",
-                                                    "AppFunctionParameterMetadata")
+                                                    "AppFunctionParameterMetadata-com.example.app")
                                             .build())
                             .build(),
-                    "AppFunctionParameterMetadata",
+                    "AppFunctionParameterMetadata-com.example.app",
                     new AppSearchSchema.Builder("AppFunctionParameterMetadata-com.example.app")
                             .addProperty(
                                     new AppSearchSchema.StringPropertyConfig.Builder(