blob: 8435eaa029e229574b45339382823abb7133f26f [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) {
Dianne Hackborn28695e02011-11-02 21:59:51 -0700950 destroyActivityLocked(r, true, false, "stop-config");
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700951 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 Hackborn28695e02011-11-02 21:59:51 -0700979 destroyActivityLocked(prev, true, false, "pause-config");
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 }
Dianne Hackbornf35fe232011-11-01 19:25:20 -07001366
Dianne Hackborn28695e02011-11-02 21:59:51 -07001367 if (!prev.finishing && prev.app != null && prev.app != next.app
1368 && prev.app != mService.mHomeProcess) {
Dianne Hackbornf35fe232011-11-01 19:25:20 -07001369 // We are switching to a new activity that is in a different
1370 // process than the previous one. Note the previous process,
1371 // so we can try to keep it around.
1372 mService.mPreviousProcess = prev.app;
1373 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001374 }
1375
Dianne Hackborne7f97212011-02-24 14:40:20 -08001376 // Launching this app's activity, make sure the app is no longer
1377 // considered stopped.
1378 try {
1379 AppGlobals.getPackageManager().setPackageStoppedState(
1380 next.packageName, false);
1381 } catch (RemoteException e1) {
Dianne Hackborna925cd42011-03-10 13:18:20 -08001382 } catch (IllegalArgumentException e) {
1383 Slog.w(TAG, "Failed trying to unstop package "
1384 + next.packageName + ": " + e);
Dianne Hackborne7f97212011-02-24 14:40:20 -08001385 }
1386
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001387 // We are starting up the next activity, so tell the window manager
1388 // that the previous one will be hidden soon. This way it can know
1389 // to ignore it when computing the desired screen orientation.
1390 if (prev != null) {
1391 if (prev.finishing) {
1392 if (DEBUG_TRANSITION) Slog.v(TAG,
1393 "Prepare close transition: prev=" + prev);
1394 if (mNoAnimActivities.contains(prev)) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001395 mService.mWindowManager.prepareAppTransition(
1396 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001397 } else {
1398 mService.mWindowManager.prepareAppTransition(prev.task == next.task
1399 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001400 : WindowManagerPolicy.TRANSIT_TASK_CLOSE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001401 }
1402 mService.mWindowManager.setAppWillBeHidden(prev);
1403 mService.mWindowManager.setAppVisibility(prev, false);
1404 } else {
1405 if (DEBUG_TRANSITION) Slog.v(TAG,
1406 "Prepare open transition: prev=" + prev);
1407 if (mNoAnimActivities.contains(next)) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001408 mService.mWindowManager.prepareAppTransition(
1409 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001410 } else {
1411 mService.mWindowManager.prepareAppTransition(prev.task == next.task
1412 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001413 : WindowManagerPolicy.TRANSIT_TASK_OPEN, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001414 }
1415 }
1416 if (false) {
1417 mService.mWindowManager.setAppWillBeHidden(prev);
1418 mService.mWindowManager.setAppVisibility(prev, false);
1419 }
1420 } else if (mHistory.size() > 1) {
1421 if (DEBUG_TRANSITION) Slog.v(TAG,
1422 "Prepare open transition: no previous");
1423 if (mNoAnimActivities.contains(next)) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001424 mService.mWindowManager.prepareAppTransition(
1425 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001426 } else {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001427 mService.mWindowManager.prepareAppTransition(
1428 WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001429 }
1430 }
1431
1432 if (next.app != null && next.app.thread != null) {
1433 if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
1434
1435 // This activity is now becoming visible.
1436 mService.mWindowManager.setAppVisibility(next, true);
1437
1438 ActivityRecord lastResumedActivity = mResumedActivity;
1439 ActivityState lastState = next.state;
1440
1441 mService.updateCpuStats();
1442
Dianne Hackbornce86ba82011-07-13 19:33:41 -07001443 if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + next + " (in existing)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001444 next.state = ActivityState.RESUMED;
1445 mResumedActivity = next;
1446 next.task.touchActiveTime();
Dianne Hackborn88819b22010-12-21 18:18:02 -08001447 if (mMainStack) {
1448 mService.addRecentTaskLocked(next.task);
1449 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001450 mService.updateLruProcessLocked(next.app, true, true);
1451 updateLRUListLocked(next);
1452
1453 // Have the window manager re-evaluate the orientation of
1454 // the screen based on the new activity order.
1455 boolean updated = false;
1456 if (mMainStack) {
1457 synchronized (mService) {
1458 Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
1459 mService.mConfiguration,
1460 next.mayFreezeScreenLocked(next.app) ? next : null);
1461 if (config != null) {
1462 next.frozenBeforeDestroy = true;
1463 }
Dianne Hackborn31ca8542011-07-19 14:58:28 -07001464 updated = mService.updateConfigurationLocked(config, next, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001465 }
1466 }
1467 if (!updated) {
1468 // The configuration update wasn't able to keep the existing
1469 // instance of the activity, and instead started a new one.
1470 // We should be all done, but let's just make sure our activity
1471 // is still at the top and schedule another run if something
1472 // weird happened.
1473 ActivityRecord nextNext = topRunningActivityLocked(null);
1474 if (DEBUG_SWITCH) Slog.i(TAG,
1475 "Activity config changed during resume: " + next
1476 + ", new next: " + nextNext);
1477 if (nextNext != next) {
1478 // Do over!
1479 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
1480 }
1481 if (mMainStack) {
1482 mService.setFocusedActivityLocked(next);
1483 }
1484 ensureActivitiesVisibleLocked(null, 0);
1485 mService.mWindowManager.executeAppTransition();
1486 mNoAnimActivities.clear();
1487 return true;
1488 }
1489
1490 try {
1491 // Deliver all pending results.
1492 ArrayList a = next.results;
1493 if (a != null) {
1494 final int N = a.size();
1495 if (!next.finishing && N > 0) {
1496 if (DEBUG_RESULTS) Slog.v(
1497 TAG, "Delivering results to " + next
1498 + ": " + a);
1499 next.app.thread.scheduleSendResult(next, a);
1500 }
1501 }
1502
1503 if (next.newIntents != null) {
1504 next.app.thread.scheduleNewIntent(next.newIntents, next);
1505 }
1506
1507 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
1508 System.identityHashCode(next),
1509 next.task.taskId, next.shortComponentName);
1510
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001511 next.sleeping = false;
Dianne Hackborn36cd41f2011-05-25 21:00:46 -07001512 showAskCompatModeDialogLocked(next);
Dianne Hackborn905577f2011-09-07 18:31:28 -07001513 next.app.pendingUiClean = true;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001514 next.app.thread.scheduleResumeActivity(next,
1515 mService.isNextTransitionForward());
1516
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001517 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001518
1519 } catch (Exception e) {
1520 // Whoops, need to restart this activity!
Dianne Hackbornce86ba82011-07-13 19:33:41 -07001521 if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to "
1522 + lastState + ": " + next);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001523 next.state = lastState;
1524 mResumedActivity = lastResumedActivity;
1525 Slog.i(TAG, "Restarting because process died: " + next);
1526 if (!next.hasBeenLaunched) {
1527 next.hasBeenLaunched = true;
1528 } else {
1529 if (SHOW_APP_STARTING_PREVIEW && mMainStack) {
1530 mService.mWindowManager.setAppStartingWindow(
1531 next, next.packageName, next.theme,
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001532 mService.compatibilityInfoForPackageLocked(
1533 next.info.applicationInfo),
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001534 next.nonLocalizedLabel,
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001535 next.labelRes, next.icon, next.windowFlags,
1536 null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001537 }
1538 }
1539 startSpecificActivityLocked(next, true, false);
1540 return true;
1541 }
1542
1543 // From this point on, if something goes wrong there is no way
1544 // to recover the activity.
1545 try {
1546 next.visible = true;
1547 completeResumeLocked(next);
1548 } catch (Exception e) {
1549 // If any exception gets thrown, toss away this
1550 // activity and try the next one.
1551 Slog.w(TAG, "Exception thrown during resume of " + next, e);
1552 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
1553 "resume-exception");
1554 return true;
1555 }
1556
1557 // Didn't need to use the icicle, and it is now out of date.
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001558 if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; didn't need icicle of: " + next);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001559 next.icicle = null;
1560 next.haveState = false;
1561 next.stopped = false;
1562
1563 } else {
1564 // Whoops, need to restart this activity!
1565 if (!next.hasBeenLaunched) {
1566 next.hasBeenLaunched = true;
1567 } else {
1568 if (SHOW_APP_STARTING_PREVIEW) {
1569 mService.mWindowManager.setAppStartingWindow(
1570 next, next.packageName, next.theme,
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001571 mService.compatibilityInfoForPackageLocked(
1572 next.info.applicationInfo),
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001573 next.nonLocalizedLabel,
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001574 next.labelRes, next.icon, next.windowFlags,
1575 null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001576 }
1577 if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
1578 }
1579 startSpecificActivityLocked(next, true, true);
1580 }
1581
1582 return true;
1583 }
1584
1585 private final void startActivityLocked(ActivityRecord r, boolean newTask,
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001586 boolean doResume, boolean keepCurTransition) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001587 final int NH = mHistory.size();
1588
1589 int addPos = -1;
1590
1591 if (!newTask) {
1592 // If starting in an existing task, find where that is...
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001593 boolean startIt = true;
1594 for (int i = NH-1; i >= 0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001595 ActivityRecord p = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001596 if (p.finishing) {
1597 continue;
1598 }
1599 if (p.task == r.task) {
1600 // Here it is! Now, if this is not yet visible to the
1601 // user, then just add it without starting; it will
1602 // get started when the user navigates back to it.
1603 addPos = i+1;
1604 if (!startIt) {
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001605 if (DEBUG_ADD_REMOVE) {
1606 RuntimeException here = new RuntimeException("here");
1607 here.fillInStackTrace();
1608 Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos,
1609 here);
1610 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001611 mHistory.add(addPos, r);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001612 r.putInHistory();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001613 mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
1614 r.info.screenOrientation, r.fullscreen);
1615 if (VALIDATE_TOKENS) {
1616 mService.mWindowManager.validateAppTokens(mHistory);
1617 }
1618 return;
1619 }
1620 break;
1621 }
1622 if (p.fullscreen) {
1623 startIt = false;
1624 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001625 }
1626 }
1627
1628 // Place a new activity at top of stack, so it is next to interact
1629 // with the user.
1630 if (addPos < 0) {
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001631 addPos = NH;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001632 }
1633
1634 // If we are not placing the new activity frontmost, we do not want
1635 // to deliver the onUserLeaving callback to the actual frontmost
1636 // activity
1637 if (addPos < NH) {
1638 mUserLeaving = false;
1639 if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() behind front, mUserLeaving=false");
1640 }
1641
1642 // Slot the activity into the history stack and proceed
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001643 if (DEBUG_ADD_REMOVE) {
1644 RuntimeException here = new RuntimeException("here");
1645 here.fillInStackTrace();
1646 Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos, here);
1647 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001648 mHistory.add(addPos, r);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001649 r.putInHistory();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001650 r.frontOfTask = newTask;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001651 if (NH > 0) {
1652 // We want to show the starting preview window if we are
1653 // switching to a new task, or the next activity's process is
1654 // not currently running.
1655 boolean showStartingIcon = newTask;
1656 ProcessRecord proc = r.app;
1657 if (proc == null) {
1658 proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
1659 }
1660 if (proc == null || proc.thread == null) {
1661 showStartingIcon = true;
1662 }
1663 if (DEBUG_TRANSITION) Slog.v(TAG,
1664 "Prepare open transition: starting " + r);
1665 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001666 mService.mWindowManager.prepareAppTransition(
1667 WindowManagerPolicy.TRANSIT_NONE, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001668 mNoAnimActivities.add(r);
1669 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
1670 mService.mWindowManager.prepareAppTransition(
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001671 WindowManagerPolicy.TRANSIT_TASK_OPEN, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001672 mNoAnimActivities.remove(r);
1673 } else {
1674 mService.mWindowManager.prepareAppTransition(newTask
1675 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001676 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001677 mNoAnimActivities.remove(r);
1678 }
1679 mService.mWindowManager.addAppToken(
1680 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
1681 boolean doShow = true;
1682 if (newTask) {
1683 // Even though this activity is starting fresh, we still need
1684 // to reset it to make sure we apply affinities to move any
1685 // existing activities from other tasks in to it.
1686 // If the caller has requested that the target task be
1687 // reset, then do so.
1688 if ((r.intent.getFlags()
1689 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
1690 resetTaskIfNeededLocked(r, r);
1691 doShow = topRunningNonDelayedActivityLocked(null) == r;
1692 }
1693 }
1694 if (SHOW_APP_STARTING_PREVIEW && doShow) {
1695 // Figure out if we are transitioning from another activity that is
1696 // "has the same starting icon" as the next one. This allows the
1697 // window manager to keep the previous window it had previously
1698 // created, if it still had one.
1699 ActivityRecord prev = mResumedActivity;
1700 if (prev != null) {
1701 // We don't want to reuse the previous starting preview if:
1702 // (1) The current activity is in a different task.
1703 if (prev.task != r.task) prev = null;
1704 // (2) The current activity is already displayed.
1705 else if (prev.nowVisible) prev = null;
1706 }
1707 mService.mWindowManager.setAppStartingWindow(
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001708 r, r.packageName, r.theme,
1709 mService.compatibilityInfoForPackageLocked(
1710 r.info.applicationInfo), r.nonLocalizedLabel,
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001711 r.labelRes, r.icon, r.windowFlags, prev, showStartingIcon);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001712 }
1713 } else {
1714 // If this is the first activity, don't do any fancy animations,
1715 // because there is nothing for it to animate on top of.
1716 mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
1717 r.info.screenOrientation, r.fullscreen);
1718 }
1719 if (VALIDATE_TOKENS) {
1720 mService.mWindowManager.validateAppTokens(mHistory);
1721 }
1722
1723 if (doResume) {
1724 resumeTopActivityLocked(null);
1725 }
1726 }
1727
1728 /**
1729 * Perform a reset of the given task, if needed as part of launching it.
1730 * Returns the new HistoryRecord at the top of the task.
1731 */
1732 private final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop,
1733 ActivityRecord newActivity) {
1734 boolean forceReset = (newActivity.info.flags
1735 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001736 if (ACTIVITY_INACTIVE_RESET_TIME > 0
1737 && taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001738 if ((newActivity.info.flags
1739 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
1740 forceReset = true;
1741 }
1742 }
1743
1744 final TaskRecord task = taskTop.task;
1745
1746 // We are going to move through the history list so that we can look
1747 // at each activity 'target' with 'below' either the interesting
1748 // activity immediately below it in the stack or null.
1749 ActivityRecord target = null;
1750 int targetI = 0;
1751 int taskTopI = -1;
1752 int replyChainEnd = -1;
1753 int lastReparentPos = -1;
1754 for (int i=mHistory.size()-1; i>=-1; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001755 ActivityRecord below = i >= 0 ? mHistory.get(i) : null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001756
1757 if (below != null && below.finishing) {
1758 continue;
1759 }
1760 if (target == null) {
1761 target = below;
1762 targetI = i;
1763 // If we were in the middle of a reply chain before this
1764 // task, it doesn't appear like the root of the chain wants
1765 // anything interesting, so drop it.
1766 replyChainEnd = -1;
1767 continue;
1768 }
1769
1770 final int flags = target.info.flags;
1771
1772 final boolean finishOnTaskLaunch =
1773 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
1774 final boolean allowTaskReparenting =
1775 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
1776
1777 if (target.task == task) {
1778 // We are inside of the task being reset... we'll either
1779 // finish this activity, push it out for another task,
1780 // or leave it as-is. We only do this
1781 // for activities that are not the root of the task (since
1782 // if we finish the root, we may no longer have the task!).
1783 if (taskTopI < 0) {
1784 taskTopI = targetI;
1785 }
1786 if (below != null && below.task == task) {
1787 final boolean clearWhenTaskReset =
1788 (target.intent.getFlags()
1789 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
1790 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
1791 // If this activity is sending a reply to a previous
1792 // activity, we can't do anything with it now until
1793 // we reach the start of the reply chain.
1794 // XXX note that we are assuming the result is always
1795 // to the previous activity, which is almost always
1796 // the case but we really shouldn't count on.
1797 if (replyChainEnd < 0) {
1798 replyChainEnd = targetI;
1799 }
1800 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
1801 && target.taskAffinity != null
1802 && !target.taskAffinity.equals(task.affinity)) {
1803 // If this activity has an affinity for another
1804 // task, then we need to move it out of here. We will
1805 // move it as far out of the way as possible, to the
1806 // bottom of the activity stack. This also keeps it
1807 // correctly ordered with any activities we previously
1808 // moved.
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001809 ActivityRecord p = mHistory.get(0);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001810 if (target.taskAffinity != null
1811 && target.taskAffinity.equals(p.task.affinity)) {
1812 // If the activity currently at the bottom has the
1813 // same task affinity as the one we are moving,
1814 // then merge it into the same task.
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001815 target.setTask(p.task, p.thumbHolder, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001816 if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
1817 + " out to bottom task " + p.task);
1818 } else {
1819 mService.mCurTask++;
1820 if (mService.mCurTask <= 0) {
1821 mService.mCurTask = 1;
1822 }
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001823 target.setTask(new TaskRecord(mService.mCurTask, target.info, null),
1824 null, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001825 target.task.affinityIntent = target.intent;
1826 if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
1827 + " out to new task " + target.task);
1828 }
1829 mService.mWindowManager.setAppGroupId(target, task.taskId);
1830 if (replyChainEnd < 0) {
1831 replyChainEnd = targetI;
1832 }
1833 int dstPos = 0;
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001834 ThumbnailHolder curThumbHolder = target.thumbHolder;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001835 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001836 p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001837 if (p.finishing) {
1838 continue;
1839 }
1840 if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
1841 + " out to target's task " + target.task);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001842 p.setTask(target.task, curThumbHolder, false);
1843 curThumbHolder = p.thumbHolder;
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001844 if (DEBUG_ADD_REMOVE) {
1845 RuntimeException here = new RuntimeException("here");
1846 here.fillInStackTrace();
1847 Slog.i(TAG, "Removing and adding activity " + p + " to stack at "
1848 + dstPos, here);
1849 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001850 mHistory.remove(srcPos);
1851 mHistory.add(dstPos, p);
1852 mService.mWindowManager.moveAppToken(dstPos, p);
1853 mService.mWindowManager.setAppGroupId(p, p.task.taskId);
1854 dstPos++;
1855 if (VALIDATE_TOKENS) {
1856 mService.mWindowManager.validateAppTokens(mHistory);
1857 }
1858 i++;
1859 }
1860 if (taskTop == p) {
1861 taskTop = below;
1862 }
1863 if (taskTopI == replyChainEnd) {
1864 taskTopI = -1;
1865 }
1866 replyChainEnd = -1;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001867 } else if (forceReset || finishOnTaskLaunch
1868 || clearWhenTaskReset) {
1869 // If the activity should just be removed -- either
1870 // because it asks for it, or the task should be
1871 // cleared -- then finish it and anything that is
1872 // part of its reply chain.
1873 if (clearWhenTaskReset) {
1874 // In this case, we want to finish this activity
1875 // and everything above it, so be sneaky and pretend
1876 // like these are all in the reply chain.
1877 replyChainEnd = targetI+1;
1878 while (replyChainEnd < mHistory.size() &&
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001879 (mHistory.get(
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001880 replyChainEnd)).task == task) {
1881 replyChainEnd++;
1882 }
1883 replyChainEnd--;
1884 } else if (replyChainEnd < 0) {
1885 replyChainEnd = targetI;
1886 }
1887 ActivityRecord p = null;
1888 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001889 p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001890 if (p.finishing) {
1891 continue;
1892 }
1893 if (finishActivityLocked(p, srcPos,
1894 Activity.RESULT_CANCELED, null, "reset")) {
1895 replyChainEnd--;
1896 srcPos--;
1897 }
1898 }
1899 if (taskTop == p) {
1900 taskTop = below;
1901 }
1902 if (taskTopI == replyChainEnd) {
1903 taskTopI = -1;
1904 }
1905 replyChainEnd = -1;
1906 } else {
1907 // If we were in the middle of a chain, well the
1908 // activity that started it all doesn't want anything
1909 // special, so leave it all as-is.
1910 replyChainEnd = -1;
1911 }
1912 } else {
1913 // Reached the bottom of the task -- any reply chain
1914 // should be left as-is.
1915 replyChainEnd = -1;
1916 }
1917
1918 } else if (target.resultTo != null) {
1919 // If this activity is sending a reply to a previous
1920 // activity, we can't do anything with it now until
1921 // we reach the start of the reply chain.
1922 // XXX note that we are assuming the result is always
1923 // to the previous activity, which is almost always
1924 // the case but we really shouldn't count on.
1925 if (replyChainEnd < 0) {
1926 replyChainEnd = targetI;
1927 }
1928
1929 } else if (taskTopI >= 0 && allowTaskReparenting
1930 && task.affinity != null
1931 && task.affinity.equals(target.taskAffinity)) {
1932 // We are inside of another task... if this activity has
1933 // an affinity for our task, then either remove it if we are
1934 // clearing or move it over to our task. Note that
1935 // we currently punt on the case where we are resetting a
1936 // task that is not at the top but who has activities above
1937 // with an affinity to it... this is really not a normal
1938 // case, and we will need to later pull that task to the front
1939 // and usually at that point we will do the reset and pick
1940 // up those remaining activities. (This only happens if
1941 // someone starts an activity in a new task from an activity
1942 // in a task that is not currently on top.)
1943 if (forceReset || finishOnTaskLaunch) {
1944 if (replyChainEnd < 0) {
1945 replyChainEnd = targetI;
1946 }
1947 ActivityRecord p = null;
1948 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001949 p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001950 if (p.finishing) {
1951 continue;
1952 }
1953 if (finishActivityLocked(p, srcPos,
1954 Activity.RESULT_CANCELED, null, "reset")) {
1955 taskTopI--;
1956 lastReparentPos--;
1957 replyChainEnd--;
1958 srcPos--;
1959 }
1960 }
1961 replyChainEnd = -1;
1962 } else {
1963 if (replyChainEnd < 0) {
1964 replyChainEnd = targetI;
1965 }
1966 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001967 ActivityRecord p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001968 if (p.finishing) {
1969 continue;
1970 }
1971 if (lastReparentPos < 0) {
1972 lastReparentPos = taskTopI;
1973 taskTop = p;
1974 } else {
1975 lastReparentPos--;
1976 }
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001977 if (DEBUG_ADD_REMOVE) {
1978 RuntimeException here = new RuntimeException("here");
1979 here.fillInStackTrace();
1980 Slog.i(TAG, "Removing and adding activity " + p + " to stack at "
1981 + lastReparentPos, here);
1982 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001983 mHistory.remove(srcPos);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001984 p.setTask(task, null, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001985 mHistory.add(lastReparentPos, p);
1986 if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
1987 + " in to resetting task " + task);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001988 mService.mWindowManager.moveAppToken(lastReparentPos, p);
1989 mService.mWindowManager.setAppGroupId(p, p.task.taskId);
1990 if (VALIDATE_TOKENS) {
1991 mService.mWindowManager.validateAppTokens(mHistory);
1992 }
1993 }
1994 replyChainEnd = -1;
1995
1996 // Now we've moved it in to place... but what if this is
1997 // a singleTop activity and we have put it on top of another
1998 // instance of the same activity? Then we drop the instance
1999 // below so it remains singleTop.
2000 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
2001 for (int j=lastReparentPos-1; j>=0; j--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002002 ActivityRecord p = mHistory.get(j);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002003 if (p.finishing) {
2004 continue;
2005 }
2006 if (p.intent.getComponent().equals(target.intent.getComponent())) {
2007 if (finishActivityLocked(p, j,
2008 Activity.RESULT_CANCELED, null, "replace")) {
2009 taskTopI--;
2010 lastReparentPos--;
2011 }
2012 }
2013 }
2014 }
2015 }
2016 }
2017
2018 target = below;
2019 targetI = i;
2020 }
2021
2022 return taskTop;
2023 }
2024
2025 /**
2026 * Perform clear operation as requested by
2027 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2028 * stack to the given task, then look for
2029 * an instance of that activity in the stack and, if found, finish all
2030 * activities on top of it and return the instance.
2031 *
2032 * @param newR Description of the new activity being started.
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002033 * @return Returns the old activity that should be continued to be used,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002034 * or null if none was found.
2035 */
2036 private final ActivityRecord performClearTaskLocked(int taskId,
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002037 ActivityRecord newR, int launchFlags) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002038 int i = mHistory.size();
2039
2040 // First find the requested task.
2041 while (i > 0) {
2042 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002043 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002044 if (r.task.taskId == taskId) {
2045 i++;
2046 break;
2047 }
2048 }
2049
2050 // Now clear it.
2051 while (i > 0) {
2052 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002053 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002054 if (r.finishing) {
2055 continue;
2056 }
2057 if (r.task.taskId != taskId) {
2058 return null;
2059 }
2060 if (r.realActivity.equals(newR.realActivity)) {
2061 // Here it is! Now finish everything in front...
2062 ActivityRecord ret = r;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002063 while (i < (mHistory.size()-1)) {
2064 i++;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002065 r = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002066 if (r.task.taskId != taskId) {
2067 break;
2068 }
2069 if (r.finishing) {
2070 continue;
2071 }
2072 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2073 null, "clear")) {
2074 i--;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002075 }
2076 }
2077
2078 // Finally, if this is a normal launch mode (that is, not
2079 // expecting onNewIntent()), then we will finish the current
2080 // instance of the activity so a new fresh one can be started.
2081 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2082 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
2083 if (!ret.finishing) {
2084 int index = indexOfTokenLocked(ret);
2085 if (index >= 0) {
2086 finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
2087 null, "clear");
2088 }
2089 return null;
2090 }
2091 }
2092
2093 return ret;
2094 }
2095 }
2096
2097 return null;
2098 }
2099
2100 /**
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002101 * Completely remove all activities associated with an existing
2102 * task starting at a specified index.
2103 */
2104 private final void performClearTaskAtIndexLocked(int taskId, int i) {
Dianne Hackborneabd3282011-10-13 16:26:49 -07002105 while (i < mHistory.size()) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002106 ActivityRecord r = mHistory.get(i);
2107 if (r.task.taskId != taskId) {
2108 // Whoops hit the end.
2109 return;
2110 }
2111 if (r.finishing) {
2112 i++;
2113 continue;
2114 }
2115 if (!finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2116 null, "clear")) {
2117 i++;
2118 }
2119 }
2120 }
2121
2122 /**
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002123 * Completely remove all activities associated with an existing task.
2124 */
2125 private final void performClearTaskLocked(int taskId) {
2126 int i = mHistory.size();
2127
2128 // First find the requested task.
2129 while (i > 0) {
2130 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002131 ActivityRecord r = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002132 if (r.task.taskId == taskId) {
2133 i++;
2134 break;
2135 }
2136 }
2137
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002138 // Now find the start and clear it.
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002139 while (i > 0) {
2140 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002141 ActivityRecord r = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002142 if (r.finishing) {
2143 continue;
2144 }
2145 if (r.task.taskId != taskId) {
2146 // We hit the bottom. Now finish it all...
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002147 performClearTaskAtIndexLocked(taskId, i+1);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002148 return;
2149 }
2150 }
2151 }
2152
2153 /**
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002154 * Find the activity in the history stack within the given task. Returns
2155 * the index within the history at which it's found, or < 0 if not found.
2156 */
2157 private final int findActivityInHistoryLocked(ActivityRecord r, int task) {
2158 int i = mHistory.size();
2159 while (i > 0) {
2160 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002161 ActivityRecord candidate = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002162 if (candidate.task.taskId != task) {
2163 break;
2164 }
2165 if (candidate.realActivity.equals(r.realActivity)) {
2166 return i;
2167 }
2168 }
2169
2170 return -1;
2171 }
2172
2173 /**
2174 * Reorder the history stack so that the activity at the given index is
2175 * brought to the front.
2176 */
2177 private final ActivityRecord moveActivityToFrontLocked(int where) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002178 ActivityRecord newTop = mHistory.remove(where);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002179 int top = mHistory.size();
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002180 ActivityRecord oldTop = mHistory.get(top-1);
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07002181 if (DEBUG_ADD_REMOVE) {
2182 RuntimeException here = new RuntimeException("here");
2183 here.fillInStackTrace();
2184 Slog.i(TAG, "Removing and adding activity " + newTop + " to stack at "
2185 + top, here);
2186 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002187 mHistory.add(top, newTop);
2188 oldTop.frontOfTask = false;
2189 newTop.frontOfTask = true;
2190 return newTop;
2191 }
2192
2193 final int startActivityLocked(IApplicationThread caller,
2194 Intent intent, String resolvedType,
2195 Uri[] grantedUriPermissions,
2196 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2197 String resultWho, int requestCode,
2198 int callingPid, int callingUid, boolean onlyIfNeeded,
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002199 boolean componentSpecified, ActivityRecord[] outActivity) {
Dianne Hackbornefb58102010-10-14 16:47:34 -07002200
2201 int err = START_SUCCESS;
2202
2203 ProcessRecord callerApp = null;
2204 if (caller != null) {
2205 callerApp = mService.getRecordForAppLocked(caller);
2206 if (callerApp != null) {
2207 callingPid = callerApp.pid;
2208 callingUid = callerApp.info.uid;
2209 } else {
2210 Slog.w(TAG, "Unable to find app for caller " + caller
2211 + " (pid=" + callingPid + ") when starting: "
2212 + intent.toString());
2213 err = START_PERMISSION_DENIED;
2214 }
2215 }
2216
2217 if (err == START_SUCCESS) {
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002218 Slog.i(TAG, "START {" + intent.toShortString(true, true, true) + "} from pid "
Dianne Hackbornefb58102010-10-14 16:47:34 -07002219 + (callerApp != null ? callerApp.pid : callingPid));
2220 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002221
2222 ActivityRecord sourceRecord = null;
2223 ActivityRecord resultRecord = null;
2224 if (resultTo != null) {
2225 int index = indexOfTokenLocked(resultTo);
2226 if (DEBUG_RESULTS) Slog.v(
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07002227 TAG, "Will send result to " + resultTo + " (index " + index + ")");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002228 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002229 sourceRecord = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002230 if (requestCode >= 0 && !sourceRecord.finishing) {
2231 resultRecord = sourceRecord;
2232 }
2233 }
2234 }
2235
2236 int launchFlags = intent.getFlags();
2237
2238 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2239 && sourceRecord != null) {
2240 // Transfer the result target from the source activity to the new
2241 // one being started, including any failures.
2242 if (requestCode >= 0) {
2243 return START_FORWARD_AND_REQUEST_CONFLICT;
2244 }
2245 resultRecord = sourceRecord.resultTo;
2246 resultWho = sourceRecord.resultWho;
2247 requestCode = sourceRecord.requestCode;
2248 sourceRecord.resultTo = null;
2249 if (resultRecord != null) {
2250 resultRecord.removeResultsLocked(
2251 sourceRecord, resultWho, requestCode);
2252 }
2253 }
2254
Dianne Hackbornefb58102010-10-14 16:47:34 -07002255 if (err == START_SUCCESS && intent.getComponent() == null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002256 // We couldn't find a class that can handle the given Intent.
2257 // That's the end of that!
2258 err = START_INTENT_NOT_RESOLVED;
2259 }
2260
2261 if (err == START_SUCCESS && aInfo == null) {
2262 // We couldn't find the specific class specified in the Intent.
2263 // Also the end of the line.
2264 err = START_CLASS_NOT_FOUND;
2265 }
2266
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002267 if (err != START_SUCCESS) {
2268 if (resultRecord != null) {
2269 sendActivityResultLocked(-1,
2270 resultRecord, resultWho, requestCode,
2271 Activity.RESULT_CANCELED, null);
2272 }
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002273 mDismissKeyguardOnNextActivity = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002274 return err;
2275 }
2276
2277 final int perm = mService.checkComponentPermission(aInfo.permission, callingPid,
Dianne Hackborn6c2c5fc2011-01-18 17:02:33 -08002278 callingUid, aInfo.applicationInfo.uid, aInfo.exported);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002279 if (perm != PackageManager.PERMISSION_GRANTED) {
2280 if (resultRecord != null) {
2281 sendActivityResultLocked(-1,
2282 resultRecord, resultWho, requestCode,
2283 Activity.RESULT_CANCELED, null);
2284 }
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002285 mDismissKeyguardOnNextActivity = false;
Dianne Hackborn6c2c5fc2011-01-18 17:02:33 -08002286 String msg;
2287 if (!aInfo.exported) {
2288 msg = "Permission Denial: starting " + intent.toString()
2289 + " from " + callerApp + " (pid=" + callingPid
2290 + ", uid=" + callingUid + ")"
2291 + " not exported from uid " + aInfo.applicationInfo.uid;
2292 } else {
2293 msg = "Permission Denial: starting " + intent.toString()
2294 + " from " + callerApp + " (pid=" + callingPid
2295 + ", uid=" + callingUid + ")"
2296 + " requires " + aInfo.permission;
2297 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002298 Slog.w(TAG, msg);
2299 throw new SecurityException(msg);
2300 }
2301
2302 if (mMainStack) {
2303 if (mService.mController != null) {
2304 boolean abort = false;
2305 try {
2306 // The Intent we give to the watcher has the extra data
2307 // stripped off, since it can contain private information.
2308 Intent watchIntent = intent.cloneFilter();
2309 abort = !mService.mController.activityStarting(watchIntent,
2310 aInfo.applicationInfo.packageName);
2311 } catch (RemoteException e) {
2312 mService.mController = null;
2313 }
2314
2315 if (abort) {
2316 if (resultRecord != null) {
2317 sendActivityResultLocked(-1,
2318 resultRecord, resultWho, requestCode,
2319 Activity.RESULT_CANCELED, null);
2320 }
2321 // We pretend to the caller that it was really started, but
2322 // they will just get a cancel result.
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002323 mDismissKeyguardOnNextActivity = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002324 return START_SUCCESS;
2325 }
2326 }
2327 }
2328
2329 ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
2330 intent, resolvedType, aInfo, mService.mConfiguration,
2331 resultRecord, resultWho, requestCode, componentSpecified);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002332 if (outActivity != null) {
2333 outActivity[0] = r;
2334 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002335
2336 if (mMainStack) {
2337 if (mResumedActivity == null
2338 || mResumedActivity.info.applicationInfo.uid != callingUid) {
2339 if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
2340 PendingActivityLaunch pal = new PendingActivityLaunch();
2341 pal.r = r;
2342 pal.sourceRecord = sourceRecord;
2343 pal.grantedUriPermissions = grantedUriPermissions;
2344 pal.grantedMode = grantedMode;
2345 pal.onlyIfNeeded = onlyIfNeeded;
2346 mService.mPendingActivityLaunches.add(pal);
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002347 mDismissKeyguardOnNextActivity = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002348 return START_SWITCHES_CANCELED;
2349 }
2350 }
2351
2352 if (mService.mDidAppSwitch) {
2353 // This is the second allowed switch since we stopped switches,
2354 // so now just generally allow switches. Use case: user presses
2355 // home (switches disabled, switch to home, mDidAppSwitch now true);
2356 // user taps a home icon (coming from home so allowed, we hit here
2357 // and now allow anyone to switch again).
2358 mService.mAppSwitchesAllowedTime = 0;
2359 } else {
2360 mService.mDidAppSwitch = true;
2361 }
2362
2363 mService.doPendingActivityLaunchesLocked(false);
2364 }
2365
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002366 err = startActivityUncheckedLocked(r, sourceRecord,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002367 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002368 if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
2369 // Someone asked to have the keyguard dismissed on the next
2370 // activity start, but we are not actually doing an activity
2371 // switch... just dismiss the keyguard now, because we
2372 // probably want to see whatever is behind it.
2373 mDismissKeyguardOnNextActivity = false;
2374 mService.mWindowManager.dismissKeyguard();
2375 }
2376 return err;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002377 }
2378
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002379 final void moveHomeToFrontFromLaunchLocked(int launchFlags) {
2380 if ((launchFlags &
2381 (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
2382 == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
2383 // Caller wants to appear on home activity, so before starting
2384 // their own activity we will bring home to the front.
2385 moveHomeToFrontLocked();
2386 }
2387 }
2388
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002389 final int startActivityUncheckedLocked(ActivityRecord r,
2390 ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
2391 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
2392 final Intent intent = r.intent;
2393 final int callingUid = r.launchedFromUid;
2394
2395 int launchFlags = intent.getFlags();
2396
2397 // We'll invoke onUserLeaving before onPause only if the launching
2398 // activity did not explicitly state that this is an automated launch.
2399 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
2400 if (DEBUG_USER_LEAVING) Slog.v(TAG,
2401 "startActivity() => mUserLeaving=" + mUserLeaving);
2402
2403 // If the caller has asked not to resume at this point, we make note
2404 // of this in the record so that we can skip it when trying to find
2405 // the top running activity.
2406 if (!doResume) {
2407 r.delayedResume = true;
2408 }
2409
2410 ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
2411 != 0 ? r : null;
2412
2413 // If the onlyIfNeeded flag is set, then we can do this if the activity
2414 // being launched is the same as the one making the call... or, as
2415 // a special case, if we do not know the caller then we count the
2416 // current top activity as the caller.
2417 if (onlyIfNeeded) {
2418 ActivityRecord checkedCaller = sourceRecord;
2419 if (checkedCaller == null) {
2420 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
2421 }
2422 if (!checkedCaller.realActivity.equals(r.realActivity)) {
2423 // Caller is not the same as launcher, so always needed.
2424 onlyIfNeeded = false;
2425 }
2426 }
2427
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002428 if (sourceRecord == null) {
2429 // This activity is not being started from another... in this
2430 // case we -always- start a new task.
2431 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
2432 Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
2433 + intent);
2434 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2435 }
2436 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2437 // The original activity who is starting us is running as a single
2438 // instance... this new activity it is starting must go on its
2439 // own task.
2440 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2441 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
2442 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
2443 // The activity being started is a single instance... it always
2444 // gets launched into its own task.
2445 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2446 }
2447
2448 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
2449 // For whatever reason this activity is being launched into a new
2450 // task... yet the caller has requested a result back. Well, that
2451 // is pretty messed up, so instead immediately send back a cancel
2452 // and let the new task continue launched as normal without a
2453 // dependency on its originator.
2454 Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
2455 sendActivityResultLocked(-1,
2456 r.resultTo, r.resultWho, r.requestCode,
2457 Activity.RESULT_CANCELED, null);
2458 r.resultTo = null;
2459 }
2460
2461 boolean addingToTask = false;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002462 TaskRecord reuseTask = null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002463 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
2464 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
2465 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
2466 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2467 // If bring to front is requested, and no result is requested, and
2468 // we can find a task that was started with this same
2469 // component, then instead of launching bring that one to the front.
2470 if (r.resultTo == null) {
2471 // See if there is a task to bring to the front. If this is
2472 // a SINGLE_INSTANCE activity, there can be one and only one
2473 // instance of it in the history, and it is always in its own
2474 // unique task, so we do a special search.
2475 ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
2476 ? findTaskLocked(intent, r.info)
2477 : findActivityLocked(intent, r.info);
2478 if (taskTop != null) {
2479 if (taskTop.task.intent == null) {
2480 // This task was started because of movement of
2481 // the activity based on affinity... now that we
2482 // are actually launching it, we can assign the
2483 // base intent.
2484 taskTop.task.setIntent(intent, r.info);
2485 }
2486 // If the target task is not in the front, then we need
2487 // to bring it to the front... except... well, with
2488 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
2489 // to have the same behavior as if a new instance was
2490 // being started, which means not bringing it to the front
2491 // if the caller is not itself in the front.
2492 ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
Jean-Baptiste Queru66a5d692010-10-25 17:27:16 -07002493 if (curTop != null && curTop.task != taskTop.task) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002494 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
2495 boolean callerAtFront = sourceRecord == null
2496 || curTop.task == sourceRecord.task;
2497 if (callerAtFront) {
2498 // We really do want to push this one into the
2499 // user's face, right now.
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002500 moveHomeToFrontFromLaunchLocked(launchFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002501 moveTaskToFrontLocked(taskTop.task, r);
2502 }
2503 }
2504 // If the caller has requested that the target task be
2505 // reset, then do so.
2506 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2507 taskTop = resetTaskIfNeededLocked(taskTop, r);
2508 }
2509 if (onlyIfNeeded) {
2510 // We don't need to start a new activity, and
2511 // the client said not to do anything if that
2512 // is the case, so this is it! And for paranoia, make
2513 // sure we have correctly resumed the top activity.
2514 if (doResume) {
2515 resumeTopActivityLocked(null);
2516 }
2517 return START_RETURN_INTENT_TO_CALLER;
2518 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002519 if ((launchFlags &
2520 (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
2521 == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
2522 // The caller has requested to completely replace any
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002523 // existing task with its new activity. Well that should
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002524 // not be too hard...
2525 reuseTask = taskTop.task;
2526 performClearTaskLocked(taskTop.task.taskId);
2527 reuseTask.setIntent(r.intent, r.info);
2528 } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002529 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
2530 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2531 // In this situation we want to remove all activities
2532 // from the task up to the one being started. In most
2533 // cases this means we are resetting the task to its
2534 // initial state.
2535 ActivityRecord top = performClearTaskLocked(
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002536 taskTop.task.taskId, r, launchFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002537 if (top != null) {
2538 if (top.frontOfTask) {
2539 // Activity aliases may mean we use different
2540 // intents for the top activity, so make sure
2541 // the task now has the identity of the new
2542 // intent.
2543 top.task.setIntent(r.intent, r.info);
2544 }
2545 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002546 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002547 } else {
2548 // A special case: we need to
2549 // start the activity because it is not currently
2550 // running, and the caller has asked to clear the
2551 // current task to have this activity at the top.
2552 addingToTask = true;
2553 // Now pretend like this activity is being started
2554 // by the top of its task, so it is put in the
2555 // right place.
2556 sourceRecord = taskTop;
2557 }
2558 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
2559 // In this case the top activity on the task is the
2560 // same as the one being launched, so we take that
2561 // as a request to bring the task to the foreground.
2562 // If the top activity in the task is the root
2563 // activity, deliver this new intent to it if it
2564 // desires.
2565 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
2566 && taskTop.realActivity.equals(r.realActivity)) {
2567 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
2568 if (taskTop.frontOfTask) {
2569 taskTop.task.setIntent(r.intent, r.info);
2570 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002571 taskTop.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002572 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
2573 // In this case we are launching the root activity
2574 // of the task, but with a different intent. We
2575 // should start a new instance on top.
2576 addingToTask = true;
2577 sourceRecord = taskTop;
2578 }
2579 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
2580 // In this case an activity is being launched in to an
2581 // existing task, without resetting that task. This
2582 // is typically the situation of launching an activity
2583 // from a notification or shortcut. We want to place
2584 // the new activity on top of the current task.
2585 addingToTask = true;
2586 sourceRecord = taskTop;
2587 } else if (!taskTop.task.rootWasReset) {
2588 // In this case we are launching in to an existing task
2589 // that has not yet been started from its front door.
2590 // The current task has been brought to the front.
2591 // Ideally, we'd probably like to place this new task
2592 // at the bottom of its stack, but that's a little hard
2593 // to do with the current organization of the code so
2594 // for now we'll just drop it.
2595 taskTop.task.setIntent(r.intent, r.info);
2596 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002597 if (!addingToTask && reuseTask == null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002598 // We didn't do anything... but it was needed (a.k.a., client
2599 // don't use that intent!) And for paranoia, make
2600 // sure we have correctly resumed the top activity.
2601 if (doResume) {
2602 resumeTopActivityLocked(null);
2603 }
2604 return START_TASK_TO_FRONT;
2605 }
2606 }
2607 }
2608 }
2609
2610 //String uri = r.intent.toURI();
2611 //Intent intent2 = new Intent(uri);
2612 //Slog.i(TAG, "Given intent: " + r.intent);
2613 //Slog.i(TAG, "URI is: " + uri);
2614 //Slog.i(TAG, "To intent: " + intent2);
2615
2616 if (r.packageName != null) {
2617 // If the activity being launched is the same as the one currently
2618 // at the top, then we need to check if it should only be launched
2619 // once.
2620 ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
2621 if (top != null && r.resultTo == null) {
2622 if (top.realActivity.equals(r.realActivity)) {
2623 if (top.app != null && top.app.thread != null) {
2624 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
2625 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
2626 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
2627 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
2628 // For paranoia, make sure we have correctly
2629 // resumed the top activity.
2630 if (doResume) {
2631 resumeTopActivityLocked(null);
2632 }
2633 if (onlyIfNeeded) {
2634 // We don't need to start a new activity, and
2635 // the client said not to do anything if that
2636 // is the case, so this is it!
2637 return START_RETURN_INTENT_TO_CALLER;
2638 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002639 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002640 return START_DELIVERED_TO_TOP;
2641 }
2642 }
2643 }
2644 }
2645
2646 } else {
2647 if (r.resultTo != null) {
2648 sendActivityResultLocked(-1,
2649 r.resultTo, r.resultWho, r.requestCode,
2650 Activity.RESULT_CANCELED, null);
2651 }
2652 return START_CLASS_NOT_FOUND;
2653 }
2654
2655 boolean newTask = false;
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002656 boolean keepCurTransition = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002657
2658 // Should this be considered a new task?
2659 if (r.resultTo == null && !addingToTask
2660 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002661 if (reuseTask == null) {
2662 // todo: should do better management of integers.
2663 mService.mCurTask++;
2664 if (mService.mCurTask <= 0) {
2665 mService.mCurTask = 1;
2666 }
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002667 r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002668 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2669 + " in new task " + r.task);
2670 } else {
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002671 r.setTask(reuseTask, reuseTask, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002672 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002673 newTask = true;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002674 moveHomeToFrontFromLaunchLocked(launchFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002675
2676 } else if (sourceRecord != null) {
2677 if (!addingToTask &&
2678 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
2679 // In this case, we are adding the activity to an existing
2680 // task, but the caller has asked to clear that task if the
2681 // activity is already running.
2682 ActivityRecord top = performClearTaskLocked(
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002683 sourceRecord.task.taskId, r, launchFlags);
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002684 keepCurTransition = true;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002685 if (top != null) {
2686 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002687 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002688 // For paranoia, make sure we have correctly
2689 // resumed the top activity.
2690 if (doResume) {
2691 resumeTopActivityLocked(null);
2692 }
2693 return START_DELIVERED_TO_TOP;
2694 }
2695 } else if (!addingToTask &&
2696 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
2697 // In this case, we are launching an activity in our own task
2698 // that may already be running somewhere in the history, and
2699 // we want to shuffle it to the front of the stack if so.
2700 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
2701 if (where >= 0) {
2702 ActivityRecord top = moveActivityToFrontLocked(where);
2703 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002704 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002705 if (doResume) {
2706 resumeTopActivityLocked(null);
2707 }
2708 return START_DELIVERED_TO_TOP;
2709 }
2710 }
2711 // An existing activity is starting this new activity, so we want
2712 // to keep the new one in the same task as the one that is starting
2713 // it.
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002714 r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002715 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2716 + " in existing task " + r.task);
2717
2718 } else {
2719 // This not being started from an existing activity, and not part
2720 // of a new task... just put it in the top task, though these days
2721 // this case should never happen.
2722 final int N = mHistory.size();
2723 ActivityRecord prev =
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002724 N > 0 ? mHistory.get(N-1) : null;
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002725 r.setTask(prev != null
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002726 ? prev.task
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002727 : new TaskRecord(mService.mCurTask, r.info, intent), null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002728 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2729 + " in new guessed " + r.task);
2730 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002731
2732 if (grantedUriPermissions != null && callingUid > 0) {
2733 for (int i=0; i<grantedUriPermissions.length; i++) {
2734 mService.grantUriPermissionLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002735 grantedUriPermissions[i], grantedMode, r.getUriPermissionsLocked());
Dianne Hackborn39792d22010-08-19 18:01:52 -07002736 }
2737 }
2738
2739 mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002740 intent, r.getUriPermissionsLocked());
Dianne Hackborn39792d22010-08-19 18:01:52 -07002741
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002742 if (newTask) {
2743 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
2744 }
2745 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002746 startActivityLocked(r, newTask, doResume, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002747 return START_SUCCESS;
2748 }
2749
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002750 ActivityInfo resolveActivity(Intent intent, String resolvedType, boolean debug,
2751 String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002752 // Collect information about the target of the Intent.
2753 ActivityInfo aInfo;
2754 try {
2755 ResolveInfo rInfo =
2756 AppGlobals.getPackageManager().resolveIntent(
2757 intent, resolvedType,
2758 PackageManager.MATCH_DEFAULT_ONLY
2759 | ActivityManagerService.STOCK_PM_FLAGS);
2760 aInfo = rInfo != null ? rInfo.activityInfo : null;
2761 } catch (RemoteException e) {
2762 aInfo = null;
2763 }
2764
2765 if (aInfo != null) {
2766 // Store the found target back into the intent, because now that
2767 // we have it we never want to do this again. For example, if the
2768 // user navigates back to this point in the history, we should
2769 // always restart the exact same activity.
2770 intent.setComponent(new ComponentName(
2771 aInfo.applicationInfo.packageName, aInfo.name));
2772
2773 // Don't debug things in the system process
2774 if (debug) {
2775 if (!aInfo.processName.equals("system")) {
2776 mService.setDebugApp(aInfo.processName, true, false);
2777 }
2778 }
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002779
2780 if (profileFile != null) {
2781 if (!aInfo.processName.equals("system")) {
2782 mService.setProfileApp(aInfo.applicationInfo, aInfo.processName,
2783 profileFile, profileFd, autoStopProfiler);
2784 }
2785 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002786 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002787 return aInfo;
2788 }
2789
2790 final int startActivityMayWait(IApplicationThread caller, int callingUid,
2791 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
2792 int grantedMode, IBinder resultTo,
2793 String resultWho, int requestCode, boolean onlyIfNeeded,
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002794 boolean debug, String profileFile, ParcelFileDescriptor profileFd,
2795 boolean autoStopProfiler, WaitResult outResult, Configuration config) {
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002796 // Refuse possible leaked file descriptors
2797 if (intent != null && intent.hasFileDescriptors()) {
2798 throw new IllegalArgumentException("File descriptors passed in Intent");
2799 }
2800
2801 boolean componentSpecified = intent.getComponent() != null;
2802
2803 // Don't modify the client's object!
2804 intent = new Intent(intent);
2805
2806 // Collect information about the target of the Intent.
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002807 ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug,
2808 profileFile, profileFd, autoStopProfiler);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002809
2810 synchronized (mService) {
2811 int callingPid;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002812 if (callingUid >= 0) {
2813 callingPid = -1;
2814 } else if (caller == null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002815 callingPid = Binder.getCallingPid();
2816 callingUid = Binder.getCallingUid();
2817 } else {
2818 callingPid = callingUid = -1;
2819 }
2820
2821 mConfigWillChange = config != null
2822 && mService.mConfiguration.diff(config) != 0;
2823 if (DEBUG_CONFIGURATION) Slog.v(TAG,
2824 "Starting activity when config will change = " + mConfigWillChange);
2825
2826 final long origId = Binder.clearCallingIdentity();
2827
2828 if (mMainStack && aInfo != null &&
Dianne Hackborn54e570f2010-10-04 18:32:32 -07002829 (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002830 // This may be a heavy-weight process! Check to see if we already
2831 // have another, different heavy-weight process running.
2832 if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
2833 if (mService.mHeavyWeightProcess != null &&
2834 (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
2835 !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
2836 int realCallingPid = callingPid;
2837 int realCallingUid = callingUid;
2838 if (caller != null) {
2839 ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
2840 if (callerApp != null) {
2841 realCallingPid = callerApp.pid;
2842 realCallingUid = callerApp.info.uid;
2843 } else {
2844 Slog.w(TAG, "Unable to find app for caller " + caller
2845 + " (pid=" + realCallingPid + ") when starting: "
2846 + intent.toString());
2847 return START_PERMISSION_DENIED;
2848 }
2849 }
2850
2851 IIntentSender target = mService.getIntentSenderLocked(
2852 IActivityManager.INTENT_SENDER_ACTIVITY, "android",
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002853 realCallingUid, null, null, 0, new Intent[] { intent },
2854 new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002855 | PendingIntent.FLAG_ONE_SHOT);
2856
2857 Intent newIntent = new Intent();
2858 if (requestCode >= 0) {
2859 // Caller is requesting a result.
2860 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
2861 }
2862 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
2863 new IntentSender(target));
2864 if (mService.mHeavyWeightProcess.activities.size() > 0) {
2865 ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
2866 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
2867 hist.packageName);
2868 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
2869 hist.task.taskId);
2870 }
2871 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
2872 aInfo.packageName);
2873 newIntent.setFlags(intent.getFlags());
2874 newIntent.setClassName("android",
2875 HeavyWeightSwitcherActivity.class.getName());
2876 intent = newIntent;
2877 resolvedType = null;
2878 caller = null;
2879 callingUid = Binder.getCallingUid();
2880 callingPid = Binder.getCallingPid();
2881 componentSpecified = true;
2882 try {
2883 ResolveInfo rInfo =
2884 AppGlobals.getPackageManager().resolveIntent(
2885 intent, null,
2886 PackageManager.MATCH_DEFAULT_ONLY
2887 | ActivityManagerService.STOCK_PM_FLAGS);
2888 aInfo = rInfo != null ? rInfo.activityInfo : null;
2889 } catch (RemoteException e) {
2890 aInfo = null;
2891 }
2892 }
2893 }
2894 }
2895
2896 int res = startActivityLocked(caller, intent, resolvedType,
2897 grantedUriPermissions, grantedMode, aInfo,
2898 resultTo, resultWho, requestCode, callingPid, callingUid,
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002899 onlyIfNeeded, componentSpecified, null);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002900
2901 if (mConfigWillChange && mMainStack) {
2902 // If the caller also wants to switch to a new configuration,
2903 // do so now. This allows a clean switch, as we are waiting
2904 // for the current activity to pause (so we will not destroy
2905 // it), and have not yet started the next activity.
2906 mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
2907 "updateConfiguration()");
2908 mConfigWillChange = false;
2909 if (DEBUG_CONFIGURATION) Slog.v(TAG,
2910 "Updating to new configuration after starting activity.");
Dianne Hackborn31ca8542011-07-19 14:58:28 -07002911 mService.updateConfigurationLocked(config, null, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002912 }
2913
2914 Binder.restoreCallingIdentity(origId);
2915
2916 if (outResult != null) {
2917 outResult.result = res;
2918 if (res == IActivityManager.START_SUCCESS) {
2919 mWaitingActivityLaunched.add(outResult);
2920 do {
2921 try {
Dianne Hackbornba0492d2010-10-12 19:01:46 -07002922 mService.wait();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002923 } catch (InterruptedException e) {
2924 }
2925 } while (!outResult.timeout && outResult.who == null);
2926 } else if (res == IActivityManager.START_TASK_TO_FRONT) {
2927 ActivityRecord r = this.topRunningActivityLocked(null);
2928 if (r.nowVisible) {
2929 outResult.timeout = false;
2930 outResult.who = new ComponentName(r.info.packageName, r.info.name);
2931 outResult.totalTime = 0;
2932 outResult.thisTime = 0;
2933 } else {
2934 outResult.thisTime = SystemClock.uptimeMillis();
2935 mWaitingActivityVisible.add(outResult);
2936 do {
2937 try {
Dianne Hackbornba0492d2010-10-12 19:01:46 -07002938 mService.wait();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002939 } catch (InterruptedException e) {
2940 }
2941 } while (!outResult.timeout && outResult.who == null);
2942 }
2943 }
2944 }
2945
2946 return res;
2947 }
2948 }
2949
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002950 final int startActivities(IApplicationThread caller, int callingUid,
2951 Intent[] intents, String[] resolvedTypes, IBinder resultTo) {
2952 if (intents == null) {
2953 throw new NullPointerException("intents is null");
2954 }
2955 if (resolvedTypes == null) {
2956 throw new NullPointerException("resolvedTypes is null");
2957 }
2958 if (intents.length != resolvedTypes.length) {
2959 throw new IllegalArgumentException("intents are length different than resolvedTypes");
2960 }
2961
2962 ActivityRecord[] outActivity = new ActivityRecord[1];
2963
2964 int callingPid;
2965 if (callingUid >= 0) {
2966 callingPid = -1;
2967 } else if (caller == null) {
2968 callingPid = Binder.getCallingPid();
2969 callingUid = Binder.getCallingUid();
2970 } else {
2971 callingPid = callingUid = -1;
2972 }
2973 final long origId = Binder.clearCallingIdentity();
2974 try {
2975 synchronized (mService) {
2976
2977 for (int i=0; i<intents.length; i++) {
2978 Intent intent = intents[i];
2979 if (intent == null) {
2980 continue;
2981 }
2982
2983 // Refuse possible leaked file descriptors
2984 if (intent != null && intent.hasFileDescriptors()) {
2985 throw new IllegalArgumentException("File descriptors passed in Intent");
2986 }
2987
2988 boolean componentSpecified = intent.getComponent() != null;
2989
2990 // Don't modify the client's object!
2991 intent = new Intent(intent);
2992
2993 // Collect information about the target of the Intent.
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002994 ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], false,
2995 null, null, false);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002996
2997 if (mMainStack && aInfo != null && (aInfo.applicationInfo.flags
2998 & ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
2999 throw new IllegalArgumentException(
3000 "FLAG_CANT_SAVE_STATE not supported here");
3001 }
3002
3003 int res = startActivityLocked(caller, intent, resolvedTypes[i],
3004 null, 0, aInfo, resultTo, null, -1, callingPid, callingUid,
3005 false, componentSpecified, outActivity);
3006 if (res < 0) {
3007 return res;
3008 }
3009
3010 resultTo = outActivity[0];
3011 }
3012 }
3013 } finally {
3014 Binder.restoreCallingIdentity(origId);
3015 }
3016
3017 return IActivityManager.START_SUCCESS;
3018 }
3019
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003020 void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r,
3021 long thisTime, long totalTime) {
3022 for (int i=mWaitingActivityLaunched.size()-1; i>=0; i--) {
3023 WaitResult w = mWaitingActivityLaunched.get(i);
3024 w.timeout = timeout;
3025 if (r != null) {
3026 w.who = new ComponentName(r.info.packageName, r.info.name);
3027 }
3028 w.thisTime = thisTime;
3029 w.totalTime = totalTime;
3030 }
3031 mService.notifyAll();
3032 }
3033
3034 void reportActivityVisibleLocked(ActivityRecord r) {
3035 for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
3036 WaitResult w = mWaitingActivityVisible.get(i);
3037 w.timeout = false;
3038 if (r != null) {
3039 w.who = new ComponentName(r.info.packageName, r.info.name);
3040 }
3041 w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
3042 w.thisTime = w.totalTime;
3043 }
3044 mService.notifyAll();
Dianne Hackborn90c52de2011-09-23 12:57:44 -07003045
3046 if (mDismissKeyguardOnNextActivity) {
3047 mDismissKeyguardOnNextActivity = false;
3048 mService.mWindowManager.dismissKeyguard();
3049 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003050 }
3051
3052 void sendActivityResultLocked(int callingUid, ActivityRecord r,
3053 String resultWho, int requestCode, int resultCode, Intent data) {
3054
3055 if (callingUid > 0) {
3056 mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07003057 data, r.getUriPermissionsLocked());
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003058 }
3059
3060 if (DEBUG_RESULTS) Slog.v(TAG, "Send activity result to " + r
3061 + " : who=" + resultWho + " req=" + requestCode
3062 + " res=" + resultCode + " data=" + data);
3063 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3064 try {
3065 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3066 list.add(new ResultInfo(resultWho, requestCode,
3067 resultCode, data));
3068 r.app.thread.scheduleSendResult(r, list);
3069 return;
3070 } catch (Exception e) {
3071 Slog.w(TAG, "Exception thrown sending result to " + r, e);
3072 }
3073 }
3074
3075 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3076 }
3077
3078 private final void stopActivityLocked(ActivityRecord r) {
3079 if (DEBUG_SWITCH) Slog.d(TAG, "Stopping: " + r);
3080 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3081 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3082 if (!r.finishing) {
3083 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3084 "no-history");
3085 }
3086 } else if (r.app != null && r.app.thread != null) {
3087 if (mMainStack) {
3088 if (mService.mFocusedActivity == r) {
3089 mService.setFocusedActivityLocked(topRunningActivityLocked(null));
3090 }
3091 }
3092 r.resumeKeyDispatchingLocked();
3093 try {
3094 r.stopped = false;
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003095 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
3096 + " (stop requested)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003097 r.state = ActivityState.STOPPING;
3098 if (DEBUG_VISBILITY) Slog.v(
3099 TAG, "Stopping visible=" + r.visible + " for " + r);
3100 if (!r.visible) {
3101 mService.mWindowManager.setAppVisibility(r, false);
3102 }
3103 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003104 if (mService.isSleeping()) {
3105 r.setSleeping(true);
3106 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003107 } catch (Exception e) {
3108 // Maybe just ignore exceptions here... if the process
3109 // has crashed, our death notification will clean things
3110 // up.
3111 Slog.w(TAG, "Exception thrown during pause", e);
3112 // Just in case, assume it to be stopped.
3113 r.stopped = true;
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003114 if (DEBUG_STATES) Slog.v(TAG, "Stop failed; moving to STOPPED: " + r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003115 r.state = ActivityState.STOPPED;
3116 if (r.configDestroy) {
Dianne Hackborn28695e02011-11-02 21:59:51 -07003117 destroyActivityLocked(r, true, false, "stop-except");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003118 }
3119 }
3120 }
3121 }
3122
3123 final ArrayList<ActivityRecord> processStoppingActivitiesLocked(
3124 boolean remove) {
3125 int N = mStoppingActivities.size();
3126 if (N <= 0) return null;
3127
3128 ArrayList<ActivityRecord> stops = null;
3129
3130 final boolean nowVisible = mResumedActivity != null
3131 && mResumedActivity.nowVisible
3132 && !mResumedActivity.waitingVisible;
3133 for (int i=0; i<N; i++) {
3134 ActivityRecord s = mStoppingActivities.get(i);
3135 if (localLOGV) Slog.v(TAG, "Stopping " + s + ": nowVisible="
3136 + nowVisible + " waitingVisible=" + s.waitingVisible
3137 + " finishing=" + s.finishing);
3138 if (s.waitingVisible && nowVisible) {
3139 mWaitingVisibleActivities.remove(s);
3140 s.waitingVisible = false;
3141 if (s.finishing) {
3142 // If this activity is finishing, it is sitting on top of
3143 // everyone else but we now know it is no longer needed...
3144 // so get rid of it. Otherwise, we need to go through the
3145 // normal flow and hide it once we determine that it is
3146 // hidden by the activities in front of it.
3147 if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
3148 mService.mWindowManager.setAppVisibility(s, false);
3149 }
3150 }
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003151 if ((!s.waitingVisible || mService.isSleeping()) && remove) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003152 if (localLOGV) Slog.v(TAG, "Ready to stop: " + s);
3153 if (stops == null) {
3154 stops = new ArrayList<ActivityRecord>();
3155 }
3156 stops.add(s);
3157 mStoppingActivities.remove(i);
3158 N--;
3159 i--;
3160 }
3161 }
3162
3163 return stops;
3164 }
3165
Dianne Hackborn80a7ac12011-09-22 18:32:52 -07003166 final void scheduleIdleLocked() {
3167 Message msg = Message.obtain();
3168 msg.what = IDLE_NOW_MSG;
3169 mHandler.sendMessage(msg);
3170 }
3171
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003172 final ActivityRecord activityIdleInternal(IBinder token, boolean fromTimeout,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003173 Configuration config) {
3174 if (localLOGV) Slog.v(TAG, "Activity idle: " + token);
3175
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003176 ActivityRecord res = null;
3177
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003178 ArrayList<ActivityRecord> stops = null;
3179 ArrayList<ActivityRecord> finishes = null;
3180 ArrayList<ActivityRecord> thumbnails = null;
3181 int NS = 0;
3182 int NF = 0;
3183 int NT = 0;
3184 IApplicationThread sendThumbnail = null;
3185 boolean booting = false;
3186 boolean enableScreen = false;
3187
3188 synchronized (mService) {
3189 if (token != null) {
3190 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
3191 }
3192
3193 // Get the activity record.
3194 int index = indexOfTokenLocked(token);
3195 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003196 ActivityRecord r = mHistory.get(index);
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003197 res = r;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003198
3199 if (fromTimeout) {
3200 reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
3201 }
3202
3203 // This is a hack to semi-deal with a race condition
3204 // in the client where it can be constructed with a
3205 // newer configuration from when we asked it to launch.
3206 // We'll update with whatever configuration it now says
3207 // it used to launch.
3208 if (config != null) {
3209 r.configuration = config;
3210 }
3211
3212 // No longer need to keep the device awake.
3213 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
3214 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
3215 mLaunchingActivity.release();
3216 }
3217
3218 // We are now idle. If someone is waiting for a thumbnail from
3219 // us, we can now deliver.
3220 r.idle = true;
3221 mService.scheduleAppGcsLocked();
3222 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
3223 sendThumbnail = r.app.thread;
3224 r.thumbnailNeeded = false;
3225 }
3226
3227 // If this activity is fullscreen, set up to hide those under it.
3228
3229 if (DEBUG_VISBILITY) Slog.v(TAG, "Idle activity for " + r);
3230 ensureActivitiesVisibleLocked(null, 0);
3231
3232 //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
3233 if (mMainStack) {
Dianne Hackborn29aae6f2011-08-18 18:30:09 -07003234 if (!mService.mBooted) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003235 mService.mBooted = true;
3236 enableScreen = true;
3237 }
3238 }
3239
3240 } else if (fromTimeout) {
3241 reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
3242 }
3243
3244 // Atomically retrieve all of the other things to do.
3245 stops = processStoppingActivitiesLocked(true);
3246 NS = stops != null ? stops.size() : 0;
3247 if ((NF=mFinishingActivities.size()) > 0) {
3248 finishes = new ArrayList<ActivityRecord>(mFinishingActivities);
3249 mFinishingActivities.clear();
3250 }
3251 if ((NT=mService.mCancelledThumbnails.size()) > 0) {
3252 thumbnails = new ArrayList<ActivityRecord>(mService.mCancelledThumbnails);
3253 mService.mCancelledThumbnails.clear();
3254 }
3255
3256 if (mMainStack) {
3257 booting = mService.mBooting;
3258 mService.mBooting = false;
3259 }
3260 }
3261
3262 int i;
3263
3264 // Send thumbnail if requested.
3265 if (sendThumbnail != null) {
3266 try {
3267 sendThumbnail.requestThumbnail(token);
3268 } catch (Exception e) {
3269 Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
3270 mService.sendPendingThumbnail(null, token, null, null, true);
3271 }
3272 }
3273
3274 // Stop any activities that are scheduled to do so but have been
3275 // waiting for the next one to start.
3276 for (i=0; i<NS; i++) {
3277 ActivityRecord r = (ActivityRecord)stops.get(i);
3278 synchronized (mService) {
3279 if (r.finishing) {
3280 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
3281 } else {
3282 stopActivityLocked(r);
3283 }
3284 }
3285 }
3286
3287 // Finish any activities that are scheduled to do so but have been
3288 // waiting for the next one to start.
3289 for (i=0; i<NF; i++) {
3290 ActivityRecord r = (ActivityRecord)finishes.get(i);
3291 synchronized (mService) {
Dianne Hackborn28695e02011-11-02 21:59:51 -07003292 destroyActivityLocked(r, true, false, "finish-idle");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003293 }
3294 }
3295
3296 // Report back to any thumbnail receivers.
3297 for (i=0; i<NT; i++) {
3298 ActivityRecord r = (ActivityRecord)thumbnails.get(i);
3299 mService.sendPendingThumbnail(r, null, null, null, true);
3300 }
3301
3302 if (booting) {
3303 mService.finishBooting();
3304 }
3305
3306 mService.trimApplications();
3307 //dump();
3308 //mWindowManager.dump();
3309
3310 if (enableScreen) {
3311 mService.enableScreenAfterBoot();
3312 }
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003313
3314 return res;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003315 }
3316
3317 /**
3318 * @return Returns true if the activity is being finished, false if for
3319 * some reason it is being left as-is.
3320 */
3321 final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3322 Intent resultData, String reason) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003323 int index = indexOfTokenLocked(token);
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07003324 if (DEBUG_RESULTS) Slog.v(
3325 TAG, "Finishing activity @" + index + ": token=" + token
3326 + ", result=" + resultCode + ", data=" + resultData);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003327 if (index < 0) {
3328 return false;
3329 }
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003330 ActivityRecord r = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003331
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003332 finishActivityLocked(r, index, resultCode, resultData, reason);
3333 return true;
3334 }
3335
3336 /**
3337 * @return Returns true if this activity has been removed from the history
3338 * list, or false if it is still in the list and will be removed later.
3339 */
3340 final boolean finishActivityLocked(ActivityRecord r, int index,
3341 int resultCode, Intent resultData, String reason) {
3342 if (r.finishing) {
3343 Slog.w(TAG, "Duplicate finish request for " + r);
3344 return false;
3345 }
3346
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -08003347 r.makeFinishing();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003348 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
3349 System.identityHashCode(r),
3350 r.task.taskId, r.shortComponentName, reason);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003351 if (index < (mHistory.size()-1)) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003352 ActivityRecord next = mHistory.get(index+1);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003353 if (next.task == r.task) {
3354 if (r.frontOfTask) {
3355 // The next activity is now the front of the task.
3356 next.frontOfTask = true;
3357 }
3358 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
3359 // If the caller asked that this activity (and all above it)
3360 // be cleared when the task is reset, don't lose that information,
3361 // but propagate it up to the next activity.
3362 next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
3363 }
3364 }
3365 }
3366
3367 r.pauseKeyDispatchingLocked();
3368 if (mMainStack) {
3369 if (mService.mFocusedActivity == r) {
3370 mService.setFocusedActivityLocked(topRunningActivityLocked(null));
3371 }
3372 }
3373
3374 // send the result
3375 ActivityRecord resultTo = r.resultTo;
3376 if (resultTo != null) {
3377 if (DEBUG_RESULTS) Slog.v(TAG, "Adding result to " + resultTo
3378 + " who=" + r.resultWho + " req=" + r.requestCode
3379 + " res=" + resultCode + " data=" + resultData);
3380 if (r.info.applicationInfo.uid > 0) {
3381 mService.grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
Dianne Hackborna1c69e02010-09-01 22:55:02 -07003382 resultTo.packageName, resultData,
3383 resultTo.getUriPermissionsLocked());
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003384 }
3385 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3386 resultData);
3387 r.resultTo = null;
3388 }
3389 else if (DEBUG_RESULTS) Slog.v(TAG, "No result destination from " + r);
3390
3391 // Make sure this HistoryRecord is not holding on to other resources,
3392 // because clients have remote IPC references to this object so we
3393 // can't assume that will go away and want to avoid circular IPC refs.
3394 r.results = null;
3395 r.pendingResults = null;
3396 r.newIntents = null;
3397 r.icicle = null;
3398
3399 if (mService.mPendingThumbnails.size() > 0) {
3400 // There are clients waiting to receive thumbnails so, in case
3401 // this is an activity that someone is waiting for, add it
3402 // to the pending list so we can correctly update the clients.
3403 mService.mCancelledThumbnails.add(r);
3404 }
3405
3406 if (mResumedActivity == r) {
3407 boolean endTask = index <= 0
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003408 || (mHistory.get(index-1)).task != r.task;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003409 if (DEBUG_TRANSITION) Slog.v(TAG,
3410 "Prepare close transition: finishing " + r);
3411 mService.mWindowManager.prepareAppTransition(endTask
3412 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003413 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003414
3415 // Tell window manager to prepare for this one to be removed.
3416 mService.mWindowManager.setAppVisibility(r, false);
3417
3418 if (mPausingActivity == null) {
3419 if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
3420 if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
3421 startPausingLocked(false, false);
3422 }
3423
3424 } else if (r.state != ActivityState.PAUSING) {
3425 // If the activity is PAUSING, we will complete the finish once
3426 // it is done pausing; else we can just directly finish it here.
3427 if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
3428 return finishCurrentActivityLocked(r, index,
3429 FINISH_AFTER_PAUSE) == null;
3430 } else {
3431 if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
3432 }
3433
3434 return false;
3435 }
3436
3437 private static final int FINISH_IMMEDIATELY = 0;
3438 private static final int FINISH_AFTER_PAUSE = 1;
3439 private static final int FINISH_AFTER_VISIBLE = 2;
3440
3441 private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
3442 int mode) {
3443 final int index = indexOfTokenLocked(r);
3444 if (index < 0) {
3445 return null;
3446 }
3447
3448 return finishCurrentActivityLocked(r, index, mode);
3449 }
3450
3451 private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
3452 int index, int mode) {
3453 // First things first: if this activity is currently visible,
3454 // and the resumed activity is not yet visible, then hold off on
3455 // finishing until the resumed one becomes visible.
3456 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3457 if (!mStoppingActivities.contains(r)) {
3458 mStoppingActivities.add(r);
3459 if (mStoppingActivities.size() > 3) {
3460 // If we already have a few activities waiting to stop,
3461 // then give up on things going idle and start clearing
3462 // them out.
Dianne Hackborn80a7ac12011-09-22 18:32:52 -07003463 scheduleIdleLocked();
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003464 } else {
3465 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003466 }
3467 }
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003468 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
3469 + " (finish requested)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003470 r.state = ActivityState.STOPPING;
3471 mService.updateOomAdjLocked();
3472 return r;
3473 }
3474
3475 // make sure the record is cleaned out of other places.
3476 mStoppingActivities.remove(r);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003477 mGoingToSleepActivities.remove(r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003478 mWaitingVisibleActivities.remove(r);
3479 if (mResumedActivity == r) {
3480 mResumedActivity = null;
3481 }
3482 final ActivityState prevState = r.state;
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003483 if (DEBUG_STATES) Slog.v(TAG, "Moving to FINISHING: " + r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003484 r.state = ActivityState.FINISHING;
3485
3486 if (mode == FINISH_IMMEDIATELY
3487 || prevState == ActivityState.STOPPED
3488 || prevState == ActivityState.INITIALIZING) {
3489 // If this activity is already stopped, we can just finish
3490 // it right now.
Dianne Hackborn28695e02011-11-02 21:59:51 -07003491 return destroyActivityLocked(r, true, true, "finish-imm") ? null : r;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003492 } else {
3493 // Need to go through the full pause cycle to get this
3494 // activity into the stopped state and then finish it.
3495 if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
3496 mFinishingActivities.add(r);
3497 resumeTopActivityLocked(null);
3498 }
3499 return r;
3500 }
3501
3502 /**
3503 * Perform the common clean-up of an activity record. This is called both
3504 * as part of destroyActivityLocked() (when destroying the client-side
3505 * representation) and cleaning things up as a result of its hosting
3506 * processing going away, in which case there is no remaining client-side
3507 * state to destroy so only the cleanup here is needed.
3508 */
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003509 final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices,
3510 boolean setState) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003511 if (mResumedActivity == r) {
3512 mResumedActivity = null;
3513 }
3514 if (mService.mFocusedActivity == r) {
3515 mService.mFocusedActivity = null;
3516 }
3517
3518 r.configDestroy = false;
3519 r.frozenBeforeDestroy = false;
3520
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003521 if (setState) {
3522 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (cleaning up)");
3523 r.state = ActivityState.DESTROYED;
3524 }
3525
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003526 // Make sure this record is no longer in the pending finishes list.
3527 // This could happen, for example, if we are trimming activities
3528 // down to the max limit while they are still waiting to finish.
3529 mFinishingActivities.remove(r);
3530 mWaitingVisibleActivities.remove(r);
3531
3532 // Remove any pending results.
3533 if (r.finishing && r.pendingResults != null) {
3534 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
3535 PendingIntentRecord rec = apr.get();
3536 if (rec != null) {
3537 mService.cancelIntentSenderLocked(rec, false);
3538 }
3539 }
3540 r.pendingResults = null;
3541 }
3542
3543 if (cleanServices) {
3544 cleanUpActivityServicesLocked(r);
3545 }
3546
3547 if (mService.mPendingThumbnails.size() > 0) {
3548 // There are clients waiting to receive thumbnails so, in case
3549 // this is an activity that someone is waiting for, add it
3550 // to the pending list so we can correctly update the clients.
3551 mService.mCancelledThumbnails.add(r);
3552 }
3553
3554 // Get rid of any pending idle timeouts.
3555 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
3556 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003557 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003558 }
3559
3560 private final void removeActivityFromHistoryLocked(ActivityRecord r) {
3561 if (r.state != ActivityState.DESTROYED) {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -08003562 r.makeFinishing();
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07003563 if (DEBUG_ADD_REMOVE) {
3564 RuntimeException here = new RuntimeException("here");
3565 here.fillInStackTrace();
3566 Slog.i(TAG, "Removing activity " + r + " from stack");
3567 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003568 mHistory.remove(r);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07003569 r.takeFromHistory();
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003570 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
3571 + " (removed from history)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003572 r.state = ActivityState.DESTROYED;
3573 mService.mWindowManager.removeAppToken(r);
3574 if (VALIDATE_TOKENS) {
3575 mService.mWindowManager.validateAppTokens(mHistory);
3576 }
3577 cleanUpActivityServicesLocked(r);
3578 r.removeUriPermissionsLocked();
3579 }
3580 }
3581
3582 /**
3583 * Perform clean-up of service connections in an activity record.
3584 */
3585 final void cleanUpActivityServicesLocked(ActivityRecord r) {
3586 // Throw away any services that have been bound by this activity.
3587 if (r.connections != null) {
3588 Iterator<ConnectionRecord> it = r.connections.iterator();
3589 while (it.hasNext()) {
3590 ConnectionRecord c = it.next();
3591 mService.removeConnectionLocked(c, null, r);
3592 }
3593 r.connections = null;
3594 }
3595 }
3596
Dianne Hackborn28695e02011-11-02 21:59:51 -07003597 final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj, String reason) {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003598 for (int i=mHistory.size()-1; i>=0; i--) {
3599 ActivityRecord r = mHistory.get(i);
3600 if (owner != null && r.app != owner) {
3601 continue;
3602 }
3603 // We can destroy this one if we have its icicle saved and
3604 // it is not in the process of pausing/stopping/finishing.
3605 if (r.app != null && r.haveState && !r.visible && r.stopped && !r.finishing
3606 && r.state != ActivityState.DESTROYING
3607 && r.state != ActivityState.DESTROYED) {
Dianne Hackborn28695e02011-11-02 21:59:51 -07003608 destroyActivityLocked(r, true, oomAdj, "trim");
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003609 }
3610 }
3611 }
3612
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003613 /**
3614 * Destroy the current CLIENT SIDE instance of an activity. This may be
3615 * called both when actually finishing an activity, or when performing
3616 * a configuration switch where we destroy the current client-side object
3617 * but then create a new client-side object for this same HistoryRecord.
3618 */
3619 final boolean destroyActivityLocked(ActivityRecord r,
Dianne Hackborn28695e02011-11-02 21:59:51 -07003620 boolean removeFromApp, boolean oomAdj, String reason) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003621 if (DEBUG_SWITCH) Slog.v(
3622 TAG, "Removing activity: token=" + r
3623 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
3624 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
3625 System.identityHashCode(r),
Dianne Hackborn28695e02011-11-02 21:59:51 -07003626 r.task.taskId, r.shortComponentName, reason);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003627
3628 boolean removedFromHistory = false;
3629
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003630 cleanUpActivityLocked(r, false, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003631
3632 final boolean hadApp = r.app != null;
3633
3634 if (hadApp) {
3635 if (removeFromApp) {
3636 int idx = r.app.activities.indexOf(r);
3637 if (idx >= 0) {
3638 r.app.activities.remove(idx);
3639 }
3640 if (mService.mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) {
3641 mService.mHeavyWeightProcess = null;
3642 mService.mHandler.sendEmptyMessage(
3643 ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
3644 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003645 if (r.app.activities.size() == 0) {
3646 // No longer have activities, so update location in
3647 // LRU list.
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003648 mService.updateLruProcessLocked(r.app, oomAdj, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003649 }
3650 }
3651
3652 boolean skipDestroy = false;
3653
3654 try {
3655 if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
3656 r.app.thread.scheduleDestroyActivity(r, r.finishing,
3657 r.configChangeFlags);
3658 } catch (Exception e) {
3659 // We can just ignore exceptions here... if the process
3660 // has crashed, our death notification will clean things
3661 // up.
3662 //Slog.w(TAG, "Exception thrown during finish", e);
3663 if (r.finishing) {
3664 removeActivityFromHistoryLocked(r);
3665 removedFromHistory = true;
3666 skipDestroy = true;
3667 }
3668 }
3669
3670 r.app = null;
3671 r.nowVisible = false;
3672
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003673 // If the activity is finishing, we need to wait on removing it
3674 // from the list to give it a chance to do its cleanup. During
3675 // that time it may make calls back with its token so we need to
3676 // be able to find it on the list and so we don't want to remove
3677 // it from the list yet. Otherwise, we can just immediately put
3678 // it in the destroyed state since we are not removing it from the
3679 // list.
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003680 if (r.finishing && !skipDestroy) {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003681 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYING: " + r
3682 + " (destroy requested)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003683 r.state = ActivityState.DESTROYING;
3684 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
3685 msg.obj = r;
3686 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
3687 } else {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003688 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
3689 + " (destroy skipped)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003690 r.state = ActivityState.DESTROYED;
3691 }
3692 } else {
3693 // remove this record from the history.
3694 if (r.finishing) {
3695 removeActivityFromHistoryLocked(r);
3696 removedFromHistory = true;
3697 } else {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003698 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
3699 + " (no app)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003700 r.state = ActivityState.DESTROYED;
3701 }
3702 }
3703
3704 r.configChangeFlags = 0;
3705
3706 if (!mLRUActivities.remove(r) && hadApp) {
3707 Slog.w(TAG, "Activity " + r + " being finished, but not in LRU list");
3708 }
3709
3710 return removedFromHistory;
3711 }
3712
3713 final void activityDestroyed(IBinder token) {
3714 synchronized (mService) {
3715 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
3716
3717 int index = indexOfTokenLocked(token);
3718 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003719 ActivityRecord r = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003720 if (r.state == ActivityState.DESTROYING) {
3721 final long origId = Binder.clearCallingIdentity();
3722 removeActivityFromHistoryLocked(r);
3723 Binder.restoreCallingIdentity(origId);
3724 }
3725 }
3726 }
3727 }
3728
3729 private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
3730 int i = list.size();
3731 if (localLOGV) Slog.v(
3732 TAG, "Removing app " + app + " from list " + list
3733 + " with " + i + " entries");
3734 while (i > 0) {
3735 i--;
3736 ActivityRecord r = (ActivityRecord)list.get(i);
3737 if (localLOGV) Slog.v(
3738 TAG, "Record #" + i + " " + r + ": app=" + r.app);
3739 if (r.app == app) {
3740 if (localLOGV) Slog.v(TAG, "Removing this entry!");
3741 list.remove(i);
3742 }
3743 }
3744 }
3745
3746 void removeHistoryRecordsForAppLocked(ProcessRecord app) {
3747 removeHistoryRecordsForAppLocked(mLRUActivities, app);
3748 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003749 removeHistoryRecordsForAppLocked(mGoingToSleepActivities, app);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003750 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
3751 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
3752 }
3753
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003754 /**
3755 * Move the current home activity's task (if one exists) to the front
3756 * of the stack.
3757 */
3758 final void moveHomeToFrontLocked() {
3759 TaskRecord homeTask = null;
3760 for (int i=mHistory.size()-1; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003761 ActivityRecord hr = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003762 if (hr.isHomeActivity) {
3763 homeTask = hr.task;
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -08003764 break;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003765 }
3766 }
3767 if (homeTask != null) {
3768 moveTaskToFrontLocked(homeTask, null);
3769 }
3770 }
3771
3772
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003773 final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason) {
3774 if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
3775
3776 final int task = tr.taskId;
3777 int top = mHistory.size()-1;
3778
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003779 if (top < 0 || (mHistory.get(top)).task.taskId == task) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003780 // nothing to do!
3781 return;
3782 }
3783
3784 ArrayList moved = new ArrayList();
3785
3786 // Applying the affinities may have removed entries from the history,
3787 // so get the size again.
3788 top = mHistory.size()-1;
3789 int pos = top;
3790
3791 // Shift all activities with this task up to the top
3792 // of the stack, keeping them in the same internal order.
3793 while (pos >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003794 ActivityRecord r = mHistory.get(pos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003795 if (localLOGV) Slog.v(
3796 TAG, "At " + pos + " ckp " + r.task + ": " + r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003797 if (r.task.taskId == task) {
3798 if (localLOGV) Slog.v(TAG, "Removing and adding at " + top);
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07003799 if (DEBUG_ADD_REMOVE) {
3800 RuntimeException here = new RuntimeException("here");
3801 here.fillInStackTrace();
3802 Slog.i(TAG, "Removing and adding activity " + r + " to stack at " + top, here);
3803 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003804 mHistory.remove(pos);
3805 mHistory.add(top, r);
3806 moved.add(0, r);
3807 top--;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003808 }
3809 pos--;
3810 }
3811
3812 if (DEBUG_TRANSITION) Slog.v(TAG,
3813 "Prepare to front transition: task=" + tr);
3814 if (reason != null &&
3815 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003816 mService.mWindowManager.prepareAppTransition(
3817 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003818 ActivityRecord r = topRunningActivityLocked(null);
3819 if (r != null) {
3820 mNoAnimActivities.add(r);
3821 }
3822 } else {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003823 mService.mWindowManager.prepareAppTransition(
3824 WindowManagerPolicy.TRANSIT_TASK_TO_FRONT, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003825 }
3826
3827 mService.mWindowManager.moveAppTokensToTop(moved);
3828 if (VALIDATE_TOKENS) {
3829 mService.mWindowManager.validateAppTokens(mHistory);
3830 }
3831
3832 finishTaskMoveLocked(task);
3833 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
3834 }
3835
3836 private final void finishTaskMoveLocked(int task) {
3837 resumeTopActivityLocked(null);
3838 }
3839
3840 /**
3841 * Worker method for rearranging history stack. Implements the function of moving all
3842 * activities for a specific task (gathering them if disjoint) into a single group at the
3843 * bottom of the stack.
3844 *
3845 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
3846 * to premeptively cancel the move.
3847 *
3848 * @param task The taskId to collect and move to the bottom.
3849 * @return Returns true if the move completed, false if not.
3850 */
3851 final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
3852 Slog.i(TAG, "moveTaskToBack: " + task);
3853
3854 // If we have a watcher, preflight the move before committing to it. First check
3855 // for *other* available tasks, but if none are available, then try again allowing the
3856 // current task to be selected.
3857 if (mMainStack && mService.mController != null) {
3858 ActivityRecord next = topRunningActivityLocked(null, task);
3859 if (next == null) {
3860 next = topRunningActivityLocked(null, 0);
3861 }
3862 if (next != null) {
3863 // ask watcher if this is allowed
3864 boolean moveOK = true;
3865 try {
3866 moveOK = mService.mController.activityResuming(next.packageName);
3867 } catch (RemoteException e) {
3868 mService.mController = null;
3869 }
3870 if (!moveOK) {
3871 return false;
3872 }
3873 }
3874 }
3875
3876 ArrayList moved = new ArrayList();
3877
3878 if (DEBUG_TRANSITION) Slog.v(TAG,
3879 "Prepare to back transition: task=" + task);
3880
3881 final int N = mHistory.size();
3882 int bottom = 0;
3883 int pos = 0;
3884
3885 // Shift all activities with this task down to the bottom
3886 // of the stack, keeping them in the same internal order.
3887 while (pos < N) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003888 ActivityRecord r = mHistory.get(pos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003889 if (localLOGV) Slog.v(
3890 TAG, "At " + pos + " ckp " + r.task + ": " + r);
3891 if (r.task.taskId == task) {
3892 if (localLOGV) Slog.v(TAG, "Removing and adding at " + (N-1));
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07003893 if (DEBUG_ADD_REMOVE) {
3894 RuntimeException here = new RuntimeException("here");
3895 here.fillInStackTrace();
3896 Slog.i(TAG, "Removing and adding activity " + r + " to stack at "
3897 + bottom, here);
3898 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003899 mHistory.remove(pos);
3900 mHistory.add(bottom, r);
3901 moved.add(r);
3902 bottom++;
3903 }
3904 pos++;
3905 }
3906
3907 if (reason != null &&
3908 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003909 mService.mWindowManager.prepareAppTransition(
3910 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003911 ActivityRecord r = topRunningActivityLocked(null);
3912 if (r != null) {
3913 mNoAnimActivities.add(r);
3914 }
3915 } else {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003916 mService.mWindowManager.prepareAppTransition(
3917 WindowManagerPolicy.TRANSIT_TASK_TO_BACK, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003918 }
3919 mService.mWindowManager.moveAppTokensToBottom(moved);
3920 if (VALIDATE_TOKENS) {
3921 mService.mWindowManager.validateAppTokens(mHistory);
3922 }
3923
3924 finishTaskMoveLocked(task);
3925 return true;
3926 }
3927
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003928 public ActivityManager.TaskThumbnails getTaskThumbnailsLocked(TaskRecord tr) {
3929 TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
3930 ActivityRecord resumed = mResumedActivity;
3931 if (resumed != null && resumed.thumbHolder == tr) {
3932 info.mainThumbnail = resumed.stack.screenshotActivities(resumed);
3933 } else {
3934 info.mainThumbnail = tr.lastThumbnail;
3935 }
3936 return info;
3937 }
3938
3939 public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex) {
3940 TaskAccessInfo info = getTaskAccessInfoLocked(taskId, false);
3941 if (info.root == null) {
3942 Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId);
3943 return null;
3944 }
3945
3946 if (subTaskIndex < 0) {
3947 // Just remove the entire task.
3948 performClearTaskAtIndexLocked(taskId, info.rootIndex);
3949 return info.root;
3950 }
3951
3952 if (subTaskIndex >= info.subtasks.size()) {
3953 Slog.w(TAG, "removeTaskLocked: unknown subTaskIndex " + subTaskIndex);
3954 return null;
3955 }
3956
3957 // Remove all of this task's activies starting at the sub task.
3958 TaskAccessInfo.SubTask subtask = info.subtasks.get(subTaskIndex);
3959 performClearTaskAtIndexLocked(taskId, subtask.index);
3960 return subtask.activity;
3961 }
3962
3963 public TaskAccessInfo getTaskAccessInfoLocked(int taskId, boolean inclThumbs) {
3964 ActivityRecord resumed = mResumedActivity;
3965 final TaskAccessInfo thumbs = new TaskAccessInfo();
3966 // How many different sub-thumbnails?
3967 final int NA = mHistory.size();
3968 int j = 0;
3969 ThumbnailHolder holder = null;
3970 while (j < NA) {
3971 ActivityRecord ar = mHistory.get(j);
3972 if (!ar.finishing && ar.task.taskId == taskId) {
3973 holder = ar.thumbHolder;
3974 break;
3975 }
3976 j++;
3977 }
3978
3979 if (j >= NA) {
3980 return thumbs;
3981 }
3982
3983 thumbs.root = mHistory.get(j);
3984 thumbs.rootIndex = j;
3985
3986 ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>();
3987 thumbs.subtasks = subtasks;
3988 ActivityRecord lastActivity = null;
3989 while (j < NA) {
3990 ActivityRecord ar = mHistory.get(j);
3991 j++;
3992 if (ar.finishing) {
3993 continue;
3994 }
3995 if (ar.task.taskId != taskId) {
3996 break;
3997 }
3998 lastActivity = ar;
3999 if (ar.thumbHolder != holder && holder != null) {
4000 thumbs.numSubThumbbails++;
4001 holder = ar.thumbHolder;
4002 TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask();
4003 sub.thumbnail = holder.lastThumbnail;
4004 sub.activity = ar;
4005 sub.index = j-1;
4006 subtasks.add(sub);
4007 }
4008 }
4009 if (lastActivity != null && subtasks.size() > 0) {
4010 if (resumed == lastActivity) {
4011 TaskAccessInfo.SubTask sub = subtasks.get(subtasks.size()-1);
4012 sub.thumbnail = lastActivity.stack.screenshotActivities(lastActivity);
4013 }
4014 }
4015 if (thumbs.numSubThumbbails > 0) {
4016 thumbs.retriever = new IThumbnailRetriever.Stub() {
4017 public Bitmap getThumbnail(int index) {
4018 if (index < 0 || index >= thumbs.subtasks.size()) {
4019 return null;
4020 }
4021 return thumbs.subtasks.get(index).thumbnail;
4022 }
4023 };
4024 }
4025 return thumbs;
4026 }
4027
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004028 private final void logStartActivity(int tag, ActivityRecord r,
4029 TaskRecord task) {
4030 EventLog.writeEvent(tag,
4031 System.identityHashCode(r), task.taskId,
4032 r.shortComponentName, r.intent.getAction(),
4033 r.intent.getType(), r.intent.getDataString(),
4034 r.intent.getFlags());
4035 }
4036
4037 /**
4038 * Make sure the given activity matches the current configuration. Returns
4039 * false if the activity had to be destroyed. Returns true if the
4040 * configuration is the same, or the activity will remain running as-is
4041 * for whatever reason. Ensures the HistoryRecord is updated with the
4042 * correct configuration and all other bookkeeping is handled.
4043 */
4044 final boolean ensureActivityConfigurationLocked(ActivityRecord r,
4045 int globalChanges) {
4046 if (mConfigWillChange) {
4047 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4048 "Skipping config check (will change): " + r);
4049 return true;
4050 }
4051
4052 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4053 "Ensuring correct configuration: " + r);
4054
4055 // Short circuit: if the two configurations are the exact same
4056 // object (the common case), then there is nothing to do.
4057 Configuration newConfig = mService.mConfiguration;
Dianne Hackborne2515ee2011-04-27 18:52:56 -04004058 if (r.configuration == newConfig && !r.forceNewConfig) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004059 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4060 "Configuration unchanged in " + r);
4061 return true;
4062 }
4063
4064 // We don't worry about activities that are finishing.
4065 if (r.finishing) {
4066 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4067 "Configuration doesn't matter in finishing " + r);
4068 r.stopFreezingScreenLocked(false);
4069 return true;
4070 }
4071
4072 // Okay we now are going to make this activity have the new config.
4073 // But then we need to figure out how it needs to deal with that.
4074 Configuration oldConfig = r.configuration;
4075 r.configuration = newConfig;
Dianne Hackborn58f42a52011-10-10 13:46:34 -07004076
4077 // Determine what has changed. May be nothing, if this is a config
4078 // that has come back from the app after going idle. In that case
4079 // we just want to leave the official config object now in the
4080 // activity and do nothing else.
4081 final int changes = oldConfig.diff(newConfig);
4082 if (changes == 0 && !r.forceNewConfig) {
4083 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4084 "Configuration no differences in " + r);
4085 return true;
4086 }
4087
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004088 // If the activity isn't currently running, just leave the new
4089 // configuration and it will pick that up next time it starts.
4090 if (r.app == null || r.app.thread == null) {
4091 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4092 "Configuration doesn't matter not running " + r);
4093 r.stopFreezingScreenLocked(false);
Dianne Hackborne2515ee2011-04-27 18:52:56 -04004094 r.forceNewConfig = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004095 return true;
4096 }
4097
Dianne Hackborn58f42a52011-10-10 13:46:34 -07004098 // Figure out how to handle the changes between the configurations.
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004099 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
4100 Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
4101 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborne6676352011-06-01 16:51:20 -07004102 + Integer.toHexString(r.info.getRealConfigChanged())
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004103 + ", newConfig=" + newConfig);
4104 }
Dianne Hackborne6676352011-06-01 16:51:20 -07004105 if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) {
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004106 // Aha, the activity isn't handling the change, so DIE DIE DIE.
4107 r.configChangeFlags |= changes;
4108 r.startFreezingScreenLocked(r.app, globalChanges);
Dianne Hackborne2515ee2011-04-27 18:52:56 -04004109 r.forceNewConfig = false;
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004110 if (r.app == null || r.app.thread == null) {
4111 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4112 "Switch is destroying non-running " + r);
Dianne Hackborn28695e02011-11-02 21:59:51 -07004113 destroyActivityLocked(r, true, false, "config");
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004114 } else if (r.state == ActivityState.PAUSING) {
4115 // A little annoying: we are waiting for this activity to
4116 // finish pausing. Let's not do anything now, but just
4117 // flag that it needs to be restarted when done pausing.
4118 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4119 "Switch is skipping already pausing " + r);
4120 r.configDestroy = true;
4121 return true;
4122 } else if (r.state == ActivityState.RESUMED) {
4123 // Try to optimize this case: the configuration is changing
4124 // and we need to restart the top, resumed activity.
4125 // Instead of doing the normal handshaking, just say
4126 // "restart!".
4127 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4128 "Switch is restarting resumed " + r);
4129 relaunchActivityLocked(r, r.configChangeFlags, true);
4130 r.configChangeFlags = 0;
4131 } else {
4132 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4133 "Switch is restarting non-resumed " + r);
4134 relaunchActivityLocked(r, r.configChangeFlags, false);
4135 r.configChangeFlags = 0;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004136 }
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004137
4138 // All done... tell the caller we weren't able to keep this
4139 // activity around.
4140 return false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004141 }
4142
4143 // Default case: the activity can handle this new configuration, so
4144 // hand it over. Note that we don't need to give it the new
4145 // configuration, since we always send configuration changes to all
4146 // process when they happen so it can just use whatever configuration
4147 // it last got.
4148 if (r.app != null && r.app.thread != null) {
4149 try {
4150 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
4151 r.app.thread.scheduleActivityConfigurationChanged(r);
4152 } catch (RemoteException e) {
4153 // If process died, whatever.
4154 }
4155 }
4156 r.stopFreezingScreenLocked(false);
4157
4158 return true;
4159 }
4160
4161 private final boolean relaunchActivityLocked(ActivityRecord r,
4162 int changes, boolean andResume) {
4163 List<ResultInfo> results = null;
4164 List<Intent> newIntents = null;
4165 if (andResume) {
4166 results = r.results;
4167 newIntents = r.newIntents;
4168 }
4169 if (DEBUG_SWITCH) Slog.v(TAG, "Relaunching: " + r
4170 + " with results=" + results + " newIntents=" + newIntents
4171 + " andResume=" + andResume);
4172 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
4173 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
4174 r.task.taskId, r.shortComponentName);
4175
4176 r.startFreezingScreenLocked(r.app, 0);
4177
4178 try {
4179 if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
Dianne Hackborne2515ee2011-04-27 18:52:56 -04004180 r.forceNewConfig = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004181 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
4182 changes, !andResume, mService.mConfiguration);
4183 // Note: don't need to call pauseIfSleepingLocked() here, because
4184 // the caller will only pass in 'andResume' if this activity is
4185 // currently resumed, which implies we aren't sleeping.
4186 } catch (RemoteException e) {
4187 return false;
4188 }
4189
4190 if (andResume) {
4191 r.results = null;
4192 r.newIntents = null;
4193 if (mMainStack) {
4194 mService.reportResumedActivityLocked(r);
4195 }
4196 }
4197
4198 return true;
4199 }
Dianne Hackborn90c52de2011-09-23 12:57:44 -07004200
4201 public void dismissKeyguardOnNextActivityLocked() {
4202 mDismissKeyguardOnNextActivity = true;
4203 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004204}