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
This commit is contained in:
felkachang
2022-12-06 07:55:15 +00:00
parent d9c0b685fa
commit ccc347f14a

View File

@@ -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.
* <p>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.
* <pre>{@code
* <overlayable name="SignatureOverlayable" actor="overlay://theme">
* <!-- The app with the same signature can overlay the below resources -->
* <policy type="signature">
* <item type="color" name="mycolor" />
* <item type="string" name="mystring" />
* </policy>
* </overlayable>
* }</pre>
*
* Processes with {@link Android.Manifest.permission.CHANGE_OVERLAY_PACKAGES} can manage normal
* overlays and fabricated overlays.
* <p>The overlay must assign the target overlayable name just like the above example by calling
* {@link #setTargetOverlayable(String)}. Here is an example:
*
* <pre>{@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")
* }</pre>
*
* <p>The app can create any {@link FabricatedOverlay} instance by calling the following APIs.
*
* <ul>
* <li>{@link #setTargetOverlayable(String)}
* <li>{@link #setResourceValue(String, int, int, String)}
* <li>{@link #setResourceValue(String, int, String, String)}
* <li>{@link #setResourceValue(String, ParcelFileDescriptor, String)}
* </ul>
*
* @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).
* <p>The target package defines may define several overlayables. The
* {@link FabricatedOverlay} should specify which overlayable to be overlaid.
*
* <p>The target overlayable should be defined in {@code <overlayable>} 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<FabricatedOverlayInternalEntry> 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));
}
}