blob: 5cc3a2420811ed6bb32a36df3337451966705e41 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.content.pm.PackageManager;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
/**
* This class represents rules around how a context being created via
* {@link Context#createContext} should behave.
*
* <p>One of the dimensions to customize is how permissions should behave.
* For example, you can specify how permission accesses from a context should
* be attributed in the platform's permission tracking system.
*
* <p>The two main types of attribution are: against an attribution tag which
* is an arbitrary string your app specifies for the purposes of tracking permission
* accesses from a given portion of your app; against another package and optionally
* its attribution tag if you are accessing the data on behalf of another app and
* you will be passing that data to this app, recursively. Both attributions are
* not mutually exclusive.
*
* @see Context#createContext(ContextParams)
* @see AttributionSource
*/
public final class ContextParams {
private final @Nullable String mAttributionTag;
private final @Nullable AttributionSource mNext;
private final @NonNull Set<String> mRenouncedPermissions;
/** {@hide} */
public static final ContextParams EMPTY = new ContextParams.Builder().build();
private ContextParams(@Nullable String attributionTag,
@Nullable AttributionSource next,
@Nullable Set<String> renouncedPermissions) {
mAttributionTag = attributionTag;
mNext = next;
mRenouncedPermissions = (renouncedPermissions != null)
? renouncedPermissions : Collections.emptySet();
}
/**
* @return The attribution tag.
*/
@Nullable
public String getAttributionTag() {
return mAttributionTag;
}
/**
* @return The set of permissions to treat as renounced.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
public @NonNull Set<String> getRenouncedPermissions() {
return mRenouncedPermissions;
}
/** @hide */
public boolean isRenouncedPermission(@NonNull String permission) {
return mRenouncedPermissions.contains(permission);
}
/**
* @return The receiving attribution source.
*/
@Nullable
public AttributionSource getNextAttributionSource() {
return mNext;
}
/**
* Builder for creating a {@link ContextParams}.
*/
public static final class Builder {
private @Nullable String mAttributionTag;
private @NonNull Set<String> mRenouncedPermissions = Collections.emptySet();
private @Nullable AttributionSource mNext;
/**
* Create a new builder.
* <p>
* This is valuable when you are interested in having explicit control
* over every sub-parameter, and don't want to inherit any values from
* an existing Context.
* <p>
* Developers should strongly consider using
* {@link #Builder(ContextParams)} instead of this constructor, since
* that will will automatically inherit any new sub-parameters added in
* future platform releases.
*/
public Builder() {
}
/**
* Create a new builder that inherits all sub-parameters by default.
* <p>
* This is valuable when you are only interested in overriding specific
* sub-parameters, and want to preserve all other parameters. Setting a
* specific sub-parameter on the returned builder will override any
* inherited value.
*/
public Builder(@NonNull ContextParams params) {
Objects.requireNonNull(params);
mAttributionTag = params.mAttributionTag;
mRenouncedPermissions = params.mRenouncedPermissions;
mNext = params.mNext;
}
/**
* Sets an attribution tag against which to track permission accesses.
*
* @param attributionTag The attribution tag.
* @return This builder.
*/
@NonNull
public Builder setAttributionTag(@Nullable String attributionTag) {
mAttributionTag = attributionTag;
return this;
}
/**
* Sets the attribution source for the app on whose behalf you are doing the work.
*
* @param next The permission identity of the receiving app.
* @return This builder.
*
* @see AttributionSource
*/
@NonNull
public Builder setNextAttributionSource(@Nullable AttributionSource next) {
mNext = next;
return this;
}
/**
* Sets permissions which have been voluntarily "renounced" by the
* calling app.
* <p>
* Interactions performed through services obtained from 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. Additionally, this
* mechanism only applies to calls made through services obtained via
* {@link Context#getSystemService}; it has no effect on static or raw
* Binder calls.
*
* @param renouncedPermissions The set of permissions to treat as
* renounced, which is as if not granted.
* @return This builder.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
public @NonNull Builder setRenouncedPermissions(
@Nullable Set<String> renouncedPermissions) {
// This is not a security check but a fail fast - the OS enforces the permission too
if (renouncedPermissions != null && !renouncedPermissions.isEmpty()
&& ActivityThread.currentApplication().checkSelfPermission(Manifest.permission
.RENOUNCE_PERMISSIONS) != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Renouncing permissions requires: "
+ Manifest.permission.RENOUNCE_PERMISSIONS);
}
mRenouncedPermissions = renouncedPermissions;
return this;
}
/**
* Creates a new instance.
*
* @return The new instance.
*/
@NonNull
public ContextParams build() {
return new ContextParams(mAttributionTag, mNext,
mRenouncedPermissions);
}
}
}