1 /*
2  * Copyright (C) 2024 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.app;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.content.Intent;
23 import android.content.pm.PackageManager;
24 import android.net.Uri;
25 import android.os.IBinder;
26 import android.os.Process;
27 
28 import java.util.Objects;
29 
30 /**
31  * Represents the app that launched the component. See below for the APIs available on the component
32  * caller.
33  *
34  * <p><b>Note</b>, that in {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} only
35  * {@link Activity} has access to {@link ComponentCaller} instances.
36  *
37  * @see Activity#getInitialCaller()
38  */
39 @FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
40 public final class ComponentCaller {
41     private final IBinder mActivityToken;
42     private final IBinder mCallerToken;
43 
44     /**
45      * @hide
46      */
ComponentCaller(@ullable IBinder activityToken, @Nullable IBinder callerToken)47     public ComponentCaller(@Nullable IBinder activityToken, @Nullable IBinder callerToken) {
48         mActivityToken = activityToken;
49         mCallerToken = callerToken;
50     }
51 
52     /**
53      * Returns the uid of this component caller.
54      *
55      * <p><b>Note</b>, in {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} only
56      * {@link Activity} has access to {@link ComponentCaller} instances.
57      * <p>
58      * <h3>Requirements for {@link Activity} callers</h3>
59      *
60      * <p>In order to receive the calling app's uid, at least one of the following has to be met:
61      * <ul>
62      *     <li>The calling app must call {@link ActivityOptions#setShareIdentityEnabled(boolean)}
63      *     with a value of {@code true} and launch this activity with the resulting
64      *     {@code ActivityOptions}.
65      *     <li>The launched activity has the same uid as the calling app.
66      *     <li>The launched activity is running in a package that is signed with the same key used
67      *     to sign the platform (typically only system packages such as Settings will meet this
68      *     requirement).
69      * </ul>
70      * These are the same requirements for {@link #getPackage()}; if any of these are met, then
71      * these methods can be used to obtain the uid and package name of the calling app. If none are
72      * met, then {@link Process#INVALID_UID} is returned.
73      *
74      * <p>Note, even if the above conditions are not met, the calling app's identity may still be
75      * available from {@link Activity#getCallingPackage()} if this activity was started with
76      * {@code Activity#startActivityForResult} to allow validation of the result's recipient.
77      *
78      * @return the uid of the calling app or {@link Process#INVALID_UID} if the current component
79      * cannot access the identity of the calling app or the caller is invalid
80      *
81      * @see ActivityOptions#setShareIdentityEnabled(boolean)
82      * @see Activity#getLaunchedFromUid()
83      */
getUid()84     public int getUid() {
85         return ActivityClient.getInstance().getActivityCallerUid(mActivityToken, mCallerToken);
86     }
87 
88     /**
89      * Returns the package name of this component caller.
90      *
91      * <p><b>Note</b>, in {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} only
92      * {@link Activity} has access to {@link ComponentCaller} instances.
93      * <p>
94      * <h3>Requirements for {@link Activity} callers</h3>
95      *
96      * <p>In order to receive the calling app's package name, at least one of the following has to
97      * be met:
98      * <ul>
99      *     <li>The calling app must call {@link ActivityOptions#setShareIdentityEnabled(boolean)}
100      *     with a value of {@code true} and launch this activity with the resulting
101      *     {@code ActivityOptions}.
102      *     <li>The launched activity has the same uid as the calling app.
103      *     <li>The launched activity is running in a package that is signed with the same key used
104      *     to sign the platform (typically only system packages such as Settings will meet this
105      *     meet this requirement).
106      * </ul>
107      * These are the same requirements for {@link #getUid()}; if any of these are met, then these
108      * methods can be used to obtain the uid and package name of the calling app. If none are met,
109      * then {@code null} is returned.
110      *
111      * <p>Note, even if the above conditions are not met, the calling app's identity may still be
112      * available from {@link Activity#getCallingPackage()} if this activity was started with
113      * {@code Activity#startActivityForResult} to allow validation of the result's recipient.
114      *
115      * @return the package name of the calling app or null if the current component cannot access
116      * the identity of the calling app or the caller is invalid
117      *
118      * @see ActivityOptions#setShareIdentityEnabled(boolean)
119      * @see Activity#getLaunchedFromPackage()
120      */
121     @Nullable
getPackage()122     public String getPackage() {
123         return ActivityClient.getInstance().getActivityCallerPackage(mActivityToken, mCallerToken);
124     }
125 
126     /**
127      * Determines whether this component caller had access to a specific content URI at launch time.
128      * Apps can use this API to validate content URIs coming from other apps.
129      *
130      * <p><b>Note</b>, in {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} only
131      * {@link Activity} has access to {@link ComponentCaller} instances.
132      *
133      * <p>Before using this method, note the following:
134      * <ul>
135      *     <li>You must have access to the supplied URI, otherwise it will throw a
136      *     {@link SecurityException}.
137      *     <li>This is not a real time check, i.e. the permissions have been computed at launch
138      *     time.
139      *     <li>This method will return the correct result for content URIs passed at launch time,
140      *     specifically the ones from {@link Intent#getData()}, {@link Intent#EXTRA_STREAM}, and
141      *     {@link Intent#getClipData()} in the intent of {@code startActivity(intent)}. For others,
142      *     it will throw an {@link IllegalArgumentException}.
143      * </ul>
144      *
145      * @param uri The content uri that is being checked
146      * @param modeFlags The access modes to check
147      * @return {@link PackageManager#PERMISSION_GRANTED} if this activity caller is allowed to
148      *         access that uri, or {@link PackageManager#PERMISSION_DENIED} if it is not
149      * @throws IllegalArgumentException if uri is a non-content URI or it wasn't passed at launch in
150      *                                  {@link Intent#getData()}, {@link Intent#EXTRA_STREAM}, and
151      *                                  {@link Intent#getClipData()}
152      * @throws SecurityException if you don't have access to uri
153      *
154      * @see android.content.Context#checkContentUriPermissionFull(Uri, int, int, int)
155      */
156     @PackageManager.PermissionResult
checkContentUriPermission(@onNull Uri uri, @Intent.AccessUriMode int modeFlags)157     public int checkContentUriPermission(@NonNull Uri uri, @Intent.AccessUriMode int modeFlags) {
158         return ActivityClient.getInstance().checkActivityCallerContentUriPermission(mActivityToken,
159                 mCallerToken, uri, modeFlags);
160     }
161 
162     @Override
equals(@ullable Object obj)163     public boolean equals(@Nullable Object obj) {
164         if (obj == null || !(obj instanceof ComponentCaller other)) {
165             return false;
166         }
167         return this.mActivityToken == other.mActivityToken
168                 && this.mCallerToken == other.mCallerToken;
169     }
170 
171     @Override
hashCode()172     public int hashCode() {
173         int result = 17;
174         result = 31 * result + Objects.hashCode(mActivityToken);
175         result = 31 * result + Objects.hashCode(mCallerToken);
176         return result;
177     }
178 }
179