1 /* 2 * Copyright (C) 2023 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.appsearch.safeparcel; 18 19 import android.os.Parcel; 20 import android.os.Parcelable; 21 22 /** 23 * A SafeParcelable is a special {@link Parcelable} interface that marshalls its fields in a 24 * protobuf-like manner into a {@link Parcel}. The marshalling encodes a unique id for each field 25 * along with the size in bytes of the field. By doing this, older versions of a SafeParcelable can 26 * skip over unknown fields, which enables backwards compatibility. Because SafeParcelable extends a 27 * Parcelable, it is NOT safe for persistence. 28 * 29 * <p>To prevent the need to manually write code to marshall fields like in a Parcelable, a 30 * SafeParcelable implementing class is annotated with several annotations so that a generated 31 * "creator" class has the metadata it needs to automatically generate the boiler plate marshalling 32 * and unmarshalling code. 33 * 34 * <p>The main annotations are the following: 35 * 36 * <ul> 37 * <li>{@link Class} - This annotates the SafeParcelable implementing class and indicates the name 38 * of the generated "creator" class that has the boiler plate marshalling/unmarshalling code. 39 * You can also specify whether to call a method named validateContents() after a new instance 40 * of this class is constructed. 41 * <li>{@link VersionField} - This annotation may be on one field in the SafeParcelable to 42 * indicate the version number for this SafeParcelable. This is purely here for style reasons 43 * in case it is necessary for code to be dependent on the version of the SafeParcelable. This 44 * member field must be final. 45 * <li>{@link Field} - This annotates fields that will be marshalled and unmarshalled by the 46 * generated "creator" class. You must provide an integer "id" for each field. To ensure 47 * backwards compatibility, these field id's should never be changed. It is okay to omit field 48 * id's in future versions, but do not reuse old id's. Member fields annotated with {@link 49 * Field} may be any visibility (private, protected, etc.) and may also be final. You will 50 * have to specify the "getter" if member fields are not at least package visible. See details 51 * in {@link Field}. 52 * <li>{@link Constructor} - You must annotate one constructor with this annotation, which 53 * indicates the constructor that the "creator" class will use to construct a new instance of 54 * this class. Each parameter to this constructor must be annotated with the {@link Param} or 55 * {@link RemovedParam} annotation indicating the field id that the parameter corresponds to. 56 * Every {@link Param} must correspond to a {@link Field} or {@link VersionField}, and every 57 * {@link RemovedParam} must correspond to a {@link Reserved} field. Note that this 58 * constructor must have at least package visibility because the generated "creator" class 59 * must be able to use this constructor. (The "creator" class is generated in the same package 60 * as the SafeParcelable class.). 61 * <li>{@link Indicator} - This is an annotation on a field that keeps track of which fields are 62 * actually present in a Parcel that represents the marshalled version of a SafeParcelable. 63 * This is used in the GMS Core Apiary model class code generation. 64 * </ul> 65 * 66 * <p>Because a SafeParcelable extends Parcelable, you must have a public static final member named 67 * CREATOR and override writeToParcel() and describeContents(). Here's a typical example. 68 * 69 * <pre> 70 * @Class(creator="MySafeParcelableCreator", validate=true) 71 * public class MySafeParcelable implements SafeParcelable { 72 * public static final Parcelable.Creator<MySafeParcelable> CREATOR = 73 * new MySafeParcelableCreator(); 74 * 75 * @Field(id=1) 76 * public final String myString; 77 * 78 * @Field(id=2, getter="getInteger") 79 * private final int myInteger; 80 * 81 * @Constructor 82 * MySafeParcelable( 83 * @Param(id=1) String string, 84 * @Param(id=2) int integer) { 85 * myString = string; 86 * myInteger = integer; 87 * ) 88 * 89 * // Example public constructor (not used by MySafeParcelableCreator) 90 * public MySafeParcelable(String string, int integer) { 91 * myString = string; 92 * myInteger = integer; 93 * } 94 * 95 * // This is only needed if validate=true in @Class annotation. 96 * public void validateContents() { 97 * // Add validation here. 98 * } 99 * 100 * // This getter is needed because myInteger is private, and the generated creator class 101 * // MySafeParcelableCreator can't access private member fields. 102 * int getInteger() { 103 * return myInteger; 104 * } 105 * 106 * // This is necessary because SafeParcelable extends Parcelable. 107 * // {@link AbstractSafeParcelable} implements this for you. 108 * @Override 109 * public int describeContents() { 110 * return MySafeParcelableCreator.CONTENT_DESCRIPTION; 111 * } 112 * 113 * // This is necessary because SafeParcelable extends Parcelable. 114 * @Override 115 * public void writeToParcel(Parcel out, int flags) { 116 * // This invokes the generated MySafeParcelableCreator class's marshalling to a Parcel. 117 * // In the event you need custom logic when writing to a Parcel, that logic can be 118 * // inserted here. 119 * MySafeParcelableCreator.writeToParcel(this, out, flags); 120 * } 121 * } 122 * </pre> 123 * 124 * @hide 125 */ 126 // Include the SafeParcel source code directly in AppSearch until it gets officially open-sourced. 127 public interface SafeParcelable extends Parcelable { 128 /** @hide */ 129 // Note: the field name and value are accessed using reflection for backwards compatibility, and 130 // must not be changed. 131 String NULL = "SAFE_PARCELABLE_NULL_STRING"; 132 133 /** 134 * This annotates your class and specifies the name of the generated "creator" class for 135 * marshalling/unmarshalling a SafeParcelable to/from a {@link Parcel}. The "creator" class is 136 * generated in the same package as the SafeParcelable class. You can also set "validate" to 137 * true, which will cause the "creator" to invoke the method validateContents() on your class 138 * after constructing an instance. 139 */ 140 @SuppressWarnings("JavaLangClash") 141 @interface Class { 142 /** 143 * Simple name of the generated "creator" class generated in the same package as the 144 * SafeParceable. 145 */ creator()146 String creator(); 147 148 /** Whether the generated "creator" class is final. */ creatorIsFinal()149 boolean creatorIsFinal() default true; 150 151 /** 152 * When set to true, invokes the validateContents() method in this SafeParcelable object 153 * after constructing a new instance. 154 */ validate()155 boolean validate() default false; 156 157 /** 158 * When set to true, it will not write type default values to the Parcel. 159 * 160 * <p>boolean: false byte/char/short/int/long: 0 float: 0.0f double: 0.0 Objects/arrays: 161 * null 162 * 163 * <p>Cannot be used with Field(defaultValue) 164 */ doNotParcelTypeDefaultValues()165 boolean doNotParcelTypeDefaultValues() default false; 166 } 167 168 /** Use this annotation on members that you wish to be marshalled in the SafeParcelable. */ 169 @interface Field { 170 /** 171 * Valid values for id are between 1 and 65535. This field id is marshalled into a Parcel . 172 * To maintain backwards compatibility, never reuse old id's. It is okay to no longer use 173 * old id's and add new ones in subsequent versions of a SafeParcelable. 174 */ id()175 int id(); 176 177 /** 178 * This specifies the name of the getter method for retrieving the value of this field. This 179 * must be specified for fields that do not have at least package visibility because the 180 * "creator" class will be unable to access the value when attempting to marshall this 181 * field. The getter method should take no parameters and return the type of this field 182 * (unless overridden by the "type" attribute below). 183 */ getter()184 String getter() default NULL; 185 186 /** 187 * For advanced uses, this specifies the type for the field when marshalling and 188 * unmarshalling by the "creator" class to be something different than the declared type of 189 * the member variable. This is useful if you want to incorporate an object that is not 190 * SafeParcelable (or a system Parcelable object). Be sure to enter the fully qualified name 191 * for the class (i.e., android.os.Bundle and not Bundle). For example, 192 * 193 * <pre> 194 * @Class(creator="MyAdvancedCreator") 195 * public class MyAdvancedSafeParcelable implements SafeParcelable { 196 * public static final Parcelable.Creator<MyAdvancedSafeParcelable> CREATOR = 197 * new MyAdvancedCreator(); 198 * 199 * @Field(id=1, getter="getObjectAsBundle", type="android.os.Bundle") 200 * private final MyCustomObject myObject; 201 * 202 * @Constructor 203 * MyAdvancedSafeParcelable( 204 * @Param(id=1) Bundle objectAsBundle) { 205 * myObject = myConvertFromBundleToObject(objectAsBundle); 206 * } 207 * 208 * Bundle getObjectAsBundle() { 209 * // The code here can convert your custom object to one that can be parcelled. 210 * return myConvertFromObjectToBundle(myObject); 211 * } 212 * 213 * ... 214 * } 215 * </pre> 216 */ type()217 String type() default NULL; 218 219 /** 220 * This can be used to specify the default value for primitive types (e.g., boolean, int, 221 * long), primitive type object wrappers (e.g., Boolean, Integer, Long) and String in the 222 * case a value for a field was not explicitly set in the marshalled Parcel. This performs 223 * compile-time checks for the type of the field and inserts the appropriate quotes or 224 * double quotes around strings and chars or removes them completely for booleans and 225 * numbers. To insert a generic string for initializing field, use {@link 226 * #defaultValueUnchecked()}. You can specify at most one of {@link #defaultValue()} or 227 * {@link #defaultValueUnchecked()}. For example, 228 * 229 * <pre> 230 * @Field(id=2, defaultValue="true") 231 * boolean myBoolean; 232 * 233 * @Field(id=3, defaultValue="13") 234 * Integer myInteger; 235 * 236 * @Field(id=4, defaultValue="foo") 237 * String myString; 238 * </pre> 239 */ defaultValue()240 String defaultValue() default NULL; 241 242 /** 243 * This can be used to specify the default value for any object and the string value is 244 * literally added to the generated creator class code unchecked. You can specify at most 245 * one of {@link #defaultValue()} or {@link #defaultValueUnchecked()}. You must fully 246 * qualify any classes you reference within the string. For example, 247 * 248 * <pre> 249 * @Field(id=2, defaultValueUnchecked="new android.os.Bundle()") 250 * Bundle myBundle; 251 * </pre> 252 */ defaultValueUnchecked()253 String defaultValueUnchecked() default NULL; 254 } 255 256 /** 257 * There may be exactly one member annotated with VersionField, which represents the version of 258 * this safe parcelable. The attributes are the same as those of {@link Field}. Note you can use 259 * any type you want for your version field, although most people use int's. 260 */ 261 @interface VersionField { id()262 int id(); 263 getter()264 String getter() default NULL; 265 type()266 String type() default NULL; 267 } 268 269 /** 270 * Use this to indicate the member field that holds whether a field was set or not. The member 271 * field type currently supported is a HashSet<Integer> which is the set of safe 272 * parcelable field id's that have been explicitly set. 273 * 274 * <p>This annotation should also be used to annotate one of the parameters to the constructor 275 * annotated with @Constructor. Note that this annotation should either be present on 276 * exactly one member field and one constructor parameter or left out completely. 277 */ 278 @interface Indicator { getter()279 String getter() default NULL; 280 } 281 282 /** 283 * Use this to indicate the constructor that the creator should use. The constructor annotated 284 * with this must be package or public visibility, so that the generated "creator" class can 285 * invoke this. 286 */ 287 @interface Constructor {} 288 289 /** 290 * Use this on each parameter passed in to the Constructor to indicate to which field id each 291 * formal parameter corresponds. 292 */ 293 @interface Param { id()294 int id(); 295 } 296 297 /** 298 * Use this on a parameter passed in to the Constructor to indicate that a removed field should 299 * be read on construction. If the field is not present when read, the default value will be 300 * used instead. 301 */ 302 @interface RemovedParam { id()303 int id(); 304 defaultValue()305 String defaultValue() default NULL; 306 defaultValueUnchecked()307 String defaultValueUnchecked() default NULL; 308 } 309 310 /** 311 * Use this to mark tombstones for removed {@link Field Fields} or {@link VersionField 312 * VersionFields}. 313 */ 314 @interface Reserved { value()315 int[] value(); 316 } 317 } 318