Merge "Support for a Context to "renounce" permissions." into sc-dev

This commit is contained in:
Jeff Sharkey
2021-03-07 19:05:26 +00:00
committed by Android (Google) Code Review
7 changed files with 154 additions and 35 deletions

View File

@@ -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);

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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;
private ContextParams() {
/* hide ctor */
/** {@hide} */
public static final ContextParams EMPTY = new ContextParams.Builder().build();
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;
}
/**
* Creates a new instance. You need to either specify an attribution tag
* or a receiver package or both.
* 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.
*
* @return The new instance.
*/
@NonNull
public ContextParams build() {
return new ContextParams();
return new ContextParams(this);
}
}
}

View File

@@ -171,6 +171,11 @@ public class ContextWrapper extends Context {
return mBase.getAttributionTag();
}
@Override
public @Nullable ContextParams getParams() {
return mBase.getParams();
}
@Override
public ApplicationInfo getApplicationInfo() {
return mBase.getApplicationInfo();
@@ -1044,6 +1049,12 @@ public class ContextWrapper extends Context {
return mBase.createWindowContext(display, type, options);
}
@Override
@NonNull
public Context createContext(@NonNull ContextParams contextParams) {
return mBase.createContext(contextParams);
}
@Override
public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
return mBase.createAttributionContext(attributionTag);

View File

@@ -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. -->