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