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