blob: 9c7eb9562721bbd75da28996f81ebe6f68a56693 [file] [log] [blame]
Kenny Guyb1b30262016-02-09 16:02:35 +00001/*
2 * Copyright (C) 2016 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
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080017package com.android.server.am;
18
Wale Ogunwale01d66562015-12-29 08:19:19 -080019import static android.app.Activity.RESULT_CANCELED;
20import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
21import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
22import static android.app.ActivityManager.START_FLAG_ONLY_IF_NEEDED;
23import static android.app.ActivityManager.START_RETURN_INTENT_TO_CALLER;
24import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
25import static android.app.ActivityManager.START_SUCCESS;
26import static android.app.ActivityManager.START_TASK_TO_FRONT;
Wale Ogunwale854809c2015-12-27 16:18:19 -080027import static android.app.ActivityManager.StackId;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080028import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
29import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
30import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
Wale Ogunwale854809c2015-12-27 16:18:19 -080031import static android.app.ActivityManager.StackId.HOME_STACK_ID;
32import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
33import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080034import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
35import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
Wale Ogunwale2a25a622016-01-30 11:27:21 -080036import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080037import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
Wale Ogunwale01d66562015-12-29 08:19:19 -080038import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080039import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
Wale Ogunwale01d66562015-12-29 08:19:19 -080040import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
41import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
Wale Ogunwale01d66562015-12-29 08:19:19 -080042import static android.content.Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP;
43import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
44import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
45import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
46import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
Filip Gruszczynski303210b2016-01-08 16:28:08 -080047import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
Wale Ogunwale01d66562015-12-29 08:19:19 -080048import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
49import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
50import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
51import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080052import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
53import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
54import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
Filip Gruszczynski303210b2016-01-08 16:28:08 -080055import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080056import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RESULTS;
57import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
58import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
59import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USER_LEAVING;
60import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
61import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
62import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RESULTS;
63import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_USER_LEAVING;
64import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
65import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
66import static com.android.server.am.ActivityManagerService.ANIMATE;
Wale Ogunwale673cbd22016-01-30 18:30:55 -080067import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080068import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
69import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
70import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
Filip Gruszczynski0e381e22016-01-14 16:31:33 -080071import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080072import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
73import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
74import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
Wale Ogunwalecacfaa22016-01-15 11:26:08 -080075import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080076import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS;
Filip Gruszczynskie826f322016-01-11 17:15:22 -080077import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080078
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080079import android.app.ActivityManager;
80import android.app.ActivityOptions;
81import android.app.AppGlobals;
82import android.app.IActivityContainer;
83import android.app.IActivityManager;
84import android.app.IApplicationThread;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080085import android.app.PendingIntent;
86import android.app.ProfilerInfo;
87import android.content.ComponentName;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080088import android.content.IIntentSender;
89import android.content.Intent;
90import android.content.IntentSender;
91import android.content.pm.ActivityInfo;
92import android.content.pm.ApplicationInfo;
Kenny Guyb1b30262016-02-09 16:02:35 +000093import android.content.pm.PackageManager;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080094import android.content.pm.ResolveInfo;
Kenny Guyb1b30262016-02-09 16:02:35 +000095import android.content.pm.UserInfo;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -080096import android.content.res.Configuration;
97import android.graphics.Rect;
98import android.os.Binder;
99import android.os.Build;
100import android.os.Bundle;
101import android.os.IBinder;
102import android.os.RemoteException;
103import android.os.SystemClock;
104import android.os.UserHandle;
Kenny Guyb1b30262016-02-09 16:02:35 +0000105import android.os.UserManager;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800106import android.service.voice.IVoiceInteractionSession;
107import android.util.EventLog;
108import android.util.Slog;
109import android.view.Display;
110
111import com.android.internal.app.HeavyWeightSwitcherActivity;
112import com.android.internal.app.IVoiceInteractor;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800113import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
114import com.android.server.wm.WindowManagerService;
115
116import java.util.ArrayList;
117
118/**
119 * Controller for interpreting how and then launching activities.
120 *
121 * This class collects all the logic for determining how an intent and flags should be turned into
122 * an activity and associated task and stack.
123 */
Wale Ogunwale01d66562015-12-29 08:19:19 -0800124class ActivityStarter {
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800125 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStarter" : TAG_AM;
126 private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
127 private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
128 private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
129 private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
130
131 private final ActivityManagerService mService;
132 private final ActivityStackSupervisor mSupervisor;
Rubin Xu58d25992016-01-21 17:47:13 +0000133 private ActivityStartInterceptor mInterceptor;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800134 private WindowManagerService mWindowManager;
135
136 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>();
137
Wale Ogunwale01d66562015-12-29 08:19:19 -0800138 // Share state variable among methods when starting an activity.
139 private ActivityRecord mStartActivity;
140 private Intent mIntent;
141 private int mCallingUid;
142 private ActivityOptions mOptions;
143
144 private boolean mLaunchSingleTop;
145 private boolean mLaunchSingleInstance;
146 private boolean mLaunchSingleTask;
147 private boolean mLaunchTaskBehind;
148 private int mLaunchFlags;
149
150 private Rect mLaunchBounds;
151
152 private ActivityRecord mNotTop;
153 private boolean mDoResume;
154 private int mStartFlags;
155 private ActivityRecord mSourceRecord;
156
157 private TaskRecord mInTask;
158 private boolean mAddingToTask;
159 private TaskRecord mReuseTask;
160
161 private ActivityInfo mNewTaskInfo;
162 private Intent mNewTaskIntent;
163 private ActivityStack mSourceStack;
164 private ActivityStack mTargetStack;
165 // TODO: Is the mMoveHome flag really needed?
166 private boolean mMovedHome;
167 private boolean mMovedToFront;
168 private boolean mNoAnimation;
169 private boolean mKeepCurTransition;
170
171 private IVoiceInteractionSession mVoiceSession;
172 private IVoiceInteractor mVoiceInteractor;
173
174 private void reset() {
175 mStartActivity = null;
176 mIntent = null;
177 mCallingUid = -1;
178 mOptions = null;
179
180 mLaunchSingleTop = false;
181 mLaunchSingleInstance = false;
182 mLaunchSingleTask = false;
183 mLaunchTaskBehind = false;
184 mLaunchFlags = 0;
185
186 mLaunchBounds = null;
187
188 mNotTop = null;
189 mDoResume = false;
190 mStartFlags = 0;
191 mSourceRecord = null;
192
193 mInTask = null;
194 mAddingToTask = false;
195 mReuseTask = null;
196
197 mNewTaskInfo = null;
198 mNewTaskIntent = null;
199 mSourceStack = null;
200
201 mTargetStack = null;
202 mMovedHome = false;
203 mMovedToFront = false;
204 mNoAnimation = false;
205 mKeepCurTransition = false;
206
207 mVoiceSession = null;
208 mVoiceInteractor = null;
209 }
210
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800211 ActivityStarter(ActivityManagerService service, ActivityStackSupervisor supervisor) {
212 mService = service;
213 mSupervisor = supervisor;
Rubin Xu58d25992016-01-21 17:47:13 +0000214 mInterceptor = new ActivityStartInterceptor(mService, mSupervisor);
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800215 }
216
217 final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
218 String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
219 IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
220 IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
221 String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
222 ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
223 ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
224 TaskRecord inTask) {
225 int err = ActivityManager.START_SUCCESS;
226
227 ProcessRecord callerApp = null;
228 if (caller != null) {
229 callerApp = mService.getRecordForAppLocked(caller);
230 if (callerApp != null) {
231 callingPid = callerApp.pid;
232 callingUid = callerApp.info.uid;
233 } else {
234 Slog.w(TAG, "Unable to find app for caller " + caller
235 + " (pid=" + callingPid + ") when starting: "
236 + intent.toString());
237 err = ActivityManager.START_PERMISSION_DENIED;
238 }
239 }
240
241 final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
242
243 if (err == ActivityManager.START_SUCCESS) {
244 Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
245 + "} from uid " + callingUid
246 + " on display " + (container == null ? (mSupervisor.mFocusedStack == null ?
247 Display.DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId) :
248 (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
249 container.mActivityDisplay.mDisplayId)));
250 }
251
252 ActivityRecord sourceRecord = null;
253 ActivityRecord resultRecord = null;
254 if (resultTo != null) {
255 sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
256 if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
257 "Will send result to " + resultTo + " " + sourceRecord);
258 if (sourceRecord != null) {
259 if (requestCode >= 0 && !sourceRecord.finishing) {
260 resultRecord = sourceRecord;
261 }
262 }
263 }
264
265 final int launchFlags = intent.getFlags();
266
267 if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
268 // Transfer the result target from the source activity to the new
269 // one being started, including any failures.
270 if (requestCode >= 0) {
271 ActivityOptions.abort(options);
272 return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
273 }
274 resultRecord = sourceRecord.resultTo;
275 if (resultRecord != null && !resultRecord.isInStackLocked()) {
276 resultRecord = null;
277 }
278 resultWho = sourceRecord.resultWho;
279 requestCode = sourceRecord.requestCode;
280 sourceRecord.resultTo = null;
281 if (resultRecord != null) {
282 resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
283 }
284 if (sourceRecord.launchedFromUid == callingUid) {
285 // The new activity is being launched from the same uid as the previous
286 // activity in the flow, and asking to forward its result back to the
287 // previous. In this case the activity is serving as a trampoline between
288 // the two, so we also want to update its launchedFromPackage to be the
289 // same as the previous activity. Note that this is safe, since we know
290 // these two packages come from the same uid; the caller could just as
291 // well have supplied that same package name itself. This specifially
292 // deals with the case of an intent picker/chooser being launched in the app
293 // flow to redirect to an activity picked by the user, where we want the final
294 // activity to consider it to have been launched by the previous app activity.
295 callingPackage = sourceRecord.launchedFromPackage;
296 }
297 }
298
299 if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
300 // We couldn't find a class that can handle the given Intent.
301 // That's the end of that!
302 err = ActivityManager.START_INTENT_NOT_RESOLVED;
303 }
304
305 if (err == ActivityManager.START_SUCCESS && aInfo == null) {
306 // We couldn't find the specific class specified in the Intent.
307 // Also the end of the line.
308 err = ActivityManager.START_CLASS_NOT_FOUND;
309 }
310
311 if (err == ActivityManager.START_SUCCESS && sourceRecord != null
312 && sourceRecord.task.voiceSession != null) {
313 // If this activity is being launched as part of a voice session, we need
314 // to ensure that it is safe to do so. If the upcoming activity will also
315 // be part of the voice session, we can only launch it if it has explicitly
316 // said it supports the VOICE category, or it is a part of the calling app.
317 if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
318 && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
319 try {
320 intent.addCategory(Intent.CATEGORY_VOICE);
321 if (!AppGlobals.getPackageManager().activitySupportsIntent(
322 intent.getComponent(), intent, resolvedType)) {
323 Slog.w(TAG,
324 "Activity being started in current voice task does not support voice: "
325 + intent);
326 err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
327 }
328 } catch (RemoteException e) {
329 Slog.w(TAG, "Failure checking voice capabilities", e);
330 err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
331 }
332 }
333 }
334
335 if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
336 // If the caller is starting a new voice session, just make sure the target
337 // is actually allowing it to run this way.
338 try {
339 if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
340 intent, resolvedType)) {
341 Slog.w(TAG,
342 "Activity being started in new voice task does not support: "
343 + intent);
344 err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
345 }
346 } catch (RemoteException e) {
347 Slog.w(TAG, "Failure checking voice capabilities", e);
348 err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
349 }
350 }
351
352 final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
353
Wale Ogunwale01d66562015-12-29 08:19:19 -0800354 if (err != START_SUCCESS) {
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800355 if (resultRecord != null) {
Wale Ogunwale01d66562015-12-29 08:19:19 -0800356 resultStack.sendActivityResultLocked(
357 -1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null);
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800358 }
359 ActivityOptions.abort(options);
360 return err;
361 }
362
363 boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
364 requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
365 resultRecord, resultStack);
366 abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
367 callingPid, resolvedType, aInfo.applicationInfo);
368
369 if (mService.mController != null) {
370 try {
371 // The Intent we give to the watcher has the extra data
372 // stripped off, since it can contain private information.
373 Intent watchIntent = intent.cloneFilter();
374 abort |= !mService.mController.activityStarting(watchIntent,
375 aInfo.applicationInfo.packageName);
376 } catch (RemoteException e) {
377 mService.mController = null;
378 }
379 }
380
Rubin Xu58d25992016-01-21 17:47:13 +0000381 mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage);
382 mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, callingUid);
383 intent = mInterceptor.mIntent;
384 rInfo = mInterceptor.mRInfo;
385 aInfo = mInterceptor.mAInfo;
386 resolvedType = mInterceptor.mResolvedType;
387 inTask = mInterceptor.mInTask;
388 callingPid = mInterceptor.mCallingPid;
389 callingUid = mInterceptor.mCallingUid;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800390
391 if (abort) {
392 if (resultRecord != null) {
393 resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
Wale Ogunwale01d66562015-12-29 08:19:19 -0800394 RESULT_CANCELED, null);
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800395 }
396 // We pretend to the caller that it was really started, but
397 // they will just get a cancel result.
398 ActivityOptions.abort(options);
Wale Ogunwale01d66562015-12-29 08:19:19 -0800399 return START_SUCCESS;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800400 }
401
402 // If permissions need a review before any of the app components can run, we
403 // launch the review activity and pass a pending intent to start the activity
404 // we are to launching now after the review is completed.
405 if (Build.PERMISSIONS_REVIEW_REQUIRED && aInfo != null) {
406 if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
407 aInfo.packageName, userId)) {
408 IIntentSender target = mService.getIntentSenderLocked(
409 ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
410 callingUid, userId, null, null, 0, new Intent[]{intent},
411 new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
412 | PendingIntent.FLAG_ONE_SHOT, null);
413
414 final int flags = intent.getFlags();
415 Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
416 newIntent.setFlags(flags
417 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
418 newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
419 newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
420 if (resultRecord != null) {
421 newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);
422 }
423 intent = newIntent;
424
425 resolvedType = null;
426 callingUid = realCallingUid;
427 callingPid = realCallingPid;
428
429 rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
430 aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
431 null /*profilerInfo*/);
432
433 if (DEBUG_PERMISSIONS_REVIEW) {
434 Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
435 true, false) + "} from uid " + callingUid + " on display "
436 + (container == null ? (mSupervisor.mFocusedStack == null ?
437 Display.DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId) :
438 (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
439 container.mActivityDisplay.mDisplayId)));
440 }
441 }
442 }
443
444 // If we have an ephemeral app, abort the process of launching the resolved intent.
445 // Instead, launch the ephemeral installer. Once the installer is finished, it
446 // starts either the intent we resolved here [on install error] or the ephemeral
447 // app [on install success].
448 if (rInfo != null && rInfo.ephemeralResolveInfo != null) {
449 // Create a pending intent to start the intent resolved here.
450 final IIntentSender failureTarget = mService.getIntentSenderLocked(
451 ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
452 Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
453 new String[]{ resolvedType },
454 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
455 | PendingIntent.FLAG_IMMUTABLE, null);
456
457 // Create a pending intent to start the ephemeral application; force it to be
458 // directed to the ephemeral package.
459 ephemeralIntent.setPackage(rInfo.ephemeralResolveInfo.getPackageName());
460 final IIntentSender ephemeralTarget = mService.getIntentSenderLocked(
461 ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
462 Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ ephemeralIntent },
463 new String[]{ resolvedType },
464 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
465 | PendingIntent.FLAG_IMMUTABLE, null);
466
467 int flags = intent.getFlags();
468 intent = new Intent();
469 intent.setFlags(flags
470 | Intent.FLAG_ACTIVITY_NEW_TASK
471 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
472 intent.putExtra(Intent.EXTRA_PACKAGE_NAME,
473 rInfo.ephemeralResolveInfo.getPackageName());
474 intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureTarget));
475 intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(ephemeralTarget));
476
477 resolvedType = null;
478 callingUid = realCallingUid;
479 callingPid = realCallingPid;
480
481 rInfo = rInfo.ephemeralInstaller;
482 aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
483 }
484
485 ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
486 intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
487 requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
488 options);
489 if (outActivity != null) {
490 outActivity[0] = r;
491 }
492
493 if (r.appTimeTracker == null && sourceRecord != null) {
494 // If the caller didn't specify an explicit time tracker, we want to continue
495 // tracking under any it has.
496 r.appTimeTracker = sourceRecord.appTimeTracker;
497 }
498
499 final ActivityStack stack = mSupervisor.mFocusedStack;
500 if (voiceSession == null && (stack.mResumedActivity == null
501 || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
502 if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
503 realCallingPid, realCallingUid, "Activity start")) {
504 PendingActivityLaunch pal = new PendingActivityLaunch(r,
505 sourceRecord, startFlags, stack, callerApp);
506 mPendingActivityLaunches.add(pal);
507 ActivityOptions.abort(options);
508 return ActivityManager.START_SWITCHES_CANCELED;
509 }
510 }
511
512 if (mService.mDidAppSwitch) {
513 // This is the second allowed switch since we stopped switches,
514 // so now just generally allow switches. Use case: user presses
515 // home (switches disabled, switch to home, mDidAppSwitch now true);
516 // user taps a home icon (coming from home so allowed, we hit here
517 // and now allow anyone to switch again).
518 mService.mAppSwitchesAllowedTime = 0;
519 } else {
520 mService.mDidAppSwitch = true;
521 }
522
523 doPendingActivityLaunchesLocked(false);
524
Wale Ogunwale01d66562015-12-29 08:19:19 -0800525 err = startActivityUnchecked(
526 r, sourceRecord, voiceSession, voiceInteractor, startFlags, true, options, inTask);
Wale Ogunwalecc25a8a2016-01-23 14:31:37 -0800527 postStartActivityUncheckedProcessing(r, err, stack.mStackId);
528 return err;
529 }
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800530
Wale Ogunwalecc25a8a2016-01-23 14:31:37 -0800531 void postStartActivityUncheckedProcessing(
532 ActivityRecord r, int result, int prevFocusedStackId) {
533
534 if (result < START_SUCCESS) {
535 // If someone asked to have the keyguard dismissed on the next activity start,
536 // but we are not actually doing an activity switch... just dismiss the keyguard now,
537 // because we probably want to see whatever is behind it.
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800538 mSupervisor.notifyActivityDrawnForKeyguard();
Wale Ogunwalecc25a8a2016-01-23 14:31:37 -0800539 return;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800540 }
Filip Gruszczynski303210b2016-01-08 16:28:08 -0800541
Wale Ogunwalecc25a8a2016-01-23 14:31:37 -0800542 int startedActivityStackId = INVALID_STACK_ID;
543 if (r.task != null && r.task.stack != null) {
544 startedActivityStackId = r.task.stack.mStackId;
545 } else if (mTargetStack != null) {
546 startedActivityStackId = mTargetStack.mStackId;
547 }
548
549 if (startedActivityStackId == DOCKED_STACK_ID && prevFocusedStackId == HOME_STACK_ID) {
550 // We launch an activity while being in home stack, which means either launcher or
551 // recents into docked stack. We don't want the launched activity to be alone in a
552 // docked stack, so we want to immediately launch recents too.
553 if (DEBUG_RECENTS) Slog.d(TAG, "Scheduling recents launch.");
554 mWindowManager.showRecentApps();
555 return;
556 }
557
558 if (startedActivityStackId == PINNED_STACK_ID
559 && (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP)) {
560 // The activity was already running in the pinned stack so it wasn't started, but either
561 // brought to the front or the new intent was delivered to it since it was already in
562 // front. Notify anyone interested in this piece of information.
563 mService.notifyPinnedActivityRestartAttemptLocked();
564 return;
565 }
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800566 }
567
568 void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
569 mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
570 startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/,
571 null /*resolvedType*/, aInfo, null /*rInfo*/, null /*voiceSession*/,
572 null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,
573 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/,
574 0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/,
575 false /*ignoreTargetSecurity*/, false /*componentSpecified*/, null /*outActivity*/,
576 null /*container*/, null /*inTask*/);
577 if (mSupervisor.inResumeTopActivity) {
578 // If we are in resume section already, home activity will be initialized, but not
579 // resumed (to avoid recursive resume) and will stay that way until something pokes it
580 // again. We need to schedule another resume.
581 mSupervisor.scheduleResumeTopActivities();
582 }
583 }
584
585 final int startActivityMayWait(IApplicationThread caller, int callingUid,
586 String callingPackage, Intent intent, String resolvedType,
587 IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
588 IBinder resultTo, String resultWho, int requestCode, int startFlags,
589 ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
590 Bundle bOptions, boolean ignoreTargetSecurity, int userId,
591 IActivityContainer iContainer, TaskRecord inTask) {
592 // Refuse possible leaked file descriptors
593 if (intent != null && intent.hasFileDescriptors()) {
594 throw new IllegalArgumentException("File descriptors passed in Intent");
595 }
596 boolean componentSpecified = intent.getComponent() != null;
597
598 // Save a copy in case ephemeral needs it
599 final Intent ephemeralIntent = new Intent(intent);
600 // Don't modify the client's object!
601 intent = new Intent(intent);
602
603 ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
Kenny Guyb1b30262016-02-09 16:02:35 +0000604 if (rInfo == null) {
605 UserInfo userInfo = mSupervisor.getUserInfo(userId);
606 if (userInfo != null && userInfo.isManagedProfile()) {
607 // Special case for managed profiles, if attempting to launch non-cryto aware
608 // app in a locked managed profile from an unlocked parent allow it to resolve
609 // as user will be sent via confirm credentials to unlock the profile.
610 UserManager userManager = UserManager.get(mService.mContext);
Tony Mak13436452016-02-24 11:08:38 +0000611 UserInfo parent = null;
612 long token = Binder.clearCallingIdentity();
613 try {
614 parent = userManager.getProfileParent(userId);
615 } finally {
616 Binder.restoreCallingIdentity(token);
617 }
Kenny Guyb1b30262016-02-09 16:02:35 +0000618 if (parent != null
619 && userManager.isUserUnlocked(parent.getUserHandle())
620 && !userManager.isUserUnlocked(userInfo.getUserHandle())) {
621 rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
622 PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
623 }
624 }
625 }
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800626 // Collect information about the target of the Intent.
627 ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
628
629 ActivityOptions options = ActivityOptions.fromBundle(bOptions);
630 ActivityStackSupervisor.ActivityContainer container =
631 (ActivityStackSupervisor.ActivityContainer)iContainer;
632 synchronized (mService) {
633 if (container != null && container.mParentActivity != null &&
634 container.mParentActivity.state != RESUMED) {
635 // Cannot start a child activity if the parent is not resumed.
636 return ActivityManager.START_CANCELED;
637 }
638 final int realCallingPid = Binder.getCallingPid();
639 final int realCallingUid = Binder.getCallingUid();
640 int callingPid;
641 if (callingUid >= 0) {
642 callingPid = -1;
643 } else if (caller == null) {
644 callingPid = realCallingPid;
645 callingUid = realCallingUid;
646 } else {
647 callingPid = callingUid = -1;
648 }
649
650 final ActivityStack stack;
651 if (container == null || container.mStack.isOnHomeDisplay()) {
652 stack = mSupervisor.mFocusedStack;
653 } else {
654 stack = container.mStack;
655 }
656 stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0;
657 if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
658 "Starting activity when config will change = " + stack.mConfigWillChange);
659
660 final long origId = Binder.clearCallingIdentity();
661
662 if (aInfo != null &&
663 (aInfo.applicationInfo.privateFlags
664 & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
665 // This may be a heavy-weight process! Check to see if we already
666 // have another, different heavy-weight process running.
667 if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
668 final ProcessRecord heavy = mService.mHeavyWeightProcess;
669 if (heavy != null && (heavy.info.uid != aInfo.applicationInfo.uid
670 || !heavy.processName.equals(aInfo.processName))) {
671 int appCallingUid = callingUid;
672 if (caller != null) {
673 ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
674 if (callerApp != null) {
675 appCallingUid = callerApp.info.uid;
676 } else {
677 Slog.w(TAG, "Unable to find app for caller " + caller
678 + " (pid=" + callingPid + ") when starting: "
679 + intent.toString());
680 ActivityOptions.abort(options);
681 return ActivityManager.START_PERMISSION_DENIED;
682 }
683 }
684
685 IIntentSender target = mService.getIntentSenderLocked(
686 ActivityManager.INTENT_SENDER_ACTIVITY, "android",
687 appCallingUid, userId, null, null, 0, new Intent[] { intent },
688 new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
689 | PendingIntent.FLAG_ONE_SHOT, null);
690
691 Intent newIntent = new Intent();
692 if (requestCode >= 0) {
693 // Caller is requesting a result.
694 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
695 }
696 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
697 new IntentSender(target));
698 if (heavy.activities.size() > 0) {
699 ActivityRecord hist = heavy.activities.get(0);
700 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
701 hist.packageName);
702 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
703 hist.task.taskId);
704 }
705 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
706 aInfo.packageName);
707 newIntent.setFlags(intent.getFlags());
708 newIntent.setClassName("android",
709 HeavyWeightSwitcherActivity.class.getName());
710 intent = newIntent;
711 resolvedType = null;
712 caller = null;
713 callingUid = Binder.getCallingUid();
714 callingPid = Binder.getCallingPid();
715 componentSpecified = true;
716 rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId);
717 aInfo = rInfo != null ? rInfo.activityInfo : null;
718 if (aInfo != null) {
719 aInfo = mService.getActivityInfoForUser(aInfo, userId);
720 }
721 }
722 }
723 }
724
725 int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
726 aInfo, rInfo, voiceSession, voiceInteractor,
727 resultTo, resultWho, requestCode, callingPid,
728 callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
729 options, ignoreTargetSecurity, componentSpecified, null, container, inTask);
730
731 Binder.restoreCallingIdentity(origId);
732
733 if (stack.mConfigWillChange) {
734 // If the caller also wants to switch to a new configuration,
735 // do so now. This allows a clean switch, as we are waiting
736 // for the current activity to pause (so we will not destroy
737 // it), and have not yet started the next activity.
738 mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
739 "updateConfiguration()");
740 stack.mConfigWillChange = false;
741 if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
742 "Updating to new configuration after starting activity.");
743 mService.updateConfigurationLocked(config, null, false);
744 }
745
746 if (outResult != null) {
747 outResult.result = res;
748 if (res == ActivityManager.START_SUCCESS) {
749 mSupervisor.mWaitingActivityLaunched.add(outResult);
750 do {
751 try {
752 mService.wait();
753 } catch (InterruptedException e) {
754 }
755 } while (!outResult.timeout && outResult.who == null);
Wale Ogunwale01d66562015-12-29 08:19:19 -0800756 } else if (res == START_TASK_TO_FRONT) {
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800757 ActivityRecord r = stack.topRunningActivityLocked();
758 if (r.nowVisible && r.state == RESUMED) {
759 outResult.timeout = false;
760 outResult.who = new ComponentName(r.info.packageName, r.info.name);
761 outResult.totalTime = 0;
762 outResult.thisTime = 0;
763 } else {
764 outResult.thisTime = SystemClock.uptimeMillis();
765 mSupervisor.mWaitingActivityVisible.add(outResult);
766 do {
767 try {
768 mService.wait();
769 } catch (InterruptedException e) {
770 }
771 } while (!outResult.timeout && outResult.who == null);
772 }
773 }
774 }
775
776 return res;
777 }
778 }
779
Filip Gruszczynski07a0e492015-12-17 14:16:38 -0800780 final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
781 Intent[] intents, String[] resolvedTypes, IBinder resultTo,
782 Bundle bOptions, int userId) {
783 if (intents == null) {
784 throw new NullPointerException("intents is null");
785 }
786 if (resolvedTypes == null) {
787 throw new NullPointerException("resolvedTypes is null");
788 }
789 if (intents.length != resolvedTypes.length) {
790 throw new IllegalArgumentException("intents are length different than resolvedTypes");
791 }
792
793
794 int callingPid;
795 if (callingUid >= 0) {
796 callingPid = -1;
797 } else if (caller == null) {
798 callingPid = Binder.getCallingPid();
799 callingUid = Binder.getCallingUid();
800 } else {
801 callingPid = callingUid = -1;
802 }
803 final long origId = Binder.clearCallingIdentity();
804 try {
805 synchronized (mService) {
806 ActivityRecord[] outActivity = new ActivityRecord[1];
807 for (int i=0; i<intents.length; i++) {
808 Intent intent = intents[i];
809 if (intent == null) {
810 continue;
811 }
812
813 // Refuse possible leaked file descriptors
814 if (intent != null && intent.hasFileDescriptors()) {
815 throw new IllegalArgumentException("File descriptors passed in Intent");
816 }
817
818 boolean componentSpecified = intent.getComponent() != null;
819
820 // Don't modify the client's object!
821 intent = new Intent(intent);
822
823 // Collect information about the target of the Intent.
824 ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0,
825 null, userId);
826 // TODO: New, check if this is correct
827 aInfo = mService.getActivityInfoForUser(aInfo, userId);
828
829 if (aInfo != null &&
830 (aInfo.applicationInfo.privateFlags
831 & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
832 throw new IllegalArgumentException(
833 "FLAG_CANT_SAVE_STATE not supported here");
834 }
835
836 ActivityOptions options = ActivityOptions.fromBundle(
837 i == intents.length - 1 ? bOptions : null);
838 int res = startActivityLocked(caller, intent, null /*ephemeralIntent*/,
839 resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
840 callingPid, callingUid, callingPackage, callingPid, callingUid, 0,
841 options, false, componentSpecified, outActivity, null, null);
842 if (res < 0) {
843 return res;
844 }
845
846 resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
847 }
848 }
849 } finally {
850 Binder.restoreCallingIdentity(origId);
851 }
852
Wale Ogunwale01d66562015-12-29 08:19:19 -0800853 return START_SUCCESS;
854 }
855
856 private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
857 IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
858 int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
859
860 setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
861 voiceInteractor);
862
863 computeLaunchingTaskFlags();
864
865 computeSourceStack();
866
867 mIntent.setFlags(mLaunchFlags);
868
869 ActivityRecord intentActivity = getReusableIntentActivity();
870
871 if (intentActivity != null) {
872 // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
873 // still needs to be a lock task mode violation since the task gets cleared out and
874 // the device would otherwise leave the locked task.
875 if (mSupervisor.isLockTaskModeViolation(intentActivity.task,
876 (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
877 == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
878 mSupervisor.showLockTaskToast();
879 Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
880 return START_RETURN_LOCK_TASK_MODE_VIOLATION;
881 }
882
883 if (mStartActivity.task == null) {
884 mStartActivity.task = intentActivity.task;
885 }
886 if (intentActivity.task.intent == null) {
887 // This task was started because of movement of the activity based on affinity...
888 // Now that we are actually launching it, we can assign the base intent.
889 intentActivity.task.setIntent(mStartActivity);
890 }
891
Filip Gruszczynskie826f322016-01-11 17:15:22 -0800892 // This code path leads to delivering a new intent, we want to make sure we schedule it
893 // as the first operation, in case the activity will be resumed as a result of later
894 // operations.
895 if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
896 || mLaunchSingleInstance || mLaunchSingleTask) {
897 // In this situation we want to remove all activities from the task up to the one
898 // being started. In most cases this means we are resetting the task to its initial
899 // state.
Filip Gruszczynskibe9dabd2016-01-19 12:23:10 -0800900 final ActivityRecord top = intentActivity.task.performClearTaskForReuseLocked(
Filip Gruszczynskie826f322016-01-11 17:15:22 -0800901 mStartActivity, mLaunchFlags);
902 if (top != null) {
903 if (top.frontOfTask) {
904 // Activity aliases may mean we use different intents for the top activity,
905 // so make sure the task now has the identity of the new intent.
906 top.task.setIntent(mStartActivity);
907 }
908 ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
909 top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
910 mStartActivity.launchedFromPackage);
911 }
912 }
913
Wale Ogunwale01d66562015-12-29 08:19:19 -0800914 intentActivity = setTargetStackAndMoveToFrontIfNeeded(intentActivity);
915
916 if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
917 // We don't need to start a new activity, and the client said not to do anything
918 // if that is the case, so this is it! And for paranoia, make sure we have
919 // correctly resumed the top activity.
920 resumeTargetStackIfNeeded();
921 return START_RETURN_INTENT_TO_CALLER;
922 }
923
924 setTaskFromIntentActivity(intentActivity);
925
926 if (!mAddingToTask && mReuseTask == null) {
927 // We didn't do anything... but it was needed (a.k.a., client don't use that
928 // intent!) And for paranoia, make sure we have correctly resumed the top activity.
929 resumeTargetStackIfNeeded();
930 return START_TASK_TO_FRONT;
931 }
932 }
933
934 if (mStartActivity.packageName == null) {
935 if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
936 mStartActivity.resultTo.task.stack.sendActivityResultLocked(
937 -1, mStartActivity.resultTo, mStartActivity.resultWho,
938 mStartActivity.requestCode, RESULT_CANCELED, null);
939 }
940 ActivityOptions.abort(mOptions);
941 return START_CLASS_NOT_FOUND;
942 }
943
944 // If the activity being launched is the same as the one currently at the top, then
945 // we need to check if it should only be launched once.
946 final ActivityStack topStack = mSupervisor.mFocusedStack;
947 final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
948 final boolean dontStart = top != null && mStartActivity.resultTo == null
949 && top.realActivity.equals(mStartActivity.realActivity)
950 && top.userId == mStartActivity.userId
951 && top.app != null && top.app.thread != null
952 && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
953 || mLaunchSingleTop || mLaunchSingleTask);
954 if (dontStart) {
Filip Gruszczynskie826f322016-01-11 17:15:22 -0800955 ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
Wale Ogunwale01d66562015-12-29 08:19:19 -0800956 // For paranoia, make sure we have correctly resumed the top activity.
957 topStack.mLastPausedActivity = null;
958 if (mDoResume) {
959 mSupervisor.resumeFocusedStackTopActivityLocked();
960 }
961 ActivityOptions.abort(mOptions);
962 if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
963 // We don't need to start a new activity, and the client said not to do
964 // anything if that is the case, so this is it!
965 return START_RETURN_INTENT_TO_CALLER;
966 }
967 top.deliverNewIntentLocked(
968 mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
969 return START_DELIVERED_TO_TOP;
970 }
971
972 boolean newTask = false;
973 final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
974 ? mSourceRecord.task : null;
975
976 // Should this be considered a new task?
977 if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
978 && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
979 newTask = true;
980 setTaskFromReuseOrCreateNewTask(taskToAffiliate);
981
982 if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
983 Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
984 return START_RETURN_LOCK_TASK_MODE_VIOLATION;
985 }
Wale Ogunwale673cbd22016-01-30 18:30:55 -0800986 if (!mMovedHome) {
987 updateTaskReturnToType(mStartActivity.task, mLaunchFlags, topStack);
Wale Ogunwale01d66562015-12-29 08:19:19 -0800988 }
989 } else if (mSourceRecord != null) {
990 if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
991 Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
992 return START_RETURN_LOCK_TASK_MODE_VIOLATION;
993 }
994
995 final int result = setTaskFromSourceRecord();
996 if (result != START_SUCCESS) {
997 return result;
998 }
999 } else if (mInTask != null) {
1000 // The caller is asking that the new activity be started in an explicit
1001 // task it has provided to us.
1002 if (mSupervisor.isLockTaskModeViolation(mInTask)) {
1003 Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
1004 return START_RETURN_LOCK_TASK_MODE_VIOLATION;
1005 }
1006
1007 final int result = setTaskFromInTask();
1008 if (result != START_SUCCESS) {
1009 return result;
1010 }
1011 } else {
1012 // This not being started from an existing activity, and not part of a new task...
1013 // just put it in the top task, though these days this case should never happen.
1014 setTaskToCurrentTopOrCreateNewTask();
1015 }
1016
1017 mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
1018 mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
1019
1020 if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
1021 mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
1022 }
1023 if (newTask) {
1024 EventLog.writeEvent(
1025 EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
1026 }
1027 ActivityStack.logStartActivity(
1028 EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
1029 mTargetStack.mLastPausedActivity = null;
1030 mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
1031 if (mDoResume) {
1032 if (!mLaunchTaskBehind) {
1033 // TODO(b/26381750): Remove this code after verification that all the decision
1034 // points above moved targetStack to the front which will also set the focus
1035 // activity.
1036 mService.setFocusedActivityLocked(mStartActivity, "startedActivity");
1037 }
Filip Gruszczynski3d7fdc12016-01-31 17:33:29 -08001038 if (mTargetStack.isFocusable()) {
1039 mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
1040 mOptions);
1041 } else {
1042 // If the activity is not focusable, we can't resume it, but still would like to
1043 // make sure it becomes visible as it starts (this will also trigger entry
1044 // animation). An example of this are PIP activities.
Wale Ogunwale480dca02016-02-06 13:58:29 -08001045 mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
Wale Ogunwaleae846f42016-02-22 14:00:56 -08001046 // Go ahead and tell window manager to execute app transition for this activity
1047 // since the app transition will not be triggered through the resume channel.
1048 mWindowManager.executeAppTransition();
Filip Gruszczynski3d7fdc12016-01-31 17:33:29 -08001049 }
Wale Ogunwale01d66562015-12-29 08:19:19 -08001050 } else {
1051 mTargetStack.addRecentActivityLocked(mStartActivity);
1052 }
1053 mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
1054
Wale Ogunwaleb9b16a72016-01-27 12:24:44 -08001055 final int preferredLaunchStackId =
1056 (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
1057 mSupervisor.showNonResizeableDockToastIfNeeded(
1058 mStartActivity.task, preferredLaunchStackId, mTargetStack.mStackId);
Wale Ogunwale01d66562015-12-29 08:19:19 -08001059
1060 return START_SUCCESS;
1061 }
1062
1063 private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
1064 boolean doResume, int startFlags, ActivityRecord sourceRecord,
1065 IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
1066 reset();
1067
1068 mStartActivity = r;
1069 mIntent = r.intent;
1070 mOptions = options;
1071 mCallingUid = r.launchedFromUid;
1072 mSourceRecord = sourceRecord;
1073 mVoiceSession = voiceSession;
1074 mVoiceInteractor = voiceInteractor;
1075
1076 mLaunchBounds = getOverrideBounds(r, options, inTask);
1077
1078 mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;
1079 mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
1080 mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;
1081 mLaunchFlags = adjustLaunchFlagsToDocumentMode(
1082 r, mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());
1083 mLaunchTaskBehind = r.mLaunchTaskBehind
1084 && !mLaunchSingleTask && !mLaunchSingleInstance
1085 && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
1086
1087 sendNewTaskResultRequestIfNeeded();
1088
1089 if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
1090 mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
1091 }
1092
1093 // If we are actually going to launch in to a new task, there are some cases where
1094 // we further want to do multiple task.
1095 if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
1096 if (mLaunchTaskBehind
1097 || r.info.documentLaunchMode == DOCUMENT_LAUNCH_ALWAYS) {
1098 mLaunchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
1099 }
1100 }
1101
1102 // We'll invoke onUserLeaving before onPause only if the launching
1103 // activity did not explicitly state that this is an automated launch.
1104 mSupervisor.mUserLeaving = (mLaunchFlags & FLAG_ACTIVITY_NO_USER_ACTION) == 0;
1105 if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
1106 "startActivity() => mUserLeaving=" + mSupervisor.mUserLeaving);
1107
1108 // If the caller has asked not to resume at this point, we make note
1109 // of this in the record so that we can skip it when trying to find
1110 // the top running activity.
1111 mDoResume = doResume;
1112 if (!doResume || !mSupervisor.okToShowLocked(r)) {
1113 r.delayedResume = true;
1114 mDoResume = false;
1115 }
1116
1117 mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
1118
1119 mInTask = inTask;
1120 // In some flows in to this function, we retrieve the task record and hold on to it
1121 // without a lock before calling back in to here... so the task at this point may
1122 // not actually be in recents. Check for that, and if it isn't in recents just
1123 // consider it invalid.
1124 if (inTask != null && !inTask.inRecents) {
1125 Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
1126 mInTask = null;
1127 }
1128
1129 mStartFlags = startFlags;
1130 // If the onlyIfNeeded flag is set, then we can do this if the activity being launched
1131 // is the same as the one making the call... or, as a special case, if we do not know
1132 // the caller then we count the current top activity as the caller.
1133 if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
1134 ActivityRecord checkedCaller = sourceRecord;
1135 if (checkedCaller == null) {
1136 checkedCaller = mSupervisor.mFocusedStack.topRunningNonDelayedActivityLocked(
1137 mNotTop);
1138 }
1139 if (!checkedCaller.realActivity.equals(r.realActivity)) {
1140 // Caller is not the same as launcher, so always needed.
1141 mStartFlags &= ~START_FLAG_ONLY_IF_NEEDED;
1142 }
1143 }
1144
1145 mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
1146 }
1147
1148 private void sendNewTaskResultRequestIfNeeded() {
1149 if (mStartActivity.resultTo != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
1150 && mStartActivity.resultTo.task.stack != null) {
1151 // For whatever reason this activity is being launched into a new task...
1152 // yet the caller has requested a result back. Well, that is pretty messed up,
1153 // so instead immediately send back a cancel and let the new task continue launched
1154 // as normal without a dependency on its originator.
1155 Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
1156 mStartActivity.resultTo.task.stack.sendActivityResultLocked(-1, mStartActivity.resultTo,
1157 mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED, null);
1158 mStartActivity.resultTo = null;
1159 }
1160 }
1161
1162 private void computeLaunchingTaskFlags() {
1163 // If the caller is not coming from another activity, but has given us an explicit task into
1164 // which they would like us to launch the new activity, then let's see about doing that.
1165 if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
1166 final Intent baseIntent = mInTask.getBaseIntent();
1167 final ActivityRecord root = mInTask.getRootActivity();
1168 if (baseIntent == null) {
1169 ActivityOptions.abort(mOptions);
1170 throw new IllegalArgumentException("Launching into task without base intent: "
1171 + mInTask);
1172 }
1173
1174 // If this task is empty, then we are adding the first activity -- it
1175 // determines the root, and must be launching as a NEW_TASK.
1176 if (mLaunchSingleInstance || mLaunchSingleTask) {
1177 if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) {
1178 ActivityOptions.abort(mOptions);
1179 throw new IllegalArgumentException("Trying to launch singleInstance/Task "
1180 + mStartActivity + " into different task " + mInTask);
1181 }
1182 if (root != null) {
1183 ActivityOptions.abort(mOptions);
1184 throw new IllegalArgumentException("Caller with mInTask " + mInTask
1185 + " has root " + root + " but target is singleInstance/Task");
1186 }
1187 }
1188
1189 // If task is empty, then adopt the interesting intent launch flags in to the
1190 // activity being started.
1191 if (root == null) {
1192 final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
1193 | FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
1194 mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
1195 | (baseIntent.getFlags() & flagsOfInterest);
1196 mIntent.setFlags(mLaunchFlags);
1197 mInTask.setIntent(mStartActivity);
1198 mAddingToTask = true;
1199
1200 // If the task is not empty and the caller is asking to start it as the root of
1201 // a new task, then we don't actually want to start this on the task. We will
1202 // bring the task to the front, and possibly give it a new intent.
1203 } else if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
1204 mAddingToTask = false;
1205
1206 } else {
1207 mAddingToTask = true;
1208 }
1209
1210 mReuseTask = mInTask;
1211 } else {
1212 mInTask = null;
1213 // Launch ResolverActivity in the source task, so that it stays in the task bounds
1214 // when in freeform workspace.
1215 // Also put noDisplay activities in the source task. These by itself can be placed
1216 // in any task/stack, however it could launch other activities like ResolverActivity,
1217 // and we want those to stay in the original task.
1218 if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
1219 && mSourceRecord.isFreeform()) {
1220 mAddingToTask = true;
1221 }
1222 }
1223
1224 if (mInTask == null) {
1225 if (mSourceRecord == null) {
1226 // This activity is not being started from another... in this
1227 // case we -always- start a new task.
1228 if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
1229 Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
1230 "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
1231 mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
1232 }
1233 } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
1234 // The original activity who is starting us is running as a single
1235 // instance... this new activity it is starting must go on its
1236 // own task.
1237 mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
1238 } else if (mLaunchSingleInstance || mLaunchSingleTask) {
1239 // The activity being started is a single instance... it always
1240 // gets launched into its own task.
1241 mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
1242 }
1243 }
1244 }
1245
1246 private void computeSourceStack() {
1247 if (mSourceRecord == null) {
1248 mSourceStack = null;
1249 return;
1250 }
1251 if (!mSourceRecord.finishing) {
1252 mSourceStack = mSourceRecord.task.stack;
1253 return;
1254 }
1255
1256 // If the source is finishing, we can't further count it as our source. This is because the
1257 // task it is associated with may now be empty and on its way out, so we don't want to
1258 // blindly throw it in to that task. Instead we will take the NEW_TASK flow and try to find
1259 // a task for it. But save the task information so it can be used when creating the new task.
1260 if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
1261 Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
1262 + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
1263 mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
1264 mNewTaskInfo = mSourceRecord.info;
1265 mNewTaskIntent = mSourceRecord.task.intent;
1266 }
1267 mSourceRecord = null;
1268 mSourceStack = null;
1269 }
1270
1271 /**
1272 * Decide whether the new activity should be inserted into an existing task. Returns null
1273 * if not or an ActivityRecord with the task into which the new activity should be added.
1274 */
1275 private ActivityRecord getReusableIntentActivity() {
1276 // We may want to try to place the new activity in to an existing task. We always
1277 // do this if the target activity is singleTask or singleInstance; we will also do
1278 // this if NEW_TASK has been requested, and there is not an additional qualifier telling
1279 // us to still place it in a new task: multi task, always doc mode, or being asked to
1280 // launch this as a new task behind the current one.
1281 boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
1282 (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
1283 || mLaunchSingleInstance || mLaunchSingleTask;
1284 // If bring to front is requested, and no result is requested and we have not been given
1285 // an explicit task to launch in to, and we can find a task that was started with this
1286 // same component, then instead of launching bring that one to the front.
1287 putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
1288 ActivityRecord intentActivity = null;
1289 if (putIntoExistingTask) {
1290 // See if there is a task to bring to the front. If this is a SINGLE_INSTANCE
1291 // activity, there can be one and only one instance of it in the history, and it is
1292 // always in its own unique task, so we do a special search.
1293 intentActivity = mLaunchSingleInstance ? mSupervisor.findActivityLocked(mIntent, mStartActivity.info)
1294 : mSupervisor.findTaskLocked(mStartActivity);
1295 }
1296 return intentActivity;
1297 }
1298
1299 private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
1300 mTargetStack = intentActivity.task.stack;
1301 mTargetStack.mLastPausedActivity = null;
1302 // If the target task is not in the front, then we need to bring it to the front...
1303 // except... well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
1304 // the same behavior as if a new instance was being started, which means not bringing it
1305 // to the front if the caller is not itself in the front.
1306 final ActivityStack focusStack = mSupervisor.getFocusedStack();
1307 ActivityRecord curTop = (focusStack == null)
1308 ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
1309
1310 if (curTop != null && (curTop.task != intentActivity.task ||
1311 curTop.task != focusStack.topTask())) {
1312 mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
1313 if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
1314 mSourceStack.topActivity().task == mSourceRecord.task)) {
1315 // We really do want to push this one into the user's face, right now.
1316 if (mLaunchTaskBehind && mSourceRecord != null) {
1317 intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
1318 }
1319 mMovedHome = true;
1320 final ActivityStack launchStack =
1321 getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
1322 mOptions, true);
1323 if (launchStack == null || launchStack == mTargetStack) {
1324 // We only want to move to the front, if we aren't going to launch on a
1325 // different stack. If we launch on a different stack, we will put the
1326 // task on top there.
1327 mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation,
1328 mOptions, mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
1329 mMovedToFront = true;
1330 }
Wale Ogunwale673cbd22016-01-30 18:30:55 -08001331 updateTaskReturnToType(intentActivity.task, mLaunchFlags, focusStack);
Wale Ogunwale01d66562015-12-29 08:19:19 -08001332 mOptions = null;
1333 }
1334 }
1335 if (!mMovedToFront && mDoResume) {
1336 if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + mTargetStack
1337 + " from " + intentActivity);
1338 mTargetStack.moveToFront("intentActivityFound");
1339 }
1340
1341 // If the caller has requested that the target task be reset, then do so.
1342 if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
1343 return mTargetStack.resetTaskIfNeededLocked(intentActivity, mStartActivity);
1344 }
1345 return intentActivity;
1346 }
1347
Wale Ogunwale673cbd22016-01-30 18:30:55 -08001348 private void updateTaskReturnToType(
1349 TaskRecord task, int launchFlags, ActivityStack focusedStack) {
1350 if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
1351 == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
1352 // Caller wants to appear on home activity.
1353 task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
1354 return;
1355 } else if (focusedStack == null || focusedStack.mStackId == HOME_STACK_ID) {
1356 // Task will be launched over the home stack, so return home.
1357 task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
1358 return;
1359 }
1360
1361 // Else we are coming from an application stack so return to an application.
1362 task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
1363 }
1364
Wale Ogunwale01d66562015-12-29 08:19:19 -08001365 private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
1366 if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
1367 == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
1368 // The caller has requested to completely replace any existing task with its new
1369 // activity. Well that should not be too hard...
1370 mReuseTask = intentActivity.task;
1371 mReuseTask.performClearTaskLocked();
1372 mReuseTask.setIntent(mStartActivity);
1373 } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
1374 || mLaunchSingleInstance || mLaunchSingleTask) {
Wale Ogunwale01d66562015-12-29 08:19:19 -08001375 ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
1376 mLaunchFlags);
Filip Gruszczynskie826f322016-01-11 17:15:22 -08001377 if (top == null) {
Wale Ogunwale01d66562015-12-29 08:19:19 -08001378 // A special case: we need to start the activity because it is not currently
1379 // running, and the caller has asked to clear the current task to have this
1380 // activity at the top.
1381 mAddingToTask = true;
1382 // Now pretend like this activity is being started by the top of its task, so it
1383 // is put in the right place.
1384 mSourceRecord = intentActivity;
1385 final TaskRecord task = mSourceRecord.task;
1386 if (task != null && task.stack == null) {
1387 // Target stack got cleared when we all activities were removed above.
1388 // Go ahead and reset it.
1389 mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
1390 null /* bounds */, mLaunchFlags, mOptions);
1391 mTargetStack.addTask(task,
1392 !mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
1393 }
1394 }
1395 } else if (mStartActivity.realActivity.equals(intentActivity.task.realActivity)) {
1396 // In this case the top activity on the task is the same as the one being launched,
1397 // so we take that as a request to bring the task to the foreground. If the top
1398 // activity in the task is the root activity, deliver this new intent to it if it
1399 // desires.
1400 if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
1401 && intentActivity.realActivity.equals(mStartActivity.realActivity)) {
Filip Gruszczynskie826f322016-01-11 17:15:22 -08001402 ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity,
Wale Ogunwale01d66562015-12-29 08:19:19 -08001403 intentActivity.task);
1404 if (intentActivity.frontOfTask) {
1405 intentActivity.task.setIntent(mStartActivity);
1406 }
1407 intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
1408 mStartActivity.launchedFromPackage);
Robert Carr8f640752016-02-16 14:12:00 -08001409 } else if (!mStartActivity.intent.filterEquals(intentActivity.intent)) {
Wale Ogunwale01d66562015-12-29 08:19:19 -08001410 // In this case we are launching the root activity of the task, but with a
1411 // different intent. We should start a new instance on top.
1412 mAddingToTask = true;
1413 mSourceRecord = intentActivity;
1414 }
1415 } else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
1416 // In this case an activity is being launched in to an existing task, without
1417 // resetting that task. This is typically the situation of launching an activity
1418 // from a notification or shortcut. We want to place the new activity on top of the
1419 // current task.
1420 mAddingToTask = true;
1421 mSourceRecord = intentActivity;
1422 } else if (!intentActivity.task.rootWasReset) {
1423 // In this case we are launching into an existing task that has not yet been started
1424 // from its front door. The current task has been brought to the front. Ideally,
1425 // we'd probably like to place this new task at the bottom of its stack, but that's
1426 // a little hard to do with the current organization of the code so for now we'll
1427 // just drop it.
1428 intentActivity.task.setIntent(mStartActivity);
1429 }
1430 }
1431
1432 private void resumeTargetStackIfNeeded() {
1433 if (mDoResume) {
1434 mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, null, mOptions);
1435 if (!mMovedToFront) {
1436 // Make sure to notify Keyguard as well if we are not running an app transition
1437 // later.
1438 mSupervisor.notifyActivityDrawnForKeyguard();
1439 }
1440 } else {
1441 ActivityOptions.abort(mOptions);
1442 }
1443 mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
1444 }
1445
1446 private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
1447 mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags,
1448 mOptions);
1449 if (mDoResume) {
1450 mTargetStack.moveToFront("startingNewTask");
1451 }
1452
1453 if (mReuseTask == null) {
Suprabh Shukla09a88f52015-12-02 14:36:31 -08001454 final TaskRecord task = mTargetStack.createTaskRecord(
1455 mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
Wale Ogunwale01d66562015-12-29 08:19:19 -08001456 mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
1457 mNewTaskIntent != null ? mNewTaskIntent : mIntent,
1458 mVoiceSession, mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
1459 mStartActivity.setTask(task, taskToAffiliate);
1460 if (mLaunchBounds != null) {
Wale Ogunwalecacfaa22016-01-15 11:26:08 -08001461 final int stackId = mTargetStack.mStackId;
1462 if (StackId.resizeStackWithLaunchBounds(stackId)) {
Filip Gruszczynski47dae582016-02-02 11:52:13 -08001463 mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE);
Wale Ogunwalecacfaa22016-01-15 11:26:08 -08001464 } else {
1465 mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
1466 }
Wale Ogunwale01d66562015-12-29 08:19:19 -08001467 }
1468 if (DEBUG_TASKS) Slog.v(TAG_TASKS,
1469 "Starting new activity " +
1470 mStartActivity + " in new task " + mStartActivity.task);
1471 } else {
1472 mStartActivity.setTask(mReuseTask, taskToAffiliate);
1473 }
1474 }
1475
1476 private int setTaskFromSourceRecord() {
1477 final TaskRecord sourceTask = mSourceRecord.task;
1478 // We only want to allow changing stack if the target task is not the top one,
1479 // otherwise we would move the launching task to the other side, rather than show
1480 // two side by side.
1481 final boolean launchToSideAllowed = sourceTask.stack.topTask() != sourceTask;
1482 mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task, mOptions, launchToSideAllowed);
1483
1484 if (mTargetStack == null) {
1485 mTargetStack = sourceTask.stack;
1486 } else if (mTargetStack != sourceTask.stack) {
1487 mSupervisor.moveTaskToStackLocked(sourceTask.taskId, mTargetStack.mStackId,
1488 ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
1489 }
1490 if (mDoResume) {
1491 mTargetStack.moveToFront("sourceStackToFront");
1492 }
1493 final TaskRecord topTask = mTargetStack.topTask();
1494 if (topTask != sourceTask) {
1495 mTargetStack.moveTaskToFrontLocked(sourceTask, mNoAnimation, mOptions,
1496 mStartActivity.appTimeTracker, "sourceTaskToFront");
1497 }
1498 if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0) {
1499 // In this case, we are adding the activity to an existing task, but the caller has
1500 // asked to clear that task if the activity is already running.
1501 ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags);
1502 mKeepCurTransition = true;
1503 if (top != null) {
Filip Gruszczynskie826f322016-01-11 17:15:22 -08001504 ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
Wale Ogunwale01d66562015-12-29 08:19:19 -08001505 top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
1506 // For paranoia, make sure we have correctly resumed the top activity.
1507 mTargetStack.mLastPausedActivity = null;
1508 if (mDoResume) {
1509 mSupervisor.resumeFocusedStackTopActivityLocked();
1510 }
1511 ActivityOptions.abort(mOptions);
1512 return START_DELIVERED_TO_TOP;
1513 }
1514 } else if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
1515 // In this case, we are launching an activity in our own task that may already be
1516 // running somewhere in the history, and we want to shuffle it to the front of the
1517 // stack if so.
1518 final ActivityRecord top = sourceTask.findActivityInHistoryLocked(mStartActivity);
1519 if (top != null) {
1520 final TaskRecord task = top.task;
1521 task.moveActivityToFrontLocked(top);
1522 top.updateOptionsLocked(mOptions);
Filip Gruszczynskie826f322016-01-11 17:15:22 -08001523 ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, task);
Wale Ogunwale01d66562015-12-29 08:19:19 -08001524 top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
1525 mTargetStack.mLastPausedActivity = null;
1526 if (mDoResume) {
1527 mSupervisor.resumeFocusedStackTopActivityLocked();
1528 }
1529 return START_DELIVERED_TO_TOP;
1530 }
1531 }
1532
1533 // An existing activity is starting this new activity, so we want to keep the new one in
1534 // the same task as the one that is starting it.
1535 mStartActivity.setTask(sourceTask, null);
1536 if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
1537 + " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
1538 return START_SUCCESS;
1539 }
1540
1541 private int setTaskFromInTask() {
1542 if (mLaunchBounds != null) {
1543 mInTask.updateOverrideConfiguration(mLaunchBounds);
1544 int stackId = mInTask.getLaunchStackId();
1545 if (stackId != mInTask.stack.mStackId) {
Wale Ogunwale513346d2016-01-27 10:55:01 -08001546 final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(
Wale Ogunwale01d66562015-12-29 08:19:19 -08001547 mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
Wale Ogunwale513346d2016-01-27 10:55:01 -08001548 stackId = stack.mStackId;
Wale Ogunwale01d66562015-12-29 08:19:19 -08001549 }
Wale Ogunwalecacfaa22016-01-15 11:26:08 -08001550 if (StackId.resizeStackWithLaunchBounds(stackId)) {
Filip Gruszczynski47dae582016-02-02 11:52:13 -08001551 mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE);
Wale Ogunwalecacfaa22016-01-15 11:26:08 -08001552 }
Wale Ogunwale01d66562015-12-29 08:19:19 -08001553 }
1554 mTargetStack = mInTask.stack;
1555 mTargetStack.moveTaskToFrontLocked(
1556 mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront");
1557
1558 // Check whether we should actually launch the new activity in to the task,
1559 // or just reuse the current activity on top.
1560 ActivityRecord top = mInTask.getTopActivity();
1561 if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) {
1562 if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
1563 || mLaunchSingleTop || mLaunchSingleTask) {
Filip Gruszczynskie826f322016-01-11 17:15:22 -08001564 ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
Wale Ogunwale01d66562015-12-29 08:19:19 -08001565 if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
1566 // We don't need to start a new activity, and the client said not to do
1567 // anything if that is the case, so this is it!
1568 return START_RETURN_INTENT_TO_CALLER;
1569 }
1570 top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
1571 return START_DELIVERED_TO_TOP;
1572 }
1573 }
1574
1575 if (!mAddingToTask) {
1576 // We don't actually want to have this activity added to the task, so just
1577 // stop here but still tell the caller that we consumed the intent.
1578 ActivityOptions.abort(mOptions);
1579 return START_TASK_TO_FRONT;
1580 }
1581
1582 mStartActivity.setTask(mInTask, null);
1583 if (DEBUG_TASKS) Slog.v(TAG_TASKS,
1584 "Starting new activity " + mStartActivity + " in explicit task " + mStartActivity.task);
1585
1586 return START_SUCCESS;
1587 }
1588
1589 private void setTaskToCurrentTopOrCreateNewTask() {
1590 mTargetStack = computeStackFocus(mStartActivity, false, null /* bounds */, mLaunchFlags,
1591 mOptions);
1592 if (mDoResume) {
1593 mTargetStack.moveToFront("addingToTopTask");
1594 }
1595 final ActivityRecord prev = mTargetStack.topActivity();
Suprabh Shukla09a88f52015-12-02 14:36:31 -08001596 final TaskRecord task = (prev != null) ? prev.task : mTargetStack.createTaskRecord(
1597 mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
1598 mStartActivity.info, mIntent, null, null, true);
Wale Ogunwale01d66562015-12-29 08:19:19 -08001599 mStartActivity.setTask(task, null);
1600 mWindowManager.moveTaskToTop(mStartActivity.task.taskId);
1601 if (DEBUG_TASKS) Slog.v(TAG_TASKS,
1602 "Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.task);
1603 }
1604
1605 private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
1606 boolean launchSingleTask, int launchFlags) {
1607 if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
1608 (launchSingleInstance || launchSingleTask)) {
1609 // We have a conflict between the Intent and the Activity manifest, manifest wins.
1610 Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
1611 "\"singleInstance\" or \"singleTask\"");
1612 launchFlags &=
1613 ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
1614 } else {
1615 switch (r.info.documentLaunchMode) {
1616 case ActivityInfo.DOCUMENT_LAUNCH_NONE:
1617 break;
1618 case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
1619 launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
1620 break;
1621 case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
1622 launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
1623 break;
1624 case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
1625 launchFlags &= ~FLAG_ACTIVITY_MULTIPLE_TASK;
1626 break;
1627 }
1628 }
1629 return launchFlags;
Filip Gruszczynski07a0e492015-12-17 14:16:38 -08001630 }
1631
1632 final void doPendingActivityLaunchesLocked(boolean doResume) {
1633 while (!mPendingActivityLaunches.isEmpty()) {
Wale Ogunwalecc25a8a2016-01-23 14:31:37 -08001634 final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
1635 final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
Filip Gruszczynski07a0e492015-12-17 14:16:38 -08001636 try {
Wale Ogunwalecc25a8a2016-01-23 14:31:37 -08001637 final int result = startActivityUnchecked(
1638 pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null, null);
1639 postStartActivityUncheckedProcessing(
1640 pal.r, result, mSupervisor.mFocusedStack.mStackId);
Filip Gruszczynski07a0e492015-12-17 14:16:38 -08001641 } catch (Exception e) {
1642 Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
1643 pal.sendErrorResult(e.getMessage());
1644 }
1645 }
1646 }
1647
1648 private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds,
Wale Ogunwale854809c2015-12-27 16:18:19 -08001649 int launchFlags, ActivityOptions aOptions) {
Filip Gruszczynski07a0e492015-12-17 14:16:38 -08001650 final TaskRecord task = r.task;
1651 if (!(r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
1652 return mSupervisor.mHomeStack;
1653 }
1654
Wale Ogunwale854809c2015-12-27 16:18:19 -08001655 ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions, true);
Filip Gruszczynski07a0e492015-12-17 14:16:38 -08001656 if (stack != null) {
1657 return stack;
1658 }
1659
1660 if (task != null && task.stack != null) {
1661 stack = task.stack;
1662 if (stack.isOnHomeDisplay()) {
1663 if (mSupervisor.mFocusedStack != stack) {
1664 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
1665 "computeStackFocus: Setting " + "focused stack to r=" + r
1666 + " task=" + task);
1667 } else {
1668 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
1669 "computeStackFocus: Focused stack already="
1670 + mSupervisor.mFocusedStack);
1671 }
1672 }
1673 return stack;
1674 }
1675
1676 final ActivityStackSupervisor.ActivityContainer container = r.mInitialActivityContainer;
1677 if (container != null) {
1678 // The first time put it on the desired stack, after this put on task stack.
1679 r.mInitialActivityContainer = null;
1680 return container.mStack;
1681 }
1682
1683 // The fullscreen stack can contain any task regardless of if the task is resizeable
1684 // or not. So, we let the task go in the fullscreen task if it is the focus stack.
1685 // If the freeform or docked stack has focus, and the activity to be launched is resizeable,
1686 // we can also put it in the focused stack.
1687 final int focusedStackId = mSupervisor.mFocusedStack.mStackId;
Wale Ogunwale513346d2016-01-27 10:55:01 -08001688 final boolean canUseFocusedStack = focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
1689 || (focusedStackId == DOCKED_STACK_ID && r.canGoInDockedStack())
1690 || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeableOrForced());
Filip Gruszczynski07a0e492015-12-17 14:16:38 -08001691 if (canUseFocusedStack && (!newTask
1692 || mSupervisor.mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
1693 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
1694 "computeStackFocus: Have a focused stack=" + mSupervisor.mFocusedStack);
1695 return mSupervisor.mFocusedStack;
1696 }
1697
1698 // We first try to put the task in the first dynamic stack.
1699 final ArrayList<ActivityStack> homeDisplayStacks = mSupervisor.mHomeStack.mStacks;
1700 for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
1701 stack = homeDisplayStacks.get(stackNdx);
1702 if (!ActivityManager.StackId.isStaticStack(stack.mStackId)) {
1703 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
1704 "computeStackFocus: Setting focused stack=" + stack);
1705 return stack;
1706 }
1707 }
1708
1709 // If there is no suitable dynamic stack then we figure out which static stack to use.
1710 final int stackId = task != null ? task.getLaunchStackId() :
1711 bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
1712 FULLSCREEN_WORKSPACE_STACK_ID;
1713 stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
1714 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
1715 + r + " stackId=" + stack.mStackId);
1716 return stack;
1717 }
1718
Wale Ogunwale854809c2015-12-27 16:18:19 -08001719 private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
1720 ActivityOptions aOptions, boolean launchToSideAllowed) {
1721 final int launchStackId =
1722 (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID;
1723
1724 if (isValidLaunchStackId(launchStackId, r)) {
1725 return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP);
Wale Ogunwale513346d2016-01-27 10:55:01 -08001726 } else if (launchStackId == DOCKED_STACK_ID) {
1727 // The preferred launch stack is the docked stack, but it isn't a valid launch stack
1728 // for this activity, so we put the activity in the fullscreen stack.
1729 return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
Wale Ogunwale854809c2015-12-27 16:18:19 -08001730 }
1731
Wale Ogunwale2a25a622016-01-30 11:27:21 -08001732 if (!launchToSideAllowed || (launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) {
Filip Gruszczynski07a0e492015-12-17 14:16:38 -08001733 return null;
1734 }
Wale Ogunwale854809c2015-12-27 16:18:19 -08001735
Filip Gruszczynski07a0e492015-12-17 14:16:38 -08001736 // The parent activity doesn't want to launch the activity on top of itself, but
1737 // instead tries to put it onto other side in side-by-side mode.
1738 final ActivityStack parentStack = task != null ? task.stack
1739 : r.mInitialActivityContainer != null ? r.mInitialActivityContainer.mStack
1740 : mSupervisor.mFocusedStack;
1741 if (parentStack != null && parentStack.mStackId == DOCKED_STACK_ID) {
1742 // If parent was in docked stack, the natural place to launch another activity
1743 // will be fullscreen, so it can appear alongside the docked window.
1744 return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
1745 } else {
1746 // If the parent is not in the docked stack, we check if there is docked window
1747 // and if yes, we will launch into that stack. If not, we just put the new
1748 // activity into parent's stack, because we can't find a better place.
1749 final ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
Filip Gruszczynski0e381e22016-01-14 16:31:33 -08001750 if (stack != null && stack.getStackVisibilityLocked() == STACK_INVISIBLE) {
Filip Gruszczynski07a0e492015-12-17 14:16:38 -08001751 // There is a docked stack, but it isn't visible, so we can't launch into that.
1752 return null;
1753 } else {
1754 return stack;
1755 }
1756 }
1757 }
1758
Wale Ogunwale854809c2015-12-27 16:18:19 -08001759 private boolean isValidLaunchStackId(int stackId, ActivityRecord r) {
1760 if (stackId == INVALID_STACK_ID || stackId == HOME_STACK_ID
1761 || !StackId.isStaticStack(stackId)) {
1762 return false;
1763 }
1764
Wale Ogunwale513346d2016-01-27 10:55:01 -08001765 if (stackId == DOCKED_STACK_ID && r.canGoInDockedStack()) {
1766 return true;
1767 }
Wale Ogunwale854809c2015-12-27 16:18:19 -08001768
Wale Ogunwale513346d2016-01-27 10:55:01 -08001769 if (stackId != FULLSCREEN_WORKSPACE_STACK_ID && !r.isResizeableOrForced()) {
Wale Ogunwale854809c2015-12-27 16:18:19 -08001770 return false;
1771 }
1772
1773 if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
1774 return false;
1775 }
1776
1777 final boolean supportsPip = mService.mSupportsPictureInPicture
1778 && (r.supportsPictureInPicture() || mService.mForceResizableActivities);
1779 if (stackId == PINNED_STACK_ID && !supportsPip) {
1780 return false;
1781 }
1782 return true;
1783 }
1784
Wale Ogunwale854809c2015-12-27 16:18:19 -08001785 Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
1786 Rect newBounds = null;
Wale Ogunwaleb1faf602016-01-27 09:12:31 -08001787 if (options != null && (r.isResizeable() || (inTask != null && inTask.isResizeable()))) {
Wale Ogunwale854809c2015-12-27 16:18:19 -08001788 if (mSupervisor.canUseActivityOptionsLaunchBounds(
1789 options, options.getLaunchStackId())) {
Filip Gruszczynskidce2d162016-01-12 15:40:13 -08001790 newBounds = TaskRecord.validateBounds(options.getLaunchBounds());
Wale Ogunwale854809c2015-12-27 16:18:19 -08001791 }
1792 }
1793 return newBounds;
1794 }
1795
Filip Gruszczynski07a0e492015-12-17 14:16:38 -08001796 void setWindowManager(WindowManagerService wm) {
1797 mWindowManager = wm;
1798 }
1799
1800 void removePendingActivityLaunchesLocked(ActivityStack stack) {
1801 for (int palNdx = mPendingActivityLaunches.size() - 1; palNdx >= 0; --palNdx) {
1802 PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
1803 if (pal.stack == stack) {
1804 mPendingActivityLaunches.remove(palNdx);
1805 }
1806 }
1807 }
1808}