• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app.appfunctions;
18 
19 import static android.app.appfunctions.AppFunctionManager.APP_FUNCTION_STATE_DEFAULT;
20 import static android.app.appfunctions.AppFunctionManager.APP_FUNCTION_STATE_DISABLED;
21 import static android.app.appfunctions.AppFunctionManager.APP_FUNCTION_STATE_ENABLED;
22 import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
23 
24 import android.annotation.FlaggedApi;
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.app.appfunctions.AppFunctionManager.EnabledState;
28 import android.app.appsearch.AppSearchSchema;
29 import android.app.appsearch.GenericDocument;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 
33 import java.util.Objects;
34 
35 /**
36  * Represents runtime function metadata of an app function.
37  *
38  * <p>This is a temporary solution for app function indexing, as later we would like to index the
39  * actual function signature entity class shape instead of just the schema info.
40  *
41  * @hide
42  */
43 // TODO(b/357551503): Link to canonical docs rather than duplicating once they
44 // are available.
45 @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
46 public class AppFunctionRuntimeMetadata extends GenericDocument {
47     public static final String RUNTIME_SCHEMA_TYPE = "AppFunctionRuntimeMetadata";
48     public static final String APP_FUNCTION_INDEXER_PACKAGE = "android";
49     public static final String APP_FUNCTION_RUNTIME_METADATA_DB = "appfunctions-db";
50     public static final String APP_FUNCTION_RUNTIME_NAMESPACE = "app_functions_runtime";
51     public static final String PROPERTY_FUNCTION_ID = "functionId";
52     public static final String PROPERTY_PACKAGE_NAME = "packageName";
53     public static final String PROPERTY_ENABLED = "enabled";
54     public static final String PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID =
55             "appFunctionStaticMetadataQualifiedId";
56     private static final String TAG = "AppSearchAppFunction";
57     private static final String RUNTIME_SCHEMA_TYPE_SEPARATOR = "-";
58 
AppFunctionRuntimeMetadata(@onNull GenericDocument genericDocument)59     public AppFunctionRuntimeMetadata(@NonNull GenericDocument genericDocument) {
60         super(genericDocument);
61     }
62 
63     /** Returns a per-app runtime metadata schema name, to store all functions for that package. */
getRuntimeSchemaNameForPackage(@onNull String pkg)64     public static String getRuntimeSchemaNameForPackage(@NonNull String pkg) {
65         return RUNTIME_SCHEMA_TYPE + RUNTIME_SCHEMA_TYPE_SEPARATOR + Objects.requireNonNull(pkg);
66     }
67 
68     /** Returns the package name from the runtime metadata schema name. */
69     @NonNull
getPackageNameFromSchema(String metadataSchemaType)70     public static String getPackageNameFromSchema(String metadataSchemaType) {
71         String[] split = metadataSchemaType.split(RUNTIME_SCHEMA_TYPE_SEPARATOR);
72         if (split.length > 2) {
73             throw new IllegalArgumentException(
74                     "Invalid schema type: " + metadataSchemaType + " for app function runtime");
75         }
76         if (split.length < 2) {
77             return APP_FUNCTION_INDEXER_PACKAGE;
78         }
79         return split[1];
80     }
81 
82     /** Returns the document id for an app function's runtime metadata. */
getDocumentIdForAppFunction( @onNull String pkg, @NonNull String functionId)83     public static String getDocumentIdForAppFunction(
84             @NonNull String pkg, @NonNull String functionId) {
85         return pkg + "/" + functionId;
86     }
87 
88     /**
89      * Different packages have different visibility requirements. To allow for different visibility,
90      * we need to have per-package app function schemas.
91      *
92      * <p>This schema should be set visible to callers from the package owner itself and for callers
93      * with the permission {@link android.Manifest.permission#EXECUTE_APP_FUNCTIONS}.
94      *
95      * @param packageName The package name to create a schema for.
96      */
97     @NonNull
createAppFunctionRuntimeSchema(@onNull String packageName)98     public static AppSearchSchema createAppFunctionRuntimeSchema(@NonNull String packageName) {
99         return getAppFunctionRuntimeSchemaBuilder(getRuntimeSchemaNameForPackage(packageName))
100                 .addParentType(RUNTIME_SCHEMA_TYPE)
101                 .build();
102     }
103 
104     /**
105      * Creates a parent schema for all app function runtime schemas.
106      *
107      * <p>This schema should be set visible to the owner itself and for callers with
108      * the permission {@link android.permission.EXECUTE_APP_FUNCTIONS}.
109      */
createParentAppFunctionRuntimeSchema()110     public static AppSearchSchema createParentAppFunctionRuntimeSchema() {
111         return getAppFunctionRuntimeSchemaBuilder(RUNTIME_SCHEMA_TYPE).build();
112     }
113 
getAppFunctionRuntimeSchemaBuilder( @onNull String schemaType)114     private static AppSearchSchema.Builder getAppFunctionRuntimeSchemaBuilder(
115             @NonNull String schemaType) {
116         return new AppSearchSchema.Builder(schemaType)
117                 .addProperty(
118                         new AppSearchSchema.StringPropertyConfig.Builder(PROPERTY_FUNCTION_ID)
119                                 .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
120                                 .setIndexingType(
121                                         AppSearchSchema.StringPropertyConfig
122                                                 .INDEXING_TYPE_EXACT_TERMS)
123                                 .setTokenizerType(
124                                         AppSearchSchema.StringPropertyConfig
125                                                 .TOKENIZER_TYPE_VERBATIM)
126                                 .build())
127                 .addProperty(
128                         new AppSearchSchema.StringPropertyConfig.Builder(PROPERTY_PACKAGE_NAME)
129                                 .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
130                                 .setIndexingType(
131                                         AppSearchSchema.StringPropertyConfig
132                                                 .INDEXING_TYPE_EXACT_TERMS)
133                                 .setTokenizerType(
134                                         AppSearchSchema.StringPropertyConfig
135                                                 .TOKENIZER_TYPE_VERBATIM)
136                                 .build())
137                 .addProperty(
138                         new AppSearchSchema.LongPropertyConfig.Builder(PROPERTY_ENABLED)
139                                 .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
140                                 .setIndexingType(
141                                         AppSearchSchema.LongPropertyConfig.INDEXING_TYPE_RANGE)
142                                 .build())
143                 .addProperty(
144                         new AppSearchSchema.StringPropertyConfig.Builder(
145                                         PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID)
146                                 .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
147                                 .setJoinableValueType(
148                                         AppSearchSchema.StringPropertyConfig
149                                                 .JOINABLE_VALUE_TYPE_QUALIFIED_ID)
150                                 .build());
151     }
152 
153     /** Returns the function id. This might look like "com.example.message#send_message". */
154     @NonNull
getFunctionId()155     public String getFunctionId() {
156         return Objects.requireNonNull(getPropertyString(PROPERTY_FUNCTION_ID));
157     }
158 
159     /** Returns the package name of the package that owns this function. */
160     @NonNull
getPackageName()161     public String getPackageName() {
162         return Objects.requireNonNull(getPropertyString(PROPERTY_PACKAGE_NAME));
163     }
164 
165     /**
166      * Returns if the function is set to be enabled or not. If not set, the {@link
167      * AppFunctionStaticMetadataHelper#STATIC_PROPERTY_ENABLED_BY_DEFAULT} value would be used.
168      */
169     @EnabledState
getEnabled()170     public int getEnabled() {
171         // getPropertyLong returns the first long associated with the given path or default value 0
172         // if there is no such value or the value is of a different type.
173         // APP_FUNCTION_STATE_DEFAULT also equals 0 which means the returned value will be 0 when an
174         // app as either never changed the enabled bit at runtime or has reset it to the default.
175         return (int) getPropertyLong(PROPERTY_ENABLED);
176     }
177 
178     /** Returns the qualified id linking to the static metadata of the app function. */
179     @Nullable
180     @VisibleForTesting
getAppFunctionStaticMetadataQualifiedId()181     public String getAppFunctionStaticMetadataQualifiedId() {
182         return getPropertyString(PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID);
183     }
184 
185     public static final class Builder extends GenericDocument.Builder<Builder> {
186         /**
187          * Creates a Builder for a {@link AppFunctionRuntimeMetadata}.
188          *
189          * @param packageName the name of the package that owns the function.
190          * @param functionId the id of the function.
191          */
Builder(@onNull String packageName, @NonNull String functionId)192         public Builder(@NonNull String packageName, @NonNull String functionId) {
193             super(
194                     APP_FUNCTION_RUNTIME_NAMESPACE,
195                     getDocumentIdForAppFunction(
196                             Objects.requireNonNull(packageName),
197                             Objects.requireNonNull(functionId)),
198                     getRuntimeSchemaNameForPackage(packageName));
199             setPropertyString(PROPERTY_PACKAGE_NAME, packageName);
200             setPropertyString(PROPERTY_FUNCTION_ID, functionId);
201 
202             // Set qualified id automatically
203             setPropertyString(
204                     PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID,
205                     AppFunctionStaticMetadataHelper.getStaticMetadataQualifiedId(
206                             packageName, functionId));
207         }
208 
Builder(AppFunctionRuntimeMetadata original)209         public Builder(AppFunctionRuntimeMetadata original) {
210             this(original.getPackageName(), original.getFunctionId());
211             setEnabled(original.getEnabled());
212         }
213 
214         /** Sets an indicator specifying the function enabled state. */
215         @NonNull
setEnabled(@nabledState int enabledState)216         public Builder setEnabled(@EnabledState int enabledState) {
217             if (enabledState != APP_FUNCTION_STATE_DEFAULT
218                     && enabledState != APP_FUNCTION_STATE_ENABLED
219                     && enabledState != APP_FUNCTION_STATE_DISABLED) {
220                 throw new IllegalArgumentException("Value of EnabledState is unsupported.");
221             }
222             setPropertyLong(PROPERTY_ENABLED, enabledState);
223             return this;
224         }
225 
226         /** Creates the {@link AppFunctionRuntimeMetadata} GenericDocument. */
227         @NonNull
build()228         public AppFunctionRuntimeMetadata build() {
229             return new AppFunctionRuntimeMetadata(super.build());
230         }
231     }
232 }
233