• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotation.FlaggedApi;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresPermission;
23 import android.annotation.SystemApi;
24 import android.annotation.TestApi;
25 import android.app.ActivityThread;
26 import android.app.AppGlobals;
27 import android.os.Binder;
28 import android.os.Build;
29 import android.os.IBinder;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 import android.os.Process;
33 import android.os.UserHandle;
34 import android.permission.PermissionManager;
35 import android.permission.flags.Flags;
36 import android.util.ArraySet;
37 import android.util.Log;
38 
39 import com.android.internal.annotations.Immutable;
40 
41 import java.util.Arrays;
42 import java.util.Collections;
43 import java.util.Objects;
44 import java.util.Set;
45 
46 /**
47  * This class represents a source to which access to permission protected data should be
48  * attributed. Attribution sources can be chained to represent cases where the protected
49  * data would flow through several applications. For example, app A may ask app B for
50  * contacts and in turn app B may ask app C for contacts. In this case, the attribution
51  * chain would be A -> B -> C and the data flow would be C -> B -> A. There are two
52  * main benefits of using the attribution source mechanism: avoid doing explicit permission
53  * checks on behalf of the calling app if you are accessing private data on their behalf
54  * to send back; avoid double data access blaming which happens as you check the calling
55  * app's permissions and when you access the data behind these permissions (for runtime
56  * permissions). Also if not explicitly blaming the caller the data access would be
57  * counted towards your app vs to the previous app where yours was just a proxy.
58  * <p>
59  * Every {@link Context} has an attribution source and you can get it via {@link
60  * Context#getAttributionSource()} representing itself, which is a chain of one. You
61  * can attribute work to another app, or more precisely to a chain of apps, through
62  * which the data you would be accessing would flow, via {@link Context#createContext(
63  * ContextParams)} plus specifying an attribution source for the next app to receive
64  * the protected data you are accessing via {@link AttributionSource.Builder#setNext(
65  * AttributionSource)}. Creating this attribution chain ensures that the datasource would
66  * check whether every app in the attribution chain has permission to access the data
67  * before releasing it. The datasource will also record appropriately that this data was
68  * accessed by the apps in the sequence if the data is behind a sensitive permission
69  * (e.g. dangerous). Again, this is useful if you are accessing the data on behalf of another
70  * app, for example a speech recognizer using the mic so it can provide recognition to
71  * a calling app.
72  * <p>
73  * You can create an attribution chain of you and any other app without any verification
74  * as this is something already available via the {@link android.app.AppOpsManager} APIs.
75  * This is supported to handle cases where you don't have access to the caller's attribution
76  * source and you can directly use the {@link AttributionSource.Builder} APIs. However,
77  * if the data flows through more than two apps (more than you access the data for the
78  * caller) you need to have a handle to the {@link AttributionSource} for the calling app's
79  * context in order to create an attribution context. This means you either need to have an
80  * API for the other app to send you its attribution source or use a platform API that pipes
81  * the callers attribution source.
82  * <p>
83  * You cannot forge an attribution chain without the participation of every app in the
84  * attribution chain (aside of the special case mentioned above). To create an attribution
85  * source that is trusted you need to create an attribution context that points to an
86  * attribution source that was explicitly created by the app that it refers to, recursively.
87  * <p>
88  * Since creating an attribution context leads to all permissions for apps in the attribution
89  * chain being checked, you need to expect getting a security exception when accessing
90  * permission protected APIs since some app in the chain may not have the permission.
91  */
92 @Immutable
93 public final class AttributionSource implements Parcelable {
94     private static final String TAG = "AttributionSource";
95     private static final String DESCRIPTOR = "android.content.AttributionSource";
96 
97     private static final Binder sDefaultToken = new Binder(DESCRIPTOR);
98 
99     private final @NonNull AttributionSourceState mAttributionSourceState;
100 
101     private @Nullable AttributionSource mNextCached;
102     private @Nullable Set<String> mRenouncedPermissionsCached;
103 
104     /** @hide */
105     @TestApi
AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag)106     public AttributionSource(int uid, @Nullable String packageName,
107             @Nullable String attributionTag) {
108         this(uid, Process.INVALID_PID, packageName, attributionTag, sDefaultToken);
109     }
110 
111     /** @hide */
AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag, int virtualDeviceId)112     public AttributionSource(int uid, @Nullable String packageName,
113             @Nullable String attributionTag, int virtualDeviceId) {
114         this(uid, Process.INVALID_PID, packageName, attributionTag, sDefaultToken, null,
115                 virtualDeviceId, null);
116     }
117 
118     /** @hide */
AttributionSource(int uid, int pid, @Nullable String packageName, @Nullable String attributionTag)119     public AttributionSource(int uid, int pid, @Nullable String packageName,
120             @Nullable String attributionTag) {
121         this(uid, pid, packageName, attributionTag, sDefaultToken);
122     }
123 
124     /** @hide */
125     @TestApi
AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag, @NonNull IBinder token)126     public AttributionSource(int uid, @Nullable String packageName,
127             @Nullable String attributionTag, @NonNull IBinder token) {
128         this(uid, Process.INVALID_PID, packageName, attributionTag, token,
129                 /*renouncedPermissions*/ null, Context.DEVICE_ID_DEFAULT, /*next*/ null);
130     }
131 
132     /** @hide */
AttributionSource(int uid, int pid, @Nullable String packageName, @Nullable String attributionTag, @NonNull IBinder token)133     public AttributionSource(int uid, int pid, @Nullable String packageName,
134             @Nullable String attributionTag, @NonNull IBinder token) {
135         this(uid, pid, packageName, attributionTag, token, /*renouncedPermissions*/ null,
136                 Context.DEVICE_ID_DEFAULT, /*next*/ null);
137     }
138 
139     /** @hide */
140     @TestApi
AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable Set<String> renouncedPermissions, @Nullable AttributionSource next)141     public AttributionSource(int uid, @Nullable String packageName,
142             @Nullable String attributionTag, @Nullable Set<String> renouncedPermissions,
143             @Nullable AttributionSource next) {
144         this(uid, Process.INVALID_PID, packageName, attributionTag, sDefaultToken,
145                 (renouncedPermissions != null)
146                 ? renouncedPermissions.toArray(new String[0]) : null, Context.DEVICE_ID_DEFAULT,
147                 /*next*/ next);
148     }
149 
150     /** @hide */
AttributionSource(@onNull AttributionSource current, @Nullable AttributionSource next)151     public AttributionSource(@NonNull AttributionSource current, @Nullable AttributionSource next) {
152         this(current.getUid(), current.getPid(), current.getPackageName(),
153                 current.getAttributionTag(), current.getToken(),
154                 current.mAttributionSourceState.renouncedPermissions, current.getDeviceId(), next);
155     }
156 
157     /** @hide */
AttributionSource(int uid, int pid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String[] renouncedPermissions, int deviceId, @Nullable AttributionSource next)158     public AttributionSource(int uid, int pid, @Nullable String packageName,
159             @Nullable String attributionTag, @Nullable String[] renouncedPermissions, int deviceId,
160             @Nullable AttributionSource next) {
161         this(uid, pid, packageName, attributionTag, sDefaultToken, renouncedPermissions, deviceId,
162                 next);
163     }
164 
165     /** @hide */
166     @TestApi
167     @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
AttributionSource(int uid, int pid, @Nullable String packageName, @Nullable String attributionTag, @NonNull IBinder token, @Nullable String[] renouncedPermissions, int deviceId, @Nullable AttributionSource next)168     public AttributionSource(int uid, int pid, @Nullable String packageName,
169             @Nullable String attributionTag, @NonNull IBinder token,
170             @Nullable String[] renouncedPermissions,
171             int deviceId, @Nullable AttributionSource next) {
172         mAttributionSourceState = new AttributionSourceState();
173         mAttributionSourceState.uid = uid;
174         mAttributionSourceState.pid = pid;
175         mAttributionSourceState.token = token;
176         mAttributionSourceState.packageName = packageName;
177         mAttributionSourceState.attributionTag = attributionTag;
178         mAttributionSourceState.renouncedPermissions = renouncedPermissions;
179         mAttributionSourceState.deviceId = deviceId;
180         mAttributionSourceState.next = (next != null) ? new AttributionSourceState[]
181                 {next.mAttributionSourceState} : new AttributionSourceState[0];
182     }
183 
AttributionSource(@onNull Parcel in)184     AttributionSource(@NonNull Parcel in) {
185         this(AttributionSourceState.CREATOR.createFromParcel(in));
186 
187         if (!Binder.isDirectlyHandlingTransaction()) {
188             throw new SecurityException("AttributionSource should be unparceled during a binder "
189                     + "transaction for proper verification.");
190         }
191 
192         // Since we just unpacked this object as part of it transiting a Binder
193         // call, this is the perfect time to enforce that its UID and PID can be trusted
194         enforceCallingUid();
195 
196         // If this object is being constructed as part of a oneway Binder call, getCallingPid will
197         // return 0 instead of the true PID. In that case, invalidate the PID by setting it to
198         // INVALID_PID (-1).
199         final int callingPid = Binder.getCallingPid();
200         if (callingPid == 0) {
201             mAttributionSourceState.pid = Process.INVALID_PID;
202         }
203 
204         enforceCallingPid();
205     }
206 
207     /** @hide */
AttributionSource(@onNull AttributionSourceState attributionSourceState)208     public AttributionSource(@NonNull AttributionSourceState attributionSourceState) {
209         mAttributionSourceState = attributionSourceState;
210     }
211 
212     /** @hide */
withNextAttributionSource(@ullable AttributionSource next)213     public AttributionSource withNextAttributionSource(@Nullable AttributionSource next) {
214         return new AttributionSource(getUid(), getPid(), getPackageName(), getAttributionTag(),
215                 getToken(), mAttributionSourceState.renouncedPermissions, getDeviceId(), next);
216     }
217 
218     /** @hide */
withPackageName(@ullable String packageName)219     public AttributionSource withPackageName(@Nullable String packageName) {
220         return new AttributionSource(getUid(), getPid(), packageName, getAttributionTag(),
221                getToken(), mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext());
222     }
223 
224     /** @hide */
withToken(@onNull IBinder token)225     public AttributionSource withToken(@NonNull IBinder token) {
226         return new AttributionSource(getUid(), getPid(), getPackageName(), getAttributionTag(),
227                 token, mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext());
228     }
229 
230     /** @hide */
withDefaultToken()231     public AttributionSource withDefaultToken() {
232         return withToken(sDefaultToken);
233     }
234 
235     /** @hide */
withPid(int pid)236     public AttributionSource withPid(int pid) {
237         return new AttributionSource(getUid(), pid, getPackageName(), getAttributionTag(),
238                 getToken(), mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext());
239     }
240 
241     /** @hide */
withDeviceId(int deviceId)242     public AttributionSource withDeviceId(int deviceId) {
243         return new AttributionSource(getUid(), getPid(), getPackageName(), getAttributionTag(),
244                 getToken(), mAttributionSourceState.renouncedPermissions, deviceId, getNext());
245     }
246 
247     /** @hide */
asState()248     public @NonNull AttributionSourceState asState() {
249         return mAttributionSourceState;
250     }
251 
252     /** @hide */
asScopedParcelState()253     public @NonNull ScopedParcelState asScopedParcelState() {
254         return new ScopedParcelState(this);
255     }
256 
257     /**
258      * Returns a generic {@link AttributionSource} that represents the entire
259      * calling process.
260      *
261      * <p>Callers are <em>strongly</em> encouraged to use a more specific
262      * attribution source whenever possible, such as from
263      * {@link Context#getAttributionSource()}, since that enables developers to
264      * have more detailed and scoped control over attribution within
265      * sub-components of their app.
266      *
267      * @see Context#createAttributionContext(String)
268      * @see Context#getAttributionTag()
269      * @return a generic {@link AttributionSource} representing the entire
270      *         calling process
271      * @throws IllegalStateException when no accurate {@link AttributionSource}
272      *         can be determined
273      */
myAttributionSource()274     public static @NonNull AttributionSource myAttributionSource() {
275 
276         final AttributionSource globalSource = ActivityThread.currentAttributionSource();
277         if (globalSource != null) {
278             if (Flags.enforceDefaultDeviceIdInMyAttributionSource()
279                     && globalSource.getDeviceId() != Context.DEVICE_ID_DEFAULT) {
280                 Log.w(TAG,
281                         "Avoid using myAttributionSource() to fetch an attributionSource with a "
282                                 + "non-default device Id");
283                 return globalSource.withDeviceId(Context.DEVICE_ID_DEFAULT);
284             }
285             return globalSource;
286         }
287 
288         int uid = Process.myUid();
289         if (uid == Process.ROOT_UID) {
290             uid = Process.SYSTEM_UID;
291         }
292         try {
293             return new AttributionSource.Builder(uid)
294                 .setPid(Process.myPid())
295                 .setDeviceId(Context.DEVICE_ID_DEFAULT)
296                 .setPackageName(AppGlobals.getPackageManager().getPackagesForUid(uid)[0])
297                 .build();
298         } catch (Exception ignored) {
299         }
300 
301         throw new IllegalStateException("Failed to resolve AttributionSource");
302     }
303 
304     /**
305      * This is a scoped object that exposes the content of an attribution source
306      * as a parcel. This is useful when passing one to native and avoid custom
307      * conversion logic from Java to native state that needs to be kept in sync
308      * as attribution source evolves. This way we use the same logic for passing
309      * to native as the ones for passing in an IPC - in both cases this is the
310      * same auto generated code.
311      *
312      * @hide
313      */
314     public static class ScopedParcelState implements AutoCloseable {
315         private final Parcel mParcel;
316 
getParcel()317         public @NonNull Parcel getParcel() {
318             return mParcel;
319         }
320 
ScopedParcelState(AttributionSource attributionSource)321         public ScopedParcelState(AttributionSource attributionSource) {
322             mParcel = Parcel.obtain();
323             attributionSource.writeToParcel(mParcel, 0);
324             mParcel.setDataPosition(0);
325         }
326 
close()327         public void close() {
328             mParcel.recycle();
329         }
330     }
331 
332     /**
333      * If you are handling an IPC and you don't trust the caller you need to validate
334      * whether the attribution source is one for the calling app to prevent the caller
335      * to pass you a source from another app without including themselves in the
336      * attribution chain.
337      *
338      * @throws SecurityException if the attribution source cannot be trusted to be from the caller.
339      */
enforceCallingUid()340     public void enforceCallingUid() {
341         if (!checkCallingUid()) {
342             throw new SecurityException("Calling uid: " + Binder.getCallingUid()
343                     + " doesn't match source uid: " + mAttributionSourceState.uid);
344         }
345         // No need to check package as app ops manager does it already.
346     }
347 
348     /**
349      * If you are handling an IPC and you don't trust the caller you need to validate
350      * whether the attribution source is one for the calling app to prevent the caller
351      * to pass you a source from another app without including themselves in the
352      * attribution chain.
353      *
354      * @return if the attribution source cannot be trusted to be from the caller.
355      */
checkCallingUid()356     public boolean checkCallingUid() {
357         final int callingUid = Binder.getCallingUid();
358         if (callingUid != Process.ROOT_UID
359                 && UserHandle.getAppId(callingUid) != Process.SYSTEM_UID
360                 && callingUid != mAttributionSourceState.uid) {
361             return false;
362         }
363         // No need to check package as app ops manager does it already.
364         return true;
365     }
366 
367     /**
368      * Validate that the pid being claimed for the calling app is not spoofed.
369      *
370      * Note that the PID may be unavailable, for example if we're in a oneway Binder call. In this
371      * case, calling enforceCallingPid is guaranteed to fail. The caller should anticipate this.
372      *
373      * @throws SecurityException if the attribution source cannot be trusted to be from the caller.
374      * @hide
375      */
376     @TestApi
enforceCallingPid()377     public void enforceCallingPid() {
378         if (!checkCallingPid()) {
379             if (Binder.getCallingPid() == 0) {
380                 throw new SecurityException("Calling pid unavailable due to oneway Binder call.");
381             } else {
382                 throw new SecurityException("Calling pid: " + Binder.getCallingPid()
383                         + " doesn't match source pid: " + mAttributionSourceState.pid);
384             }
385         }
386     }
387 
388     /**
389      * Validate that the pid being claimed for the calling app is not spoofed
390      *
391      * @return if the attribution source cannot be trusted to be from the caller.
392      */
checkCallingPid()393     private boolean checkCallingPid() {
394         final int callingPid = Binder.getCallingPid();
395         if (mAttributionSourceState.pid != Process.INVALID_PID
396                 && callingPid != mAttributionSourceState.pid) {
397             return false;
398         }
399         return true;
400     }
401 
402     @Override
toString()403     public String toString() {
404         if (Build.IS_DEBUGGABLE) {
405             return "AttributionSource { " +
406                     "uid = " + mAttributionSourceState.uid + ", " +
407                     "packageName = " + mAttributionSourceState.packageName + ", " +
408                     "attributionTag = " + mAttributionSourceState.attributionTag + ", " +
409                     "token = " + mAttributionSourceState.token + ", " +
410                     "deviceId = " + mAttributionSourceState.deviceId + ", " +
411                     "next = " + (mAttributionSourceState.next != null
412                     && mAttributionSourceState.next.length > 0
413                     ? new AttributionSource(mAttributionSourceState.next[0]).toString() : null) +
414                     " }";
415         }
416         return super.toString();
417     }
418 
419     /**
420      * @return The next UID that would receive the permission protected data.
421      *
422      * @hide
423      */
getNextUid()424     public int getNextUid() {
425         if (mAttributionSourceState.next != null
426                 && mAttributionSourceState.next.length > 0) {
427             return mAttributionSourceState.next[0].uid;
428         }
429         return Process.INVALID_UID;
430     }
431 
432     /**
433      * @return The next package that would receive the permission protected data.
434      *
435      * @hide
436      */
getNextPackageName()437     public @Nullable String getNextPackageName() {
438         if (mAttributionSourceState.next != null
439                 && mAttributionSourceState.next.length > 0) {
440             return mAttributionSourceState.next[0].packageName;
441         }
442         return null;
443     }
444 
445     /**
446      * @return The next package's attribution tag that would receive
447      * the permission protected data.
448      *
449      * @hide
450      */
getNextAttributionTag()451     public @Nullable String getNextAttributionTag() {
452         if (mAttributionSourceState.next != null
453                 && mAttributionSourceState.next.length > 0) {
454             return mAttributionSourceState.next[0].attributionTag;
455         }
456         return null;
457     }
458 
459     /**
460      * @return The next package's token that would receive
461      * the permission protected data.
462      *
463      * @hide
464      */
getNextToken()465     public @Nullable IBinder getNextToken() {
466         if (mAttributionSourceState.next != null
467                 && mAttributionSourceState.next.length > 0) {
468             return mAttributionSourceState.next[0].token;
469         }
470         return null;
471     }
472 
473     /**
474      * @return The next package's device Id from its context.
475      * This device ID is used for permissions checking during attribution source validation.
476      *
477      * @hide
478      */
getNextDeviceId()479     public int getNextDeviceId() {
480         if (mAttributionSourceState.next != null
481                 && mAttributionSourceState.next.length > 0) {
482             return mAttributionSourceState.next[0].deviceId;
483         }
484         return Context.DEVICE_ID_DEFAULT;
485     }
486 
487     /**
488      * Checks whether this attribution source can be trusted. That is whether
489      * the app it refers to created it and provided to the attribution chain.
490      *
491      * @param context Context handle.
492      * @return Whether this is a trusted source.
493      */
isTrusted(@onNull Context context)494     public boolean isTrusted(@NonNull Context context) {
495         return mAttributionSourceState.token != null
496                 && context.getSystemService(PermissionManager.class)
497                         .isRegisteredAttributionSource(this);
498     }
499 
500     /**
501      * Permissions that should be considered revoked regardless if granted.
502      *
503      * @hide
504      */
505     @SystemApi
506     @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
507     @NonNull
getRenouncedPermissions()508     public Set<String> getRenouncedPermissions() {
509         if (mRenouncedPermissionsCached == null) {
510             if (mAttributionSourceState.renouncedPermissions != null) {
511                 mRenouncedPermissionsCached = new ArraySet<>(
512                         mAttributionSourceState.renouncedPermissions);
513             } else {
514                 mRenouncedPermissionsCached = Collections.emptySet();
515             }
516         }
517         return mRenouncedPermissionsCached;
518     }
519 
520     /**
521      * The UID that is accessing the permission protected data.
522      */
getUid()523     public int getUid() {
524         return mAttributionSourceState.uid;
525     }
526 
527     /**
528      * The PID that is accessing the permission protected data.
529      */
getPid()530     public int getPid() {
531         return mAttributionSourceState.pid;
532     }
533 
534     /**
535      * The package that is accessing the permission protected data.
536      */
getPackageName()537     public @Nullable String getPackageName() {
538         return mAttributionSourceState.packageName;
539     }
540 
541     /**
542      * The attribution tag of the app accessing the permission protected data.
543      */
getAttributionTag()544     public @Nullable String getAttributionTag() {
545         return mAttributionSourceState.attributionTag;
546     }
547 
548     /**
549      * Gets the device ID for this attribution source. Attribution source can set the device ID
550      * using {@link Builder#setDeviceId(int)}, the default device ID is
551      * {@link Context#DEVICE_ID_DEFAULT}.
552      * <p>
553      * This device ID is used for permissions checking during attribution source validation.
554      */
555     @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
getDeviceId()556     public int getDeviceId() {
557         return mAttributionSourceState.deviceId;
558     }
559 
560     /**
561      * Unique token for that source.
562      *
563      * @hide
564      */
getToken()565     public @NonNull IBinder getToken() {
566         return mAttributionSourceState.token;
567     }
568 
569     /**
570      * The next app to receive the permission protected data.
571      */
getNext()572     public @Nullable AttributionSource getNext() {
573         if (mNextCached == null && mAttributionSourceState.next != null
574                 && mAttributionSourceState.next.length > 0) {
575             mNextCached = new AttributionSource(mAttributionSourceState.next[0]);
576         }
577         return mNextCached;
578     }
579 
580     @Override
equals(@ullable Object o)581     public boolean equals(@Nullable Object o) {
582         if (this == o) return true;
583         if (o == null || getClass() != o.getClass()) return false;
584         AttributionSource that = (AttributionSource) o;
585         return equalsExceptToken(that) && Objects.equals(
586                 mAttributionSourceState.token, that.mAttributionSourceState.token);
587     }
588 
589     /**
590      * We store trusted attribution sources without their token (the token is the key to the map)
591      * to avoid having a strong reference to the token. This means, when checking the equality of a
592      * supplied AttributionSource in PermissionManagerService.isTrustedAttributionSource, we want to
593      * compare everything except the token.
594      *
595      * @hide
596      */
equalsExceptToken(@ullable AttributionSource o)597     public boolean equalsExceptToken(@Nullable AttributionSource o) {
598         if (o == null) return false;
599         return mAttributionSourceState.uid == o.mAttributionSourceState.uid
600                 && Objects.equals(mAttributionSourceState.packageName,
601                 o.mAttributionSourceState.packageName)
602                 && Objects.equals(mAttributionSourceState.attributionTag,
603                 o.mAttributionSourceState.attributionTag)
604                 && Arrays.equals(mAttributionSourceState.renouncedPermissions,
605                 o.mAttributionSourceState.renouncedPermissions)
606                 && Objects.equals(getNext(), o.getNext());
607     }
608 
609     @Override
hashCode()610     public int hashCode() {
611         return Objects.hash(mAttributionSourceState.uid, mAttributionSourceState.packageName,
612                 mAttributionSourceState.attributionTag, mAttributionSourceState.token,
613                 Arrays.hashCode(mAttributionSourceState.renouncedPermissions), getNext());
614     }
615 
616     @Override
writeToParcel(@onNull Parcel dest, int flags)617     public void writeToParcel(@NonNull Parcel dest, int flags) {
618         mAttributionSourceState.writeToParcel(dest, flags);
619     }
620 
621     @Override
describeContents()622     public int describeContents() { return 0; }
623 
624     public static final @NonNull Parcelable.Creator<AttributionSource> CREATOR
625             = new Parcelable.Creator<AttributionSource>() {
626         @Override
627         public AttributionSource[] newArray(int size) {
628             return new AttributionSource[size];
629         }
630 
631         @Override
632         public AttributionSource createFromParcel(@NonNull Parcel in) {
633             return new AttributionSource(in);
634         }
635     };
636 
637     /**
638      * A builder for {@link AttributionSource}
639      */
640     public static final class Builder {
641         private boolean mHasBeenUsed;
642         private @NonNull final AttributionSourceState mAttributionSourceState =
643                 new AttributionSourceState();
644 
645         /**
646          * Creates a new Builder.
647          *
648          * @param uid
649          *   The UID that is accessing the permission protected data.
650          */
Builder(int uid)651         public Builder(int uid) {
652             mAttributionSourceState.uid = uid;
653             mAttributionSourceState.pid = Process.INVALID_PID;
654             mAttributionSourceState.deviceId = Context.DEVICE_ID_DEFAULT;
655             mAttributionSourceState.token = sDefaultToken;
656         }
657 
658         /**
659          * Creates a builder that is ready to build a new {@link AttributionSource} where
660          * all fields (primitive, immutable data, pointers) are copied from the given
661          * {@link AttributionSource}. Builder methods can still be used to mutate fields further.
662          * @param current The source to copy fields from.
663          */
Builder(@onNull AttributionSource current)664         public Builder(@NonNull AttributionSource current) {
665             if (current == null) {
666                 throw new IllegalArgumentException("current AttributionSource can not be null");
667             }
668             mAttributionSourceState.uid = current.getUid();
669             mAttributionSourceState.pid = current.getPid();
670             mAttributionSourceState.packageName = current.getPackageName();
671             mAttributionSourceState.attributionTag = current.getAttributionTag();
672             mAttributionSourceState.renouncedPermissions =
673                 current.mAttributionSourceState.renouncedPermissions;
674             mAttributionSourceState.deviceId = current.getDeviceId();
675             mAttributionSourceState.next = current.mAttributionSourceState.next;
676             mAttributionSourceState.token = current.getToken();
677         }
678 
679         /**
680          * The PID of the process that is accessing the permission protected data.
681          *
682          * If not called, pid will default to {@link Process@INVALID_PID} (-1). This indicates that
683          * the PID data is missing. Supplying a PID is not required, but recommended when
684          * accessible.
685          */
setPid(int value)686         public @NonNull Builder setPid(int value) {
687             checkNotUsed();
688             mAttributionSourceState.pid = value;
689             return this;
690         }
691 
692         /**
693          * The package that is accessing the permission protected data.
694          */
setPackageName(@ullable String value)695         public @NonNull Builder setPackageName(@Nullable String value) {
696             checkNotUsed();
697             mAttributionSourceState.packageName = value;
698             return this;
699         }
700 
701         /**
702          * The attribution tag of the app accessing the permission protected data.
703          */
setAttributionTag(@ullable String value)704         public @NonNull Builder setAttributionTag(@Nullable String value) {
705             checkNotUsed();
706             mAttributionSourceState.attributionTag = value;
707             return this;
708         }
709 
710         /**
711          * Sets permissions which have been voluntarily "renounced" by the
712          * calling app.
713          * <p>
714          * Interactions performed through services obtained from the created
715          * Context will ideally be treated as if these "renounced" permissions
716          * have not actually been granted to the app, regardless of their actual
717          * grant status.
718          * <p>
719          * This is designed for use by separate logical components within an app
720          * which have no intention of interacting with data or services that are
721          * protected by the renounced permissions.
722          * <p>
723          * Note that only {@link PermissionInfo#PROTECTION_DANGEROUS}
724          * permissions are supported by this mechanism. Additionally, this
725          * mechanism only applies to calls made through services obtained via
726          * {@link Context#getSystemService}; it has no effect on static or raw
727          * Binder calls.
728          *
729          * @param renouncedPermissions The set of permissions to treat as
730          *            renounced, which is as if not granted.
731          * @return This builder.
732          * @hide
733          */
734         @SystemApi
735         @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
setRenouncedPermissions( @ullable Set<String> renouncedPermissions)736         public @NonNull Builder setRenouncedPermissions(
737                 @Nullable Set<String> renouncedPermissions) {
738             checkNotUsed();
739             mAttributionSourceState.renouncedPermissions = (renouncedPermissions != null)
740                     ? renouncedPermissions.toArray(new String[0]) : null;
741             return this;
742         }
743 
744         /**
745          * Set the device ID for this attribution source, permission check would happen
746          * against this device ID.
747          *
748          * @return the builder
749          */
750         @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
setDeviceId(int deviceId)751         public @NonNull Builder setDeviceId(int deviceId) {
752             checkNotUsed();
753             mAttributionSourceState.deviceId = deviceId;
754             return this;
755         }
756 
757         /**
758          * The next app to receive the permission protected data.
759          */
setNext(@ullable AttributionSource value)760         public @NonNull Builder setNext(@Nullable AttributionSource value) {
761             checkNotUsed();
762             mAttributionSourceState.next = (value != null) ? new AttributionSourceState[]
763                     {value.mAttributionSourceState} : mAttributionSourceState.next;
764             return this;
765         }
766 
767         /**
768          * The next app to receive the permission protected data.
769          */
770         @FlaggedApi(Flags.FLAG_SET_NEXT_ATTRIBUTION_SOURCE)
setNextAttributionSource(@onNull AttributionSource value)771         public @NonNull Builder setNextAttributionSource(@NonNull AttributionSource value) {
772             checkNotUsed();
773             if (value == null) {
774                 throw new IllegalArgumentException("Null AttributionSource not permitted.");
775             }
776             mAttributionSourceState.next =
777                     new AttributionSourceState[]{value.mAttributionSourceState};
778             return this;
779         }
780 
781         /** Builds the instance. This builder should not be touched after calling this! */
build()782         public @NonNull AttributionSource build() {
783             checkNotUsed();
784             mHasBeenUsed = true;
785 
786             if (mAttributionSourceState.next == null) {
787                 // The NDK aidl backend doesn't support null parcelable arrays.
788                 mAttributionSourceState.next = new AttributionSourceState[0];
789             }
790             return new AttributionSource(mAttributionSourceState);
791         }
792 
checkNotUsed()793         private void checkNotUsed() {
794             if (mHasBeenUsed) {
795                 throw new IllegalStateException(
796                         "This Builder should not be reused. Use a new Builder instance instead");
797             }
798         }
799     }
800 }
801