diff options
| -rw-r--r-- | core/api/current.txt | 1 | ||||
| -rw-r--r-- | core/api/system-current.txt | 9 | ||||
| -rw-r--r-- | core/java/android/app/ContextImpl.java | 73 | ||||
| -rw-r--r-- | core/java/android/content/Context.java | 8 | ||||
| -rw-r--r-- | core/java/android/content/ContextParams.java | 82 | ||||
| -rw-r--r-- | core/java/android/content/ContextWrapper.java | 11 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 5 |
7 files changed, 154 insertions, 35 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index a5647cbcbc5e..b1e8645a2ae3 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -10387,6 +10387,7 @@ package android.content { method public abstract android.content.pm.PackageManager getPackageManager(); method public abstract String getPackageName(); method public abstract String getPackageResourcePath(); + method @Nullable public android.content.ContextParams getParams(); method public abstract android.content.res.Resources getResources(); method public abstract android.content.SharedPreferences getSharedPreferences(String, int); method @NonNull public final String getString(@StringRes int); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 53e1539b3339..5d8eade65dc6 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -228,6 +228,7 @@ package android { field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER"; field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES"; field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS"; + field public static final String RENOUNCE_PERMISSIONS = "android.permission.RENOUNCE_PERMISSIONS"; field public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES"; field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE"; field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD"; @@ -2184,6 +2185,14 @@ package android.content { field public static final String WIFI_SCANNING_SERVICE = "wifiscanner"; } + public final class ContextParams { + method @Nullable @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public java.util.Set<java.lang.String> getRenouncedPermissions(); + } + + public static final class ContextParams.Builder { + method @NonNull @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public android.content.ContextParams.Builder setRenouncedPermissions(@NonNull java.util.Set<java.lang.String>); + } + public class ContextWrapper extends android.content.Context { method public android.content.Context createCredentialProtectedStorageContext(); method @Nullable public java.io.File getPreloadsFileCache(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index fd56c449012f..d040938803f6 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -24,7 +24,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; -import android.content.ContextParams; import android.content.AutofillOptions; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -32,6 +31,7 @@ import android.content.ContentCaptureOptions; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; +import android.content.ContextParams; import android.content.ContextWrapper; import android.content.IContentProvider; import android.content.IIntentReceiver; @@ -221,8 +221,7 @@ class ContextImpl extends Context { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final String mOpPackageName; - /** Attribution tag of this context */ - private final @Nullable String mAttributionTag; + private final @NonNull ContextParams mParams; private final @NonNull ResourcesManager mResourcesManager; @UnsupportedAppUsage @@ -470,7 +469,12 @@ class ContextImpl extends Context { /** @hide */ @Override public @Nullable String getAttributionTag() { - return mAttributionTag; + return mParams.getAttributionTag(); + } + + @Override + public @Nullable ContextParams getParams() { + return mParams; } @Override @@ -2047,6 +2051,11 @@ class ContextImpl extends Context { if (permission == null) { throw new IllegalArgumentException("permission is null"); } + if (mParams.isRenouncedPermission(permission) + && pid == android.os.Process.myPid() && uid == android.os.Process.myUid()) { + Log.v(TAG, "Treating renounced permission " + permission + " as denied"); + return PERMISSION_DENIED; + } return PermissionManager.checkPermission(permission, pid, uid); } @@ -2056,6 +2065,11 @@ class ContextImpl extends Context { if (permission == null) { throw new IllegalArgumentException("permission is null"); } + if (mParams.isRenouncedPermission(permission) + && pid == android.os.Process.myPid() && uid == android.os.Process.myUid()) { + Log.v(TAG, "Treating renounced permission " + permission + " as denied"); + return PERMISSION_DENIED; + } try { return ActivityManager.getService().checkPermissionWithToken( @@ -2093,6 +2107,10 @@ class ContextImpl extends Context { if (permission == null) { throw new IllegalArgumentException("permission is null"); } + if (mParams.isRenouncedPermission(permission)) { + Log.v(TAG, "Treating renounced permission " + permission + " as denied"); + return PERMISSION_DENIED; + } return checkPermission(permission, Process.myPid(), Process.myUid()); } @@ -2393,8 +2411,9 @@ class ContextImpl extends Context { LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(), flags | CONTEXT_REGISTER_PACKAGE); if (pi != null) { - ContextImpl c = new ContextImpl(this, mMainThread, pi, null, null, mToken, - new UserHandle(UserHandle.getUserId(application.uid)), flags, null, null); + ContextImpl c = new ContextImpl(this, mMainThread, pi, ContextParams.EMPTY, null, + mToken, new UserHandle(UserHandle.getUserId(application.uid)), + flags, null, null); final int displayId = getDisplayId(); final Integer overrideDisplayId = mForceDisplayOverrideInResources @@ -2423,14 +2442,14 @@ class ContextImpl extends Context { if (packageName.equals("system") || packageName.equals("android")) { // The system resources are loaded in every application, so we can safely copy // the context without reloading Resources. - return new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, null, + return new ContextImpl(this, mMainThread, mPackageInfo, mParams, null, mToken, user, flags, null, null); } LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier()); if (pi != null) { - ContextImpl c = new ContextImpl(this, mMainThread, pi, mAttributionTag, null, + ContextImpl c = new ContextImpl(this, mMainThread, pi, mParams, null, mToken, user, flags, null, null); final int displayId = getDisplayId(); @@ -2469,7 +2488,7 @@ class ContextImpl extends Context { final String[] paths = mPackageInfo.getSplitPaths(splitName); final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, - mAttributionTag, splitName, mToken, mUser, mFlags, classLoader, null); + mParams, splitName, mToken, mUser, mFlags, classLoader, null); context.setResources(ResourcesManager.getInstance().getResources( mToken, @@ -2502,7 +2521,7 @@ class ContextImpl extends Context { overrideConfiguration = displayAdjustedConfig; } - ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, + ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams, mSplitName, mToken, mUser, mFlags, mClassLoader, null); final int displayId = getDisplayId(); @@ -2520,7 +2539,7 @@ class ContextImpl extends Context { throw new IllegalArgumentException("display must not be null"); } - ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, + ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams, mSplitName, mToken, mUser, mFlags, mClassLoader, null); final int displayId = display.getDisplayId(); @@ -2578,7 +2597,7 @@ class ContextImpl extends Context { ContextImpl createBaseWindowContext(IBinder token, Display display) { - ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, + ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams, mSplitName, token, mUser, mFlags, mClassLoader, null); // Window contexts receive configurations directly from the server and as such do not // need to override their display in ResourcesManager. @@ -2609,21 +2628,21 @@ class ContextImpl extends Context { @NonNull @Override - public Context createContext(@NonNull ContextParams contextParams) { - return this; + public Context createContext(@NonNull ContextParams params) { + return new ContextImpl(this, mMainThread, mPackageInfo, params, mSplitName, + mToken, mUser, mFlags, mClassLoader, null); } @Override public @NonNull Context createAttributionContext(@Nullable String attributionTag) { - return new ContextImpl(this, mMainThread, mPackageInfo, attributionTag, mSplitName, - mToken, mUser, mFlags, mClassLoader, null); + return createContext(new ContextParams.Builder().setAttributionTag(attributionTag).build()); } @Override public Context createDeviceProtectedStorageContext() { final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE) | Context.CONTEXT_DEVICE_PROTECTED_STORAGE; - return new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, mSplitName, + return new ContextImpl(this, mMainThread, mPackageInfo, mParams, mSplitName, mToken, mUser, flags, mClassLoader, null); } @@ -2631,7 +2650,7 @@ class ContextImpl extends Context { public Context createCredentialProtectedStorageContext() { final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE) | Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE; - return new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, mSplitName, + return new ContextImpl(this, mMainThread, mPackageInfo, mParams, mSplitName, mToken, mUser, flags, mClassLoader, null); } @@ -2805,8 +2824,8 @@ class ContextImpl extends Context { @UnsupportedAppUsage static ContextImpl createSystemContext(ActivityThread mainThread) { LoadedApk packageInfo = new LoadedApk(mainThread); - ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, null, - 0, null, null); + ContextImpl context = new ContextImpl(null, mainThread, packageInfo, + ContextParams.EMPTY, null, null, null, 0, null, null); context.setResources(packageInfo.getResources()); context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(), context.mResourcesManager.getDisplayMetrics()); @@ -2823,8 +2842,8 @@ class ContextImpl extends Context { */ static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) { final LoadedApk packageInfo = systemContext.mPackageInfo; - ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null, - null, null, null, 0, null, null); + ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, + ContextParams.EMPTY, null, null, null, 0, null, null); context.setResources(createResources(null, packageInfo, null, displayId, null, packageInfo.getCompatibilityInfo(), null)); context.updateDisplay(displayId); @@ -2848,8 +2867,8 @@ class ContextImpl extends Context { static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo, String opPackageName) { if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); - ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, null, - 0, null, opPackageName); + ContextImpl context = new ContextImpl(null, mainThread, packageInfo, + ContextParams.EMPTY, null, null, null, 0, null, opPackageName); context.setResources(packageInfo.getResources()); context.mContextType = isSystemOrSystemUI(context) ? CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI : CONTEXT_TYPE_NON_UI; @@ -2878,7 +2897,7 @@ class ContextImpl extends Context { } } - ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, + ContextImpl context = new ContextImpl(null, mainThread, packageInfo, ContextParams.EMPTY, activityInfo.splitName, activityToken, null, 0, classLoader, null); context.mContextType = CONTEXT_TYPE_ACTIVITY; @@ -2911,7 +2930,7 @@ class ContextImpl extends Context { } private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread, - @NonNull LoadedApk packageInfo, @Nullable String attributionTag, + @NonNull LoadedApk packageInfo, @NonNull ContextParams params, @Nullable String splitName, @Nullable IBinder token, @Nullable UserHandle user, int flags, @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) { mOuterContext = this; @@ -2966,7 +2985,7 @@ class ContextImpl extends Context { } mOpPackageName = overrideOpPackageName != null ? overrideOpPackageName : opPackageName; - mAttributionTag = attributionTag; + mParams = Objects.requireNonNull(params); mContentResolver = new ApplicationContentResolver(this, mainThread); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 30b3d43ab23e..df5c58c2634f 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -888,6 +888,14 @@ public abstract class Context { return getAttributionTag(); } + /** + * Return the set of parameters which this Context was created with, if it + * was created via {@link #createContext(ContextParams)}. + */ + public @Nullable ContextParams getParams() { + return null; + } + /** Return the full application info for this context's package. */ public abstract ApplicationInfo getApplicationInfo(); diff --git a/core/java/android/content/ContextParams.java b/core/java/android/content/ContextParams.java index 16128a650c12..17ec2a847d4f 100644 --- a/core/java/android/content/ContextParams.java +++ b/core/java/android/content/ContextParams.java @@ -18,6 +18,13 @@ package android.content; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; + +import java.util.Collections; +import java.util.Objects; +import java.util.Set; /** * This class represents rules around how a context being created via @@ -48,9 +55,19 @@ import android.annotation.Nullable; * @see Context#createContext(ContextParams) */ public final class ContextParams { + private final String mAttributionTag; + private final String mReceiverPackage; + private final String mReceiverAttributionTag; + private final Set<String> mRenouncedPermissions; + + /** {@hide} */ + public static final ContextParams EMPTY = new ContextParams.Builder().build(); - private ContextParams() { - /* hide ctor */ + private ContextParams(@NonNull ContextParams.Builder builder) { + mAttributionTag = builder.mAttributionTag; + mReceiverPackage = builder.mReceiverPackage; + mReceiverAttributionTag = builder.mReceiverAttributionTag; + mRenouncedPermissions = builder.mRenouncedPermissions; } /** @@ -58,7 +75,7 @@ public final class ContextParams { */ @Nullable public String getAttributionTag() { - return null; + return mAttributionTag; } /** @@ -66,7 +83,7 @@ public final class ContextParams { */ @Nullable public String getReceiverPackage() { - return null; + return mReceiverPackage; } /** @@ -74,13 +91,33 @@ public final class ContextParams { */ @Nullable public String getReceiverAttributionTag() { - return null; + return mReceiverAttributionTag; + } + + /** + * @return The set of permissions to treat as renounced. + * @hide + */ + @SystemApi + @SuppressLint("NullableCollection") + @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) + public @Nullable Set<String> getRenouncedPermissions() { + return mRenouncedPermissions; + } + + /** @hide */ + public boolean isRenouncedPermission(@NonNull String permission) { + return mRenouncedPermissions != null && mRenouncedPermissions.contains(permission); } /** * Builder for creating a {@link ContextParams}. */ public static final class Builder { + private String mAttributionTag; + private String mReceiverPackage; + private String mReceiverAttributionTag; + private Set<String> mRenouncedPermissions; /** * Sets an attribution tag against which to track permission accesses. @@ -90,6 +127,7 @@ public final class ContextParams { */ @NonNull public Builder setAttributionTag(@NonNull String attributionTag) { + mAttributionTag = Objects.requireNonNull(attributionTag); return this; } @@ -104,18 +142,46 @@ public final class ContextParams { @NonNull public Builder setReceiverPackage(@NonNull String packageName, @Nullable String attributionTag) { + mReceiverPackage = Objects.requireNonNull(packageName); + mReceiverAttributionTag = attributionTag; + return this; + } + + /** + * Sets permissions which have been voluntarily "renounced" by the + * calling app. + * <p> + * Interactions performed through the created Context will ideally be + * treated as if these "renounced" permissions have not actually been + * granted to the app, regardless of their actual grant status. + * <p> + * This is designed for use by separate logical components within an app + * which have no intention of interacting with data or services that are + * protected by the renounced permissions. + * <p> + * Note that only {@link PermissionInfo#PROTECTION_DANGEROUS} + * permissions are supported by this mechanism. + * + * @param renouncedPermissions The set of permissions to treat as + * renounced. + * @return This builder. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) + public @NonNull Builder setRenouncedPermissions(@NonNull Set<String> renouncedPermissions) { + mRenouncedPermissions = Collections.unmodifiableSet(renouncedPermissions); return this; } /** - * Creates a new instance. You need to either specify an attribution tag - * or a receiver package or both. + * Creates a new instance. * * @return The new instance. */ @NonNull public ContextParams build() { - return new ContextParams(); + return new ContextParams(this); } } } diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index b71fb2712c24..609f417a8008 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -172,6 +172,11 @@ public class ContextWrapper extends Context { } @Override + public @Nullable ContextParams getParams() { + return mBase.getParams(); + } + + @Override public ApplicationInfo getApplicationInfo() { return mBase.getApplicationInfo(); } @@ -1045,6 +1050,12 @@ public class ContextWrapper extends Context { } @Override + @NonNull + public Context createContext(@NonNull ContextParams contextParams) { + return mBase.createContext(contextParams); + } + + @Override public @NonNull Context createAttributionContext(@Nullable String attributionTag) { return mBase.createAttributionContext(attributionTag); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 072bb8799e59..4bbb69fdeb97 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5561,6 +5561,11 @@ <permission android:name="android.permission.READ_PEOPLE_DATA" android:protectionLevel="signature|appPredictor|recents"/> + <!-- @hide @SystemApi Allows a logical component within an application to + temporarily renounce a set of otherwise granted permissions. --> + <permission android:name="android.permission.RENOUNCE_PERMISSIONS" + android:protectionLevel="signature|privileged" /> + <!-- Attribution for Geofencing service. --> <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> |