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