1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.content;
18 
19 import android.Manifest;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresPermission;
23 import android.annotation.SystemApi;
24 import android.app.ActivityThread;
25 import android.content.pm.PackageManager;
26 
27 import java.util.Collections;
28 import java.util.Objects;
29 import java.util.Set;
30 
31 /**
32  * This class represents rules around how a context being created via
33  * {@link Context#createContext} should behave.
34  *
35  * <p>One of the dimensions to customize is how permissions should behave.
36  * For example, you can specify how permission accesses from a context should
37  * be attributed in the platform's permission tracking system.
38  *
39  * <p>The two main types of attribution are: against an attribution tag which
40  * is an arbitrary string your app specifies for the purposes of tracking permission
41  * accesses from a given portion of your app; against another package and optionally
42  * its attribution tag if you are accessing the data on behalf of another app and
43  * you will be passing that data to this app, recursively. Both attributions are
44  * not mutually exclusive.
45  *
46  * @see Context#createContext(ContextParams)
47  * @see AttributionSource
48  */
49 public final class ContextParams {
50     private final @Nullable String mAttributionTag;
51     private final @Nullable AttributionSource mNext;
52     private final @NonNull Set<String> mRenouncedPermissions;
53 
54     /** {@hide} */
55     public static final ContextParams EMPTY = new ContextParams.Builder().build();
56 
ContextParams(@ullable String attributionTag, @Nullable AttributionSource next, @Nullable Set<String> renouncedPermissions)57     private ContextParams(@Nullable String attributionTag,
58             @Nullable AttributionSource next,
59             @Nullable Set<String> renouncedPermissions) {
60         mAttributionTag = attributionTag;
61         mNext = next;
62         mRenouncedPermissions = (renouncedPermissions != null)
63                 ? renouncedPermissions : Collections.emptySet();
64     }
65 
66     /**
67      * @return The attribution tag.
68      */
69     @Nullable
getAttributionTag()70     public String getAttributionTag() {
71         return mAttributionTag;
72     }
73 
74     /**
75      * @return The set of permissions to treat as renounced.
76      * @hide
77      */
78     @SystemApi
79     @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
getRenouncedPermissions()80     public @NonNull Set<String> getRenouncedPermissions() {
81         return mRenouncedPermissions;
82     }
83 
84     /** @hide */
isRenouncedPermission(@onNull String permission)85     public boolean isRenouncedPermission(@NonNull String permission) {
86         return mRenouncedPermissions.contains(permission);
87     }
88 
89     /**
90      * @return The receiving attribution source.
91      */
92     @Nullable
getNextAttributionSource()93     public AttributionSource getNextAttributionSource() {
94         return mNext;
95     }
96 
97     /**
98      * Builder for creating a {@link ContextParams}.
99      */
100     public static final class Builder {
101         private @Nullable String mAttributionTag;
102         private @NonNull Set<String> mRenouncedPermissions = Collections.emptySet();
103         private @Nullable AttributionSource mNext;
104 
105         /**
106          * Create a new builder.
107          * <p>
108          * This is valuable when you are interested in having explicit control
109          * over every sub-parameter, and don't want to inherit any values from
110          * an existing Context.
111          * <p>
112          * Developers should strongly consider using
113          * {@link #Builder(ContextParams)} instead of this constructor, since
114          * that will will automatically inherit any new sub-parameters added in
115          * future platform releases.
116          */
Builder()117         public Builder() {
118         }
119 
120         /**
121          * Create a new builder that inherits all sub-parameters by default.
122          * <p>
123          * This is valuable when you are only interested in overriding specific
124          * sub-parameters, and want to preserve all other parameters. Setting a
125          * specific sub-parameter on the returned builder will override any
126          * inherited value.
127          */
Builder(@onNull ContextParams params)128         public Builder(@NonNull ContextParams params) {
129             Objects.requireNonNull(params);
130             mAttributionTag = params.mAttributionTag;
131             mRenouncedPermissions = params.mRenouncedPermissions;
132             mNext = params.mNext;
133         }
134 
135         /**
136          * Sets an attribution tag against which to track permission accesses.
137          *
138          * @param attributionTag The attribution tag.
139          * @return This builder.
140          */
141         @NonNull
setAttributionTag(@ullable String attributionTag)142         public Builder setAttributionTag(@Nullable String attributionTag) {
143             mAttributionTag = attributionTag;
144             return this;
145         }
146 
147         /**
148          * Sets the attribution source for the app on whose behalf you are doing the work.
149          *
150          * @param next The permission identity of the receiving app.
151          * @return This builder.
152          *
153          * @see AttributionSource
154          */
155         @NonNull
setNextAttributionSource(@ullable AttributionSource next)156         public Builder setNextAttributionSource(@Nullable AttributionSource next) {
157             mNext = next;
158             return this;
159         }
160 
161         /**
162          * Sets permissions which have been voluntarily "renounced" by the
163          * calling app.
164          * <p>
165          * Interactions performed through services obtained from the created
166          * Context will ideally be treated as if these "renounced" permissions
167          * have not actually been granted to the app, regardless of their actual
168          * grant status.
169          * <p>
170          * This is designed for use by separate logical components within an app
171          * which have no intention of interacting with data or services that are
172          * protected by the renounced permissions.
173          * <p>
174          * Note that only {@link PermissionInfo#PROTECTION_DANGEROUS}
175          * permissions are supported by this mechanism. Additionally, this
176          * mechanism only applies to calls made through services obtained via
177          * {@link Context#getSystemService}; it has no effect on static or raw
178          * Binder calls.
179          *
180          * @param renouncedPermissions The set of permissions to treat as
181          *            renounced, which is as if not granted.
182          * @return This builder.
183          * @hide
184          */
185         @SystemApi
186         @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
setRenouncedPermissions( @ullable Set<String> renouncedPermissions)187         public @NonNull Builder setRenouncedPermissions(
188                 @Nullable Set<String> renouncedPermissions) {
189             // This is not a security check but a fail fast - the OS enforces the permission too
190             if (renouncedPermissions != null && !renouncedPermissions.isEmpty()
191                     && ActivityThread.currentApplication().checkSelfPermission(Manifest.permission
192                     .RENOUNCE_PERMISSIONS) != PackageManager.PERMISSION_GRANTED) {
193                 throw new SecurityException("Renouncing permissions requires: "
194                         + Manifest.permission.RENOUNCE_PERMISSIONS);
195             }
196             mRenouncedPermissions = renouncedPermissions;
197             return this;
198         }
199 
200         /**
201          * Creates a new instance.
202          *
203          * @return The new instance.
204          */
205         @NonNull
build()206         public ContextParams build() {
207             return new ContextParams(mAttributionTag, mNext,
208                     mRenouncedPermissions);
209         }
210     }
211 }
212