blob: 28c3baeb7b6350c4119b6f913aa5f7cc7439d8cd [file] [log] [blame]
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001/*
2 * Copyright (C) 2010 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 com.android.internal.app.HeavyWeightSwitcherActivity;
20import com.android.internal.os.BatteryStatsImpl;
21import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
22
23import android.app.Activity;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -070024import android.app.ActivityManager;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070025import android.app.AppGlobals;
26import android.app.IActivityManager;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -070027import android.app.IThumbnailRetriever;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070028import static android.app.IActivityManager.START_CLASS_NOT_FOUND;
29import static android.app.IActivityManager.START_DELIVERED_TO_TOP;
30import static android.app.IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
31import static android.app.IActivityManager.START_INTENT_NOT_RESOLVED;
32import static android.app.IActivityManager.START_PERMISSION_DENIED;
33import static android.app.IActivityManager.START_RETURN_INTENT_TO_CALLER;
34import static android.app.IActivityManager.START_SUCCESS;
35import static android.app.IActivityManager.START_SWITCHES_CANCELED;
36import static android.app.IActivityManager.START_TASK_TO_FRONT;
37import android.app.IApplicationThread;
38import android.app.PendingIntent;
39import android.app.ResultInfo;
40import android.app.IActivityManager.WaitResult;
41import android.content.ComponentName;
42import android.content.Context;
43import android.content.IIntentSender;
44import android.content.Intent;
45import android.content.IntentSender;
46import android.content.pm.ActivityInfo;
47import android.content.pm.ApplicationInfo;
48import android.content.pm.PackageManager;
49import android.content.pm.ResolveInfo;
50import android.content.res.Configuration;
Dianne Hackborn0aae2d42010-12-07 23:51:29 -080051import android.content.res.Resources;
52import android.graphics.Bitmap;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070053import android.net.Uri;
54import android.os.Binder;
Dianne Hackbornce86ba82011-07-13 19:33:41 -070055import android.os.Bundle;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070056import android.os.Handler;
57import android.os.IBinder;
58import android.os.Message;
Dianne Hackborn62f20ec2011-08-15 17:40:28 -070059import android.os.ParcelFileDescriptor;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070060import android.os.PowerManager;
61import android.os.RemoteException;
62import android.os.SystemClock;
63import android.util.EventLog;
64import android.util.Log;
65import android.util.Slog;
66import android.view.WindowManagerPolicy;
67
Dianne Hackborn62f20ec2011-08-15 17:40:28 -070068import java.io.IOException;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070069import java.lang.ref.WeakReference;
70import java.util.ArrayList;
71import java.util.Iterator;
72import java.util.List;
73
74/**
75 * State and management of a single stack of activities.
76 */
Dianne Hackborn0c5001d2011-04-12 18:16:08 -070077final class ActivityStack {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070078 static final String TAG = ActivityManagerService.TAG;
Dianne Hackbornb961cd22011-06-21 12:13:37 -070079 static final boolean localLOGV = ActivityManagerService.localLOGV;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070080 static final boolean DEBUG_SWITCH = ActivityManagerService.DEBUG_SWITCH;
81 static final boolean DEBUG_PAUSE = ActivityManagerService.DEBUG_PAUSE;
82 static final boolean DEBUG_VISBILITY = ActivityManagerService.DEBUG_VISBILITY;
83 static final boolean DEBUG_USER_LEAVING = ActivityManagerService.DEBUG_USER_LEAVING;
84 static final boolean DEBUG_TRANSITION = ActivityManagerService.DEBUG_TRANSITION;
85 static final boolean DEBUG_RESULTS = ActivityManagerService.DEBUG_RESULTS;
86 static final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
87 static final boolean DEBUG_TASKS = ActivityManagerService.DEBUG_TASKS;
88
Dianne Hackbornce86ba82011-07-13 19:33:41 -070089 static final boolean DEBUG_STATES = false;
Dianne Hackborn98cfebc2011-10-18 13:17:33 -070090 static final boolean DEBUG_ADD_REMOVE = false;
91 static final boolean DEBUG_SAVED_STATE = false;
Dianne Hackbornce86ba82011-07-13 19:33:41 -070092
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070093 static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
94
95 // How long we wait until giving up on the last activity telling us it
96 // is idle.
97 static final int IDLE_TIMEOUT = 10*1000;
98
99 // How long we wait until giving up on the last activity to pause. This
100 // is short because it directly impacts the responsiveness of starting the
101 // next activity.
102 static final int PAUSE_TIMEOUT = 500;
103
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800104 // How long we can hold the sleep wake lock before giving up.
105 static final int SLEEP_TIMEOUT = 5*1000;
106
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700107 // How long we can hold the launch wake lock before giving up.
108 static final int LAUNCH_TIMEOUT = 10*1000;
109
110 // How long we wait until giving up on an activity telling us it has
111 // finished destroying itself.
112 static final int DESTROY_TIMEOUT = 10*1000;
113
114 // How long until we reset a task when the user returns to it. Currently
Dianne Hackborn621e17d2010-11-22 15:59:56 -0800115 // disabled.
116 static final long ACTIVITY_INACTIVE_RESET_TIME = 0;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700117
Dianne Hackborn0dad3642010-09-09 21:25:35 -0700118 // How long between activity launches that we consider safe to not warn
119 // the user about an unexpected activity being launched on top.
120 static final long START_WARN_TIME = 5*1000;
121
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700122 // Set to false to disable the preview that is shown while a new activity
123 // is being started.
124 static final boolean SHOW_APP_STARTING_PREVIEW = true;
125
126 enum ActivityState {
127 INITIALIZING,
128 RESUMED,
129 PAUSING,
130 PAUSED,
131 STOPPING,
132 STOPPED,
133 FINISHING,
134 DESTROYING,
135 DESTROYED
136 }
137
138 final ActivityManagerService mService;
139 final boolean mMainStack;
140
141 final Context mContext;
142
143 /**
144 * The back history of all previous (and possibly still
145 * running) activities. It contains HistoryRecord objects.
146 */
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700147 final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700148
149 /**
150 * List of running activities, sorted by recent usage.
151 * The first entry in the list is the least recently used.
152 * It contains HistoryRecord objects.
153 */
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700154 final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<ActivityRecord>();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700155
156 /**
157 * List of activities that are waiting for a new activity
158 * to become visible before completing whatever operation they are
159 * supposed to do.
160 */
161 final ArrayList<ActivityRecord> mWaitingVisibleActivities
162 = new ArrayList<ActivityRecord>();
163
164 /**
165 * List of activities that are ready to be stopped, but waiting
166 * for the next activity to settle down before doing so. It contains
167 * HistoryRecord objects.
168 */
169 final ArrayList<ActivityRecord> mStoppingActivities
170 = new ArrayList<ActivityRecord>();
171
172 /**
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800173 * List of activities that are in the process of going to sleep.
174 */
175 final ArrayList<ActivityRecord> mGoingToSleepActivities
176 = new ArrayList<ActivityRecord>();
177
178 /**
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700179 * Animations that for the current transition have requested not to
180 * be considered for the transition animation.
181 */
182 final ArrayList<ActivityRecord> mNoAnimActivities
183 = new ArrayList<ActivityRecord>();
184
185 /**
186 * List of activities that are ready to be finished, but waiting
187 * for the previous activity to settle down before doing so. It contains
188 * HistoryRecord objects.
189 */
190 final ArrayList<ActivityRecord> mFinishingActivities
191 = new ArrayList<ActivityRecord>();
192
193 /**
194 * List of people waiting to find out about the next launched activity.
195 */
196 final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched
197 = new ArrayList<IActivityManager.WaitResult>();
198
199 /**
200 * List of people waiting to find out about the next visible activity.
201 */
202 final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible
203 = new ArrayList<IActivityManager.WaitResult>();
204
205 /**
206 * Set when the system is going to sleep, until we have
207 * successfully paused the current activity and released our wake lock.
208 * At that point the system is allowed to actually sleep.
209 */
210 final PowerManager.WakeLock mGoingToSleep;
211
212 /**
213 * We don't want to allow the device to go to sleep while in the process
214 * of launching an activity. This is primarily to allow alarm intent
215 * receivers to launch an activity and get that to run before the device
216 * goes back to sleep.
217 */
218 final PowerManager.WakeLock mLaunchingActivity;
219
220 /**
221 * When we are in the process of pausing an activity, before starting the
222 * next one, this variable holds the activity that is currently being paused.
223 */
224 ActivityRecord mPausingActivity = null;
225
226 /**
227 * This is the last activity that we put into the paused state. This is
228 * used to determine if we need to do an activity transition while sleeping,
229 * when we normally hold the top activity paused.
230 */
231 ActivityRecord mLastPausedActivity = null;
232
233 /**
234 * Current activity that is resumed, or null if there is none.
235 */
236 ActivityRecord mResumedActivity = null;
237
238 /**
Dianne Hackborn0dad3642010-09-09 21:25:35 -0700239 * This is the last activity that has been started. It is only used to
240 * identify when multiple activities are started at once so that the user
241 * can be warned they may not be in the activity they think they are.
242 */
243 ActivityRecord mLastStartedActivity = null;
244
245 /**
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700246 * Set when we know we are going to be calling updateConfiguration()
247 * soon, so want to skip intermediate config checks.
248 */
249 boolean mConfigWillChange;
250
251 /**
252 * Set to indicate whether to issue an onUserLeaving callback when a
253 * newly launched activity is being brought in front of us.
254 */
255 boolean mUserLeaving = false;
256
257 long mInitialStartTime = 0;
258
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800259 /**
260 * Set when we have taken too long waiting to go to sleep.
261 */
262 boolean mSleepTimeout = false;
263
Dianne Hackborn90c52de2011-09-23 12:57:44 -0700264 /**
265 * Dismiss the keyguard after the next activity is displayed?
266 */
267 boolean mDismissKeyguardOnNextActivity = false;
268
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800269 int mThumbnailWidth = -1;
270 int mThumbnailHeight = -1;
271
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800272 static final int SLEEP_TIMEOUT_MSG = 8;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700273 static final int PAUSE_TIMEOUT_MSG = 9;
274 static final int IDLE_TIMEOUT_MSG = 10;
275 static final int IDLE_NOW_MSG = 11;
276 static final int LAUNCH_TIMEOUT_MSG = 16;
277 static final int DESTROY_TIMEOUT_MSG = 17;
278 static final int RESUME_TOP_ACTIVITY_MSG = 19;
279
280 final Handler mHandler = new Handler() {
281 //public Handler() {
282 // if (localLOGV) Slog.v(TAG, "Handler started!");
283 //}
284
285 public void handleMessage(Message msg) {
286 switch (msg.what) {
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800287 case SLEEP_TIMEOUT_MSG: {
Dianne Hackborn8e8d65f2011-08-11 19:36:18 -0700288 synchronized (mService) {
289 if (mService.isSleeping()) {
290 Slog.w(TAG, "Sleep timeout! Sleeping now.");
291 mSleepTimeout = true;
292 checkReadyForSleepLocked();
293 }
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800294 }
295 } break;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700296 case PAUSE_TIMEOUT_MSG: {
297 IBinder token = (IBinder)msg.obj;
298 // We don't at this point know if the activity is fullscreen,
299 // so we need to be conservative and assume it isn't.
300 Slog.w(TAG, "Activity pause timeout for " + token);
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800301 activityPaused(token, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700302 } break;
303 case IDLE_TIMEOUT_MSG: {
304 if (mService.mDidDexOpt) {
305 mService.mDidDexOpt = false;
306 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
307 nmsg.obj = msg.obj;
308 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
309 return;
310 }
311 // We don't at this point know if the activity is fullscreen,
312 // so we need to be conservative and assume it isn't.
313 IBinder token = (IBinder)msg.obj;
314 Slog.w(TAG, "Activity idle timeout for " + token);
315 activityIdleInternal(token, true, null);
316 } break;
317 case DESTROY_TIMEOUT_MSG: {
318 IBinder token = (IBinder)msg.obj;
319 // We don't at this point know if the activity is fullscreen,
320 // so we need to be conservative and assume it isn't.
321 Slog.w(TAG, "Activity destroy timeout for " + token);
322 activityDestroyed(token);
323 } break;
324 case IDLE_NOW_MSG: {
325 IBinder token = (IBinder)msg.obj;
326 activityIdleInternal(token, false, null);
327 } break;
328 case LAUNCH_TIMEOUT_MSG: {
329 if (mService.mDidDexOpt) {
330 mService.mDidDexOpt = false;
331 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
332 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
333 return;
334 }
335 synchronized (mService) {
336 if (mLaunchingActivity.isHeld()) {
337 Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
338 mLaunchingActivity.release();
339 }
340 }
341 } break;
342 case RESUME_TOP_ACTIVITY_MSG: {
343 synchronized (mService) {
344 resumeTopActivityLocked(null);
345 }
346 } break;
347 }
348 }
349 };
350
351 ActivityStack(ActivityManagerService service, Context context, boolean mainStack) {
352 mService = service;
353 mContext = context;
354 mMainStack = mainStack;
355 PowerManager pm =
356 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
357 mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
358 mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
359 mLaunchingActivity.setReferenceCounted(false);
360 }
361
362 final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
363 int i = mHistory.size()-1;
364 while (i >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700365 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700366 if (!r.finishing && r != notTop) {
367 return r;
368 }
369 i--;
370 }
371 return null;
372 }
373
374 final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
375 int i = mHistory.size()-1;
376 while (i >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700377 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700378 if (!r.finishing && !r.delayedResume && r != notTop) {
379 return r;
380 }
381 i--;
382 }
383 return null;
384 }
385
386 /**
387 * This is a simplified version of topRunningActivityLocked that provides a number of
388 * optional skip-over modes. It is intended for use with the ActivityController hook only.
389 *
390 * @param token If non-null, any history records matching this token will be skipped.
391 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
392 *
393 * @return Returns the HistoryRecord of the next activity on the stack.
394 */
395 final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
396 int i = mHistory.size()-1;
397 while (i >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700398 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700399 // Note: the taskId check depends on real taskId fields being non-zero
400 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
401 return r;
402 }
403 i--;
404 }
405 return null;
406 }
407
408 final int indexOfTokenLocked(IBinder token) {
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700409 try {
410 ActivityRecord r = (ActivityRecord)token;
411 return mHistory.indexOf(r);
412 } catch (ClassCastException e) {
413 Slog.w(TAG, "Bad activity token: " + token, e);
414 return -1;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700415 }
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700416 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700417
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700418 final ActivityRecord isInStackLocked(IBinder token) {
419 try {
420 ActivityRecord r = (ActivityRecord)token;
421 if (mHistory.contains(r)) {
422 return r;
423 }
424 } catch (ClassCastException e) {
425 Slog.w(TAG, "Bad activity token: " + token, e);
426 }
427 return null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700428 }
429
430 private final boolean updateLRUListLocked(ActivityRecord r) {
431 final boolean hadit = mLRUActivities.remove(r);
432 mLRUActivities.add(r);
433 return hadit;
434 }
435
436 /**
437 * Returns the top activity in any existing task matching the given
438 * Intent. Returns null if no such task is found.
439 */
440 private ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) {
441 ComponentName cls = intent.getComponent();
442 if (info.targetActivity != null) {
443 cls = new ComponentName(info.packageName, info.targetActivity);
444 }
445
446 TaskRecord cp = null;
447
448 final int N = mHistory.size();
449 for (int i=(N-1); i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700450 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700451 if (!r.finishing && r.task != cp
452 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
453 cp = r.task;
454 //Slog.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
455 // + "/aff=" + r.task.affinity + " to new cls="
456 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
457 if (r.task.affinity != null) {
458 if (r.task.affinity.equals(info.taskAffinity)) {
459 //Slog.i(TAG, "Found matching affinity!");
460 return r;
461 }
462 } else if (r.task.intent != null
463 && r.task.intent.getComponent().equals(cls)) {
464 //Slog.i(TAG, "Found matching class!");
465 //dump();
466 //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
467 return r;
468 } else if (r.task.affinityIntent != null
469 && r.task.affinityIntent.getComponent().equals(cls)) {
470 //Slog.i(TAG, "Found matching class!");
471 //dump();
472 //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
473 return r;
474 }
475 }
476 }
477
478 return null;
479 }
480
481 /**
482 * Returns the first activity (starting from the top of the stack) that
483 * is the same as the given activity. Returns null if no such activity
484 * is found.
485 */
486 private ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
487 ComponentName cls = intent.getComponent();
488 if (info.targetActivity != null) {
489 cls = new ComponentName(info.packageName, info.targetActivity);
490 }
491
492 final int N = mHistory.size();
493 for (int i=(N-1); i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700494 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700495 if (!r.finishing) {
496 if (r.intent.getComponent().equals(cls)) {
497 //Slog.i(TAG, "Found matching class!");
498 //dump();
499 //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
500 return r;
501 }
502 }
503 }
504
505 return null;
506 }
507
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700508 final void showAskCompatModeDialogLocked(ActivityRecord r) {
509 Message msg = Message.obtain();
510 msg.what = ActivityManagerService.SHOW_COMPAT_MODE_DIALOG_MSG;
511 msg.obj = r.task.askedCompatMode ? null : r;
512 mService.mHandler.sendMessage(msg);
513 }
514
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700515 final boolean realStartActivityLocked(ActivityRecord r,
516 ProcessRecord app, boolean andResume, boolean checkConfig)
517 throws RemoteException {
518
519 r.startFreezingScreenLocked(app, 0);
520 mService.mWindowManager.setAppVisibility(r, true);
521
522 // Have the window manager re-evaluate the orientation of
523 // the screen based on the new activity order. Note that
524 // as a result of this, it can call back into the activity
525 // manager with a new orientation. We don't care about that,
526 // because the activity is not currently running so we are
527 // just restarting it anyway.
528 if (checkConfig) {
529 Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
530 mService.mConfiguration,
531 r.mayFreezeScreenLocked(app) ? r : null);
Dianne Hackborn31ca8542011-07-19 14:58:28 -0700532 mService.updateConfigurationLocked(config, r, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700533 }
534
535 r.app = app;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700536 app.waitingToKill = null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700537
538 if (localLOGV) Slog.v(TAG, "Launching: " + r);
539
540 int idx = app.activities.indexOf(r);
541 if (idx < 0) {
542 app.activities.add(r);
543 }
544 mService.updateLruProcessLocked(app, true, true);
545
546 try {
547 if (app.thread == null) {
548 throw new RemoteException();
549 }
550 List<ResultInfo> results = null;
551 List<Intent> newIntents = null;
552 if (andResume) {
553 results = r.results;
554 newIntents = r.newIntents;
555 }
556 if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
557 + " icicle=" + r.icicle
558 + " with results=" + results + " newIntents=" + newIntents
559 + " andResume=" + andResume);
560 if (andResume) {
561 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
562 System.identityHashCode(r),
563 r.task.taskId, r.shortComponentName);
564 }
565 if (r.isHomeActivity) {
566 mService.mHomeProcess = app;
567 }
568 mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800569 r.sleeping = false;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400570 r.forceNewConfig = false;
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700571 showAskCompatModeDialogLocked(r);
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700572 r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700573 String profileFile = null;
574 ParcelFileDescriptor profileFd = null;
575 boolean profileAutoStop = false;
576 if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) {
577 if (mService.mProfileProc == null || mService.mProfileProc == app) {
578 mService.mProfileProc = app;
579 profileFile = mService.mProfileFile;
580 profileFd = mService.mProfileFd;
581 profileAutoStop = mService.mAutoStopProfiler;
582 }
583 }
Dianne Hackbornf0754f5b2011-07-21 16:02:07 -0700584 app.hasShownUi = true;
Dianne Hackbornc68c9132011-07-29 01:25:18 -0700585 app.pendingUiClean = true;
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700586 if (profileFd != null) {
587 try {
588 profileFd = profileFd.dup();
589 } catch (IOException e) {
590 profileFd = null;
591 }
592 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700593 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackborn58f42a52011-10-10 13:46:34 -0700594 System.identityHashCode(r), r.info, mService.mConfiguration,
595 r.compat, r.icicle, results, newIntents, !andResume,
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700596 mService.isNextTransitionForward(), profileFile, profileFd,
597 profileAutoStop);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700598
Dianne Hackborn54e570f2010-10-04 18:32:32 -0700599 if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700600 // This may be a heavy-weight process! Note that the package
601 // manager will ensure that only activity can run in the main
602 // process of the .apk, which is the only thing that will be
603 // considered heavy-weight.
604 if (app.processName.equals(app.info.packageName)) {
605 if (mService.mHeavyWeightProcess != null
606 && mService.mHeavyWeightProcess != app) {
607 Log.w(TAG, "Starting new heavy weight process " + app
608 + " when already running "
609 + mService.mHeavyWeightProcess);
610 }
611 mService.mHeavyWeightProcess = app;
612 Message msg = mService.mHandler.obtainMessage(
613 ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
614 msg.obj = r;
615 mService.mHandler.sendMessage(msg);
616 }
617 }
618
619 } catch (RemoteException e) {
620 if (r.launchFailed) {
621 // This is the second time we failed -- finish activity
622 // and give up.
623 Slog.e(TAG, "Second failure launching "
624 + r.intent.getComponent().flattenToShortString()
625 + ", giving up", e);
626 mService.appDiedLocked(app, app.pid, app.thread);
627 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
628 "2nd-crash");
629 return false;
630 }
631
632 // This is the first time we failed -- restart process and
633 // retry.
634 app.activities.remove(r);
635 throw e;
636 }
637
638 r.launchFailed = false;
639 if (updateLRUListLocked(r)) {
640 Slog.w(TAG, "Activity " + r
641 + " being launched, but already in LRU list");
642 }
643
644 if (andResume) {
645 // As part of the process of launching, ActivityThread also performs
646 // a resume.
647 r.state = ActivityState.RESUMED;
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700648 if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + r
649 + " (starting new instance)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700650 r.stopped = false;
651 mResumedActivity = r;
652 r.task.touchActiveTime();
Dianne Hackborn88819b22010-12-21 18:18:02 -0800653 if (mMainStack) {
654 mService.addRecentTaskLocked(r.task);
655 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700656 completeResumeLocked(r);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800657 checkReadyForSleepLocked();
Dianne Hackborn98cfebc2011-10-18 13:17:33 -0700658 if (DEBUG_SAVED_STATE) Slog.i(TAG, "Launch completed; removing icicle of " + r.icicle);
659 r.icicle = null;
660 r.haveState = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700661 } else {
662 // This activity is not starting in the resumed state... which
663 // should look like we asked it to pause+stop (but remain visible),
664 // and it has done so and reported back the current icicle and
665 // other state.
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700666 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r
667 + " (starting in stopped state)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700668 r.state = ActivityState.STOPPED;
669 r.stopped = true;
670 }
671
672 // Launch the new version setup screen if needed. We do this -after-
673 // launching the initial activity (that is, home), so that it can have
674 // a chance to initialize itself while in the background, making the
675 // switch back to it faster and look better.
676 if (mMainStack) {
677 mService.startSetupActivityLocked();
678 }
679
680 return true;
681 }
682
683 private final void startSpecificActivityLocked(ActivityRecord r,
684 boolean andResume, boolean checkConfig) {
685 // Is this activity's application already running?
686 ProcessRecord app = mService.getProcessRecordLocked(r.processName,
687 r.info.applicationInfo.uid);
688
Dianne Hackborn0dad3642010-09-09 21:25:35 -0700689 if (r.launchTime == 0) {
690 r.launchTime = SystemClock.uptimeMillis();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700691 if (mInitialStartTime == 0) {
Dianne Hackborn0dad3642010-09-09 21:25:35 -0700692 mInitialStartTime = r.launchTime;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700693 }
694 } else if (mInitialStartTime == 0) {
695 mInitialStartTime = SystemClock.uptimeMillis();
696 }
697
698 if (app != null && app.thread != null) {
699 try {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700700 app.addPackage(r.info.packageName);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700701 realStartActivityLocked(r, app, andResume, checkConfig);
702 return;
703 } catch (RemoteException e) {
704 Slog.w(TAG, "Exception when starting activity "
705 + r.intent.getComponent().flattenToShortString(), e);
706 }
707
708 // If a dead object exception was thrown -- fall through to
709 // restart the application.
710 }
711
712 mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
713 "activity", r.intent.getComponent(), false);
714 }
715
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800716 void stopIfSleepingLocked() {
717 if (mService.isSleeping()) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700718 if (!mGoingToSleep.isHeld()) {
719 mGoingToSleep.acquire();
720 if (mLaunchingActivity.isHeld()) {
721 mLaunchingActivity.release();
722 mService.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
723 }
724 }
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800725 mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
726 Message msg = mHandler.obtainMessage(SLEEP_TIMEOUT_MSG);
727 mHandler.sendMessageDelayed(msg, SLEEP_TIMEOUT);
728 checkReadyForSleepLocked();
729 }
730 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700731
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800732 void awakeFromSleepingLocked() {
733 mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
734 mSleepTimeout = false;
735 if (mGoingToSleep.isHeld()) {
736 mGoingToSleep.release();
737 }
738 // Ensure activities are no longer sleeping.
739 for (int i=mHistory.size()-1; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700740 ActivityRecord r = mHistory.get(i);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800741 r.setSleeping(false);
742 }
743 mGoingToSleepActivities.clear();
744 }
745
746 void activitySleptLocked(ActivityRecord r) {
747 mGoingToSleepActivities.remove(r);
748 checkReadyForSleepLocked();
749 }
750
751 void checkReadyForSleepLocked() {
752 if (!mService.isSleeping()) {
753 // Do not care.
754 return;
755 }
756
757 if (!mSleepTimeout) {
758 if (mResumedActivity != null) {
759 // Still have something resumed; can't sleep until it is paused.
760 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause " + mResumedActivity);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700761 if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false");
762 startPausingLocked(false, true);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800763 return;
764 }
765 if (mPausingActivity != null) {
766 // Still waiting for something to pause; can't sleep yet.
767 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity);
768 return;
769 }
770
771 if (mStoppingActivities.size() > 0) {
772 // Still need to tell some activities to stop; can't sleep yet.
773 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to stop "
774 + mStoppingActivities.size() + " activities");
Dianne Hackborn80a7ac12011-09-22 18:32:52 -0700775 scheduleIdleLocked();
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800776 return;
777 }
778
779 ensureActivitiesVisibleLocked(null, 0);
780
781 // Make sure any stopped but visible activities are now sleeping.
782 // This ensures that the activity's onStop() is called.
783 for (int i=mHistory.size()-1; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700784 ActivityRecord r = mHistory.get(i);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800785 if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) {
786 r.setSleeping(true);
787 }
788 }
789
790 if (mGoingToSleepActivities.size() > 0) {
791 // Still need to tell some activities to sleep; can't sleep yet.
792 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to sleep "
793 + mGoingToSleepActivities.size() + " activities");
794 return;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700795 }
796 }
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800797
798 mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
799
800 if (mGoingToSleep.isHeld()) {
801 mGoingToSleep.release();
802 }
803 if (mService.mShuttingDown) {
804 mService.notifyAll();
805 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700806 }
807
Dianne Hackbornd2835932010-12-13 16:28:46 -0800808 public final Bitmap screenshotActivities(ActivityRecord who) {
Dianne Hackbornff801ec2011-01-22 18:05:38 -0800809 if (who.noDisplay) {
810 return null;
811 }
812
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800813 Resources res = mService.mContext.getResources();
814 int w = mThumbnailWidth;
815 int h = mThumbnailHeight;
816 if (w < 0) {
817 mThumbnailWidth = w =
818 res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
819 mThumbnailHeight = h =
820 res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
821 }
822
823 if (w > 0) {
Dianne Hackborn7c8a4b32010-12-15 14:58:00 -0800824 return mService.mWindowManager.screenshotApplications(who, w, h);
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800825 }
826 return null;
827 }
828
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700829 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
830 if (mPausingActivity != null) {
831 RuntimeException e = new RuntimeException();
832 Slog.e(TAG, "Trying to pause when pause is already pending for "
833 + mPausingActivity, e);
834 }
835 ActivityRecord prev = mResumedActivity;
836 if (prev == null) {
837 RuntimeException e = new RuntimeException();
838 Slog.e(TAG, "Trying to pause when nothing is resumed", e);
839 resumeTopActivityLocked(null);
840 return;
841 }
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700842 if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
843 else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700844 mResumedActivity = null;
845 mPausingActivity = prev;
846 mLastPausedActivity = prev;
847 prev.state = ActivityState.PAUSING;
848 prev.task.touchActiveTime();
Dianne Hackbornf26fd992011-04-08 18:14:09 -0700849 prev.updateThumbnail(screenshotActivities(prev), null);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700850
851 mService.updateCpuStats();
852
853 if (prev.app != null && prev.app.thread != null) {
854 if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
855 try {
856 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
857 System.identityHashCode(prev),
858 prev.shortComponentName);
859 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
860 prev.configChangeFlags);
861 if (mMainStack) {
862 mService.updateUsageStats(prev, false);
863 }
864 } catch (Exception e) {
865 // Ignore exception, if process died other code will cleanup.
866 Slog.w(TAG, "Exception thrown during pause", e);
867 mPausingActivity = null;
868 mLastPausedActivity = null;
869 }
870 } else {
871 mPausingActivity = null;
872 mLastPausedActivity = null;
873 }
874
875 // If we are not going to sleep, we want to ensure the device is
876 // awake until the next activity is started.
877 if (!mService.mSleeping && !mService.mShuttingDown) {
878 mLaunchingActivity.acquire();
879 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
880 // To be safe, don't allow the wake lock to be held for too long.
881 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
882 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
883 }
884 }
885
886
887 if (mPausingActivity != null) {
888 // Have the window manager pause its key dispatching until the new
889 // activity has started. If we're pausing the activity just because
890 // the screen is being turned off and the UI is sleeping, don't interrupt
891 // key dispatch; the same activity will pick it up again on wakeup.
892 if (!uiSleeping) {
893 prev.pauseKeyDispatchingLocked();
894 } else {
895 if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
896 }
897
898 // Schedule a pause timeout in case the app doesn't respond.
899 // We don't give it much time because this directly impacts the
900 // responsiveness seen by the user.
901 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
902 msg.obj = prev;
903 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
904 if (DEBUG_PAUSE) Slog.v(TAG, "Waiting for pause to complete...");
905 } else {
906 // This activity failed to schedule the
907 // pause, so just treat it as being paused now.
908 if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
909 resumeTopActivityLocked(null);
910 }
911 }
912
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800913 final void activityPaused(IBinder token, boolean timeout) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700914 if (DEBUG_PAUSE) Slog.v(
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800915 TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700916
917 ActivityRecord r = null;
918
919 synchronized (mService) {
920 int index = indexOfTokenLocked(token);
921 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700922 r = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700923 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
924 if (mPausingActivity == r) {
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700925 if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
926 + (timeout ? " (due to timeout)" : " (pause complete)"));
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700927 r.state = ActivityState.PAUSED;
928 completePauseLocked();
929 } else {
930 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
931 System.identityHashCode(r), r.shortComponentName,
932 mPausingActivity != null
933 ? mPausingActivity.shortComponentName : "(none)");
934 }
935 }
936 }
937 }
938
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700939 final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
940 CharSequence description) {
Dianne Hackborn98cfebc2011-10-18 13:17:33 -0700941 if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700942 r.icicle = icicle;
943 r.haveState = true;
944 r.updateThumbnail(thumbnail, description);
945 r.stopped = true;
946 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
947 r.state = ActivityState.STOPPED;
948 if (!r.finishing) {
949 if (r.configDestroy) {
950 destroyActivityLocked(r, true, false);
951 resumeTopActivityLocked(null);
952 }
953 }
954 }
955
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700956 private final void completePauseLocked() {
957 ActivityRecord prev = mPausingActivity;
958 if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
959
960 if (prev != null) {
961 if (prev.finishing) {
962 if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
963 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
964 } else if (prev.app != null) {
965 if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
966 if (prev.waitingVisible) {
967 prev.waitingVisible = false;
968 mWaitingVisibleActivities.remove(prev);
969 if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
970 TAG, "Complete pause, no longer waiting: " + prev);
971 }
972 if (prev.configDestroy) {
973 // The previous is being paused because the configuration
974 // is changing, which means it is actually stopping...
975 // To juggle the fact that we are also starting a new
976 // instance right now, we need to first completely stop
977 // the current instance before starting the new one.
978 if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700979 destroyActivityLocked(prev, true, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700980 } else {
981 mStoppingActivities.add(prev);
982 if (mStoppingActivities.size() > 3) {
983 // If we already have a few activities waiting to stop,
984 // then give up on things going idle and start clearing
985 // them out.
986 if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
Dianne Hackborn80a7ac12011-09-22 18:32:52 -0700987 scheduleIdleLocked();
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800988 } else {
989 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700990 }
991 }
992 } else {
993 if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
994 prev = null;
995 }
996 mPausingActivity = null;
997 }
998
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800999 if (!mService.isSleeping()) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001000 resumeTopActivityLocked(prev);
1001 } else {
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001002 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001003 }
1004
1005 if (prev != null) {
1006 prev.resumeKeyDispatchingLocked();
1007 }
1008
1009 if (prev.app != null && prev.cpuTimeAtResume > 0
1010 && mService.mBatteryStatsService.isOnBattery()) {
1011 long diff = 0;
1012 synchronized (mService.mProcessStatsThread) {
1013 diff = mService.mProcessStats.getCpuTimeForPid(prev.app.pid)
1014 - prev.cpuTimeAtResume;
1015 }
1016 if (diff > 0) {
1017 BatteryStatsImpl bsi = mService.mBatteryStatsService.getActiveStatistics();
1018 synchronized (bsi) {
1019 BatteryStatsImpl.Uid.Proc ps =
1020 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
1021 prev.info.packageName);
1022 if (ps != null) {
1023 ps.addForegroundTimeLocked(diff);
1024 }
1025 }
1026 }
1027 }
1028 prev.cpuTimeAtResume = 0; // reset it
1029 }
1030
1031 /**
1032 * Once we know that we have asked an application to put an activity in
1033 * the resumed state (either by launching it or explicitly telling it),
1034 * this function updates the rest of our state to match that fact.
1035 */
1036 private final void completeResumeLocked(ActivityRecord next) {
1037 next.idle = false;
1038 next.results = null;
1039 next.newIntents = null;
1040
1041 // schedule an idle timeout in case the app doesn't do it for us.
1042 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1043 msg.obj = next;
1044 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
1045
1046 if (false) {
1047 // The activity was never told to pause, so just keep
1048 // things going as-is. To maintain our own state,
1049 // we need to emulate it coming back and saying it is
1050 // idle.
1051 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
1052 msg.obj = next;
1053 mHandler.sendMessage(msg);
1054 }
1055
1056 if (mMainStack) {
1057 mService.reportResumedActivityLocked(next);
1058 }
1059
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001060 next.clearThumbnail();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001061 if (mMainStack) {
1062 mService.setFocusedActivityLocked(next);
1063 }
1064 next.resumeKeyDispatchingLocked();
1065 ensureActivitiesVisibleLocked(null, 0);
1066 mService.mWindowManager.executeAppTransition();
1067 mNoAnimActivities.clear();
1068
1069 // Mark the point when the activity is resuming
1070 // TODO: To be more accurate, the mark should be before the onCreate,
1071 // not after the onResume. But for subsequent starts, onResume is fine.
1072 if (next.app != null) {
1073 synchronized (mService.mProcessStatsThread) {
1074 next.cpuTimeAtResume = mService.mProcessStats.getCpuTimeForPid(next.app.pid);
1075 }
1076 } else {
1077 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
1078 }
1079 }
1080
1081 /**
1082 * Make sure that all activities that need to be visible (that is, they
1083 * currently can be seen by the user) actually are.
1084 */
1085 final void ensureActivitiesVisibleLocked(ActivityRecord top,
1086 ActivityRecord starting, String onlyThisProcess, int configChanges) {
1087 if (DEBUG_VISBILITY) Slog.v(
1088 TAG, "ensureActivitiesVisible behind " + top
1089 + " configChanges=0x" + Integer.toHexString(configChanges));
1090
1091 // If the top activity is not fullscreen, then we need to
1092 // make sure any activities under it are now visible.
1093 final int count = mHistory.size();
1094 int i = count-1;
1095 while (mHistory.get(i) != top) {
1096 i--;
1097 }
1098 ActivityRecord r;
1099 boolean behindFullscreen = false;
1100 for (; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001101 r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001102 if (DEBUG_VISBILITY) Slog.v(
1103 TAG, "Make visible? " + r + " finishing=" + r.finishing
1104 + " state=" + r.state);
1105 if (r.finishing) {
1106 continue;
1107 }
1108
1109 final boolean doThisProcess = onlyThisProcess == null
1110 || onlyThisProcess.equals(r.processName);
1111
1112 // First: if this is not the current activity being started, make
1113 // sure it matches the current configuration.
1114 if (r != starting && doThisProcess) {
1115 ensureActivityConfigurationLocked(r, 0);
1116 }
1117
1118 if (r.app == null || r.app.thread == null) {
1119 if (onlyThisProcess == null
1120 || onlyThisProcess.equals(r.processName)) {
1121 // This activity needs to be visible, but isn't even
1122 // running... get it started, but don't resume it
1123 // at this point.
1124 if (DEBUG_VISBILITY) Slog.v(
1125 TAG, "Start and freeze screen for " + r);
1126 if (r != starting) {
1127 r.startFreezingScreenLocked(r.app, configChanges);
1128 }
1129 if (!r.visible) {
1130 if (DEBUG_VISBILITY) Slog.v(
1131 TAG, "Starting and making visible: " + r);
1132 mService.mWindowManager.setAppVisibility(r, true);
1133 }
1134 if (r != starting) {
1135 startSpecificActivityLocked(r, false, false);
1136 }
1137 }
1138
1139 } else if (r.visible) {
1140 // If this activity is already visible, then there is nothing
1141 // else to do here.
1142 if (DEBUG_VISBILITY) Slog.v(
1143 TAG, "Skipping: already visible at " + r);
1144 r.stopFreezingScreenLocked(false);
1145
1146 } else if (onlyThisProcess == null) {
1147 // This activity is not currently visible, but is running.
1148 // Tell it to become visible.
1149 r.visible = true;
1150 if (r.state != ActivityState.RESUMED && r != starting) {
1151 // If this activity is paused, tell it
1152 // to now show its window.
1153 if (DEBUG_VISBILITY) Slog.v(
1154 TAG, "Making visible and scheduling visibility: " + r);
1155 try {
1156 mService.mWindowManager.setAppVisibility(r, true);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001157 r.sleeping = false;
Dianne Hackborn905577f2011-09-07 18:31:28 -07001158 r.app.pendingUiClean = true;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001159 r.app.thread.scheduleWindowVisibility(r, true);
1160 r.stopFreezingScreenLocked(false);
1161 } catch (Exception e) {
1162 // Just skip on any failure; we'll make it
1163 // visible when it next restarts.
1164 Slog.w(TAG, "Exception thrown making visibile: "
1165 + r.intent.getComponent(), e);
1166 }
1167 }
1168 }
1169
1170 // Aggregate current change flags.
1171 configChanges |= r.configChangeFlags;
1172
1173 if (r.fullscreen) {
1174 // At this point, nothing else needs to be shown
1175 if (DEBUG_VISBILITY) Slog.v(
1176 TAG, "Stopping: fullscreen at " + r);
1177 behindFullscreen = true;
1178 i--;
1179 break;
1180 }
1181 }
1182
1183 // Now for any activities that aren't visible to the user, make
1184 // sure they no longer are keeping the screen frozen.
1185 while (i >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001186 r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001187 if (DEBUG_VISBILITY) Slog.v(
1188 TAG, "Make invisible? " + r + " finishing=" + r.finishing
1189 + " state=" + r.state
1190 + " behindFullscreen=" + behindFullscreen);
1191 if (!r.finishing) {
1192 if (behindFullscreen) {
1193 if (r.visible) {
1194 if (DEBUG_VISBILITY) Slog.v(
1195 TAG, "Making invisible: " + r);
1196 r.visible = false;
1197 try {
1198 mService.mWindowManager.setAppVisibility(r, false);
1199 if ((r.state == ActivityState.STOPPING
1200 || r.state == ActivityState.STOPPED)
1201 && r.app != null && r.app.thread != null) {
1202 if (DEBUG_VISBILITY) Slog.v(
1203 TAG, "Scheduling invisibility: " + r);
1204 r.app.thread.scheduleWindowVisibility(r, false);
1205 }
1206 } catch (Exception e) {
1207 // Just skip on any failure; we'll make it
1208 // visible when it next restarts.
1209 Slog.w(TAG, "Exception thrown making hidden: "
1210 + r.intent.getComponent(), e);
1211 }
1212 } else {
1213 if (DEBUG_VISBILITY) Slog.v(
1214 TAG, "Already invisible: " + r);
1215 }
1216 } else if (r.fullscreen) {
1217 if (DEBUG_VISBILITY) Slog.v(
1218 TAG, "Now behindFullscreen: " + r);
1219 behindFullscreen = true;
1220 }
1221 }
1222 i--;
1223 }
1224 }
1225
1226 /**
1227 * Version of ensureActivitiesVisible that can easily be called anywhere.
1228 */
1229 final void ensureActivitiesVisibleLocked(ActivityRecord starting,
1230 int configChanges) {
1231 ActivityRecord r = topRunningActivityLocked(null);
1232 if (r != null) {
1233 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
1234 }
1235 }
1236
1237 /**
1238 * Ensure that the top activity in the stack is resumed.
1239 *
1240 * @param prev The previously resumed activity, for when in the process
1241 * of pausing; can be null to call from elsewhere.
1242 *
1243 * @return Returns true if something is being resumed, or false if
1244 * nothing happened.
1245 */
1246 final boolean resumeTopActivityLocked(ActivityRecord prev) {
1247 // Find the first activity that is not finishing.
1248 ActivityRecord next = topRunningActivityLocked(null);
1249
1250 // Remember how we'll process this pause/resume situation, and ensure
1251 // that the state is reset however we wind up proceeding.
1252 final boolean userLeaving = mUserLeaving;
1253 mUserLeaving = false;
1254
1255 if (next == null) {
1256 // There are no more activities! Let's just start up the
1257 // Launcher...
1258 if (mMainStack) {
1259 return mService.startHomeActivityLocked();
1260 }
1261 }
1262
1263 next.delayedResume = false;
1264
1265 // If the top activity is the resumed one, nothing to do.
1266 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
1267 // Make sure we have executed any pending transitions, since there
1268 // should be nothing left to do at this point.
1269 mService.mWindowManager.executeAppTransition();
1270 mNoAnimActivities.clear();
1271 return false;
1272 }
1273
1274 // If we are sleeping, and there is no resumed activity, and the top
1275 // activity is paused, well that is the state we want.
1276 if ((mService.mSleeping || mService.mShuttingDown)
1277 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
1278 // Make sure we have executed any pending transitions, since there
1279 // should be nothing left to do at this point.
1280 mService.mWindowManager.executeAppTransition();
1281 mNoAnimActivities.clear();
1282 return false;
1283 }
1284
1285 // The activity may be waiting for stop, but that is no longer
1286 // appropriate for it.
1287 mStoppingActivities.remove(next);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001288 mGoingToSleepActivities.remove(next);
1289 next.sleeping = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001290 mWaitingVisibleActivities.remove(next);
1291
1292 if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
1293
1294 // If we are currently pausing an activity, then don't do anything
1295 // until that is done.
1296 if (mPausingActivity != null) {
1297 if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity);
1298 return false;
1299 }
1300
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001301 // Okay we are now going to start a switch, to 'next'. We may first
1302 // have to pause the current activity, but this is an important point
1303 // where we have decided to go to 'next' so keep track of that.
Dianne Hackborn034093a42010-09-20 22:24:38 -07001304 // XXX "App Redirected" dialog is getting too many false positives
1305 // at this point, so turn off for now.
1306 if (false) {
1307 if (mLastStartedActivity != null && !mLastStartedActivity.finishing) {
1308 long now = SystemClock.uptimeMillis();
1309 final boolean inTime = mLastStartedActivity.startTime != 0
1310 && (mLastStartedActivity.startTime + START_WARN_TIME) >= now;
1311 final int lastUid = mLastStartedActivity.info.applicationInfo.uid;
1312 final int nextUid = next.info.applicationInfo.uid;
1313 if (inTime && lastUid != nextUid
1314 && lastUid != next.launchedFromUid
1315 && mService.checkPermission(
1316 android.Manifest.permission.STOP_APP_SWITCHES,
1317 -1, next.launchedFromUid)
1318 != PackageManager.PERMISSION_GRANTED) {
1319 mService.showLaunchWarningLocked(mLastStartedActivity, next);
1320 } else {
1321 next.startTime = now;
1322 mLastStartedActivity = next;
1323 }
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001324 } else {
Dianne Hackborn034093a42010-09-20 22:24:38 -07001325 next.startTime = SystemClock.uptimeMillis();
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001326 mLastStartedActivity = next;
1327 }
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001328 }
1329
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001330 // We need to start pausing the current activity so the top one
1331 // can be resumed...
1332 if (mResumedActivity != null) {
1333 if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
1334 startPausingLocked(userLeaving, false);
1335 return true;
1336 }
1337
1338 if (prev != null && prev != next) {
1339 if (!prev.waitingVisible && next != null && !next.nowVisible) {
1340 prev.waitingVisible = true;
1341 mWaitingVisibleActivities.add(prev);
1342 if (DEBUG_SWITCH) Slog.v(
1343 TAG, "Resuming top, waiting visible to hide: " + prev);
1344 } else {
1345 // The next activity is already visible, so hide the previous
1346 // activity's windows right now so we can show the new one ASAP.
1347 // We only do this if the previous is finishing, which should mean
1348 // it is on top of the one being resumed so hiding it quickly
1349 // is good. Otherwise, we want to do the normal route of allowing
1350 // the resumed activity to be shown so we can decide if the
1351 // previous should actually be hidden depending on whether the
1352 // new one is found to be full-screen or not.
1353 if (prev.finishing) {
1354 mService.mWindowManager.setAppVisibility(prev, false);
1355 if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
1356 + prev + ", waitingVisible="
1357 + (prev != null ? prev.waitingVisible : null)
1358 + ", nowVisible=" + next.nowVisible);
1359 } else {
1360 if (DEBUG_SWITCH) Slog.v(TAG, "Previous already visible but still waiting to hide: "
1361 + prev + ", waitingVisible="
1362 + (prev != null ? prev.waitingVisible : null)
1363 + ", nowVisible=" + next.nowVisible);
1364 }
1365 }
1366 }
1367
Dianne Hackborne7f97212011-02-24 14:40:20 -08001368 // Launching this app's activity, make sure the app is no longer
1369 // considered stopped.
1370 try {
1371 AppGlobals.getPackageManager().setPackageStoppedState(
1372 next.packageName, false);
1373 } catch (RemoteException e1) {
Dianne Hackborna925cd42011-03-10 13:18:20 -08001374 } catch (IllegalArgumentException e) {
1375 Slog.w(TAG, "Failed trying to unstop package "
1376 + next.packageName + ": " + e);
Dianne Hackborne7f97212011-02-24 14:40:20 -08001377 }
1378
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001379 // We are starting up the next activity, so tell the window manager
1380 // that the previous one will be hidden soon. This way it can know
1381 // to ignore it when computing the desired screen orientation.
1382 if (prev != null) {
1383 if (prev.finishing) {
1384 if (DEBUG_TRANSITION) Slog.v(TAG,
1385 "Prepare close transition: prev=" + prev);
1386 if (mNoAnimActivities.contains(prev)) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001387 mService.mWindowManager.prepareAppTransition(
1388 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001389 } else {
1390 mService.mWindowManager.prepareAppTransition(prev.task == next.task
1391 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001392 : WindowManagerPolicy.TRANSIT_TASK_CLOSE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001393 }
1394 mService.mWindowManager.setAppWillBeHidden(prev);
1395 mService.mWindowManager.setAppVisibility(prev, false);
1396 } else {
1397 if (DEBUG_TRANSITION) Slog.v(TAG,
1398 "Prepare open transition: prev=" + prev);
1399 if (mNoAnimActivities.contains(next)) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001400 mService.mWindowManager.prepareAppTransition(
1401 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001402 } else {
1403 mService.mWindowManager.prepareAppTransition(prev.task == next.task
1404 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001405 : WindowManagerPolicy.TRANSIT_TASK_OPEN, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001406 }
1407 }
1408 if (false) {
1409 mService.mWindowManager.setAppWillBeHidden(prev);
1410 mService.mWindowManager.setAppVisibility(prev, false);
1411 }
1412 } else if (mHistory.size() > 1) {
1413 if (DEBUG_TRANSITION) Slog.v(TAG,
1414 "Prepare open transition: no previous");
1415 if (mNoAnimActivities.contains(next)) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001416 mService.mWindowManager.prepareAppTransition(
1417 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001418 } else {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001419 mService.mWindowManager.prepareAppTransition(
1420 WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001421 }
1422 }
1423
1424 if (next.app != null && next.app.thread != null) {
1425 if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
1426
1427 // This activity is now becoming visible.
1428 mService.mWindowManager.setAppVisibility(next, true);
1429
1430 ActivityRecord lastResumedActivity = mResumedActivity;
1431 ActivityState lastState = next.state;
1432
1433 mService.updateCpuStats();
1434
Dianne Hackbornce86ba82011-07-13 19:33:41 -07001435 if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + next + " (in existing)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001436 next.state = ActivityState.RESUMED;
1437 mResumedActivity = next;
1438 next.task.touchActiveTime();
Dianne Hackborn88819b22010-12-21 18:18:02 -08001439 if (mMainStack) {
1440 mService.addRecentTaskLocked(next.task);
1441 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001442 mService.updateLruProcessLocked(next.app, true, true);
1443 updateLRUListLocked(next);
1444
1445 // Have the window manager re-evaluate the orientation of
1446 // the screen based on the new activity order.
1447 boolean updated = false;
1448 if (mMainStack) {
1449 synchronized (mService) {
1450 Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
1451 mService.mConfiguration,
1452 next.mayFreezeScreenLocked(next.app) ? next : null);
1453 if (config != null) {
1454 next.frozenBeforeDestroy = true;
1455 }
Dianne Hackborn31ca8542011-07-19 14:58:28 -07001456 updated = mService.updateConfigurationLocked(config, next, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001457 }
1458 }
1459 if (!updated) {
1460 // The configuration update wasn't able to keep the existing
1461 // instance of the activity, and instead started a new one.
1462 // We should be all done, but let's just make sure our activity
1463 // is still at the top and schedule another run if something
1464 // weird happened.
1465 ActivityRecord nextNext = topRunningActivityLocked(null);
1466 if (DEBUG_SWITCH) Slog.i(TAG,
1467 "Activity config changed during resume: " + next
1468 + ", new next: " + nextNext);
1469 if (nextNext != next) {
1470 // Do over!
1471 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
1472 }
1473 if (mMainStack) {
1474 mService.setFocusedActivityLocked(next);
1475 }
1476 ensureActivitiesVisibleLocked(null, 0);
1477 mService.mWindowManager.executeAppTransition();
1478 mNoAnimActivities.clear();
1479 return true;
1480 }
1481
1482 try {
1483 // Deliver all pending results.
1484 ArrayList a = next.results;
1485 if (a != null) {
1486 final int N = a.size();
1487 if (!next.finishing && N > 0) {
1488 if (DEBUG_RESULTS) Slog.v(
1489 TAG, "Delivering results to " + next
1490 + ": " + a);
1491 next.app.thread.scheduleSendResult(next, a);
1492 }
1493 }
1494
1495 if (next.newIntents != null) {
1496 next.app.thread.scheduleNewIntent(next.newIntents, next);
1497 }
1498
1499 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
1500 System.identityHashCode(next),
1501 next.task.taskId, next.shortComponentName);
1502
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001503 next.sleeping = false;
Dianne Hackborn36cd41f2011-05-25 21:00:46 -07001504 showAskCompatModeDialogLocked(next);
Dianne Hackborn905577f2011-09-07 18:31:28 -07001505 next.app.pendingUiClean = true;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001506 next.app.thread.scheduleResumeActivity(next,
1507 mService.isNextTransitionForward());
1508
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001509 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001510
1511 } catch (Exception e) {
1512 // Whoops, need to restart this activity!
Dianne Hackbornce86ba82011-07-13 19:33:41 -07001513 if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to "
1514 + lastState + ": " + next);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001515 next.state = lastState;
1516 mResumedActivity = lastResumedActivity;
1517 Slog.i(TAG, "Restarting because process died: " + next);
1518 if (!next.hasBeenLaunched) {
1519 next.hasBeenLaunched = true;
1520 } else {
1521 if (SHOW_APP_STARTING_PREVIEW && mMainStack) {
1522 mService.mWindowManager.setAppStartingWindow(
1523 next, next.packageName, next.theme,
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001524 mService.compatibilityInfoForPackageLocked(
1525 next.info.applicationInfo),
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001526 next.nonLocalizedLabel,
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001527 next.labelRes, next.icon, next.windowFlags,
1528 null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001529 }
1530 }
1531 startSpecificActivityLocked(next, true, false);
1532 return true;
1533 }
1534
1535 // From this point on, if something goes wrong there is no way
1536 // to recover the activity.
1537 try {
1538 next.visible = true;
1539 completeResumeLocked(next);
1540 } catch (Exception e) {
1541 // If any exception gets thrown, toss away this
1542 // activity and try the next one.
1543 Slog.w(TAG, "Exception thrown during resume of " + next, e);
1544 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
1545 "resume-exception");
1546 return true;
1547 }
1548
1549 // Didn't need to use the icicle, and it is now out of date.
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001550 if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; didn't need icicle of: " + next);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001551 next.icicle = null;
1552 next.haveState = false;
1553 next.stopped = false;
1554
1555 } else {
1556 // Whoops, need to restart this activity!
1557 if (!next.hasBeenLaunched) {
1558 next.hasBeenLaunched = true;
1559 } else {
1560 if (SHOW_APP_STARTING_PREVIEW) {
1561 mService.mWindowManager.setAppStartingWindow(
1562 next, next.packageName, next.theme,
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001563 mService.compatibilityInfoForPackageLocked(
1564 next.info.applicationInfo),
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001565 next.nonLocalizedLabel,
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001566 next.labelRes, next.icon, next.windowFlags,
1567 null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001568 }
1569 if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
1570 }
1571 startSpecificActivityLocked(next, true, true);
1572 }
1573
1574 return true;
1575 }
1576
1577 private final void startActivityLocked(ActivityRecord r, boolean newTask,
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001578 boolean doResume, boolean keepCurTransition) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001579 final int NH = mHistory.size();
1580
1581 int addPos = -1;
1582
1583 if (!newTask) {
1584 // If starting in an existing task, find where that is...
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001585 boolean startIt = true;
1586 for (int i = NH-1; i >= 0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001587 ActivityRecord p = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001588 if (p.finishing) {
1589 continue;
1590 }
1591 if (p.task == r.task) {
1592 // Here it is! Now, if this is not yet visible to the
1593 // user, then just add it without starting; it will
1594 // get started when the user navigates back to it.
1595 addPos = i+1;
1596 if (!startIt) {
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001597 if (DEBUG_ADD_REMOVE) {
1598 RuntimeException here = new RuntimeException("here");
1599 here.fillInStackTrace();
1600 Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos,
1601 here);
1602 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001603 mHistory.add(addPos, r);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001604 r.putInHistory();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001605 mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
1606 r.info.screenOrientation, r.fullscreen);
1607 if (VALIDATE_TOKENS) {
1608 mService.mWindowManager.validateAppTokens(mHistory);
1609 }
1610 return;
1611 }
1612 break;
1613 }
1614 if (p.fullscreen) {
1615 startIt = false;
1616 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001617 }
1618 }
1619
1620 // Place a new activity at top of stack, so it is next to interact
1621 // with the user.
1622 if (addPos < 0) {
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001623 addPos = NH;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001624 }
1625
1626 // If we are not placing the new activity frontmost, we do not want
1627 // to deliver the onUserLeaving callback to the actual frontmost
1628 // activity
1629 if (addPos < NH) {
1630 mUserLeaving = false;
1631 if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() behind front, mUserLeaving=false");
1632 }
1633
1634 // Slot the activity into the history stack and proceed
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001635 if (DEBUG_ADD_REMOVE) {
1636 RuntimeException here = new RuntimeException("here");
1637 here.fillInStackTrace();
1638 Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos, here);
1639 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001640 mHistory.add(addPos, r);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001641 r.putInHistory();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001642 r.frontOfTask = newTask;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001643 if (NH > 0) {
1644 // We want to show the starting preview window if we are
1645 // switching to a new task, or the next activity's process is
1646 // not currently running.
1647 boolean showStartingIcon = newTask;
1648 ProcessRecord proc = r.app;
1649 if (proc == null) {
1650 proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
1651 }
1652 if (proc == null || proc.thread == null) {
1653 showStartingIcon = true;
1654 }
1655 if (DEBUG_TRANSITION) Slog.v(TAG,
1656 "Prepare open transition: starting " + r);
1657 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001658 mService.mWindowManager.prepareAppTransition(
1659 WindowManagerPolicy.TRANSIT_NONE, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001660 mNoAnimActivities.add(r);
1661 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
1662 mService.mWindowManager.prepareAppTransition(
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001663 WindowManagerPolicy.TRANSIT_TASK_OPEN, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001664 mNoAnimActivities.remove(r);
1665 } else {
1666 mService.mWindowManager.prepareAppTransition(newTask
1667 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001668 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001669 mNoAnimActivities.remove(r);
1670 }
1671 mService.mWindowManager.addAppToken(
1672 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
1673 boolean doShow = true;
1674 if (newTask) {
1675 // Even though this activity is starting fresh, we still need
1676 // to reset it to make sure we apply affinities to move any
1677 // existing activities from other tasks in to it.
1678 // If the caller has requested that the target task be
1679 // reset, then do so.
1680 if ((r.intent.getFlags()
1681 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
1682 resetTaskIfNeededLocked(r, r);
1683 doShow = topRunningNonDelayedActivityLocked(null) == r;
1684 }
1685 }
1686 if (SHOW_APP_STARTING_PREVIEW && doShow) {
1687 // Figure out if we are transitioning from another activity that is
1688 // "has the same starting icon" as the next one. This allows the
1689 // window manager to keep the previous window it had previously
1690 // created, if it still had one.
1691 ActivityRecord prev = mResumedActivity;
1692 if (prev != null) {
1693 // We don't want to reuse the previous starting preview if:
1694 // (1) The current activity is in a different task.
1695 if (prev.task != r.task) prev = null;
1696 // (2) The current activity is already displayed.
1697 else if (prev.nowVisible) prev = null;
1698 }
1699 mService.mWindowManager.setAppStartingWindow(
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001700 r, r.packageName, r.theme,
1701 mService.compatibilityInfoForPackageLocked(
1702 r.info.applicationInfo), r.nonLocalizedLabel,
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001703 r.labelRes, r.icon, r.windowFlags, prev, showStartingIcon);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001704 }
1705 } else {
1706 // If this is the first activity, don't do any fancy animations,
1707 // because there is nothing for it to animate on top of.
1708 mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
1709 r.info.screenOrientation, r.fullscreen);
1710 }
1711 if (VALIDATE_TOKENS) {
1712 mService.mWindowManager.validateAppTokens(mHistory);
1713 }
1714
1715 if (doResume) {
1716 resumeTopActivityLocked(null);
1717 }
1718 }
1719
1720 /**
1721 * Perform a reset of the given task, if needed as part of launching it.
1722 * Returns the new HistoryRecord at the top of the task.
1723 */
1724 private final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop,
1725 ActivityRecord newActivity) {
1726 boolean forceReset = (newActivity.info.flags
1727 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001728 if (ACTIVITY_INACTIVE_RESET_TIME > 0
1729 && taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001730 if ((newActivity.info.flags
1731 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
1732 forceReset = true;
1733 }
1734 }
1735
1736 final TaskRecord task = taskTop.task;
1737
1738 // We are going to move through the history list so that we can look
1739 // at each activity 'target' with 'below' either the interesting
1740 // activity immediately below it in the stack or null.
1741 ActivityRecord target = null;
1742 int targetI = 0;
1743 int taskTopI = -1;
1744 int replyChainEnd = -1;
1745 int lastReparentPos = -1;
1746 for (int i=mHistory.size()-1; i>=-1; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001747 ActivityRecord below = i >= 0 ? mHistory.get(i) : null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001748
1749 if (below != null && below.finishing) {
1750 continue;
1751 }
1752 if (target == null) {
1753 target = below;
1754 targetI = i;
1755 // If we were in the middle of a reply chain before this
1756 // task, it doesn't appear like the root of the chain wants
1757 // anything interesting, so drop it.
1758 replyChainEnd = -1;
1759 continue;
1760 }
1761
1762 final int flags = target.info.flags;
1763
1764 final boolean finishOnTaskLaunch =
1765 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
1766 final boolean allowTaskReparenting =
1767 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
1768
1769 if (target.task == task) {
1770 // We are inside of the task being reset... we'll either
1771 // finish this activity, push it out for another task,
1772 // or leave it as-is. We only do this
1773 // for activities that are not the root of the task (since
1774 // if we finish the root, we may no longer have the task!).
1775 if (taskTopI < 0) {
1776 taskTopI = targetI;
1777 }
1778 if (below != null && below.task == task) {
1779 final boolean clearWhenTaskReset =
1780 (target.intent.getFlags()
1781 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
1782 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
1783 // If this activity is sending a reply to a previous
1784 // activity, we can't do anything with it now until
1785 // we reach the start of the reply chain.
1786 // XXX note that we are assuming the result is always
1787 // to the previous activity, which is almost always
1788 // the case but we really shouldn't count on.
1789 if (replyChainEnd < 0) {
1790 replyChainEnd = targetI;
1791 }
1792 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
1793 && target.taskAffinity != null
1794 && !target.taskAffinity.equals(task.affinity)) {
1795 // If this activity has an affinity for another
1796 // task, then we need to move it out of here. We will
1797 // move it as far out of the way as possible, to the
1798 // bottom of the activity stack. This also keeps it
1799 // correctly ordered with any activities we previously
1800 // moved.
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001801 ActivityRecord p = mHistory.get(0);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001802 if (target.taskAffinity != null
1803 && target.taskAffinity.equals(p.task.affinity)) {
1804 // If the activity currently at the bottom has the
1805 // same task affinity as the one we are moving,
1806 // then merge it into the same task.
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001807 target.setTask(p.task, p.thumbHolder, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001808 if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
1809 + " out to bottom task " + p.task);
1810 } else {
1811 mService.mCurTask++;
1812 if (mService.mCurTask <= 0) {
1813 mService.mCurTask = 1;
1814 }
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001815 target.setTask(new TaskRecord(mService.mCurTask, target.info, null),
1816 null, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001817 target.task.affinityIntent = target.intent;
1818 if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
1819 + " out to new task " + target.task);
1820 }
1821 mService.mWindowManager.setAppGroupId(target, task.taskId);
1822 if (replyChainEnd < 0) {
1823 replyChainEnd = targetI;
1824 }
1825 int dstPos = 0;
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001826 ThumbnailHolder curThumbHolder = target.thumbHolder;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001827 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001828 p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001829 if (p.finishing) {
1830 continue;
1831 }
1832 if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
1833 + " out to target's task " + target.task);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001834 p.setTask(target.task, curThumbHolder, false);
1835 curThumbHolder = p.thumbHolder;
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001836 if (DEBUG_ADD_REMOVE) {
1837 RuntimeException here = new RuntimeException("here");
1838 here.fillInStackTrace();
1839 Slog.i(TAG, "Removing and adding activity " + p + " to stack at "
1840 + dstPos, here);
1841 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001842 mHistory.remove(srcPos);
1843 mHistory.add(dstPos, p);
1844 mService.mWindowManager.moveAppToken(dstPos, p);
1845 mService.mWindowManager.setAppGroupId(p, p.task.taskId);
1846 dstPos++;
1847 if (VALIDATE_TOKENS) {
1848 mService.mWindowManager.validateAppTokens(mHistory);
1849 }
1850 i++;
1851 }
1852 if (taskTop == p) {
1853 taskTop = below;
1854 }
1855 if (taskTopI == replyChainEnd) {
1856 taskTopI = -1;
1857 }
1858 replyChainEnd = -1;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001859 } else if (forceReset || finishOnTaskLaunch
1860 || clearWhenTaskReset) {
1861 // If the activity should just be removed -- either
1862 // because it asks for it, or the task should be
1863 // cleared -- then finish it and anything that is
1864 // part of its reply chain.
1865 if (clearWhenTaskReset) {
1866 // In this case, we want to finish this activity
1867 // and everything above it, so be sneaky and pretend
1868 // like these are all in the reply chain.
1869 replyChainEnd = targetI+1;
1870 while (replyChainEnd < mHistory.size() &&
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001871 (mHistory.get(
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001872 replyChainEnd)).task == task) {
1873 replyChainEnd++;
1874 }
1875 replyChainEnd--;
1876 } else if (replyChainEnd < 0) {
1877 replyChainEnd = targetI;
1878 }
1879 ActivityRecord p = null;
1880 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001881 p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001882 if (p.finishing) {
1883 continue;
1884 }
1885 if (finishActivityLocked(p, srcPos,
1886 Activity.RESULT_CANCELED, null, "reset")) {
1887 replyChainEnd--;
1888 srcPos--;
1889 }
1890 }
1891 if (taskTop == p) {
1892 taskTop = below;
1893 }
1894 if (taskTopI == replyChainEnd) {
1895 taskTopI = -1;
1896 }
1897 replyChainEnd = -1;
1898 } else {
1899 // If we were in the middle of a chain, well the
1900 // activity that started it all doesn't want anything
1901 // special, so leave it all as-is.
1902 replyChainEnd = -1;
1903 }
1904 } else {
1905 // Reached the bottom of the task -- any reply chain
1906 // should be left as-is.
1907 replyChainEnd = -1;
1908 }
1909
1910 } else if (target.resultTo != null) {
1911 // If this activity is sending a reply to a previous
1912 // activity, we can't do anything with it now until
1913 // we reach the start of the reply chain.
1914 // XXX note that we are assuming the result is always
1915 // to the previous activity, which is almost always
1916 // the case but we really shouldn't count on.
1917 if (replyChainEnd < 0) {
1918 replyChainEnd = targetI;
1919 }
1920
1921 } else if (taskTopI >= 0 && allowTaskReparenting
1922 && task.affinity != null
1923 && task.affinity.equals(target.taskAffinity)) {
1924 // We are inside of another task... if this activity has
1925 // an affinity for our task, then either remove it if we are
1926 // clearing or move it over to our task. Note that
1927 // we currently punt on the case where we are resetting a
1928 // task that is not at the top but who has activities above
1929 // with an affinity to it... this is really not a normal
1930 // case, and we will need to later pull that task to the front
1931 // and usually at that point we will do the reset and pick
1932 // up those remaining activities. (This only happens if
1933 // someone starts an activity in a new task from an activity
1934 // in a task that is not currently on top.)
1935 if (forceReset || finishOnTaskLaunch) {
1936 if (replyChainEnd < 0) {
1937 replyChainEnd = targetI;
1938 }
1939 ActivityRecord p = null;
1940 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001941 p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001942 if (p.finishing) {
1943 continue;
1944 }
1945 if (finishActivityLocked(p, srcPos,
1946 Activity.RESULT_CANCELED, null, "reset")) {
1947 taskTopI--;
1948 lastReparentPos--;
1949 replyChainEnd--;
1950 srcPos--;
1951 }
1952 }
1953 replyChainEnd = -1;
1954 } else {
1955 if (replyChainEnd < 0) {
1956 replyChainEnd = targetI;
1957 }
1958 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001959 ActivityRecord p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001960 if (p.finishing) {
1961 continue;
1962 }
1963 if (lastReparentPos < 0) {
1964 lastReparentPos = taskTopI;
1965 taskTop = p;
1966 } else {
1967 lastReparentPos--;
1968 }
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001969 if (DEBUG_ADD_REMOVE) {
1970 RuntimeException here = new RuntimeException("here");
1971 here.fillInStackTrace();
1972 Slog.i(TAG, "Removing and adding activity " + p + " to stack at "
1973 + lastReparentPos, here);
1974 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001975 mHistory.remove(srcPos);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001976 p.setTask(task, null, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001977 mHistory.add(lastReparentPos, p);
1978 if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
1979 + " in to resetting task " + task);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001980 mService.mWindowManager.moveAppToken(lastReparentPos, p);
1981 mService.mWindowManager.setAppGroupId(p, p.task.taskId);
1982 if (VALIDATE_TOKENS) {
1983 mService.mWindowManager.validateAppTokens(mHistory);
1984 }
1985 }
1986 replyChainEnd = -1;
1987
1988 // Now we've moved it in to place... but what if this is
1989 // a singleTop activity and we have put it on top of another
1990 // instance of the same activity? Then we drop the instance
1991 // below so it remains singleTop.
1992 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
1993 for (int j=lastReparentPos-1; j>=0; j--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001994 ActivityRecord p = mHistory.get(j);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001995 if (p.finishing) {
1996 continue;
1997 }
1998 if (p.intent.getComponent().equals(target.intent.getComponent())) {
1999 if (finishActivityLocked(p, j,
2000 Activity.RESULT_CANCELED, null, "replace")) {
2001 taskTopI--;
2002 lastReparentPos--;
2003 }
2004 }
2005 }
2006 }
2007 }
2008 }
2009
2010 target = below;
2011 targetI = i;
2012 }
2013
2014 return taskTop;
2015 }
2016
2017 /**
2018 * Perform clear operation as requested by
2019 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2020 * stack to the given task, then look for
2021 * an instance of that activity in the stack and, if found, finish all
2022 * activities on top of it and return the instance.
2023 *
2024 * @param newR Description of the new activity being started.
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002025 * @return Returns the old activity that should be continued to be used,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002026 * or null if none was found.
2027 */
2028 private final ActivityRecord performClearTaskLocked(int taskId,
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002029 ActivityRecord newR, int launchFlags) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002030 int i = mHistory.size();
2031
2032 // First find the requested task.
2033 while (i > 0) {
2034 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002035 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002036 if (r.task.taskId == taskId) {
2037 i++;
2038 break;
2039 }
2040 }
2041
2042 // Now clear it.
2043 while (i > 0) {
2044 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002045 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002046 if (r.finishing) {
2047 continue;
2048 }
2049 if (r.task.taskId != taskId) {
2050 return null;
2051 }
2052 if (r.realActivity.equals(newR.realActivity)) {
2053 // Here it is! Now finish everything in front...
2054 ActivityRecord ret = r;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002055 while (i < (mHistory.size()-1)) {
2056 i++;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002057 r = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002058 if (r.task.taskId != taskId) {
2059 break;
2060 }
2061 if (r.finishing) {
2062 continue;
2063 }
2064 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2065 null, "clear")) {
2066 i--;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002067 }
2068 }
2069
2070 // Finally, if this is a normal launch mode (that is, not
2071 // expecting onNewIntent()), then we will finish the current
2072 // instance of the activity so a new fresh one can be started.
2073 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2074 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
2075 if (!ret.finishing) {
2076 int index = indexOfTokenLocked(ret);
2077 if (index >= 0) {
2078 finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
2079 null, "clear");
2080 }
2081 return null;
2082 }
2083 }
2084
2085 return ret;
2086 }
2087 }
2088
2089 return null;
2090 }
2091
2092 /**
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002093 * Completely remove all activities associated with an existing
2094 * task starting at a specified index.
2095 */
2096 private final void performClearTaskAtIndexLocked(int taskId, int i) {
Dianne Hackborneabd3282011-10-13 16:26:49 -07002097 while (i < mHistory.size()) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002098 ActivityRecord r = mHistory.get(i);
2099 if (r.task.taskId != taskId) {
2100 // Whoops hit the end.
2101 return;
2102 }
2103 if (r.finishing) {
2104 i++;
2105 continue;
2106 }
2107 if (!finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2108 null, "clear")) {
2109 i++;
2110 }
2111 }
2112 }
2113
2114 /**
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002115 * Completely remove all activities associated with an existing task.
2116 */
2117 private final void performClearTaskLocked(int taskId) {
2118 int i = mHistory.size();
2119
2120 // First find the requested task.
2121 while (i > 0) {
2122 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002123 ActivityRecord r = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002124 if (r.task.taskId == taskId) {
2125 i++;
2126 break;
2127 }
2128 }
2129
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002130 // Now find the start and clear it.
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002131 while (i > 0) {
2132 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002133 ActivityRecord r = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002134 if (r.finishing) {
2135 continue;
2136 }
2137 if (r.task.taskId != taskId) {
2138 // We hit the bottom. Now finish it all...
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002139 performClearTaskAtIndexLocked(taskId, i+1);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002140 return;
2141 }
2142 }
2143 }
2144
2145 /**
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002146 * Find the activity in the history stack within the given task. Returns
2147 * the index within the history at which it's found, or < 0 if not found.
2148 */
2149 private final int findActivityInHistoryLocked(ActivityRecord r, int task) {
2150 int i = mHistory.size();
2151 while (i > 0) {
2152 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002153 ActivityRecord candidate = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002154 if (candidate.task.taskId != task) {
2155 break;
2156 }
2157 if (candidate.realActivity.equals(r.realActivity)) {
2158 return i;
2159 }
2160 }
2161
2162 return -1;
2163 }
2164
2165 /**
2166 * Reorder the history stack so that the activity at the given index is
2167 * brought to the front.
2168 */
2169 private final ActivityRecord moveActivityToFrontLocked(int where) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002170 ActivityRecord newTop = mHistory.remove(where);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002171 int top = mHistory.size();
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002172 ActivityRecord oldTop = mHistory.get(top-1);
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07002173 if (DEBUG_ADD_REMOVE) {
2174 RuntimeException here = new RuntimeException("here");
2175 here.fillInStackTrace();
2176 Slog.i(TAG, "Removing and adding activity " + newTop + " to stack at "
2177 + top, here);
2178 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002179 mHistory.add(top, newTop);
2180 oldTop.frontOfTask = false;
2181 newTop.frontOfTask = true;
2182 return newTop;
2183 }
2184
2185 final int startActivityLocked(IApplicationThread caller,
2186 Intent intent, String resolvedType,
2187 Uri[] grantedUriPermissions,
2188 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2189 String resultWho, int requestCode,
2190 int callingPid, int callingUid, boolean onlyIfNeeded,
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002191 boolean componentSpecified, ActivityRecord[] outActivity) {
Dianne Hackbornefb58102010-10-14 16:47:34 -07002192
2193 int err = START_SUCCESS;
2194
2195 ProcessRecord callerApp = null;
2196 if (caller != null) {
2197 callerApp = mService.getRecordForAppLocked(caller);
2198 if (callerApp != null) {
2199 callingPid = callerApp.pid;
2200 callingUid = callerApp.info.uid;
2201 } else {
2202 Slog.w(TAG, "Unable to find app for caller " + caller
2203 + " (pid=" + callingPid + ") when starting: "
2204 + intent.toString());
2205 err = START_PERMISSION_DENIED;
2206 }
2207 }
2208
2209 if (err == START_SUCCESS) {
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002210 Slog.i(TAG, "START {" + intent.toShortString(true, true, true) + "} from pid "
Dianne Hackbornefb58102010-10-14 16:47:34 -07002211 + (callerApp != null ? callerApp.pid : callingPid));
2212 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002213
2214 ActivityRecord sourceRecord = null;
2215 ActivityRecord resultRecord = null;
2216 if (resultTo != null) {
2217 int index = indexOfTokenLocked(resultTo);
2218 if (DEBUG_RESULTS) Slog.v(
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07002219 TAG, "Will send result to " + resultTo + " (index " + index + ")");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002220 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002221 sourceRecord = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002222 if (requestCode >= 0 && !sourceRecord.finishing) {
2223 resultRecord = sourceRecord;
2224 }
2225 }
2226 }
2227
2228 int launchFlags = intent.getFlags();
2229
2230 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2231 && sourceRecord != null) {
2232 // Transfer the result target from the source activity to the new
2233 // one being started, including any failures.
2234 if (requestCode >= 0) {
2235 return START_FORWARD_AND_REQUEST_CONFLICT;
2236 }
2237 resultRecord = sourceRecord.resultTo;
2238 resultWho = sourceRecord.resultWho;
2239 requestCode = sourceRecord.requestCode;
2240 sourceRecord.resultTo = null;
2241 if (resultRecord != null) {
2242 resultRecord.removeResultsLocked(
2243 sourceRecord, resultWho, requestCode);
2244 }
2245 }
2246
Dianne Hackbornefb58102010-10-14 16:47:34 -07002247 if (err == START_SUCCESS && intent.getComponent() == null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002248 // We couldn't find a class that can handle the given Intent.
2249 // That's the end of that!
2250 err = START_INTENT_NOT_RESOLVED;
2251 }
2252
2253 if (err == START_SUCCESS && aInfo == null) {
2254 // We couldn't find the specific class specified in the Intent.
2255 // Also the end of the line.
2256 err = START_CLASS_NOT_FOUND;
2257 }
2258
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002259 if (err != START_SUCCESS) {
2260 if (resultRecord != null) {
2261 sendActivityResultLocked(-1,
2262 resultRecord, resultWho, requestCode,
2263 Activity.RESULT_CANCELED, null);
2264 }
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002265 mDismissKeyguardOnNextActivity = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002266 return err;
2267 }
2268
2269 final int perm = mService.checkComponentPermission(aInfo.permission, callingPid,
Dianne Hackborn6c2c5fc2011-01-18 17:02:33 -08002270 callingUid, aInfo.applicationInfo.uid, aInfo.exported);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002271 if (perm != PackageManager.PERMISSION_GRANTED) {
2272 if (resultRecord != null) {
2273 sendActivityResultLocked(-1,
2274 resultRecord, resultWho, requestCode,
2275 Activity.RESULT_CANCELED, null);
2276 }
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002277 mDismissKeyguardOnNextActivity = false;
Dianne Hackborn6c2c5fc2011-01-18 17:02:33 -08002278 String msg;
2279 if (!aInfo.exported) {
2280 msg = "Permission Denial: starting " + intent.toString()
2281 + " from " + callerApp + " (pid=" + callingPid
2282 + ", uid=" + callingUid + ")"
2283 + " not exported from uid " + aInfo.applicationInfo.uid;
2284 } else {
2285 msg = "Permission Denial: starting " + intent.toString()
2286 + " from " + callerApp + " (pid=" + callingPid
2287 + ", uid=" + callingUid + ")"
2288 + " requires " + aInfo.permission;
2289 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002290 Slog.w(TAG, msg);
2291 throw new SecurityException(msg);
2292 }
2293
2294 if (mMainStack) {
2295 if (mService.mController != null) {
2296 boolean abort = false;
2297 try {
2298 // The Intent we give to the watcher has the extra data
2299 // stripped off, since it can contain private information.
2300 Intent watchIntent = intent.cloneFilter();
2301 abort = !mService.mController.activityStarting(watchIntent,
2302 aInfo.applicationInfo.packageName);
2303 } catch (RemoteException e) {
2304 mService.mController = null;
2305 }
2306
2307 if (abort) {
2308 if (resultRecord != null) {
2309 sendActivityResultLocked(-1,
2310 resultRecord, resultWho, requestCode,
2311 Activity.RESULT_CANCELED, null);
2312 }
2313 // We pretend to the caller that it was really started, but
2314 // they will just get a cancel result.
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002315 mDismissKeyguardOnNextActivity = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002316 return START_SUCCESS;
2317 }
2318 }
2319 }
2320
2321 ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
2322 intent, resolvedType, aInfo, mService.mConfiguration,
2323 resultRecord, resultWho, requestCode, componentSpecified);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002324 if (outActivity != null) {
2325 outActivity[0] = r;
2326 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002327
2328 if (mMainStack) {
2329 if (mResumedActivity == null
2330 || mResumedActivity.info.applicationInfo.uid != callingUid) {
2331 if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
2332 PendingActivityLaunch pal = new PendingActivityLaunch();
2333 pal.r = r;
2334 pal.sourceRecord = sourceRecord;
2335 pal.grantedUriPermissions = grantedUriPermissions;
2336 pal.grantedMode = grantedMode;
2337 pal.onlyIfNeeded = onlyIfNeeded;
2338 mService.mPendingActivityLaunches.add(pal);
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002339 mDismissKeyguardOnNextActivity = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002340 return START_SWITCHES_CANCELED;
2341 }
2342 }
2343
2344 if (mService.mDidAppSwitch) {
2345 // This is the second allowed switch since we stopped switches,
2346 // so now just generally allow switches. Use case: user presses
2347 // home (switches disabled, switch to home, mDidAppSwitch now true);
2348 // user taps a home icon (coming from home so allowed, we hit here
2349 // and now allow anyone to switch again).
2350 mService.mAppSwitchesAllowedTime = 0;
2351 } else {
2352 mService.mDidAppSwitch = true;
2353 }
2354
2355 mService.doPendingActivityLaunchesLocked(false);
2356 }
2357
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002358 err = startActivityUncheckedLocked(r, sourceRecord,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002359 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002360 if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
2361 // Someone asked to have the keyguard dismissed on the next
2362 // activity start, but we are not actually doing an activity
2363 // switch... just dismiss the keyguard now, because we
2364 // probably want to see whatever is behind it.
2365 mDismissKeyguardOnNextActivity = false;
2366 mService.mWindowManager.dismissKeyguard();
2367 }
2368 return err;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002369 }
2370
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002371 final void moveHomeToFrontFromLaunchLocked(int launchFlags) {
2372 if ((launchFlags &
2373 (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
2374 == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
2375 // Caller wants to appear on home activity, so before starting
2376 // their own activity we will bring home to the front.
2377 moveHomeToFrontLocked();
2378 }
2379 }
2380
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002381 final int startActivityUncheckedLocked(ActivityRecord r,
2382 ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
2383 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
2384 final Intent intent = r.intent;
2385 final int callingUid = r.launchedFromUid;
2386
2387 int launchFlags = intent.getFlags();
2388
2389 // We'll invoke onUserLeaving before onPause only if the launching
2390 // activity did not explicitly state that this is an automated launch.
2391 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
2392 if (DEBUG_USER_LEAVING) Slog.v(TAG,
2393 "startActivity() => mUserLeaving=" + mUserLeaving);
2394
2395 // If the caller has asked not to resume at this point, we make note
2396 // of this in the record so that we can skip it when trying to find
2397 // the top running activity.
2398 if (!doResume) {
2399 r.delayedResume = true;
2400 }
2401
2402 ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
2403 != 0 ? r : null;
2404
2405 // If the onlyIfNeeded flag is set, then we can do this if the activity
2406 // being launched is the same as the one making the call... or, as
2407 // a special case, if we do not know the caller then we count the
2408 // current top activity as the caller.
2409 if (onlyIfNeeded) {
2410 ActivityRecord checkedCaller = sourceRecord;
2411 if (checkedCaller == null) {
2412 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
2413 }
2414 if (!checkedCaller.realActivity.equals(r.realActivity)) {
2415 // Caller is not the same as launcher, so always needed.
2416 onlyIfNeeded = false;
2417 }
2418 }
2419
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002420 if (sourceRecord == null) {
2421 // This activity is not being started from another... in this
2422 // case we -always- start a new task.
2423 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
2424 Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
2425 + intent);
2426 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2427 }
2428 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2429 // The original activity who is starting us is running as a single
2430 // instance... this new activity it is starting must go on its
2431 // own task.
2432 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2433 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
2434 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
2435 // The activity being started is a single instance... it always
2436 // gets launched into its own task.
2437 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2438 }
2439
2440 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
2441 // For whatever reason this activity is being launched into a new
2442 // task... yet the caller has requested a result back. Well, that
2443 // is pretty messed up, so instead immediately send back a cancel
2444 // and let the new task continue launched as normal without a
2445 // dependency on its originator.
2446 Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
2447 sendActivityResultLocked(-1,
2448 r.resultTo, r.resultWho, r.requestCode,
2449 Activity.RESULT_CANCELED, null);
2450 r.resultTo = null;
2451 }
2452
2453 boolean addingToTask = false;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002454 TaskRecord reuseTask = null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002455 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
2456 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
2457 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
2458 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2459 // If bring to front is requested, and no result is requested, and
2460 // we can find a task that was started with this same
2461 // component, then instead of launching bring that one to the front.
2462 if (r.resultTo == null) {
2463 // See if there is a task to bring to the front. If this is
2464 // a SINGLE_INSTANCE activity, there can be one and only one
2465 // instance of it in the history, and it is always in its own
2466 // unique task, so we do a special search.
2467 ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
2468 ? findTaskLocked(intent, r.info)
2469 : findActivityLocked(intent, r.info);
2470 if (taskTop != null) {
2471 if (taskTop.task.intent == null) {
2472 // This task was started because of movement of
2473 // the activity based on affinity... now that we
2474 // are actually launching it, we can assign the
2475 // base intent.
2476 taskTop.task.setIntent(intent, r.info);
2477 }
2478 // If the target task is not in the front, then we need
2479 // to bring it to the front... except... well, with
2480 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
2481 // to have the same behavior as if a new instance was
2482 // being started, which means not bringing it to the front
2483 // if the caller is not itself in the front.
2484 ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
Jean-Baptiste Queru66a5d692010-10-25 17:27:16 -07002485 if (curTop != null && curTop.task != taskTop.task) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002486 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
2487 boolean callerAtFront = sourceRecord == null
2488 || curTop.task == sourceRecord.task;
2489 if (callerAtFront) {
2490 // We really do want to push this one into the
2491 // user's face, right now.
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002492 moveHomeToFrontFromLaunchLocked(launchFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002493 moveTaskToFrontLocked(taskTop.task, r);
2494 }
2495 }
2496 // If the caller has requested that the target task be
2497 // reset, then do so.
2498 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2499 taskTop = resetTaskIfNeededLocked(taskTop, r);
2500 }
2501 if (onlyIfNeeded) {
2502 // We don't need to start a new activity, and
2503 // the client said not to do anything if that
2504 // is the case, so this is it! And for paranoia, make
2505 // sure we have correctly resumed the top activity.
2506 if (doResume) {
2507 resumeTopActivityLocked(null);
2508 }
2509 return START_RETURN_INTENT_TO_CALLER;
2510 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002511 if ((launchFlags &
2512 (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
2513 == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
2514 // The caller has requested to completely replace any
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002515 // existing task with its new activity. Well that should
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002516 // not be too hard...
2517 reuseTask = taskTop.task;
2518 performClearTaskLocked(taskTop.task.taskId);
2519 reuseTask.setIntent(r.intent, r.info);
2520 } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002521 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
2522 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2523 // In this situation we want to remove all activities
2524 // from the task up to the one being started. In most
2525 // cases this means we are resetting the task to its
2526 // initial state.
2527 ActivityRecord top = performClearTaskLocked(
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002528 taskTop.task.taskId, r, launchFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002529 if (top != null) {
2530 if (top.frontOfTask) {
2531 // Activity aliases may mean we use different
2532 // intents for the top activity, so make sure
2533 // the task now has the identity of the new
2534 // intent.
2535 top.task.setIntent(r.intent, r.info);
2536 }
2537 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002538 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002539 } else {
2540 // A special case: we need to
2541 // start the activity because it is not currently
2542 // running, and the caller has asked to clear the
2543 // current task to have this activity at the top.
2544 addingToTask = true;
2545 // Now pretend like this activity is being started
2546 // by the top of its task, so it is put in the
2547 // right place.
2548 sourceRecord = taskTop;
2549 }
2550 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
2551 // In this case the top activity on the task is the
2552 // same as the one being launched, so we take that
2553 // as a request to bring the task to the foreground.
2554 // If the top activity in the task is the root
2555 // activity, deliver this new intent to it if it
2556 // desires.
2557 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
2558 && taskTop.realActivity.equals(r.realActivity)) {
2559 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
2560 if (taskTop.frontOfTask) {
2561 taskTop.task.setIntent(r.intent, r.info);
2562 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002563 taskTop.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002564 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
2565 // In this case we are launching the root activity
2566 // of the task, but with a different intent. We
2567 // should start a new instance on top.
2568 addingToTask = true;
2569 sourceRecord = taskTop;
2570 }
2571 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
2572 // In this case an activity is being launched in to an
2573 // existing task, without resetting that task. This
2574 // is typically the situation of launching an activity
2575 // from a notification or shortcut. We want to place
2576 // the new activity on top of the current task.
2577 addingToTask = true;
2578 sourceRecord = taskTop;
2579 } else if (!taskTop.task.rootWasReset) {
2580 // In this case we are launching in to an existing task
2581 // that has not yet been started from its front door.
2582 // The current task has been brought to the front.
2583 // Ideally, we'd probably like to place this new task
2584 // at the bottom of its stack, but that's a little hard
2585 // to do with the current organization of the code so
2586 // for now we'll just drop it.
2587 taskTop.task.setIntent(r.intent, r.info);
2588 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002589 if (!addingToTask && reuseTask == null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002590 // We didn't do anything... but it was needed (a.k.a., client
2591 // don't use that intent!) And for paranoia, make
2592 // sure we have correctly resumed the top activity.
2593 if (doResume) {
2594 resumeTopActivityLocked(null);
2595 }
2596 return START_TASK_TO_FRONT;
2597 }
2598 }
2599 }
2600 }
2601
2602 //String uri = r.intent.toURI();
2603 //Intent intent2 = new Intent(uri);
2604 //Slog.i(TAG, "Given intent: " + r.intent);
2605 //Slog.i(TAG, "URI is: " + uri);
2606 //Slog.i(TAG, "To intent: " + intent2);
2607
2608 if (r.packageName != null) {
2609 // If the activity being launched is the same as the one currently
2610 // at the top, then we need to check if it should only be launched
2611 // once.
2612 ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
2613 if (top != null && r.resultTo == null) {
2614 if (top.realActivity.equals(r.realActivity)) {
2615 if (top.app != null && top.app.thread != null) {
2616 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
2617 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
2618 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
2619 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
2620 // For paranoia, make sure we have correctly
2621 // resumed the top activity.
2622 if (doResume) {
2623 resumeTopActivityLocked(null);
2624 }
2625 if (onlyIfNeeded) {
2626 // We don't need to start a new activity, and
2627 // the client said not to do anything if that
2628 // is the case, so this is it!
2629 return START_RETURN_INTENT_TO_CALLER;
2630 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002631 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002632 return START_DELIVERED_TO_TOP;
2633 }
2634 }
2635 }
2636 }
2637
2638 } else {
2639 if (r.resultTo != null) {
2640 sendActivityResultLocked(-1,
2641 r.resultTo, r.resultWho, r.requestCode,
2642 Activity.RESULT_CANCELED, null);
2643 }
2644 return START_CLASS_NOT_FOUND;
2645 }
2646
2647 boolean newTask = false;
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002648 boolean keepCurTransition = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002649
2650 // Should this be considered a new task?
2651 if (r.resultTo == null && !addingToTask
2652 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002653 if (reuseTask == null) {
2654 // todo: should do better management of integers.
2655 mService.mCurTask++;
2656 if (mService.mCurTask <= 0) {
2657 mService.mCurTask = 1;
2658 }
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002659 r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002660 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2661 + " in new task " + r.task);
2662 } else {
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002663 r.setTask(reuseTask, reuseTask, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002664 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002665 newTask = true;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002666 moveHomeToFrontFromLaunchLocked(launchFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002667
2668 } else if (sourceRecord != null) {
2669 if (!addingToTask &&
2670 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
2671 // In this case, we are adding the activity to an existing
2672 // task, but the caller has asked to clear that task if the
2673 // activity is already running.
2674 ActivityRecord top = performClearTaskLocked(
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002675 sourceRecord.task.taskId, r, launchFlags);
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002676 keepCurTransition = true;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002677 if (top != null) {
2678 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002679 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002680 // For paranoia, make sure we have correctly
2681 // resumed the top activity.
2682 if (doResume) {
2683 resumeTopActivityLocked(null);
2684 }
2685 return START_DELIVERED_TO_TOP;
2686 }
2687 } else if (!addingToTask &&
2688 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
2689 // In this case, we are launching an activity in our own task
2690 // that may already be running somewhere in the history, and
2691 // we want to shuffle it to the front of the stack if so.
2692 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
2693 if (where >= 0) {
2694 ActivityRecord top = moveActivityToFrontLocked(where);
2695 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002696 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002697 if (doResume) {
2698 resumeTopActivityLocked(null);
2699 }
2700 return START_DELIVERED_TO_TOP;
2701 }
2702 }
2703 // An existing activity is starting this new activity, so we want
2704 // to keep the new one in the same task as the one that is starting
2705 // it.
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002706 r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002707 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2708 + " in existing task " + r.task);
2709
2710 } else {
2711 // This not being started from an existing activity, and not part
2712 // of a new task... just put it in the top task, though these days
2713 // this case should never happen.
2714 final int N = mHistory.size();
2715 ActivityRecord prev =
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002716 N > 0 ? mHistory.get(N-1) : null;
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002717 r.setTask(prev != null
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002718 ? prev.task
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002719 : new TaskRecord(mService.mCurTask, r.info, intent), null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002720 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2721 + " in new guessed " + r.task);
2722 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002723
2724 if (grantedUriPermissions != null && callingUid > 0) {
2725 for (int i=0; i<grantedUriPermissions.length; i++) {
2726 mService.grantUriPermissionLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002727 grantedUriPermissions[i], grantedMode, r.getUriPermissionsLocked());
Dianne Hackborn39792d22010-08-19 18:01:52 -07002728 }
2729 }
2730
2731 mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002732 intent, r.getUriPermissionsLocked());
Dianne Hackborn39792d22010-08-19 18:01:52 -07002733
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002734 if (newTask) {
2735 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
2736 }
2737 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002738 startActivityLocked(r, newTask, doResume, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002739 return START_SUCCESS;
2740 }
2741
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002742 ActivityInfo resolveActivity(Intent intent, String resolvedType, boolean debug,
2743 String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002744 // Collect information about the target of the Intent.
2745 ActivityInfo aInfo;
2746 try {
2747 ResolveInfo rInfo =
2748 AppGlobals.getPackageManager().resolveIntent(
2749 intent, resolvedType,
2750 PackageManager.MATCH_DEFAULT_ONLY
2751 | ActivityManagerService.STOCK_PM_FLAGS);
2752 aInfo = rInfo != null ? rInfo.activityInfo : null;
2753 } catch (RemoteException e) {
2754 aInfo = null;
2755 }
2756
2757 if (aInfo != null) {
2758 // Store the found target back into the intent, because now that
2759 // we have it we never want to do this again. For example, if the
2760 // user navigates back to this point in the history, we should
2761 // always restart the exact same activity.
2762 intent.setComponent(new ComponentName(
2763 aInfo.applicationInfo.packageName, aInfo.name));
2764
2765 // Don't debug things in the system process
2766 if (debug) {
2767 if (!aInfo.processName.equals("system")) {
2768 mService.setDebugApp(aInfo.processName, true, false);
2769 }
2770 }
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002771
2772 if (profileFile != null) {
2773 if (!aInfo.processName.equals("system")) {
2774 mService.setProfileApp(aInfo.applicationInfo, aInfo.processName,
2775 profileFile, profileFd, autoStopProfiler);
2776 }
2777 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002778 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002779 return aInfo;
2780 }
2781
2782 final int startActivityMayWait(IApplicationThread caller, int callingUid,
2783 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
2784 int grantedMode, IBinder resultTo,
2785 String resultWho, int requestCode, boolean onlyIfNeeded,
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002786 boolean debug, String profileFile, ParcelFileDescriptor profileFd,
2787 boolean autoStopProfiler, WaitResult outResult, Configuration config) {
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002788 // Refuse possible leaked file descriptors
2789 if (intent != null && intent.hasFileDescriptors()) {
2790 throw new IllegalArgumentException("File descriptors passed in Intent");
2791 }
2792
2793 boolean componentSpecified = intent.getComponent() != null;
2794
2795 // Don't modify the client's object!
2796 intent = new Intent(intent);
2797
2798 // Collect information about the target of the Intent.
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002799 ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug,
2800 profileFile, profileFd, autoStopProfiler);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002801
2802 synchronized (mService) {
2803 int callingPid;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002804 if (callingUid >= 0) {
2805 callingPid = -1;
2806 } else if (caller == null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002807 callingPid = Binder.getCallingPid();
2808 callingUid = Binder.getCallingUid();
2809 } else {
2810 callingPid = callingUid = -1;
2811 }
2812
2813 mConfigWillChange = config != null
2814 && mService.mConfiguration.diff(config) != 0;
2815 if (DEBUG_CONFIGURATION) Slog.v(TAG,
2816 "Starting activity when config will change = " + mConfigWillChange);
2817
2818 final long origId = Binder.clearCallingIdentity();
2819
2820 if (mMainStack && aInfo != null &&
Dianne Hackborn54e570f2010-10-04 18:32:32 -07002821 (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002822 // This may be a heavy-weight process! Check to see if we already
2823 // have another, different heavy-weight process running.
2824 if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
2825 if (mService.mHeavyWeightProcess != null &&
2826 (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
2827 !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
2828 int realCallingPid = callingPid;
2829 int realCallingUid = callingUid;
2830 if (caller != null) {
2831 ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
2832 if (callerApp != null) {
2833 realCallingPid = callerApp.pid;
2834 realCallingUid = callerApp.info.uid;
2835 } else {
2836 Slog.w(TAG, "Unable to find app for caller " + caller
2837 + " (pid=" + realCallingPid + ") when starting: "
2838 + intent.toString());
2839 return START_PERMISSION_DENIED;
2840 }
2841 }
2842
2843 IIntentSender target = mService.getIntentSenderLocked(
2844 IActivityManager.INTENT_SENDER_ACTIVITY, "android",
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002845 realCallingUid, null, null, 0, new Intent[] { intent },
2846 new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002847 | PendingIntent.FLAG_ONE_SHOT);
2848
2849 Intent newIntent = new Intent();
2850 if (requestCode >= 0) {
2851 // Caller is requesting a result.
2852 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
2853 }
2854 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
2855 new IntentSender(target));
2856 if (mService.mHeavyWeightProcess.activities.size() > 0) {
2857 ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
2858 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
2859 hist.packageName);
2860 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
2861 hist.task.taskId);
2862 }
2863 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
2864 aInfo.packageName);
2865 newIntent.setFlags(intent.getFlags());
2866 newIntent.setClassName("android",
2867 HeavyWeightSwitcherActivity.class.getName());
2868 intent = newIntent;
2869 resolvedType = null;
2870 caller = null;
2871 callingUid = Binder.getCallingUid();
2872 callingPid = Binder.getCallingPid();
2873 componentSpecified = true;
2874 try {
2875 ResolveInfo rInfo =
2876 AppGlobals.getPackageManager().resolveIntent(
2877 intent, null,
2878 PackageManager.MATCH_DEFAULT_ONLY
2879 | ActivityManagerService.STOCK_PM_FLAGS);
2880 aInfo = rInfo != null ? rInfo.activityInfo : null;
2881 } catch (RemoteException e) {
2882 aInfo = null;
2883 }
2884 }
2885 }
2886 }
2887
2888 int res = startActivityLocked(caller, intent, resolvedType,
2889 grantedUriPermissions, grantedMode, aInfo,
2890 resultTo, resultWho, requestCode, callingPid, callingUid,
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002891 onlyIfNeeded, componentSpecified, null);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002892
2893 if (mConfigWillChange && mMainStack) {
2894 // If the caller also wants to switch to a new configuration,
2895 // do so now. This allows a clean switch, as we are waiting
2896 // for the current activity to pause (so we will not destroy
2897 // it), and have not yet started the next activity.
2898 mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
2899 "updateConfiguration()");
2900 mConfigWillChange = false;
2901 if (DEBUG_CONFIGURATION) Slog.v(TAG,
2902 "Updating to new configuration after starting activity.");
Dianne Hackborn31ca8542011-07-19 14:58:28 -07002903 mService.updateConfigurationLocked(config, null, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002904 }
2905
2906 Binder.restoreCallingIdentity(origId);
2907
2908 if (outResult != null) {
2909 outResult.result = res;
2910 if (res == IActivityManager.START_SUCCESS) {
2911 mWaitingActivityLaunched.add(outResult);
2912 do {
2913 try {
Dianne Hackbornba0492d2010-10-12 19:01:46 -07002914 mService.wait();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002915 } catch (InterruptedException e) {
2916 }
2917 } while (!outResult.timeout && outResult.who == null);
2918 } else if (res == IActivityManager.START_TASK_TO_FRONT) {
2919 ActivityRecord r = this.topRunningActivityLocked(null);
2920 if (r.nowVisible) {
2921 outResult.timeout = false;
2922 outResult.who = new ComponentName(r.info.packageName, r.info.name);
2923 outResult.totalTime = 0;
2924 outResult.thisTime = 0;
2925 } else {
2926 outResult.thisTime = SystemClock.uptimeMillis();
2927 mWaitingActivityVisible.add(outResult);
2928 do {
2929 try {
Dianne Hackbornba0492d2010-10-12 19:01:46 -07002930 mService.wait();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002931 } catch (InterruptedException e) {
2932 }
2933 } while (!outResult.timeout && outResult.who == null);
2934 }
2935 }
2936 }
2937
2938 return res;
2939 }
2940 }
2941
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002942 final int startActivities(IApplicationThread caller, int callingUid,
2943 Intent[] intents, String[] resolvedTypes, IBinder resultTo) {
2944 if (intents == null) {
2945 throw new NullPointerException("intents is null");
2946 }
2947 if (resolvedTypes == null) {
2948 throw new NullPointerException("resolvedTypes is null");
2949 }
2950 if (intents.length != resolvedTypes.length) {
2951 throw new IllegalArgumentException("intents are length different than resolvedTypes");
2952 }
2953
2954 ActivityRecord[] outActivity = new ActivityRecord[1];
2955
2956 int callingPid;
2957 if (callingUid >= 0) {
2958 callingPid = -1;
2959 } else if (caller == null) {
2960 callingPid = Binder.getCallingPid();
2961 callingUid = Binder.getCallingUid();
2962 } else {
2963 callingPid = callingUid = -1;
2964 }
2965 final long origId = Binder.clearCallingIdentity();
2966 try {
2967 synchronized (mService) {
2968
2969 for (int i=0; i<intents.length; i++) {
2970 Intent intent = intents[i];
2971 if (intent == null) {
2972 continue;
2973 }
2974
2975 // Refuse possible leaked file descriptors
2976 if (intent != null && intent.hasFileDescriptors()) {
2977 throw new IllegalArgumentException("File descriptors passed in Intent");
2978 }
2979
2980 boolean componentSpecified = intent.getComponent() != null;
2981
2982 // Don't modify the client's object!
2983 intent = new Intent(intent);
2984
2985 // Collect information about the target of the Intent.
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002986 ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], false,
2987 null, null, false);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002988
2989 if (mMainStack && aInfo != null && (aInfo.applicationInfo.flags
2990 & ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
2991 throw new IllegalArgumentException(
2992 "FLAG_CANT_SAVE_STATE not supported here");
2993 }
2994
2995 int res = startActivityLocked(caller, intent, resolvedTypes[i],
2996 null, 0, aInfo, resultTo, null, -1, callingPid, callingUid,
2997 false, componentSpecified, outActivity);
2998 if (res < 0) {
2999 return res;
3000 }
3001
3002 resultTo = outActivity[0];
3003 }
3004 }
3005 } finally {
3006 Binder.restoreCallingIdentity(origId);
3007 }
3008
3009 return IActivityManager.START_SUCCESS;
3010 }
3011
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003012 void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r,
3013 long thisTime, long totalTime) {
3014 for (int i=mWaitingActivityLaunched.size()-1; i>=0; i--) {
3015 WaitResult w = mWaitingActivityLaunched.get(i);
3016 w.timeout = timeout;
3017 if (r != null) {
3018 w.who = new ComponentName(r.info.packageName, r.info.name);
3019 }
3020 w.thisTime = thisTime;
3021 w.totalTime = totalTime;
3022 }
3023 mService.notifyAll();
3024 }
3025
3026 void reportActivityVisibleLocked(ActivityRecord r) {
3027 for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
3028 WaitResult w = mWaitingActivityVisible.get(i);
3029 w.timeout = false;
3030 if (r != null) {
3031 w.who = new ComponentName(r.info.packageName, r.info.name);
3032 }
3033 w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
3034 w.thisTime = w.totalTime;
3035 }
3036 mService.notifyAll();
Dianne Hackborn90c52de2011-09-23 12:57:44 -07003037
3038 if (mDismissKeyguardOnNextActivity) {
3039 mDismissKeyguardOnNextActivity = false;
3040 mService.mWindowManager.dismissKeyguard();
3041 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003042 }
3043
3044 void sendActivityResultLocked(int callingUid, ActivityRecord r,
3045 String resultWho, int requestCode, int resultCode, Intent data) {
3046
3047 if (callingUid > 0) {
3048 mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07003049 data, r.getUriPermissionsLocked());
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003050 }
3051
3052 if (DEBUG_RESULTS) Slog.v(TAG, "Send activity result to " + r
3053 + " : who=" + resultWho + " req=" + requestCode
3054 + " res=" + resultCode + " data=" + data);
3055 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3056 try {
3057 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3058 list.add(new ResultInfo(resultWho, requestCode,
3059 resultCode, data));
3060 r.app.thread.scheduleSendResult(r, list);
3061 return;
3062 } catch (Exception e) {
3063 Slog.w(TAG, "Exception thrown sending result to " + r, e);
3064 }
3065 }
3066
3067 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3068 }
3069
3070 private final void stopActivityLocked(ActivityRecord r) {
3071 if (DEBUG_SWITCH) Slog.d(TAG, "Stopping: " + r);
3072 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3073 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3074 if (!r.finishing) {
3075 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3076 "no-history");
3077 }
3078 } else if (r.app != null && r.app.thread != null) {
3079 if (mMainStack) {
3080 if (mService.mFocusedActivity == r) {
3081 mService.setFocusedActivityLocked(topRunningActivityLocked(null));
3082 }
3083 }
3084 r.resumeKeyDispatchingLocked();
3085 try {
3086 r.stopped = false;
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003087 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
3088 + " (stop requested)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003089 r.state = ActivityState.STOPPING;
3090 if (DEBUG_VISBILITY) Slog.v(
3091 TAG, "Stopping visible=" + r.visible + " for " + r);
3092 if (!r.visible) {
3093 mService.mWindowManager.setAppVisibility(r, false);
3094 }
3095 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003096 if (mService.isSleeping()) {
3097 r.setSleeping(true);
3098 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003099 } catch (Exception e) {
3100 // Maybe just ignore exceptions here... if the process
3101 // has crashed, our death notification will clean things
3102 // up.
3103 Slog.w(TAG, "Exception thrown during pause", e);
3104 // Just in case, assume it to be stopped.
3105 r.stopped = true;
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003106 if (DEBUG_STATES) Slog.v(TAG, "Stop failed; moving to STOPPED: " + r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003107 r.state = ActivityState.STOPPED;
3108 if (r.configDestroy) {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003109 destroyActivityLocked(r, true, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003110 }
3111 }
3112 }
3113 }
3114
3115 final ArrayList<ActivityRecord> processStoppingActivitiesLocked(
3116 boolean remove) {
3117 int N = mStoppingActivities.size();
3118 if (N <= 0) return null;
3119
3120 ArrayList<ActivityRecord> stops = null;
3121
3122 final boolean nowVisible = mResumedActivity != null
3123 && mResumedActivity.nowVisible
3124 && !mResumedActivity.waitingVisible;
3125 for (int i=0; i<N; i++) {
3126 ActivityRecord s = mStoppingActivities.get(i);
3127 if (localLOGV) Slog.v(TAG, "Stopping " + s + ": nowVisible="
3128 + nowVisible + " waitingVisible=" + s.waitingVisible
3129 + " finishing=" + s.finishing);
3130 if (s.waitingVisible && nowVisible) {
3131 mWaitingVisibleActivities.remove(s);
3132 s.waitingVisible = false;
3133 if (s.finishing) {
3134 // If this activity is finishing, it is sitting on top of
3135 // everyone else but we now know it is no longer needed...
3136 // so get rid of it. Otherwise, we need to go through the
3137 // normal flow and hide it once we determine that it is
3138 // hidden by the activities in front of it.
3139 if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
3140 mService.mWindowManager.setAppVisibility(s, false);
3141 }
3142 }
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003143 if ((!s.waitingVisible || mService.isSleeping()) && remove) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003144 if (localLOGV) Slog.v(TAG, "Ready to stop: " + s);
3145 if (stops == null) {
3146 stops = new ArrayList<ActivityRecord>();
3147 }
3148 stops.add(s);
3149 mStoppingActivities.remove(i);
3150 N--;
3151 i--;
3152 }
3153 }
3154
3155 return stops;
3156 }
3157
Dianne Hackborn80a7ac12011-09-22 18:32:52 -07003158 final void scheduleIdleLocked() {
3159 Message msg = Message.obtain();
3160 msg.what = IDLE_NOW_MSG;
3161 mHandler.sendMessage(msg);
3162 }
3163
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003164 final ActivityRecord activityIdleInternal(IBinder token, boolean fromTimeout,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003165 Configuration config) {
3166 if (localLOGV) Slog.v(TAG, "Activity idle: " + token);
3167
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003168 ActivityRecord res = null;
3169
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003170 ArrayList<ActivityRecord> stops = null;
3171 ArrayList<ActivityRecord> finishes = null;
3172 ArrayList<ActivityRecord> thumbnails = null;
3173 int NS = 0;
3174 int NF = 0;
3175 int NT = 0;
3176 IApplicationThread sendThumbnail = null;
3177 boolean booting = false;
3178 boolean enableScreen = false;
3179
3180 synchronized (mService) {
3181 if (token != null) {
3182 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
3183 }
3184
3185 // Get the activity record.
3186 int index = indexOfTokenLocked(token);
3187 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003188 ActivityRecord r = mHistory.get(index);
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003189 res = r;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003190
3191 if (fromTimeout) {
3192 reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
3193 }
3194
3195 // This is a hack to semi-deal with a race condition
3196 // in the client where it can be constructed with a
3197 // newer configuration from when we asked it to launch.
3198 // We'll update with whatever configuration it now says
3199 // it used to launch.
3200 if (config != null) {
3201 r.configuration = config;
3202 }
3203
3204 // No longer need to keep the device awake.
3205 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
3206 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
3207 mLaunchingActivity.release();
3208 }
3209
3210 // We are now idle. If someone is waiting for a thumbnail from
3211 // us, we can now deliver.
3212 r.idle = true;
3213 mService.scheduleAppGcsLocked();
3214 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
3215 sendThumbnail = r.app.thread;
3216 r.thumbnailNeeded = false;
3217 }
3218
3219 // If this activity is fullscreen, set up to hide those under it.
3220
3221 if (DEBUG_VISBILITY) Slog.v(TAG, "Idle activity for " + r);
3222 ensureActivitiesVisibleLocked(null, 0);
3223
3224 //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
3225 if (mMainStack) {
Dianne Hackborn29aae6f2011-08-18 18:30:09 -07003226 if (!mService.mBooted) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003227 mService.mBooted = true;
3228 enableScreen = true;
3229 }
3230 }
3231
3232 } else if (fromTimeout) {
3233 reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
3234 }
3235
3236 // Atomically retrieve all of the other things to do.
3237 stops = processStoppingActivitiesLocked(true);
3238 NS = stops != null ? stops.size() : 0;
3239 if ((NF=mFinishingActivities.size()) > 0) {
3240 finishes = new ArrayList<ActivityRecord>(mFinishingActivities);
3241 mFinishingActivities.clear();
3242 }
3243 if ((NT=mService.mCancelledThumbnails.size()) > 0) {
3244 thumbnails = new ArrayList<ActivityRecord>(mService.mCancelledThumbnails);
3245 mService.mCancelledThumbnails.clear();
3246 }
3247
3248 if (mMainStack) {
3249 booting = mService.mBooting;
3250 mService.mBooting = false;
3251 }
3252 }
3253
3254 int i;
3255
3256 // Send thumbnail if requested.
3257 if (sendThumbnail != null) {
3258 try {
3259 sendThumbnail.requestThumbnail(token);
3260 } catch (Exception e) {
3261 Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
3262 mService.sendPendingThumbnail(null, token, null, null, true);
3263 }
3264 }
3265
3266 // Stop any activities that are scheduled to do so but have been
3267 // waiting for the next one to start.
3268 for (i=0; i<NS; i++) {
3269 ActivityRecord r = (ActivityRecord)stops.get(i);
3270 synchronized (mService) {
3271 if (r.finishing) {
3272 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
3273 } else {
3274 stopActivityLocked(r);
3275 }
3276 }
3277 }
3278
3279 // Finish any activities that are scheduled to do so but have been
3280 // waiting for the next one to start.
3281 for (i=0; i<NF; i++) {
3282 ActivityRecord r = (ActivityRecord)finishes.get(i);
3283 synchronized (mService) {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003284 destroyActivityLocked(r, true, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003285 }
3286 }
3287
3288 // Report back to any thumbnail receivers.
3289 for (i=0; i<NT; i++) {
3290 ActivityRecord r = (ActivityRecord)thumbnails.get(i);
3291 mService.sendPendingThumbnail(r, null, null, null, true);
3292 }
3293
3294 if (booting) {
3295 mService.finishBooting();
3296 }
3297
3298 mService.trimApplications();
3299 //dump();
3300 //mWindowManager.dump();
3301
3302 if (enableScreen) {
3303 mService.enableScreenAfterBoot();
3304 }
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003305
3306 return res;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003307 }
3308
3309 /**
3310 * @return Returns true if the activity is being finished, false if for
3311 * some reason it is being left as-is.
3312 */
3313 final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3314 Intent resultData, String reason) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003315 int index = indexOfTokenLocked(token);
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07003316 if (DEBUG_RESULTS) Slog.v(
3317 TAG, "Finishing activity @" + index + ": token=" + token
3318 + ", result=" + resultCode + ", data=" + resultData);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003319 if (index < 0) {
3320 return false;
3321 }
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003322 ActivityRecord r = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003323
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003324 finishActivityLocked(r, index, resultCode, resultData, reason);
3325 return true;
3326 }
3327
3328 /**
3329 * @return Returns true if this activity has been removed from the history
3330 * list, or false if it is still in the list and will be removed later.
3331 */
3332 final boolean finishActivityLocked(ActivityRecord r, int index,
3333 int resultCode, Intent resultData, String reason) {
3334 if (r.finishing) {
3335 Slog.w(TAG, "Duplicate finish request for " + r);
3336 return false;
3337 }
3338
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -08003339 r.makeFinishing();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003340 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
3341 System.identityHashCode(r),
3342 r.task.taskId, r.shortComponentName, reason);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003343 if (index < (mHistory.size()-1)) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003344 ActivityRecord next = mHistory.get(index+1);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003345 if (next.task == r.task) {
3346 if (r.frontOfTask) {
3347 // The next activity is now the front of the task.
3348 next.frontOfTask = true;
3349 }
3350 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
3351 // If the caller asked that this activity (and all above it)
3352 // be cleared when the task is reset, don't lose that information,
3353 // but propagate it up to the next activity.
3354 next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
3355 }
3356 }
3357 }
3358
3359 r.pauseKeyDispatchingLocked();
3360 if (mMainStack) {
3361 if (mService.mFocusedActivity == r) {
3362 mService.setFocusedActivityLocked(topRunningActivityLocked(null));
3363 }
3364 }
3365
3366 // send the result
3367 ActivityRecord resultTo = r.resultTo;
3368 if (resultTo != null) {
3369 if (DEBUG_RESULTS) Slog.v(TAG, "Adding result to " + resultTo
3370 + " who=" + r.resultWho + " req=" + r.requestCode
3371 + " res=" + resultCode + " data=" + resultData);
3372 if (r.info.applicationInfo.uid > 0) {
3373 mService.grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
Dianne Hackborna1c69e02010-09-01 22:55:02 -07003374 resultTo.packageName, resultData,
3375 resultTo.getUriPermissionsLocked());
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003376 }
3377 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3378 resultData);
3379 r.resultTo = null;
3380 }
3381 else if (DEBUG_RESULTS) Slog.v(TAG, "No result destination from " + r);
3382
3383 // Make sure this HistoryRecord is not holding on to other resources,
3384 // because clients have remote IPC references to this object so we
3385 // can't assume that will go away and want to avoid circular IPC refs.
3386 r.results = null;
3387 r.pendingResults = null;
3388 r.newIntents = null;
3389 r.icicle = null;
3390
3391 if (mService.mPendingThumbnails.size() > 0) {
3392 // There are clients waiting to receive thumbnails so, in case
3393 // this is an activity that someone is waiting for, add it
3394 // to the pending list so we can correctly update the clients.
3395 mService.mCancelledThumbnails.add(r);
3396 }
3397
3398 if (mResumedActivity == r) {
3399 boolean endTask = index <= 0
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003400 || (mHistory.get(index-1)).task != r.task;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003401 if (DEBUG_TRANSITION) Slog.v(TAG,
3402 "Prepare close transition: finishing " + r);
3403 mService.mWindowManager.prepareAppTransition(endTask
3404 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003405 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003406
3407 // Tell window manager to prepare for this one to be removed.
3408 mService.mWindowManager.setAppVisibility(r, false);
3409
3410 if (mPausingActivity == null) {
3411 if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
3412 if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
3413 startPausingLocked(false, false);
3414 }
3415
3416 } else if (r.state != ActivityState.PAUSING) {
3417 // If the activity is PAUSING, we will complete the finish once
3418 // it is done pausing; else we can just directly finish it here.
3419 if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
3420 return finishCurrentActivityLocked(r, index,
3421 FINISH_AFTER_PAUSE) == null;
3422 } else {
3423 if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
3424 }
3425
3426 return false;
3427 }
3428
3429 private static final int FINISH_IMMEDIATELY = 0;
3430 private static final int FINISH_AFTER_PAUSE = 1;
3431 private static final int FINISH_AFTER_VISIBLE = 2;
3432
3433 private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
3434 int mode) {
3435 final int index = indexOfTokenLocked(r);
3436 if (index < 0) {
3437 return null;
3438 }
3439
3440 return finishCurrentActivityLocked(r, index, mode);
3441 }
3442
3443 private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
3444 int index, int mode) {
3445 // First things first: if this activity is currently visible,
3446 // and the resumed activity is not yet visible, then hold off on
3447 // finishing until the resumed one becomes visible.
3448 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3449 if (!mStoppingActivities.contains(r)) {
3450 mStoppingActivities.add(r);
3451 if (mStoppingActivities.size() > 3) {
3452 // If we already have a few activities waiting to stop,
3453 // then give up on things going idle and start clearing
3454 // them out.
Dianne Hackborn80a7ac12011-09-22 18:32:52 -07003455 scheduleIdleLocked();
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003456 } else {
3457 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003458 }
3459 }
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003460 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
3461 + " (finish requested)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003462 r.state = ActivityState.STOPPING;
3463 mService.updateOomAdjLocked();
3464 return r;
3465 }
3466
3467 // make sure the record is cleaned out of other places.
3468 mStoppingActivities.remove(r);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003469 mGoingToSleepActivities.remove(r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003470 mWaitingVisibleActivities.remove(r);
3471 if (mResumedActivity == r) {
3472 mResumedActivity = null;
3473 }
3474 final ActivityState prevState = r.state;
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003475 if (DEBUG_STATES) Slog.v(TAG, "Moving to FINISHING: " + r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003476 r.state = ActivityState.FINISHING;
3477
3478 if (mode == FINISH_IMMEDIATELY
3479 || prevState == ActivityState.STOPPED
3480 || prevState == ActivityState.INITIALIZING) {
3481 // If this activity is already stopped, we can just finish
3482 // it right now.
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003483 return destroyActivityLocked(r, true, true) ? null : r;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003484 } else {
3485 // Need to go through the full pause cycle to get this
3486 // activity into the stopped state and then finish it.
3487 if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
3488 mFinishingActivities.add(r);
3489 resumeTopActivityLocked(null);
3490 }
3491 return r;
3492 }
3493
3494 /**
3495 * Perform the common clean-up of an activity record. This is called both
3496 * as part of destroyActivityLocked() (when destroying the client-side
3497 * representation) and cleaning things up as a result of its hosting
3498 * processing going away, in which case there is no remaining client-side
3499 * state to destroy so only the cleanup here is needed.
3500 */
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003501 final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices,
3502 boolean setState) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003503 if (mResumedActivity == r) {
3504 mResumedActivity = null;
3505 }
3506 if (mService.mFocusedActivity == r) {
3507 mService.mFocusedActivity = null;
3508 }
3509
3510 r.configDestroy = false;
3511 r.frozenBeforeDestroy = false;
3512
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003513 if (setState) {
3514 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (cleaning up)");
3515 r.state = ActivityState.DESTROYED;
3516 }
3517
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003518 // Make sure this record is no longer in the pending finishes list.
3519 // This could happen, for example, if we are trimming activities
3520 // down to the max limit while they are still waiting to finish.
3521 mFinishingActivities.remove(r);
3522 mWaitingVisibleActivities.remove(r);
3523
3524 // Remove any pending results.
3525 if (r.finishing && r.pendingResults != null) {
3526 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
3527 PendingIntentRecord rec = apr.get();
3528 if (rec != null) {
3529 mService.cancelIntentSenderLocked(rec, false);
3530 }
3531 }
3532 r.pendingResults = null;
3533 }
3534
3535 if (cleanServices) {
3536 cleanUpActivityServicesLocked(r);
3537 }
3538
3539 if (mService.mPendingThumbnails.size() > 0) {
3540 // There are clients waiting to receive thumbnails so, in case
3541 // this is an activity that someone is waiting for, add it
3542 // to the pending list so we can correctly update the clients.
3543 mService.mCancelledThumbnails.add(r);
3544 }
3545
3546 // Get rid of any pending idle timeouts.
3547 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
3548 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003549 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003550 }
3551
3552 private final void removeActivityFromHistoryLocked(ActivityRecord r) {
3553 if (r.state != ActivityState.DESTROYED) {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -08003554 r.makeFinishing();
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07003555 if (DEBUG_ADD_REMOVE) {
3556 RuntimeException here = new RuntimeException("here");
3557 here.fillInStackTrace();
3558 Slog.i(TAG, "Removing activity " + r + " from stack");
3559 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003560 mHistory.remove(r);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07003561 r.takeFromHistory();
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003562 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
3563 + " (removed from history)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003564 r.state = ActivityState.DESTROYED;
3565 mService.mWindowManager.removeAppToken(r);
3566 if (VALIDATE_TOKENS) {
3567 mService.mWindowManager.validateAppTokens(mHistory);
3568 }
3569 cleanUpActivityServicesLocked(r);
3570 r.removeUriPermissionsLocked();
3571 }
3572 }
3573
3574 /**
3575 * Perform clean-up of service connections in an activity record.
3576 */
3577 final void cleanUpActivityServicesLocked(ActivityRecord r) {
3578 // Throw away any services that have been bound by this activity.
3579 if (r.connections != null) {
3580 Iterator<ConnectionRecord> it = r.connections.iterator();
3581 while (it.hasNext()) {
3582 ConnectionRecord c = it.next();
3583 mService.removeConnectionLocked(c, null, r);
3584 }
3585 r.connections = null;
3586 }
3587 }
3588
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003589 final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj) {
3590 for (int i=mHistory.size()-1; i>=0; i--) {
3591 ActivityRecord r = mHistory.get(i);
3592 if (owner != null && r.app != owner) {
3593 continue;
3594 }
3595 // We can destroy this one if we have its icicle saved and
3596 // it is not in the process of pausing/stopping/finishing.
3597 if (r.app != null && r.haveState && !r.visible && r.stopped && !r.finishing
3598 && r.state != ActivityState.DESTROYING
3599 && r.state != ActivityState.DESTROYED) {
3600 destroyActivityLocked(r, true, oomAdj);
3601 }
3602 }
3603 }
3604
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003605 /**
3606 * Destroy the current CLIENT SIDE instance of an activity. This may be
3607 * called both when actually finishing an activity, or when performing
3608 * a configuration switch where we destroy the current client-side object
3609 * but then create a new client-side object for this same HistoryRecord.
3610 */
3611 final boolean destroyActivityLocked(ActivityRecord r,
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003612 boolean removeFromApp, boolean oomAdj) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003613 if (DEBUG_SWITCH) Slog.v(
3614 TAG, "Removing activity: token=" + r
3615 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
3616 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
3617 System.identityHashCode(r),
3618 r.task.taskId, r.shortComponentName);
3619
3620 boolean removedFromHistory = false;
3621
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003622 cleanUpActivityLocked(r, false, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003623
3624 final boolean hadApp = r.app != null;
3625
3626 if (hadApp) {
3627 if (removeFromApp) {
3628 int idx = r.app.activities.indexOf(r);
3629 if (idx >= 0) {
3630 r.app.activities.remove(idx);
3631 }
3632 if (mService.mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) {
3633 mService.mHeavyWeightProcess = null;
3634 mService.mHandler.sendEmptyMessage(
3635 ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
3636 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003637 if (r.app.activities.size() == 0) {
3638 // No longer have activities, so update location in
3639 // LRU list.
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003640 mService.updateLruProcessLocked(r.app, oomAdj, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003641 }
3642 }
3643
3644 boolean skipDestroy = false;
3645
3646 try {
3647 if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
3648 r.app.thread.scheduleDestroyActivity(r, r.finishing,
3649 r.configChangeFlags);
3650 } catch (Exception e) {
3651 // We can just ignore exceptions here... if the process
3652 // has crashed, our death notification will clean things
3653 // up.
3654 //Slog.w(TAG, "Exception thrown during finish", e);
3655 if (r.finishing) {
3656 removeActivityFromHistoryLocked(r);
3657 removedFromHistory = true;
3658 skipDestroy = true;
3659 }
3660 }
3661
3662 r.app = null;
3663 r.nowVisible = false;
3664
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003665 // If the activity is finishing, we need to wait on removing it
3666 // from the list to give it a chance to do its cleanup. During
3667 // that time it may make calls back with its token so we need to
3668 // be able to find it on the list and so we don't want to remove
3669 // it from the list yet. Otherwise, we can just immediately put
3670 // it in the destroyed state since we are not removing it from the
3671 // list.
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003672 if (r.finishing && !skipDestroy) {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003673 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYING: " + r
3674 + " (destroy requested)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003675 r.state = ActivityState.DESTROYING;
3676 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
3677 msg.obj = r;
3678 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
3679 } else {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003680 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
3681 + " (destroy skipped)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003682 r.state = ActivityState.DESTROYED;
3683 }
3684 } else {
3685 // remove this record from the history.
3686 if (r.finishing) {
3687 removeActivityFromHistoryLocked(r);
3688 removedFromHistory = true;
3689 } else {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003690 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
3691 + " (no app)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003692 r.state = ActivityState.DESTROYED;
3693 }
3694 }
3695
3696 r.configChangeFlags = 0;
3697
3698 if (!mLRUActivities.remove(r) && hadApp) {
3699 Slog.w(TAG, "Activity " + r + " being finished, but not in LRU list");
3700 }
3701
3702 return removedFromHistory;
3703 }
3704
3705 final void activityDestroyed(IBinder token) {
3706 synchronized (mService) {
3707 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
3708
3709 int index = indexOfTokenLocked(token);
3710 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003711 ActivityRecord r = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003712 if (r.state == ActivityState.DESTROYING) {
3713 final long origId = Binder.clearCallingIdentity();
3714 removeActivityFromHistoryLocked(r);
3715 Binder.restoreCallingIdentity(origId);
3716 }
3717 }
3718 }
3719 }
3720
3721 private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
3722 int i = list.size();
3723 if (localLOGV) Slog.v(
3724 TAG, "Removing app " + app + " from list " + list
3725 + " with " + i + " entries");
3726 while (i > 0) {
3727 i--;
3728 ActivityRecord r = (ActivityRecord)list.get(i);
3729 if (localLOGV) Slog.v(
3730 TAG, "Record #" + i + " " + r + ": app=" + r.app);
3731 if (r.app == app) {
3732 if (localLOGV) Slog.v(TAG, "Removing this entry!");
3733 list.remove(i);
3734 }
3735 }
3736 }
3737
3738 void removeHistoryRecordsForAppLocked(ProcessRecord app) {
3739 removeHistoryRecordsForAppLocked(mLRUActivities, app);
3740 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003741 removeHistoryRecordsForAppLocked(mGoingToSleepActivities, app);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003742 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
3743 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
3744 }
3745
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003746 /**
3747 * Move the current home activity's task (if one exists) to the front
3748 * of the stack.
3749 */
3750 final void moveHomeToFrontLocked() {
3751 TaskRecord homeTask = null;
3752 for (int i=mHistory.size()-1; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003753 ActivityRecord hr = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003754 if (hr.isHomeActivity) {
3755 homeTask = hr.task;
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -08003756 break;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003757 }
3758 }
3759 if (homeTask != null) {
3760 moveTaskToFrontLocked(homeTask, null);
3761 }
3762 }
3763
3764
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003765 final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason) {
3766 if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
3767
3768 final int task = tr.taskId;
3769 int top = mHistory.size()-1;
3770
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003771 if (top < 0 || (mHistory.get(top)).task.taskId == task) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003772 // nothing to do!
3773 return;
3774 }
3775
3776 ArrayList moved = new ArrayList();
3777
3778 // Applying the affinities may have removed entries from the history,
3779 // so get the size again.
3780 top = mHistory.size()-1;
3781 int pos = top;
3782
3783 // Shift all activities with this task up to the top
3784 // of the stack, keeping them in the same internal order.
3785 while (pos >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003786 ActivityRecord r = mHistory.get(pos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003787 if (localLOGV) Slog.v(
3788 TAG, "At " + pos + " ckp " + r.task + ": " + r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003789 if (r.task.taskId == task) {
3790 if (localLOGV) Slog.v(TAG, "Removing and adding at " + top);
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07003791 if (DEBUG_ADD_REMOVE) {
3792 RuntimeException here = new RuntimeException("here");
3793 here.fillInStackTrace();
3794 Slog.i(TAG, "Removing and adding activity " + r + " to stack at " + top, here);
3795 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003796 mHistory.remove(pos);
3797 mHistory.add(top, r);
3798 moved.add(0, r);
3799 top--;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003800 }
3801 pos--;
3802 }
3803
3804 if (DEBUG_TRANSITION) Slog.v(TAG,
3805 "Prepare to front transition: task=" + tr);
3806 if (reason != null &&
3807 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003808 mService.mWindowManager.prepareAppTransition(
3809 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003810 ActivityRecord r = topRunningActivityLocked(null);
3811 if (r != null) {
3812 mNoAnimActivities.add(r);
3813 }
3814 } else {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003815 mService.mWindowManager.prepareAppTransition(
3816 WindowManagerPolicy.TRANSIT_TASK_TO_FRONT, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003817 }
3818
3819 mService.mWindowManager.moveAppTokensToTop(moved);
3820 if (VALIDATE_TOKENS) {
3821 mService.mWindowManager.validateAppTokens(mHistory);
3822 }
3823
3824 finishTaskMoveLocked(task);
3825 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
3826 }
3827
3828 private final void finishTaskMoveLocked(int task) {
3829 resumeTopActivityLocked(null);
3830 }
3831
3832 /**
3833 * Worker method for rearranging history stack. Implements the function of moving all
3834 * activities for a specific task (gathering them if disjoint) into a single group at the
3835 * bottom of the stack.
3836 *
3837 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
3838 * to premeptively cancel the move.
3839 *
3840 * @param task The taskId to collect and move to the bottom.
3841 * @return Returns true if the move completed, false if not.
3842 */
3843 final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
3844 Slog.i(TAG, "moveTaskToBack: " + task);
3845
3846 // If we have a watcher, preflight the move before committing to it. First check
3847 // for *other* available tasks, but if none are available, then try again allowing the
3848 // current task to be selected.
3849 if (mMainStack && mService.mController != null) {
3850 ActivityRecord next = topRunningActivityLocked(null, task);
3851 if (next == null) {
3852 next = topRunningActivityLocked(null, 0);
3853 }
3854 if (next != null) {
3855 // ask watcher if this is allowed
3856 boolean moveOK = true;
3857 try {
3858 moveOK = mService.mController.activityResuming(next.packageName);
3859 } catch (RemoteException e) {
3860 mService.mController = null;
3861 }
3862 if (!moveOK) {
3863 return false;
3864 }
3865 }
3866 }
3867
3868 ArrayList moved = new ArrayList();
3869
3870 if (DEBUG_TRANSITION) Slog.v(TAG,
3871 "Prepare to back transition: task=" + task);
3872
3873 final int N = mHistory.size();
3874 int bottom = 0;
3875 int pos = 0;
3876
3877 // Shift all activities with this task down to the bottom
3878 // of the stack, keeping them in the same internal order.
3879 while (pos < N) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003880 ActivityRecord r = mHistory.get(pos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003881 if (localLOGV) Slog.v(
3882 TAG, "At " + pos + " ckp " + r.task + ": " + r);
3883 if (r.task.taskId == task) {
3884 if (localLOGV) Slog.v(TAG, "Removing and adding at " + (N-1));
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07003885 if (DEBUG_ADD_REMOVE) {
3886 RuntimeException here = new RuntimeException("here");
3887 here.fillInStackTrace();
3888 Slog.i(TAG, "Removing and adding activity " + r + " to stack at "
3889 + bottom, here);
3890 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003891 mHistory.remove(pos);
3892 mHistory.add(bottom, r);
3893 moved.add(r);
3894 bottom++;
3895 }
3896 pos++;
3897 }
3898
3899 if (reason != null &&
3900 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003901 mService.mWindowManager.prepareAppTransition(
3902 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003903 ActivityRecord r = topRunningActivityLocked(null);
3904 if (r != null) {
3905 mNoAnimActivities.add(r);
3906 }
3907 } else {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003908 mService.mWindowManager.prepareAppTransition(
3909 WindowManagerPolicy.TRANSIT_TASK_TO_BACK, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003910 }
3911 mService.mWindowManager.moveAppTokensToBottom(moved);
3912 if (VALIDATE_TOKENS) {
3913 mService.mWindowManager.validateAppTokens(mHistory);
3914 }
3915
3916 finishTaskMoveLocked(task);
3917 return true;
3918 }
3919
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003920 public ActivityManager.TaskThumbnails getTaskThumbnailsLocked(TaskRecord tr) {
3921 TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
3922 ActivityRecord resumed = mResumedActivity;
3923 if (resumed != null && resumed.thumbHolder == tr) {
3924 info.mainThumbnail = resumed.stack.screenshotActivities(resumed);
3925 } else {
3926 info.mainThumbnail = tr.lastThumbnail;
3927 }
3928 return info;
3929 }
3930
3931 public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex) {
3932 TaskAccessInfo info = getTaskAccessInfoLocked(taskId, false);
3933 if (info.root == null) {
3934 Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId);
3935 return null;
3936 }
3937
3938 if (subTaskIndex < 0) {
3939 // Just remove the entire task.
3940 performClearTaskAtIndexLocked(taskId, info.rootIndex);
3941 return info.root;
3942 }
3943
3944 if (subTaskIndex >= info.subtasks.size()) {
3945 Slog.w(TAG, "removeTaskLocked: unknown subTaskIndex " + subTaskIndex);
3946 return null;
3947 }
3948
3949 // Remove all of this task's activies starting at the sub task.
3950 TaskAccessInfo.SubTask subtask = info.subtasks.get(subTaskIndex);
3951 performClearTaskAtIndexLocked(taskId, subtask.index);
3952 return subtask.activity;
3953 }
3954
3955 public TaskAccessInfo getTaskAccessInfoLocked(int taskId, boolean inclThumbs) {
3956 ActivityRecord resumed = mResumedActivity;
3957 final TaskAccessInfo thumbs = new TaskAccessInfo();
3958 // How many different sub-thumbnails?
3959 final int NA = mHistory.size();
3960 int j = 0;
3961 ThumbnailHolder holder = null;
3962 while (j < NA) {
3963 ActivityRecord ar = mHistory.get(j);
3964 if (!ar.finishing && ar.task.taskId == taskId) {
3965 holder = ar.thumbHolder;
3966 break;
3967 }
3968 j++;
3969 }
3970
3971 if (j >= NA) {
3972 return thumbs;
3973 }
3974
3975 thumbs.root = mHistory.get(j);
3976 thumbs.rootIndex = j;
3977
3978 ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>();
3979 thumbs.subtasks = subtasks;
3980 ActivityRecord lastActivity = null;
3981 while (j < NA) {
3982 ActivityRecord ar = mHistory.get(j);
3983 j++;
3984 if (ar.finishing) {
3985 continue;
3986 }
3987 if (ar.task.taskId != taskId) {
3988 break;
3989 }
3990 lastActivity = ar;
3991 if (ar.thumbHolder != holder && holder != null) {
3992 thumbs.numSubThumbbails++;
3993 holder = ar.thumbHolder;
3994 TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask();
3995 sub.thumbnail = holder.lastThumbnail;
3996 sub.activity = ar;
3997 sub.index = j-1;
3998 subtasks.add(sub);
3999 }
4000 }
4001 if (lastActivity != null && subtasks.size() > 0) {
4002 if (resumed == lastActivity) {
4003 TaskAccessInfo.SubTask sub = subtasks.get(subtasks.size()-1);
4004 sub.thumbnail = lastActivity.stack.screenshotActivities(lastActivity);
4005 }
4006 }
4007 if (thumbs.numSubThumbbails > 0) {
4008 thumbs.retriever = new IThumbnailRetriever.Stub() {
4009 public Bitmap getThumbnail(int index) {
4010 if (index < 0 || index >= thumbs.subtasks.size()) {
4011 return null;
4012 }
4013 return thumbs.subtasks.get(index).thumbnail;
4014 }
4015 };
4016 }
4017 return thumbs;
4018 }
4019
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004020 private final void logStartActivity(int tag, ActivityRecord r,
4021 TaskRecord task) {
4022 EventLog.writeEvent(tag,
4023 System.identityHashCode(r), task.taskId,
4024 r.shortComponentName, r.intent.getAction(),
4025 r.intent.getType(), r.intent.getDataString(),
4026 r.intent.getFlags());
4027 }
4028
4029 /**
4030 * Make sure the given activity matches the current configuration. Returns
4031 * false if the activity had to be destroyed. Returns true if the
4032 * configuration is the same, or the activity will remain running as-is
4033 * for whatever reason. Ensures the HistoryRecord is updated with the
4034 * correct configuration and all other bookkeeping is handled.
4035 */
4036 final boolean ensureActivityConfigurationLocked(ActivityRecord r,
4037 int globalChanges) {
4038 if (mConfigWillChange) {
4039 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4040 "Skipping config check (will change): " + r);
4041 return true;
4042 }
4043
4044 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4045 "Ensuring correct configuration: " + r);
4046
4047 // Short circuit: if the two configurations are the exact same
4048 // object (the common case), then there is nothing to do.
4049 Configuration newConfig = mService.mConfiguration;
Dianne Hackborne2515ee2011-04-27 18:52:56 -04004050 if (r.configuration == newConfig && !r.forceNewConfig) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004051 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4052 "Configuration unchanged in " + r);
4053 return true;
4054 }
4055
4056 // We don't worry about activities that are finishing.
4057 if (r.finishing) {
4058 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4059 "Configuration doesn't matter in finishing " + r);
4060 r.stopFreezingScreenLocked(false);
4061 return true;
4062 }
4063
4064 // Okay we now are going to make this activity have the new config.
4065 // But then we need to figure out how it needs to deal with that.
4066 Configuration oldConfig = r.configuration;
4067 r.configuration = newConfig;
Dianne Hackborn58f42a52011-10-10 13:46:34 -07004068
4069 // Determine what has changed. May be nothing, if this is a config
4070 // that has come back from the app after going idle. In that case
4071 // we just want to leave the official config object now in the
4072 // activity and do nothing else.
4073 final int changes = oldConfig.diff(newConfig);
4074 if (changes == 0 && !r.forceNewConfig) {
4075 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4076 "Configuration no differences in " + r);
4077 return true;
4078 }
4079
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004080 // If the activity isn't currently running, just leave the new
4081 // configuration and it will pick that up next time it starts.
4082 if (r.app == null || r.app.thread == null) {
4083 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4084 "Configuration doesn't matter not running " + r);
4085 r.stopFreezingScreenLocked(false);
Dianne Hackborne2515ee2011-04-27 18:52:56 -04004086 r.forceNewConfig = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004087 return true;
4088 }
4089
Dianne Hackborn58f42a52011-10-10 13:46:34 -07004090 // Figure out how to handle the changes between the configurations.
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004091 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
4092 Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
4093 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborne6676352011-06-01 16:51:20 -07004094 + Integer.toHexString(r.info.getRealConfigChanged())
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004095 + ", newConfig=" + newConfig);
4096 }
Dianne Hackborne6676352011-06-01 16:51:20 -07004097 if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) {
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004098 // Aha, the activity isn't handling the change, so DIE DIE DIE.
4099 r.configChangeFlags |= changes;
4100 r.startFreezingScreenLocked(r.app, globalChanges);
Dianne Hackborne2515ee2011-04-27 18:52:56 -04004101 r.forceNewConfig = false;
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004102 if (r.app == null || r.app.thread == null) {
4103 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4104 "Switch is destroying non-running " + r);
Dianne Hackbornce86ba82011-07-13 19:33:41 -07004105 destroyActivityLocked(r, true, false);
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004106 } else if (r.state == ActivityState.PAUSING) {
4107 // A little annoying: we are waiting for this activity to
4108 // finish pausing. Let's not do anything now, but just
4109 // flag that it needs to be restarted when done pausing.
4110 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4111 "Switch is skipping already pausing " + r);
4112 r.configDestroy = true;
4113 return true;
4114 } else if (r.state == ActivityState.RESUMED) {
4115 // Try to optimize this case: the configuration is changing
4116 // and we need to restart the top, resumed activity.
4117 // Instead of doing the normal handshaking, just say
4118 // "restart!".
4119 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4120 "Switch is restarting resumed " + r);
4121 relaunchActivityLocked(r, r.configChangeFlags, true);
4122 r.configChangeFlags = 0;
4123 } else {
4124 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4125 "Switch is restarting non-resumed " + r);
4126 relaunchActivityLocked(r, r.configChangeFlags, false);
4127 r.configChangeFlags = 0;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004128 }
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004129
4130 // All done... tell the caller we weren't able to keep this
4131 // activity around.
4132 return false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004133 }
4134
4135 // Default case: the activity can handle this new configuration, so
4136 // hand it over. Note that we don't need to give it the new
4137 // configuration, since we always send configuration changes to all
4138 // process when they happen so it can just use whatever configuration
4139 // it last got.
4140 if (r.app != null && r.app.thread != null) {
4141 try {
4142 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
4143 r.app.thread.scheduleActivityConfigurationChanged(r);
4144 } catch (RemoteException e) {
4145 // If process died, whatever.
4146 }
4147 }
4148 r.stopFreezingScreenLocked(false);
4149
4150 return true;
4151 }
4152
4153 private final boolean relaunchActivityLocked(ActivityRecord r,
4154 int changes, boolean andResume) {
4155 List<ResultInfo> results = null;
4156 List<Intent> newIntents = null;
4157 if (andResume) {
4158 results = r.results;
4159 newIntents = r.newIntents;
4160 }
4161 if (DEBUG_SWITCH) Slog.v(TAG, "Relaunching: " + r
4162 + " with results=" + results + " newIntents=" + newIntents
4163 + " andResume=" + andResume);
4164 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
4165 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
4166 r.task.taskId, r.shortComponentName);
4167
4168 r.startFreezingScreenLocked(r.app, 0);
4169
4170 try {
4171 if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
Dianne Hackborne2515ee2011-04-27 18:52:56 -04004172 r.forceNewConfig = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004173 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
4174 changes, !andResume, mService.mConfiguration);
4175 // Note: don't need to call pauseIfSleepingLocked() here, because
4176 // the caller will only pass in 'andResume' if this activity is
4177 // currently resumed, which implies we aren't sleeping.
4178 } catch (RemoteException e) {
4179 return false;
4180 }
4181
4182 if (andResume) {
4183 r.results = null;
4184 r.newIntents = null;
4185 if (mMainStack) {
4186 mService.reportResumedActivityLocked(r);
4187 }
4188 }
4189
4190 return true;
4191 }
Dianne Hackborn90c52de2011-09-23 12:57:44 -07004192
4193 public void dismissKeyguardOnNextActivityLocked() {
4194 mDismissKeyguardOnNextActivity = true;
4195 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004196}