1/* 2 * Copyright (C) 2018 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 17package com.android.server.am; 18 19import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; 20import static android.Manifest.permission.START_TASKS_FROM_RECENTS; 21import static android.content.pm.PackageManager.PERMISSION_DENIED; 22import static android.content.pm.PackageManager.PERMISSION_GRANTED; 23import static android.view.Display.INVALID_DISPLAY; 24import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 25import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; 26import static com.android.server.am.TaskRecord.INVALID_TASK_ID; 27 28import android.annotation.Nullable; 29import android.app.ActivityOptions; 30import android.app.PendingIntent; 31import android.content.Intent; 32import android.content.pm.ActivityInfo; 33import android.os.Binder; 34import android.os.Bundle; 35import android.os.Process; 36import android.os.UserHandle; 37import android.util.Slog; 38import android.view.RemoteAnimationAdapter; 39 40import com.android.internal.annotations.VisibleForTesting; 41 42/** 43 * Wraps {@link ActivityOptions}, records binder identity, and checks permission when retrieving 44 * the inner options. Also supports having two set of options: Once from the original caller, and 45 * once from the caller that is overriding it, which happens when sending a {@link PendingIntent}. 46 */ 47class SafeActivityOptions { 48 49 private static final String TAG = TAG_WITH_CLASS_NAME ? "SafeActivityOptions" : TAG_AM; 50 51 private final int mOriginalCallingPid; 52 private final int mOriginalCallingUid; 53 private int mRealCallingPid; 54 private int mRealCallingUid; 55 private final @Nullable ActivityOptions mOriginalOptions; 56 private @Nullable ActivityOptions mCallerOptions; 57 58 /** 59 * Constructs a new instance from a bundle and records {@link Binder#getCallingPid}/ 60 * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when constructing 61 * this object. 62 * 63 * @param bOptions The {@link ActivityOptions} as {@link Bundle}. 64 */ 65 static SafeActivityOptions fromBundle(Bundle bOptions) { 66 return bOptions != null 67 ? new SafeActivityOptions(ActivityOptions.fromBundle(bOptions)) 68 : null; 69 } 70 71 /** 72 * Constructs a new instance and records {@link Binder#getCallingPid}/ 73 * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when constructing 74 * this object. 75 * 76 * @param options The options to wrap. 77 */ 78 SafeActivityOptions(@Nullable ActivityOptions options) { 79 mOriginalCallingPid = Binder.getCallingPid(); 80 mOriginalCallingUid = Binder.getCallingUid(); 81 mOriginalOptions = options; 82 } 83 84 /** 85 * Overrides options with options from a caller and records {@link Binder#getCallingPid}/ 86 * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when calling this 87 * method. 88 */ 89 void setCallerOptions(@Nullable ActivityOptions options) { 90 mRealCallingPid = Binder.getCallingPid(); 91 mRealCallingUid = Binder.getCallingUid(); 92 mCallerOptions = options; 93 } 94 95 /** 96 * Performs permission check and retrieves the options. 97 * 98 * @param r The record of the being started activity. 99 */ 100 ActivityOptions getOptions(ActivityRecord r) throws SecurityException { 101 return getOptions(r.intent, r.info, r.app, r.mStackSupervisor); 102 } 103 104 /** 105 * Performs permission check and retrieves the options when options are not being used to launch 106 * a specific activity (i.e. a task is moved to front). 107 */ 108 ActivityOptions getOptions(ActivityStackSupervisor supervisor) throws SecurityException { 109 return getOptions(null, null, null, supervisor); 110 } 111 112 /** 113 * Performs permission check and retrieves the options. 114 * 115 * @param intent The intent that is being launched. 116 * @param aInfo The info of the activity being launched. 117 * @param callerApp The record of the caller. 118 */ 119 ActivityOptions getOptions(@Nullable Intent intent, @Nullable ActivityInfo aInfo, 120 @Nullable ProcessRecord callerApp, 121 ActivityStackSupervisor supervisor) throws SecurityException { 122 if (mOriginalOptions != null) { 123 checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions, 124 mOriginalCallingPid, mOriginalCallingUid); 125 setCallingPidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid); 126 } 127 if (mCallerOptions != null) { 128 checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions, 129 mRealCallingPid, mRealCallingUid); 130 setCallingPidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid); 131 } 132 return mergeActivityOptions(mOriginalOptions, mCallerOptions); 133 } 134 135 private void setCallingPidForRemoteAnimationAdapter(ActivityOptions options, int callingPid) { 136 final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter(); 137 if (adapter == null) { 138 return; 139 } 140 if (callingPid == Process.myPid()) { 141 Slog.wtf(TAG, "Safe activity options constructed after clearing calling id"); 142 return; 143 } 144 adapter.setCallingPid(callingPid); 145 } 146 147 /** 148 * @see ActivityOptions#popAppVerificationBundle 149 */ 150 Bundle popAppVerificationBundle() { 151 return mOriginalOptions != null ? mOriginalOptions.popAppVerificationBundle() : null; 152 } 153 154 private void abort() { 155 if (mOriginalOptions != null) { 156 ActivityOptions.abort(mOriginalOptions); 157 } 158 if (mCallerOptions != null) { 159 ActivityOptions.abort(mCallerOptions); 160 } 161 } 162 163 static void abort(@Nullable SafeActivityOptions options) { 164 if (options != null) { 165 options.abort(); 166 } 167 } 168 169 /** 170 * Merges two activity options into one, with {@code options2} taking precedence in case of a 171 * conflict. 172 */ 173 @VisibleForTesting 174 @Nullable ActivityOptions mergeActivityOptions(@Nullable ActivityOptions options1, 175 @Nullable ActivityOptions options2) { 176 if (options1 == null) { 177 return options2; 178 } 179 if (options2 == null) { 180 return options1; 181 } 182 final Bundle b1 = options1.toBundle(); 183 final Bundle b2 = options2.toBundle(); 184 b1.putAll(b2); 185 return ActivityOptions.fromBundle(b1); 186 } 187 188 private void checkPermissions(@Nullable Intent intent, @Nullable ActivityInfo aInfo, 189 @Nullable ProcessRecord callerApp, ActivityStackSupervisor supervisor, 190 ActivityOptions options, int callingPid, int callingUid) { 191 // If a launch task id is specified, then ensure that the caller is the recents 192 // component or has the START_TASKS_FROM_RECENTS permission 193 if (options.getLaunchTaskId() != INVALID_TASK_ID 194 && !supervisor.mRecentTasks.isCallerRecents(callingUid)) { 195 final int startInTaskPerm = supervisor.mService.checkPermission( 196 START_TASKS_FROM_RECENTS, callingPid, callingUid); 197 if (startInTaskPerm == PERMISSION_DENIED) { 198 final String msg = "Permission Denial: starting " + getIntentString(intent) 199 + " from " + callerApp + " (pid=" + callingPid 200 + ", uid=" + callingUid + ") with launchTaskId=" 201 + options.getLaunchTaskId(); 202 Slog.w(TAG, msg); 203 throw new SecurityException(msg); 204 } 205 } 206 // Check if someone tries to launch an activity on a private display with a different 207 // owner. 208 final int launchDisplayId = options.getLaunchDisplayId(); 209 if (aInfo != null && launchDisplayId != INVALID_DISPLAY 210 && !supervisor.isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, 211 launchDisplayId, aInfo)) { 212 final String msg = "Permission Denial: starting " + getIntentString(intent) 213 + " from " + callerApp + " (pid=" + callingPid 214 + ", uid=" + callingUid + ") with launchDisplayId=" 215 + launchDisplayId; 216 Slog.w(TAG, msg); 217 throw new SecurityException(msg); 218 } 219 // Check if someone tries to launch an unwhitelisted activity into LockTask mode. 220 final boolean lockTaskMode = options.getLockTaskMode(); 221 if (aInfo != null && lockTaskMode 222 && !supervisor.mService.getLockTaskController().isPackageWhitelisted( 223 UserHandle.getUserId(callingUid), aInfo.packageName)) { 224 final String msg = "Permission Denial: starting " + getIntentString(intent) 225 + " from " + callerApp + " (pid=" + callingPid 226 + ", uid=" + callingUid + ") with lockTaskMode=true"; 227 Slog.w(TAG, msg); 228 throw new SecurityException(msg); 229 } 230 231 // Check permission for remote animations 232 final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter(); 233 if (adapter != null && supervisor.mService.checkPermission( 234 CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, callingPid, callingUid) 235 != PERMISSION_GRANTED) { 236 final String msg = "Permission Denial: starting " + getIntentString(intent) 237 + " from " + callerApp + " (pid=" + callingPid 238 + ", uid=" + callingUid + ") with remoteAnimationAdapter"; 239 Slog.w(TAG, msg); 240 throw new SecurityException(msg); 241 } 242 } 243 244 private String getIntentString(Intent intent) { 245 return intent != null ? intent.toString() : "(no intent)"; 246 } 247} 248