From ccc347f14acee64dbbf8b11a847fe1d9394b2201 Mon Sep 17 00:00:00 2001 From: felkachang Date: Tue, 6 Dec 2022 07:55:15 +0000 Subject: [PATCH] Prepare comments and annotations for public FabricatedOverlay API This patch adds the following items. * FabricatedOverlay class comments. * add a FabricatedOverlay contructor * add a public method `setTargetOverlayable` * add setResourceValue APIs for * int * String * ParcelFileDescriptor * comments and annotations for methods in FabricatedOverlay. * such as nullability Bug: 205919743 Test: atest \ OverlayHostTests \ OverlayDeviceTests \ SelfTargetingOverlayDeviceTests \ OverlayRemountedTest \ FrameworksServicesTests:com.android.server.om \ CtsContentTestCases:android.content.om.cts \ idmap2_tests Change-Id: I689f5882fc3e1fc74a343106ef310f23a83990cf --- .../android/content/om/FabricatedOverlay.java | 406 +++++++++++++----- 1 file changed, 310 insertions(+), 96 deletions(-) diff --git a/core/java/android/content/om/FabricatedOverlay.java b/core/java/android/content/om/FabricatedOverlay.java index 99fc5a3ae5430..e4936bc36742d 100644 --- a/core/java/android/content/om/FabricatedOverlay.java +++ b/core/java/android/content/om/FabricatedOverlay.java @@ -35,29 +35,84 @@ import java.util.ArrayList; import java.util.Objects; /** - * Fabricated Runtime Resource Overlays (FRROs) are overlays generated ar runtime. + * FabricatedOverlay describes the content of Fabricated Runtime Resource Overlay (FRRO) that is + * used to overlay the app's resources. The app should register the {@link FabricatedOverlay} + * instance in an {@link OverlayManagerTransaction} by calling {@link + * OverlayManagerTransaction#registerFabricatedOverlay(FabricatedOverlay)}. The FRRO is + * created once the transaction is committed successfully. * - * Fabricated overlays are enabled, disabled, and reordered just like normal overlays. The - * overlayable policies a fabricated overlay fulfills are the same policies the creator of the - * overlay fulfill. For example, a fabricated overlay created by a platform signed package on the - * system partition would fulfil the {@code system} and {@code signature} policies. + *

The app creates a FabricatedOverlay to describe the how to overlay string, integer, and file + * type resources. Before creating any frro, please define a target overlayable in {@code + * res/values/overlayable.xml} that describes what kind of resources can be overlaid, what kind of + * roles or applications can overlay the resources. Here is an example. * - * The owner of a fabricated overlay is the UID that created it. Overlays commit to the overlay - * manager persist across reboots. When the UID is uninstalled, its fabricated overlays are wiped. + *

{@code
+ * 
+ *     
+ *     
+ *         
+ *         
+ *     
+ * 
+ * }
* - * Processes with {@link Android.Manifest.permission.CHANGE_OVERLAY_PACKAGES} can manage normal - * overlays and fabricated overlays. + *

The overlay must assign the target overlayable name just like the above example by calling + * {@link #setTargetOverlayable(String)}. Here is an example: + * + *

{@code
+ * FabricatedOverlay fabricatedOverlay = new FabricatedOverlay("overlay_name",
+ *                                                             context.getPackageName());
+ * fabricatedOverlay.setTargetOverlayable("SignatureOverlayable")
+ * fabricatedOverlay.setResourceValue("mycolor", TypedValue.TYPE_INT_COLOR_ARGB8, Color.White)
+ * fabricatedOverlay.setResourceValue("mystring", TypedValue.TYPE_STRING, "Hello")
+ * }
+ * + *

The app can create any {@link FabricatedOverlay} instance by calling the following APIs. + * + *

+ * + * @see OverlayManager + * @see OverlayManagerTransaction * @hide */ public class FabricatedOverlay { - /** Retrieves the identifier for this fabricated overlay. */ + /** + * Retrieves the identifier for this fabricated overlay. + * @return the overlay identifier + * + * @hide + */ public OverlayIdentifier getIdentifier() { return new OverlayIdentifier( mOverlay.packageName, TextUtils.nullIfEmpty(mOverlay.overlayName)); } - public static class Builder { + /** + * The builder of Fabricated Runtime Resource Overlays(FRROs). + * + * Fabricated overlays are enabled, disabled, and reordered just like normal overlays. The + * overlayable policies a fabricated overlay fulfills are the same policies the creator of the + * overlay fulfill. For example, a fabricated overlay created by a platform signed package on + * the system partition would fulfil the {@code system} and {@code signature} policies. + * + * The owner of a fabricated overlay is the UID that created it. Overlays commit to the overlay + * manager persist across reboots. When the UID is uninstalled, its fabricated overlays are + * wiped. + * + * Processes with {@code android.Manifest.permission#CHANGE_OVERLAY_PACKAGES} can manage normal + * overlays and fabricated overlays. + * + * @see FabricatedOverlay + * @see OverlayManagerTransaction.Builder#registerFabricatedOverlay(FabricatedOverlay) + * @hide + */ + public static final class Builder { private final String mOwningPackage; private final String mName; private final String mTargetPackage; @@ -88,22 +143,16 @@ public class FabricatedOverlay { } /** - * Constructs a builder for building a fabricated overlay. + * Sets the name of the target overlayable to be overlaid. * - * @param name a name used to uniquely identify the fabricated overlay owned by the caller - * itself. - * @param targetPackage the name of the package to overlay - */ - public Builder(@NonNull String name, @NonNull String targetPackage) { - mName = OverlayManagerImpl.checkOverlayNameValid(name); - mTargetPackage = - Preconditions.checkStringNotEmpty( - targetPackage, "'targetPackage' must not be empty nor null"); - mOwningPackage = ""; // The package name is filled in OverlayManager.commit - } - - /** - * Sets the name of the overlayable resources to overlay (can be null). + *

The target package defines may define several overlayables. The + * {@link FabricatedOverlay} should specify which overlayable to be overlaid. + * + *

The target overlayable should be defined in {@code } and pass the value + * of its {@code name} attribute as the parameter. + * + * @param targetOverlayable is a name of the overlayable resources set + * @hide */ @NonNull public Builder setTargetOverlayable(@Nullable String targetOverlayable) { @@ -111,27 +160,6 @@ public class FabricatedOverlay { return this; } - /** - * Ensure the resource name is in the form [package]:type/entry. - * - * @param name name of the target resource to overlay (in the form [package]:type/entry) - * @return the valid name - */ - private static String ensureValidResourceName(@NonNull String name) { - Objects.requireNonNull(name); - final int slashIndex = name.indexOf('/'); /* must contain '/' */ - final int colonIndex = name.indexOf(':'); /* ':' should before '/' if ':' exist */ - - // The minimum length of resource type is "id". - Preconditions.checkArgument( - slashIndex >= 0 /* It must contain the type name */ - && colonIndex != 0 /* 0 means the package name is empty */ - && (slashIndex - colonIndex) > 2 /* The shortest length of type is "id" */, - "\"%s\" is invalid resource name", - name); - return name; - } - /** * Sets the value of the fabricated overlay for the integer-like types. * @@ -141,8 +169,12 @@ public class FabricatedOverlay { * @param value the unsigned 32 bit integer representing the new value * @return the builder itself * @see #setResourceValue(String, int, int, String) - * @see android.util.TypedValue#type + * @see android.util.TypedValue#TYPE_INT_COLOR_ARGB8 android.util.TypedValue#type + * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, int, + int, String)} instead. + * @hide */ + @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, @@ -161,8 +193,13 @@ public class FabricatedOverlay { * @param dataType the data type of the new value * @param value the unsigned 32 bit integer representing the new value * @param configuration The string representation of the config this overlay is enabled for - * @see android.util.TypedValue#type + * @return the builder itself + * @see android.util.TypedValue#TYPE_INT_COLOR_ARGB8 android.util.TypedValue#type + * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, int, + int, String)} instead. + * @hide */ + @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, @@ -171,30 +208,11 @@ public class FabricatedOverlay { int value, @Nullable String configuration) { ensureValidResourceName(resourceName); - - final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); - entry.resourceName = resourceName; - entry.dataType = - Preconditions.checkArgumentInRange( - dataType, - TypedValue.TYPE_FIRST_INT, - TypedValue.TYPE_LAST_INT, - "dataType"); - entry.data = value; - entry.configuration = configuration; - mEntries.add(entry); + mEntries.add(generateFabricatedOverlayInternalEntry(resourceName, dataType, value, + configuration)); return this; } - /** @hide */ - @IntDef( - prefix = {"OVERLAY_TYPE"}, - value = { - TypedValue.TYPE_STRING, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface StringTypeOverlayResource {} - /** * Sets the value of the fabricated overlay for the string-like type. * @@ -203,8 +221,12 @@ public class FabricatedOverlay { * @param dataType the data type of the new value * @param value the string representing the new value * @return the builder itself - * @see android.util.TypedValue#type + * @see android.util.TypedValue#TYPE_STRING android.util.TypedValue#type + * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, int, + String, String)} instead. + * @hide */ + @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, @@ -221,8 +243,13 @@ public class FabricatedOverlay { * @param dataType the data type of the new value * @param value the string representing the new value * @param configuration The string representation of the config this overlay is enabled for - * @see android.util.TypedValue#type + * @return the builder itself + * @see android.util.TypedValue#TYPE_STRING android.util.TypedValue#type + * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, int, + String, String)} instead. + * @hide */ + @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, @@ -230,39 +257,32 @@ public class FabricatedOverlay { @NonNull String value, @Nullable String configuration) { ensureValidResourceName(resourceName); - - final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); - entry.resourceName = resourceName; - entry.dataType = - Preconditions.checkArgumentInRange( - dataType, TypedValue.TYPE_STRING, TypedValue.TYPE_FRACTION, "dataType"); - entry.stringData = Objects.requireNonNull(value); - entry.configuration = configuration; - mEntries.add(entry); + mEntries.add(generateFabricatedOverlayInternalEntry(resourceName, dataType, value, + configuration)); return this; } /** - * Sets the value of the fabricated overlay + * Sets the value of the fabricated overlay for the file descriptor type. * * @param resourceName name of the target resource to overlay (in the form * [package]:type/entry) * @param value the file descriptor whose contents are the value of the frro * @param configuration The string representation of the config this overlay is enabled for * @return the builder itself + * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, + ParcelFileDescriptor, String)} instead. + * @hide */ + @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, @NonNull ParcelFileDescriptor value, @Nullable String configuration) { ensureValidResourceName(resourceName); - - final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); - entry.resourceName = resourceName; - entry.binaryData = Objects.requireNonNull(value); - entry.configuration = configuration; - mEntries.add(entry); + mEntries.add( + generateFabricatedOverlayInternalEntry(resourceName, value, configuration)); return this; } @@ -270,22 +290,216 @@ public class FabricatedOverlay { * Builds an immutable fabricated overlay. * * @return the fabricated overlay + * @hide */ @NonNull public FabricatedOverlay build() { - final FabricatedOverlayInternal overlay = new FabricatedOverlayInternal(); - overlay.packageName = mOwningPackage; - overlay.overlayName = mName; - overlay.targetPackageName = mTargetPackage; - overlay.targetOverlayable = mTargetOverlayable; - overlay.entries = new ArrayList<>(); - overlay.entries.addAll(mEntries); - return new FabricatedOverlay(overlay); + return new FabricatedOverlay( + generateFabricatedOverlayInternal(mOwningPackage, mName, mTargetPackage, + mTargetOverlayable, mEntries)); } } + private static FabricatedOverlayInternal generateFabricatedOverlayInternal( + @NonNull String owningPackage, @NonNull String overlayName, + @NonNull String targetPackageName, @Nullable String targetOverlayable, + @NonNull ArrayList entries) { + final FabricatedOverlayInternal overlay = new FabricatedOverlayInternal(); + overlay.packageName = owningPackage; + overlay.overlayName = overlayName; + overlay.targetPackageName = targetPackageName; + overlay.targetOverlayable = TextUtils.emptyIfNull(targetOverlayable); + overlay.entries = new ArrayList<>(); + overlay.entries.addAll(entries); + return overlay; + } + final FabricatedOverlayInternal mOverlay; private FabricatedOverlay(FabricatedOverlayInternal overlay) { mOverlay = overlay; } + + /** + * Create a fabricated overlay to overlay on the specified package. + * + * @param overlayName a name used to uniquely identify the fabricated overlay owned by the + * caller itself. + * @param targetPackage the name of the package to be overlaid + * @hide + */ + public FabricatedOverlay(@NonNull String overlayName, @NonNull String targetPackage) { + this(generateFabricatedOverlayInternal( + "" /* owningPackage, The package name is filled commitment */, + OverlayManagerImpl.checkOverlayNameValid(overlayName), + Preconditions.checkStringNotEmpty(targetPackage, + "'targetPackage' must not be empty nor null"), + null /* targetOverlayable */, + new ArrayList<>())); + } + + /** + * Set the target overlayable name of the overlay + * + * The target package defines may define several overlayables. The {@link FabricatedOverlay} + * should specify which overlayable to be overlaid. + * + * @param targetOverlayable the overlayable name defined in target package. + * @hide + */ + public void setTargetOverlayable(@Nullable String targetOverlayable) { + mOverlay.targetOverlayable = TextUtils.emptyIfNull(targetOverlayable); + } + + /** + * Return the target overlayable name of the overlay + * + * The target package defines may define several overlayables. The {@link FabricatedOverlay} + * should specify which overlayable to be overlaid. + * + * @return the target overlayable name. + * @hide + */ + @Nullable + public String getTargetOverlayable() { + return mOverlay.targetOverlayable; + } + + /** + * Ensure the resource name is in the form [package]:type/entry. + * + * @param name name of the target resource to overlay (in the form [package]:type/entry) + * @return the valid name + */ + private static String ensureValidResourceName(@NonNull String name) { + Objects.requireNonNull(name); + final int slashIndex = name.indexOf('/'); /* must contain '/' */ + final int colonIndex = name.indexOf(':'); /* ':' should before '/' if ':' exist */ + + // The minimum length of resource type is "id". + Preconditions.checkArgument( + slashIndex >= 0 /* It must contain the type name */ + && colonIndex != 0 /* 0 means the package name is empty */ + && (slashIndex - colonIndex) > 2 /* The shortest length of type is "id" */, + "\"%s\" is invalid resource name", + name); + return name; + } + + @NonNull + private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry( + @NonNull String resourceName, + @IntRange(from = TypedValue.TYPE_FIRST_INT, to = TypedValue.TYPE_LAST_INT) int dataType, + int value, @Nullable String configuration) { + final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); + entry.resourceName = resourceName; + entry.dataType = + Preconditions.checkArgumentInRange( + dataType, + TypedValue.TYPE_FIRST_INT, + TypedValue.TYPE_LAST_INT, + "dataType"); + entry.data = value; + entry.configuration = configuration; + return entry; + } + + @NonNull + private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry( + @NonNull String resourceName, @StringTypeOverlayResource int dataType, + @NonNull String value, @Nullable String configuration) { + final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); + entry.resourceName = resourceName; + entry.dataType = + Preconditions.checkArgumentInRange( + dataType, TypedValue.TYPE_STRING, TypedValue.TYPE_FRACTION, "dataType"); + entry.stringData = Objects.requireNonNull(value); + entry.configuration = configuration; + return entry; + } + + @NonNull + private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry( + @NonNull String resourceName, @NonNull ParcelFileDescriptor parcelFileDescriptor, + @Nullable String configuration) { + final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); + entry.resourceName = resourceName; + entry.binaryData = Objects.requireNonNull(parcelFileDescriptor); + entry.configuration = configuration; + return entry; + } + + /** + * Sets the resource value in the fabricated overlay for the integer-like types with the + * configuration. + * + * @param resourceName name of the target resource to overlay (in the form + * [package]:type/entry) + * @param dataType the data type of the new value + * @param value the integer representing the new value + * @param configuration The string representation of the config this overlay is enabled for + * @see android.util.TypedValue#TYPE_INT_COLOR_ARGB8 android.util.TypedValue#type + * @hide + */ + @NonNull + public void setResourceValue( + @NonNull String resourceName, + @IntRange(from = TypedValue.TYPE_FIRST_INT, to = TypedValue.TYPE_LAST_INT) int dataType, + int value, + @Nullable String configuration) { + ensureValidResourceName(resourceName); + mOverlay.entries.add(generateFabricatedOverlayInternalEntry(resourceName, dataType, value, + configuration)); + } + + /** @hide */ + @IntDef( + prefix = {"OVERLAY_TYPE"}, + value = { + TypedValue.TYPE_STRING, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface StringTypeOverlayResource {} + + /** + * Sets the resource value in the fabricated overlay for the string-like type with the + * configuration. + * + * @param resourceName name of the target resource to overlay (in the form + * [package]:type/entry) + * @param dataType the data type of the new value + * @param value the string representing the new value + * @param configuration The string representation of the config this overlay is enabled for + * @see android.util.TypedValue#TYPE_STRING android.util.TypedValue#type + * @hide + */ + @NonNull + public void setResourceValue( + @NonNull String resourceName, + @StringTypeOverlayResource int dataType, + @NonNull String value, + @Nullable String configuration) { + ensureValidResourceName(resourceName); + mOverlay.entries.add(generateFabricatedOverlayInternalEntry(resourceName, dataType, value, + configuration)); + } + + /** + * Sets the resource value in the fabricated overlay for the file descriptor type with the + * configuration. + * + * @param resourceName name of the target resource to overlay (in the form + * [package]:type/entry) + * @param value the file descriptor whose contents are the value of the frro + * @param configuration The string representation of the config this overlay is enabled for + * @hide + */ + @NonNull + public void setResourceValue( + @NonNull String resourceName, + @NonNull ParcelFileDescriptor value, + @Nullable String configuration) { + ensureValidResourceName(resourceName); + mOverlay.entries.add( + generateFabricatedOverlayInternalEntry(resourceName, value, configuration)); + } }