From 5014fbd6443637f4d7cd52860102cc03161172f8 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sat, 8 May 2021 08:12:00 -0600 Subject: [PATCH] Apply "attributionTags" to all component types. Components within an application are often a good boundary for developers to declare "attribution" information, such as an Activity or Service used to offer a specific sub-feature. This change expands the "android:attributionTags" manifest attribute to apply to all component types, and it then automatically configures the associated Context with Context.createAttributionContext() with no additional developer action required. Developers can still manually use Context.createAttributionContext() to adjust the attribution tag again if desired. Bug: 187097694 Test: atest CtsAppOpsTestCases:AttributionTest Test: atest CtsAppTestCases:android.app.cts.AttributionTagsTest Change-Id: Ia16c66e7b63bcbfb8c0d7348e9b5d4adb2a1f45d --- core/api/current.txt | 2 +- core/java/android/app/ActivityThread.java | 10 ++++- core/java/android/app/ContextImpl.java | 10 ++++- .../java/android/content/pm/ActivityInfo.java | 21 +---------- .../android/content/pm/ComponentInfo.java | 37 +++++++++++++++++++ .../parsing/PackageInfoWithoutStateUtils.java | 1 + .../pm/parsing/component/ParsedActivity.java | 12 ------ .../component/ParsedActivityUtils.java | 11 ++---- .../component/ParsedMainComponent.java | 15 ++++++++ .../component/ParsedMainComponentUtils.java | 10 ++++- .../component/ParsedProviderUtils.java | 3 +- .../parsing/component/ParsedServiceUtils.java | 3 +- core/res/res/values/attrs_manifest.xml | 29 +++++++++++++-- .../server/pm/parsing/PackageInfoUtils.java | 1 + 14 files changed, 116 insertions(+), 49 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index e3e90f506663a..607bb343238a2 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -11883,7 +11883,6 @@ package android.content.pm { field public static final int SCREEN_ORIENTATION_USER_LANDSCAPE = 11; // 0xb field public static final int SCREEN_ORIENTATION_USER_PORTRAIT = 12; // 0xc field public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1; // 0x1 - field public String[] attributionTags; field public int colorMode; field public int configChanges; field public int documentLaunchMode; @@ -12075,6 +12074,7 @@ package android.content.pm { method public final int getLogoResource(); method public boolean isEnabled(); field public android.content.pm.ApplicationInfo applicationInfo; + field public String[] attributionTags; field public int descriptionRes; field public boolean directBootAware; field public boolean enabled; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index a8f7a14068ba0..b1438eae65064 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3510,7 +3510,7 @@ public final class ActivityThread extends ClientTransactionHandler StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo), - activity.getAttributionSource()); + appContext.getAttributionSource()); if (r.state != null) { r.state.setClassLoader(cl); } @@ -4442,6 +4442,10 @@ public final class ActivityThread extends ClientTransactionHandler if (data.info.splitName != null) { context = (ContextImpl) context.createContextForSplit(data.info.splitName); } + if (data.info.attributionTags != null && data.info.attributionTags.length > 0) { + final String attributionTag = data.info.attributionTags[0]; + context = (ContextImpl) context.createAttributionContext(attributionTag); + } // Service resources must be initialized with the same loaders as the application // context. context.getResources().addLoaders( @@ -7353,6 +7357,10 @@ public final class ActivityThread extends ClientTransactionHandler throw new RuntimeException(e); } } + if (info.attributionTags != null && info.attributionTags.length > 0) { + final String attributionTag = info.attributionTags[0]; + c = c.createAttributionContext(attributionTag); + } try { final java.lang.ClassLoader cl = c.getClassLoader(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 17cba84acbebb..73c17b9cc96f7 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -3036,8 +3036,16 @@ class ContextImpl extends Context { } } + final String attributionTag; + if (activityInfo.attributionTags != null && activityInfo.attributionTags.length > 0) { + attributionTag = activityInfo.attributionTags[0]; + } else { + attributionTag = null; + } + ContextImpl context = new ContextImpl(null, mainThread, packageInfo, ContextParams.EMPTY, - null, null, activityInfo.splitName, activityToken, null, 0, classLoader, null); + attributionTag, null, activityInfo.splitName, activityToken, null, 0, classLoader, + null); context.mContextType = CONTEXT_TYPE_ACTIVITY; context.mIsConfigurationBasedContext = true; diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index fbed90787a97c..03f6380e279f2 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -17,8 +17,8 @@ package android.content.pm; import android.annotation.IntDef; -import android.annotation.SuppressLint; import android.annotation.TestApi; +import android.app.Activity; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.Disabled; @@ -1174,13 +1174,6 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { */ public WindowLayout windowLayout; - /** - * Attribution tags for finer grained calls if a {@link - * android.content.Context#sendBroadcast(Intent, String)} is used with a permission. - */ - @SuppressLint("MissingNullability") - public String[] attributionTags; - public ActivityInfo() { } @@ -1209,7 +1202,6 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { mMaxAspectRatio = orig.mMaxAspectRatio; mMinAspectRatio = orig.mMinAspectRatio; supportsSizeChanges = orig.supportsSizeChanges; - attributionTags = orig.attributionTags; } /** @@ -1532,15 +1524,6 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { if (supportsSizeChanges) { pw.println(prefix + "supportsSizeChanges=true"); } - if (attributionTags != null && attributionTags.length > 0) { - StringBuilder tags = new StringBuilder(); - tags.append(attributionTags[0]); - for (int i = 1; i < attributionTags.length; i++) { - tags.append(", "); - tags.append(attributionTags[i]); - } - pw.println(prefix + "attributionTags=[" + tags + "]"); - } super.dumpBack(pw, prefix, dumpFlags); } @@ -1586,7 +1569,6 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { dest.writeFloat(mMaxAspectRatio); dest.writeFloat(mMinAspectRatio); dest.writeBoolean(supportsSizeChanges); - dest.writeString8Array(attributionTags); } /** @@ -1706,7 +1688,6 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { mMaxAspectRatio = source.readFloat(); mMinAspectRatio = source.readFloat(); supportsSizeChanges = source.readBoolean(); - attributionTags = source.createString8Array(); } /** diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java index c67d00e88707e..42847c85103c7 100644 --- a/core/java/android/content/pm/ComponentInfo.java +++ b/core/java/android/content/pm/ComponentInfo.java @@ -16,8 +16,14 @@ package android.content.pm; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.Service; import android.compat.annotation.UnsupportedAppUsage; +import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Parcel; @@ -51,6 +57,25 @@ public class ComponentInfo extends PackageItemInfo { */ public String splitName; + /** + * Set of attribution tags that should be automatically applied to this + * component. + *

+ * When this component represents an {@link Activity}, {@link Service}, + * {@link ContentResolver} or {@link BroadcastReceiver}, each instance will + * be automatically configured with {@link Context#createAttributionContext} + * using the first attribution tag contained here. + *

+ * Additionally, when this component represents a {@link BroadcastReceiver} + * and the sender of a broadcast requires the receiver to hold one or more + * specific permissions, those permission checks will be performed using + * each of the attributions tags contained here. + * + * @see Context#createAttributionContext(String) + */ + @SuppressLint({"MissingNullability", "MutableBareField"}) + public String[] attributionTags; + /** * A string resource identifier (in the package's resources) containing * a user-readable description of the component. From the "description" @@ -87,6 +112,7 @@ public class ComponentInfo extends PackageItemInfo { applicationInfo = orig.applicationInfo; processName = orig.processName; splitName = orig.splitName; + attributionTags = orig.attributionTags; descriptionRes = orig.descriptionRes; enabled = orig.enabled; exported = orig.exported; @@ -172,6 +198,15 @@ public class ComponentInfo extends PackageItemInfo { if (splitName != null) { pw.println(prefix + "splitName=" + splitName); } + if (attributionTags != null && attributionTags.length > 0) { + StringBuilder tags = new StringBuilder(); + tags.append(attributionTags[0]); + for (int i = 1; i < attributionTags.length; i++) { + tags.append(", "); + tags.append(attributionTags[i]); + } + pw.println(prefix + "attributionTags=[" + tags + "]"); + } pw.println(prefix + "enabled=" + enabled + " exported=" + exported + " directBootAware=" + directBootAware); if (descriptionRes != 0) { @@ -200,6 +235,7 @@ public class ComponentInfo extends PackageItemInfo { applicationInfo.writeToParcel(dest, parcelableFlags); dest.writeString8(processName); dest.writeString8(splitName); + dest.writeString8Array(attributionTags); dest.writeInt(descriptionRes); dest.writeInt(enabled ? 1 : 0); dest.writeInt(exported ? 1 : 0); @@ -211,6 +247,7 @@ public class ComponentInfo extends PackageItemInfo { applicationInfo = ApplicationInfo.CREATOR.createFromParcel(source); processName = source.readString8(); splitName = source.readString8(); + attributionTags = source.createString8Array(); descriptionRes = source.readInt(); enabled = (source.readInt() != 0); exported = (source.readInt() != 0); diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java index a9d70c524af07..d407b106b5a30 100644 --- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java +++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java @@ -713,6 +713,7 @@ public class PackageInfoWithoutStateUtils { componentInfo.directBootAware = mainComponent.isDirectBootAware(); componentInfo.enabled = mainComponent.isEnabled(); componentInfo.splitName = mainComponent.getSplitName(); + componentInfo.attributionTags = mainComponent.getAttributionTags(); } private static void assignSharedFieldsForPackageItemInfo( diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java index 9285ccb3cf0ca..6f478accedd77 100644 --- a/core/java/android/content/pm/parsing/component/ParsedActivity.java +++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java @@ -82,9 +82,6 @@ public class ParsedActivity extends ParsedMainComponent { @Nullable ActivityInfo.WindowLayout windowLayout; - @Nullable - String[] attributionTags; - public ParsedActivity(ParsedActivity other) { super(other); this.theme = other.theme; @@ -110,7 +107,6 @@ public class ParsedActivity extends ParsedMainComponent { this.rotationAnimation = other.rotationAnimation; this.colorMode = other.colorMode; this.windowLayout = other.windowLayout; - this.attributionTags = other.attributionTags; } /** @@ -176,7 +172,6 @@ public class ParsedActivity extends ParsedMainComponent { alias.requestedVrComponent = target.requestedVrComponent; alias.directBootAware = target.directBootAware; alias.setProcessName(target.getProcessName()); - alias.attributionTags = target.attributionTags; return alias; // Not all attributes from the target ParsedActivity are copied to the alias. @@ -304,7 +299,6 @@ public class ParsedActivity extends ParsedMainComponent { } else { dest.writeBoolean(false); } - dest.writeString8Array(this.attributionTags); } public ParsedActivity() { @@ -338,7 +332,6 @@ public class ParsedActivity extends ParsedMainComponent { if (in.readBoolean()) { windowLayout = new ActivityInfo.WindowLayout(in); } - this.attributionTags = in.createString8Array(); } public static final Parcelable.Creator CREATOR = new Creator() { @@ -452,9 +445,4 @@ public class ParsedActivity extends ParsedMainComponent { public ActivityInfo.WindowLayout getWindowLayout() { return windowLayout; } - - @Nullable - public String[] getAttributionTags() { - return attributionTags; - } } diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java index aa740bdbc4068..92a90e98cb43d 100644 --- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java @@ -102,7 +102,8 @@ public class ParsedActivityUtils { R.styleable.AndroidManifestActivity_name, R.styleable.AndroidManifestActivity_process, R.styleable.AndroidManifestActivity_roundIcon, - R.styleable.AndroidManifestActivity_splitName); + R.styleable.AndroidManifestActivity_splitName, + R.styleable.AndroidManifestActivity_attributionTags); if (result.isError()) { return result; } @@ -212,11 +213,6 @@ public class ParsedActivityUtils { pkg.setVisibleToInstantApps(true); } - String attributionTags = sa.getString(R.styleable.AndroidManifestActivity_attributionTags); - if (attributionTags != null) { - activity.attributionTags = attributionTags.split("\\|"); - } - return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, receiver, false /*isAlias*/, visibleToEphemeral, input, R.styleable.AndroidManifestActivity_parentActivityName, @@ -281,7 +277,8 @@ public class ParsedActivityUtils { R.styleable.AndroidManifestActivityAlias_name, null /*processAttr*/, R.styleable.AndroidManifestActivityAlias_roundIcon, - null /*splitNameAttr*/); + null /*splitNameAttr*/, + R.styleable.AndroidManifestActivityAlias_attributionTags); if (result.isError()) { return result; } diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponent.java b/core/java/android/content/pm/parsing/component/ParsedMainComponent.java index a5e394d823567..033e30fe75821 100644 --- a/core/java/android/content/pm/parsing/component/ParsedMainComponent.java +++ b/core/java/android/content/pm/parsing/component/ParsedMainComponent.java @@ -39,6 +39,8 @@ public class ParsedMainComponent extends ParsedComponent { @Nullable String splitName; + @Nullable + String[] attributionTags; public ParsedMainComponent() { } @@ -51,6 +53,7 @@ public class ParsedMainComponent extends ParsedComponent { this.exported = other.exported; this.order = other.order; this.splitName = other.splitName; + this.attributionTags = other.attributionTags; } public ParsedMainComponent setProcessName(String processName) { @@ -84,6 +87,7 @@ public class ParsedMainComponent extends ParsedComponent { dest.writeBoolean(this.exported); dest.writeInt(this.order); dest.writeString(this.splitName); + dest.writeString8Array(this.attributionTags); } protected ParsedMainComponent(Parcel in) { @@ -94,6 +98,7 @@ public class ParsedMainComponent extends ParsedComponent { this.exported = in.readBoolean(); this.order = in.readInt(); this.splitName = in.readString(); + this.attributionTags = in.createString8Array(); } public static final Parcelable.Creator CREATOR = @@ -135,6 +140,11 @@ public class ParsedMainComponent extends ParsedComponent { return splitName; } + @Nullable + public String[] getAttributionTags() { + return attributionTags; + } + public ParsedMainComponent setDirectBootAware(boolean value) { directBootAware = value; return this; @@ -149,4 +159,9 @@ public class ParsedMainComponent extends ParsedComponent { splitName = value; return this; } + + public ParsedMainComponent setAttributionTags(@Nullable String[] value) { + attributionTags = value; + return this; + } } diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java index f70d62b56d496..54bcbdddfb342 100644 --- a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java @@ -48,7 +48,8 @@ class ParsedMainComponentUtils { TypedArray array, int flags, boolean useRoundIcon, ParseInput input, int bannerAttr, int descriptionAttr, @Nullable Integer directBootAwareAttr, @Nullable Integer enabledAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr, - @Nullable Integer processAttr, int roundIconAttr, @Nullable Integer splitNameAttr) { + @Nullable Integer processAttr, int roundIconAttr, @Nullable Integer splitNameAttr, + @Nullable Integer attributionTagsAttr) { ParseResult result = ParsedComponentUtils.parseComponent(component, tag, pkg, array, useRoundIcon, input, bannerAttr, descriptionAttr, iconAttr, labelAttr, logoAttr, nameAttr, roundIconAttr); @@ -94,6 +95,13 @@ class ParsedMainComponentUtils { component.splitName = array.getNonConfigurationString(splitNameAttr, 0); } + if (attributionTagsAttr != null) { + final String attributionTags = array.getNonConfigurationString(attributionTagsAttr, 0); + if (attributionTags != null) { + component.attributionTags = attributionTags.split("\\|"); + } + } + return input.success(component); } diff --git a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java index 4deab56c32104..28fd919e2b7e7 100644 --- a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java @@ -74,7 +74,8 @@ public class ParsedProviderUtils { R.styleable.AndroidManifestProvider_name, R.styleable.AndroidManifestProvider_process, R.styleable.AndroidManifestProvider_roundIcon, - R.styleable.AndroidManifestProvider_splitName); + R.styleable.AndroidManifestProvider_splitName, + R.styleable.AndroidManifestProvider_attributionTags); if (result.isError()) { return result; } diff --git a/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java b/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java index 739bee2fb7d9e..ae107ce65bf8a 100644 --- a/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java @@ -68,7 +68,8 @@ public class ParsedServiceUtils { R.styleable.AndroidManifestService_name, R.styleable.AndroidManifestService_process, R.styleable.AndroidManifestService_roundIcon, - R.styleable.AndroidManifestService_splitName + R.styleable.AndroidManifestService_splitName, + R.styleable.AndroidManifestService_attributionTags ); if (result.isError()) { diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 638627422eff3..ef0dc37329c71 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2593,6 +2593,12 @@ + + + + + - - + +