blob: 95588956a31aabd34d3a943834497dd0f1950ede [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 Hackborn50dc3bc2010-06-25 10:05:59 -070055import android.os.Handler;
56import android.os.IBinder;
57import android.os.Message;
58import android.os.PowerManager;
59import android.os.RemoteException;
60import android.os.SystemClock;
61import android.util.EventLog;
62import android.util.Log;
63import android.util.Slog;
64import android.view.WindowManagerPolicy;
65
66import java.lang.ref.WeakReference;
67import java.util.ArrayList;
68import java.util.Iterator;
69import java.util.List;
70
71/**
72 * State and management of a single stack of activities.
73 */
Dianne Hackborn0c5001d2011-04-12 18:16:08 -070074final class ActivityStack {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070075 static final String TAG = ActivityManagerService.TAG;
76 static final boolean localLOGV = ActivityManagerService.localLOGV;
77 static final boolean DEBUG_SWITCH = ActivityManagerService.DEBUG_SWITCH;
78 static final boolean DEBUG_PAUSE = ActivityManagerService.DEBUG_PAUSE;
79 static final boolean DEBUG_VISBILITY = ActivityManagerService.DEBUG_VISBILITY;
80 static final boolean DEBUG_USER_LEAVING = ActivityManagerService.DEBUG_USER_LEAVING;
81 static final boolean DEBUG_TRANSITION = ActivityManagerService.DEBUG_TRANSITION;
82 static final boolean DEBUG_RESULTS = ActivityManagerService.DEBUG_RESULTS;
83 static final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
84 static final boolean DEBUG_TASKS = ActivityManagerService.DEBUG_TASKS;
85
86 static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
87
88 // How long we wait until giving up on the last activity telling us it
89 // is idle.
90 static final int IDLE_TIMEOUT = 10*1000;
91
92 // How long we wait until giving up on the last activity to pause. This
93 // is short because it directly impacts the responsiveness of starting the
94 // next activity.
95 static final int PAUSE_TIMEOUT = 500;
96
Dianne Hackborn4eba96b2011-01-21 13:34:36 -080097 // How long we can hold the sleep wake lock before giving up.
98 static final int SLEEP_TIMEOUT = 5*1000;
99
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700100 // How long we can hold the launch wake lock before giving up.
101 static final int LAUNCH_TIMEOUT = 10*1000;
102
103 // How long we wait until giving up on an activity telling us it has
104 // finished destroying itself.
105 static final int DESTROY_TIMEOUT = 10*1000;
106
107 // How long until we reset a task when the user returns to it. Currently
Dianne Hackborn621e17d2010-11-22 15:59:56 -0800108 // disabled.
109 static final long ACTIVITY_INACTIVE_RESET_TIME = 0;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700110
Dianne Hackborn0dad3642010-09-09 21:25:35 -0700111 // How long between activity launches that we consider safe to not warn
112 // the user about an unexpected activity being launched on top.
113 static final long START_WARN_TIME = 5*1000;
114
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700115 // Set to false to disable the preview that is shown while a new activity
116 // is being started.
117 static final boolean SHOW_APP_STARTING_PREVIEW = true;
118
119 enum ActivityState {
120 INITIALIZING,
121 RESUMED,
122 PAUSING,
123 PAUSED,
124 STOPPING,
125 STOPPED,
126 FINISHING,
127 DESTROYING,
128 DESTROYED
129 }
130
131 final ActivityManagerService mService;
132 final boolean mMainStack;
133
134 final Context mContext;
135
136 /**
137 * The back history of all previous (and possibly still
138 * running) activities. It contains HistoryRecord objects.
139 */
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700140 final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700141
142 /**
143 * List of running activities, sorted by recent usage.
144 * The first entry in the list is the least recently used.
145 * It contains HistoryRecord objects.
146 */
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700147 final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<ActivityRecord>();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700148
149 /**
150 * List of activities that are waiting for a new activity
151 * to become visible before completing whatever operation they are
152 * supposed to do.
153 */
154 final ArrayList<ActivityRecord> mWaitingVisibleActivities
155 = new ArrayList<ActivityRecord>();
156
157 /**
158 * List of activities that are ready to be stopped, but waiting
159 * for the next activity to settle down before doing so. It contains
160 * HistoryRecord objects.
161 */
162 final ArrayList<ActivityRecord> mStoppingActivities
163 = new ArrayList<ActivityRecord>();
164
165 /**
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800166 * List of activities that are in the process of going to sleep.
167 */
168 final ArrayList<ActivityRecord> mGoingToSleepActivities
169 = new ArrayList<ActivityRecord>();
170
171 /**
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700172 * Animations that for the current transition have requested not to
173 * be considered for the transition animation.
174 */
175 final ArrayList<ActivityRecord> mNoAnimActivities
176 = new ArrayList<ActivityRecord>();
177
178 /**
179 * List of activities that are ready to be finished, but waiting
180 * for the previous activity to settle down before doing so. It contains
181 * HistoryRecord objects.
182 */
183 final ArrayList<ActivityRecord> mFinishingActivities
184 = new ArrayList<ActivityRecord>();
185
186 /**
187 * List of people waiting to find out about the next launched activity.
188 */
189 final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched
190 = new ArrayList<IActivityManager.WaitResult>();
191
192 /**
193 * List of people waiting to find out about the next visible activity.
194 */
195 final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible
196 = new ArrayList<IActivityManager.WaitResult>();
197
198 /**
199 * Set when the system is going to sleep, until we have
200 * successfully paused the current activity and released our wake lock.
201 * At that point the system is allowed to actually sleep.
202 */
203 final PowerManager.WakeLock mGoingToSleep;
204
205 /**
206 * We don't want to allow the device to go to sleep while in the process
207 * of launching an activity. This is primarily to allow alarm intent
208 * receivers to launch an activity and get that to run before the device
209 * goes back to sleep.
210 */
211 final PowerManager.WakeLock mLaunchingActivity;
212
213 /**
214 * When we are in the process of pausing an activity, before starting the
215 * next one, this variable holds the activity that is currently being paused.
216 */
217 ActivityRecord mPausingActivity = null;
218
219 /**
220 * This is the last activity that we put into the paused state. This is
221 * used to determine if we need to do an activity transition while sleeping,
222 * when we normally hold the top activity paused.
223 */
224 ActivityRecord mLastPausedActivity = null;
225
226 /**
227 * Current activity that is resumed, or null if there is none.
228 */
229 ActivityRecord mResumedActivity = null;
230
231 /**
Dianne Hackborn0dad3642010-09-09 21:25:35 -0700232 * This is the last activity that has been started. It is only used to
233 * identify when multiple activities are started at once so that the user
234 * can be warned they may not be in the activity they think they are.
235 */
236 ActivityRecord mLastStartedActivity = null;
237
238 /**
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700239 * Set when we know we are going to be calling updateConfiguration()
240 * soon, so want to skip intermediate config checks.
241 */
242 boolean mConfigWillChange;
243
244 /**
245 * Set to indicate whether to issue an onUserLeaving callback when a
246 * newly launched activity is being brought in front of us.
247 */
248 boolean mUserLeaving = false;
249
250 long mInitialStartTime = 0;
251
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800252 /**
253 * Set when we have taken too long waiting to go to sleep.
254 */
255 boolean mSleepTimeout = false;
256
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800257 int mThumbnailWidth = -1;
258 int mThumbnailHeight = -1;
259
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800260 static final int SLEEP_TIMEOUT_MSG = 8;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700261 static final int PAUSE_TIMEOUT_MSG = 9;
262 static final int IDLE_TIMEOUT_MSG = 10;
263 static final int IDLE_NOW_MSG = 11;
264 static final int LAUNCH_TIMEOUT_MSG = 16;
265 static final int DESTROY_TIMEOUT_MSG = 17;
266 static final int RESUME_TOP_ACTIVITY_MSG = 19;
267
268 final Handler mHandler = new Handler() {
269 //public Handler() {
270 // if (localLOGV) Slog.v(TAG, "Handler started!");
271 //}
272
273 public void handleMessage(Message msg) {
274 switch (msg.what) {
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800275 case SLEEP_TIMEOUT_MSG: {
276 if (mService.isSleeping()) {
277 Slog.w(TAG, "Sleep timeout! Sleeping now.");
278 mSleepTimeout = true;
279 checkReadyForSleepLocked();
280 }
281 } break;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700282 case PAUSE_TIMEOUT_MSG: {
283 IBinder token = (IBinder)msg.obj;
284 // We don't at this point know if the activity is fullscreen,
285 // so we need to be conservative and assume it isn't.
286 Slog.w(TAG, "Activity pause timeout for " + token);
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800287 activityPaused(token, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700288 } break;
289 case IDLE_TIMEOUT_MSG: {
290 if (mService.mDidDexOpt) {
291 mService.mDidDexOpt = false;
292 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
293 nmsg.obj = msg.obj;
294 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
295 return;
296 }
297 // We don't at this point know if the activity is fullscreen,
298 // so we need to be conservative and assume it isn't.
299 IBinder token = (IBinder)msg.obj;
300 Slog.w(TAG, "Activity idle timeout for " + token);
301 activityIdleInternal(token, true, null);
302 } break;
303 case DESTROY_TIMEOUT_MSG: {
304 IBinder token = (IBinder)msg.obj;
305 // We don't at this point know if the activity is fullscreen,
306 // so we need to be conservative and assume it isn't.
307 Slog.w(TAG, "Activity destroy timeout for " + token);
308 activityDestroyed(token);
309 } break;
310 case IDLE_NOW_MSG: {
311 IBinder token = (IBinder)msg.obj;
312 activityIdleInternal(token, false, null);
313 } break;
314 case LAUNCH_TIMEOUT_MSG: {
315 if (mService.mDidDexOpt) {
316 mService.mDidDexOpt = false;
317 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
318 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
319 return;
320 }
321 synchronized (mService) {
322 if (mLaunchingActivity.isHeld()) {
323 Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
324 mLaunchingActivity.release();
325 }
326 }
327 } break;
328 case RESUME_TOP_ACTIVITY_MSG: {
329 synchronized (mService) {
330 resumeTopActivityLocked(null);
331 }
332 } break;
333 }
334 }
335 };
336
337 ActivityStack(ActivityManagerService service, Context context, boolean mainStack) {
338 mService = service;
339 mContext = context;
340 mMainStack = mainStack;
341 PowerManager pm =
342 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
343 mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
344 mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
345 mLaunchingActivity.setReferenceCounted(false);
346 }
347
348 final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
349 int i = mHistory.size()-1;
350 while (i >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700351 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700352 if (!r.finishing && r != notTop) {
353 return r;
354 }
355 i--;
356 }
357 return null;
358 }
359
360 final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
361 int i = mHistory.size()-1;
362 while (i >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700363 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700364 if (!r.finishing && !r.delayedResume && r != notTop) {
365 return r;
366 }
367 i--;
368 }
369 return null;
370 }
371
372 /**
373 * This is a simplified version of topRunningActivityLocked that provides a number of
374 * optional skip-over modes. It is intended for use with the ActivityController hook only.
375 *
376 * @param token If non-null, any history records matching this token will be skipped.
377 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
378 *
379 * @return Returns the HistoryRecord of the next activity on the stack.
380 */
381 final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
382 int i = mHistory.size()-1;
383 while (i >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700384 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700385 // Note: the taskId check depends on real taskId fields being non-zero
386 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
387 return r;
388 }
389 i--;
390 }
391 return null;
392 }
393
394 final int indexOfTokenLocked(IBinder token) {
395 int count = mHistory.size();
396
397 // convert the token to an entry in the history.
398 int index = -1;
399 for (int i=count-1; i>=0; i--) {
400 Object o = mHistory.get(i);
401 if (o == token) {
402 index = i;
403 break;
404 }
405 }
406
407 return index;
408 }
409
410 private final boolean updateLRUListLocked(ActivityRecord r) {
411 final boolean hadit = mLRUActivities.remove(r);
412 mLRUActivities.add(r);
413 return hadit;
414 }
415
416 /**
417 * Returns the top activity in any existing task matching the given
418 * Intent. Returns null if no such task is found.
419 */
420 private ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) {
421 ComponentName cls = intent.getComponent();
422 if (info.targetActivity != null) {
423 cls = new ComponentName(info.packageName, info.targetActivity);
424 }
425
426 TaskRecord cp = null;
427
428 final int N = mHistory.size();
429 for (int i=(N-1); i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700430 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700431 if (!r.finishing && r.task != cp
432 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
433 cp = r.task;
434 //Slog.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
435 // + "/aff=" + r.task.affinity + " to new cls="
436 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
437 if (r.task.affinity != null) {
438 if (r.task.affinity.equals(info.taskAffinity)) {
439 //Slog.i(TAG, "Found matching affinity!");
440 return r;
441 }
442 } else if (r.task.intent != null
443 && r.task.intent.getComponent().equals(cls)) {
444 //Slog.i(TAG, "Found matching class!");
445 //dump();
446 //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
447 return r;
448 } else if (r.task.affinityIntent != null
449 && r.task.affinityIntent.getComponent().equals(cls)) {
450 //Slog.i(TAG, "Found matching class!");
451 //dump();
452 //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
453 return r;
454 }
455 }
456 }
457
458 return null;
459 }
460
461 /**
462 * Returns the first activity (starting from the top of the stack) that
463 * is the same as the given activity. Returns null if no such activity
464 * is found.
465 */
466 private ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
467 ComponentName cls = intent.getComponent();
468 if (info.targetActivity != null) {
469 cls = new ComponentName(info.packageName, info.targetActivity);
470 }
471
472 final int N = mHistory.size();
473 for (int i=(N-1); i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700474 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700475 if (!r.finishing) {
476 if (r.intent.getComponent().equals(cls)) {
477 //Slog.i(TAG, "Found matching class!");
478 //dump();
479 //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
480 return r;
481 }
482 }
483 }
484
485 return null;
486 }
487
488 final boolean realStartActivityLocked(ActivityRecord r,
489 ProcessRecord app, boolean andResume, boolean checkConfig)
490 throws RemoteException {
491
492 r.startFreezingScreenLocked(app, 0);
493 mService.mWindowManager.setAppVisibility(r, true);
494
495 // Have the window manager re-evaluate the orientation of
496 // the screen based on the new activity order. Note that
497 // as a result of this, it can call back into the activity
498 // manager with a new orientation. We don't care about that,
499 // because the activity is not currently running so we are
500 // just restarting it anyway.
501 if (checkConfig) {
502 Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
503 mService.mConfiguration,
504 r.mayFreezeScreenLocked(app) ? r : null);
505 mService.updateConfigurationLocked(config, r);
506 }
507
508 r.app = app;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700509 app.waitingToKill = null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700510
511 if (localLOGV) Slog.v(TAG, "Launching: " + r);
512
513 int idx = app.activities.indexOf(r);
514 if (idx < 0) {
515 app.activities.add(r);
516 }
517 mService.updateLruProcessLocked(app, true, true);
518
519 try {
520 if (app.thread == null) {
521 throw new RemoteException();
522 }
523 List<ResultInfo> results = null;
524 List<Intent> newIntents = null;
525 if (andResume) {
526 results = r.results;
527 newIntents = r.newIntents;
528 }
529 if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
530 + " icicle=" + r.icicle
531 + " with results=" + results + " newIntents=" + newIntents
532 + " andResume=" + andResume);
533 if (andResume) {
534 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
535 System.identityHashCode(r),
536 r.task.taskId, r.shortComponentName);
537 }
538 if (r.isHomeActivity) {
539 mService.mHomeProcess = app;
540 }
541 mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800542 r.sleeping = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700543 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
544 System.identityHashCode(r),
545 r.info, r.icicle, results, newIntents, !andResume,
546 mService.isNextTransitionForward());
547
Dianne Hackborn54e570f2010-10-04 18:32:32 -0700548 if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700549 // This may be a heavy-weight process! Note that the package
550 // manager will ensure that only activity can run in the main
551 // process of the .apk, which is the only thing that will be
552 // considered heavy-weight.
553 if (app.processName.equals(app.info.packageName)) {
554 if (mService.mHeavyWeightProcess != null
555 && mService.mHeavyWeightProcess != app) {
556 Log.w(TAG, "Starting new heavy weight process " + app
557 + " when already running "
558 + mService.mHeavyWeightProcess);
559 }
560 mService.mHeavyWeightProcess = app;
561 Message msg = mService.mHandler.obtainMessage(
562 ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
563 msg.obj = r;
564 mService.mHandler.sendMessage(msg);
565 }
566 }
567
568 } catch (RemoteException e) {
569 if (r.launchFailed) {
570 // This is the second time we failed -- finish activity
571 // and give up.
572 Slog.e(TAG, "Second failure launching "
573 + r.intent.getComponent().flattenToShortString()
574 + ", giving up", e);
575 mService.appDiedLocked(app, app.pid, app.thread);
576 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
577 "2nd-crash");
578 return false;
579 }
580
581 // This is the first time we failed -- restart process and
582 // retry.
583 app.activities.remove(r);
584 throw e;
585 }
586
587 r.launchFailed = false;
588 if (updateLRUListLocked(r)) {
589 Slog.w(TAG, "Activity " + r
590 + " being launched, but already in LRU list");
591 }
592
593 if (andResume) {
594 // As part of the process of launching, ActivityThread also performs
595 // a resume.
596 r.state = ActivityState.RESUMED;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700597 r.stopped = false;
598 mResumedActivity = r;
599 r.task.touchActiveTime();
Dianne Hackborn88819b22010-12-21 18:18:02 -0800600 if (mMainStack) {
601 mService.addRecentTaskLocked(r.task);
602 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700603 completeResumeLocked(r);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800604 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700605 } else {
606 // This activity is not starting in the resumed state... which
607 // should look like we asked it to pause+stop (but remain visible),
608 // and it has done so and reported back the current icicle and
609 // other state.
610 r.state = ActivityState.STOPPED;
611 r.stopped = true;
612 }
613
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800614 r.icicle = null;
615 r.haveState = false;
616
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700617 // Launch the new version setup screen if needed. We do this -after-
618 // launching the initial activity (that is, home), so that it can have
619 // a chance to initialize itself while in the background, making the
620 // switch back to it faster and look better.
621 if (mMainStack) {
622 mService.startSetupActivityLocked();
623 }
624
625 return true;
626 }
627
628 private final void startSpecificActivityLocked(ActivityRecord r,
629 boolean andResume, boolean checkConfig) {
630 // Is this activity's application already running?
631 ProcessRecord app = mService.getProcessRecordLocked(r.processName,
632 r.info.applicationInfo.uid);
633
Dianne Hackborn0dad3642010-09-09 21:25:35 -0700634 if (r.launchTime == 0) {
635 r.launchTime = SystemClock.uptimeMillis();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700636 if (mInitialStartTime == 0) {
Dianne Hackborn0dad3642010-09-09 21:25:35 -0700637 mInitialStartTime = r.launchTime;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700638 }
639 } else if (mInitialStartTime == 0) {
640 mInitialStartTime = SystemClock.uptimeMillis();
641 }
642
643 if (app != null && app.thread != null) {
644 try {
645 realStartActivityLocked(r, app, andResume, checkConfig);
646 return;
647 } catch (RemoteException e) {
648 Slog.w(TAG, "Exception when starting activity "
649 + r.intent.getComponent().flattenToShortString(), e);
650 }
651
652 // If a dead object exception was thrown -- fall through to
653 // restart the application.
654 }
655
656 mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
657 "activity", r.intent.getComponent(), false);
658 }
659
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800660 void stopIfSleepingLocked() {
661 if (mService.isSleeping()) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700662 if (!mGoingToSleep.isHeld()) {
663 mGoingToSleep.acquire();
664 if (mLaunchingActivity.isHeld()) {
665 mLaunchingActivity.release();
666 mService.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
667 }
668 }
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800669 mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
670 Message msg = mHandler.obtainMessage(SLEEP_TIMEOUT_MSG);
671 mHandler.sendMessageDelayed(msg, SLEEP_TIMEOUT);
672 checkReadyForSleepLocked();
673 }
674 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700675
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800676 void awakeFromSleepingLocked() {
677 mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
678 mSleepTimeout = false;
679 if (mGoingToSleep.isHeld()) {
680 mGoingToSleep.release();
681 }
682 // Ensure activities are no longer sleeping.
683 for (int i=mHistory.size()-1; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700684 ActivityRecord r = mHistory.get(i);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800685 r.setSleeping(false);
686 }
687 mGoingToSleepActivities.clear();
688 }
689
690 void activitySleptLocked(ActivityRecord r) {
691 mGoingToSleepActivities.remove(r);
692 checkReadyForSleepLocked();
693 }
694
695 void checkReadyForSleepLocked() {
696 if (!mService.isSleeping()) {
697 // Do not care.
698 return;
699 }
700
701 if (!mSleepTimeout) {
702 if (mResumedActivity != null) {
703 // Still have something resumed; can't sleep until it is paused.
704 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause " + mResumedActivity);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700705 if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false");
706 startPausingLocked(false, true);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800707 return;
708 }
709 if (mPausingActivity != null) {
710 // Still waiting for something to pause; can't sleep yet.
711 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity);
712 return;
713 }
714
715 if (mStoppingActivities.size() > 0) {
716 // Still need to tell some activities to stop; can't sleep yet.
717 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to stop "
718 + mStoppingActivities.size() + " activities");
719 Message msg = Message.obtain();
720 msg.what = IDLE_NOW_MSG;
721 mHandler.sendMessage(msg);
722 return;
723 }
724
725 ensureActivitiesVisibleLocked(null, 0);
726
727 // Make sure any stopped but visible activities are now sleeping.
728 // This ensures that the activity's onStop() is called.
729 for (int i=mHistory.size()-1; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700730 ActivityRecord r = mHistory.get(i);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800731 if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) {
732 r.setSleeping(true);
733 }
734 }
735
736 if (mGoingToSleepActivities.size() > 0) {
737 // Still need to tell some activities to sleep; can't sleep yet.
738 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to sleep "
739 + mGoingToSleepActivities.size() + " activities");
740 return;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700741 }
742 }
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800743
744 mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
745
746 if (mGoingToSleep.isHeld()) {
747 mGoingToSleep.release();
748 }
749 if (mService.mShuttingDown) {
750 mService.notifyAll();
751 }
752
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700753 }
754
Dianne Hackbornd2835932010-12-13 16:28:46 -0800755 public final Bitmap screenshotActivities(ActivityRecord who) {
Dianne Hackbornff801ec2011-01-22 18:05:38 -0800756 if (who.noDisplay) {
757 return null;
758 }
759
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800760 Resources res = mService.mContext.getResources();
761 int w = mThumbnailWidth;
762 int h = mThumbnailHeight;
763 if (w < 0) {
764 mThumbnailWidth = w =
765 res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
766 mThumbnailHeight = h =
767 res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
768 }
769
770 if (w > 0) {
Dianne Hackborn7c8a4b32010-12-15 14:58:00 -0800771 return mService.mWindowManager.screenshotApplications(who, w, h);
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800772 }
773 return null;
774 }
775
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700776 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
777 if (mPausingActivity != null) {
778 RuntimeException e = new RuntimeException();
779 Slog.e(TAG, "Trying to pause when pause is already pending for "
780 + mPausingActivity, e);
781 }
782 ActivityRecord prev = mResumedActivity;
783 if (prev == null) {
784 RuntimeException e = new RuntimeException();
785 Slog.e(TAG, "Trying to pause when nothing is resumed", e);
786 resumeTopActivityLocked(null);
787 return;
788 }
789 if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
790 mResumedActivity = null;
791 mPausingActivity = prev;
792 mLastPausedActivity = prev;
793 prev.state = ActivityState.PAUSING;
794 prev.task.touchActiveTime();
Dianne Hackbornf26fd992011-04-08 18:14:09 -0700795 prev.updateThumbnail(screenshotActivities(prev), null);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700796
797 mService.updateCpuStats();
798
799 if (prev.app != null && prev.app.thread != null) {
800 if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
801 try {
802 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
803 System.identityHashCode(prev),
804 prev.shortComponentName);
805 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
806 prev.configChangeFlags);
807 if (mMainStack) {
808 mService.updateUsageStats(prev, false);
809 }
810 } catch (Exception e) {
811 // Ignore exception, if process died other code will cleanup.
812 Slog.w(TAG, "Exception thrown during pause", e);
813 mPausingActivity = null;
814 mLastPausedActivity = null;
815 }
816 } else {
817 mPausingActivity = null;
818 mLastPausedActivity = null;
819 }
820
821 // If we are not going to sleep, we want to ensure the device is
822 // awake until the next activity is started.
823 if (!mService.mSleeping && !mService.mShuttingDown) {
824 mLaunchingActivity.acquire();
825 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
826 // To be safe, don't allow the wake lock to be held for too long.
827 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
828 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
829 }
830 }
831
832
833 if (mPausingActivity != null) {
834 // Have the window manager pause its key dispatching until the new
835 // activity has started. If we're pausing the activity just because
836 // the screen is being turned off and the UI is sleeping, don't interrupt
837 // key dispatch; the same activity will pick it up again on wakeup.
838 if (!uiSleeping) {
839 prev.pauseKeyDispatchingLocked();
840 } else {
841 if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
842 }
843
844 // Schedule a pause timeout in case the app doesn't respond.
845 // We don't give it much time because this directly impacts the
846 // responsiveness seen by the user.
847 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
848 msg.obj = prev;
849 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
850 if (DEBUG_PAUSE) Slog.v(TAG, "Waiting for pause to complete...");
851 } else {
852 // This activity failed to schedule the
853 // pause, so just treat it as being paused now.
854 if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
855 resumeTopActivityLocked(null);
856 }
857 }
858
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800859 final void activityPaused(IBinder token, boolean timeout) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700860 if (DEBUG_PAUSE) Slog.v(
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800861 TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700862
863 ActivityRecord r = null;
864
865 synchronized (mService) {
866 int index = indexOfTokenLocked(token);
867 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700868 r = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700869 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
870 if (mPausingActivity == r) {
871 r.state = ActivityState.PAUSED;
872 completePauseLocked();
873 } else {
874 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
875 System.identityHashCode(r), r.shortComponentName,
876 mPausingActivity != null
877 ? mPausingActivity.shortComponentName : "(none)");
878 }
879 }
880 }
881 }
882
883 private final void completePauseLocked() {
884 ActivityRecord prev = mPausingActivity;
885 if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
886
887 if (prev != null) {
888 if (prev.finishing) {
889 if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
890 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
891 } else if (prev.app != null) {
892 if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
893 if (prev.waitingVisible) {
894 prev.waitingVisible = false;
895 mWaitingVisibleActivities.remove(prev);
896 if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
897 TAG, "Complete pause, no longer waiting: " + prev);
898 }
899 if (prev.configDestroy) {
900 // The previous is being paused because the configuration
901 // is changing, which means it is actually stopping...
902 // To juggle the fact that we are also starting a new
903 // instance right now, we need to first completely stop
904 // the current instance before starting the new one.
905 if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
906 destroyActivityLocked(prev, true);
907 } else {
908 mStoppingActivities.add(prev);
909 if (mStoppingActivities.size() > 3) {
910 // If we already have a few activities waiting to stop,
911 // then give up on things going idle and start clearing
912 // them out.
913 if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
914 Message msg = Message.obtain();
915 msg.what = IDLE_NOW_MSG;
916 mHandler.sendMessage(msg);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800917 } else {
918 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700919 }
920 }
921 } else {
922 if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
923 prev = null;
924 }
925 mPausingActivity = null;
926 }
927
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800928 if (!mService.isSleeping()) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700929 resumeTopActivityLocked(prev);
930 } else {
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800931 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700932 }
933
934 if (prev != null) {
935 prev.resumeKeyDispatchingLocked();
936 }
937
938 if (prev.app != null && prev.cpuTimeAtResume > 0
939 && mService.mBatteryStatsService.isOnBattery()) {
940 long diff = 0;
941 synchronized (mService.mProcessStatsThread) {
942 diff = mService.mProcessStats.getCpuTimeForPid(prev.app.pid)
943 - prev.cpuTimeAtResume;
944 }
945 if (diff > 0) {
946 BatteryStatsImpl bsi = mService.mBatteryStatsService.getActiveStatistics();
947 synchronized (bsi) {
948 BatteryStatsImpl.Uid.Proc ps =
949 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
950 prev.info.packageName);
951 if (ps != null) {
952 ps.addForegroundTimeLocked(diff);
953 }
954 }
955 }
956 }
957 prev.cpuTimeAtResume = 0; // reset it
958 }
959
960 /**
961 * Once we know that we have asked an application to put an activity in
962 * the resumed state (either by launching it or explicitly telling it),
963 * this function updates the rest of our state to match that fact.
964 */
965 private final void completeResumeLocked(ActivityRecord next) {
966 next.idle = false;
967 next.results = null;
968 next.newIntents = null;
969
970 // schedule an idle timeout in case the app doesn't do it for us.
971 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
972 msg.obj = next;
973 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
974
975 if (false) {
976 // The activity was never told to pause, so just keep
977 // things going as-is. To maintain our own state,
978 // we need to emulate it coming back and saying it is
979 // idle.
980 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
981 msg.obj = next;
982 mHandler.sendMessage(msg);
983 }
984
985 if (mMainStack) {
986 mService.reportResumedActivityLocked(next);
987 }
988
Dianne Hackbornf26fd992011-04-08 18:14:09 -0700989 next.clearThumbnail();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700990 if (mMainStack) {
991 mService.setFocusedActivityLocked(next);
992 }
993 next.resumeKeyDispatchingLocked();
994 ensureActivitiesVisibleLocked(null, 0);
995 mService.mWindowManager.executeAppTransition();
996 mNoAnimActivities.clear();
997
998 // Mark the point when the activity is resuming
999 // TODO: To be more accurate, the mark should be before the onCreate,
1000 // not after the onResume. But for subsequent starts, onResume is fine.
1001 if (next.app != null) {
1002 synchronized (mService.mProcessStatsThread) {
1003 next.cpuTimeAtResume = mService.mProcessStats.getCpuTimeForPid(next.app.pid);
1004 }
1005 } else {
1006 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
1007 }
1008 }
1009
1010 /**
1011 * Make sure that all activities that need to be visible (that is, they
1012 * currently can be seen by the user) actually are.
1013 */
1014 final void ensureActivitiesVisibleLocked(ActivityRecord top,
1015 ActivityRecord starting, String onlyThisProcess, int configChanges) {
1016 if (DEBUG_VISBILITY) Slog.v(
1017 TAG, "ensureActivitiesVisible behind " + top
1018 + " configChanges=0x" + Integer.toHexString(configChanges));
1019
1020 // If the top activity is not fullscreen, then we need to
1021 // make sure any activities under it are now visible.
1022 final int count = mHistory.size();
1023 int i = count-1;
1024 while (mHistory.get(i) != top) {
1025 i--;
1026 }
1027 ActivityRecord r;
1028 boolean behindFullscreen = false;
1029 for (; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001030 r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001031 if (DEBUG_VISBILITY) Slog.v(
1032 TAG, "Make visible? " + r + " finishing=" + r.finishing
1033 + " state=" + r.state);
1034 if (r.finishing) {
1035 continue;
1036 }
1037
1038 final boolean doThisProcess = onlyThisProcess == null
1039 || onlyThisProcess.equals(r.processName);
1040
1041 // First: if this is not the current activity being started, make
1042 // sure it matches the current configuration.
1043 if (r != starting && doThisProcess) {
1044 ensureActivityConfigurationLocked(r, 0);
1045 }
1046
1047 if (r.app == null || r.app.thread == null) {
1048 if (onlyThisProcess == null
1049 || onlyThisProcess.equals(r.processName)) {
1050 // This activity needs to be visible, but isn't even
1051 // running... get it started, but don't resume it
1052 // at this point.
1053 if (DEBUG_VISBILITY) Slog.v(
1054 TAG, "Start and freeze screen for " + r);
1055 if (r != starting) {
1056 r.startFreezingScreenLocked(r.app, configChanges);
1057 }
1058 if (!r.visible) {
1059 if (DEBUG_VISBILITY) Slog.v(
1060 TAG, "Starting and making visible: " + r);
1061 mService.mWindowManager.setAppVisibility(r, true);
1062 }
1063 if (r != starting) {
1064 startSpecificActivityLocked(r, false, false);
1065 }
1066 }
1067
1068 } else if (r.visible) {
1069 // If this activity is already visible, then there is nothing
1070 // else to do here.
1071 if (DEBUG_VISBILITY) Slog.v(
1072 TAG, "Skipping: already visible at " + r);
1073 r.stopFreezingScreenLocked(false);
1074
1075 } else if (onlyThisProcess == null) {
1076 // This activity is not currently visible, but is running.
1077 // Tell it to become visible.
1078 r.visible = true;
1079 if (r.state != ActivityState.RESUMED && r != starting) {
1080 // If this activity is paused, tell it
1081 // to now show its window.
1082 if (DEBUG_VISBILITY) Slog.v(
1083 TAG, "Making visible and scheduling visibility: " + r);
1084 try {
1085 mService.mWindowManager.setAppVisibility(r, true);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001086 r.sleeping = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001087 r.app.thread.scheduleWindowVisibility(r, true);
1088 r.stopFreezingScreenLocked(false);
1089 } catch (Exception e) {
1090 // Just skip on any failure; we'll make it
1091 // visible when it next restarts.
1092 Slog.w(TAG, "Exception thrown making visibile: "
1093 + r.intent.getComponent(), e);
1094 }
1095 }
1096 }
1097
1098 // Aggregate current change flags.
1099 configChanges |= r.configChangeFlags;
1100
1101 if (r.fullscreen) {
1102 // At this point, nothing else needs to be shown
1103 if (DEBUG_VISBILITY) Slog.v(
1104 TAG, "Stopping: fullscreen at " + r);
1105 behindFullscreen = true;
1106 i--;
1107 break;
1108 }
1109 }
1110
1111 // Now for any activities that aren't visible to the user, make
1112 // sure they no longer are keeping the screen frozen.
1113 while (i >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001114 r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001115 if (DEBUG_VISBILITY) Slog.v(
1116 TAG, "Make invisible? " + r + " finishing=" + r.finishing
1117 + " state=" + r.state
1118 + " behindFullscreen=" + behindFullscreen);
1119 if (!r.finishing) {
1120 if (behindFullscreen) {
1121 if (r.visible) {
1122 if (DEBUG_VISBILITY) Slog.v(
1123 TAG, "Making invisible: " + r);
1124 r.visible = false;
1125 try {
1126 mService.mWindowManager.setAppVisibility(r, false);
1127 if ((r.state == ActivityState.STOPPING
1128 || r.state == ActivityState.STOPPED)
1129 && r.app != null && r.app.thread != null) {
1130 if (DEBUG_VISBILITY) Slog.v(
1131 TAG, "Scheduling invisibility: " + r);
1132 r.app.thread.scheduleWindowVisibility(r, false);
1133 }
1134 } catch (Exception e) {
1135 // Just skip on any failure; we'll make it
1136 // visible when it next restarts.
1137 Slog.w(TAG, "Exception thrown making hidden: "
1138 + r.intent.getComponent(), e);
1139 }
1140 } else {
1141 if (DEBUG_VISBILITY) Slog.v(
1142 TAG, "Already invisible: " + r);
1143 }
1144 } else if (r.fullscreen) {
1145 if (DEBUG_VISBILITY) Slog.v(
1146 TAG, "Now behindFullscreen: " + r);
1147 behindFullscreen = true;
1148 }
1149 }
1150 i--;
1151 }
1152 }
1153
1154 /**
1155 * Version of ensureActivitiesVisible that can easily be called anywhere.
1156 */
1157 final void ensureActivitiesVisibleLocked(ActivityRecord starting,
1158 int configChanges) {
1159 ActivityRecord r = topRunningActivityLocked(null);
1160 if (r != null) {
1161 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
1162 }
1163 }
1164
1165 /**
1166 * Ensure that the top activity in the stack is resumed.
1167 *
1168 * @param prev The previously resumed activity, for when in the process
1169 * of pausing; can be null to call from elsewhere.
1170 *
1171 * @return Returns true if something is being resumed, or false if
1172 * nothing happened.
1173 */
1174 final boolean resumeTopActivityLocked(ActivityRecord prev) {
1175 // Find the first activity that is not finishing.
1176 ActivityRecord next = topRunningActivityLocked(null);
1177
1178 // Remember how we'll process this pause/resume situation, and ensure
1179 // that the state is reset however we wind up proceeding.
1180 final boolean userLeaving = mUserLeaving;
1181 mUserLeaving = false;
1182
1183 if (next == null) {
1184 // There are no more activities! Let's just start up the
1185 // Launcher...
1186 if (mMainStack) {
1187 return mService.startHomeActivityLocked();
1188 }
1189 }
1190
1191 next.delayedResume = false;
1192
1193 // If the top activity is the resumed one, nothing to do.
1194 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
1195 // Make sure we have executed any pending transitions, since there
1196 // should be nothing left to do at this point.
1197 mService.mWindowManager.executeAppTransition();
1198 mNoAnimActivities.clear();
1199 return false;
1200 }
1201
1202 // If we are sleeping, and there is no resumed activity, and the top
1203 // activity is paused, well that is the state we want.
1204 if ((mService.mSleeping || mService.mShuttingDown)
1205 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
1206 // Make sure we have executed any pending transitions, since there
1207 // should be nothing left to do at this point.
1208 mService.mWindowManager.executeAppTransition();
1209 mNoAnimActivities.clear();
1210 return false;
1211 }
1212
1213 // The activity may be waiting for stop, but that is no longer
1214 // appropriate for it.
1215 mStoppingActivities.remove(next);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001216 mGoingToSleepActivities.remove(next);
1217 next.sleeping = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001218 mWaitingVisibleActivities.remove(next);
1219
1220 if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
1221
1222 // If we are currently pausing an activity, then don't do anything
1223 // until that is done.
1224 if (mPausingActivity != null) {
1225 if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity);
1226 return false;
1227 }
1228
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001229 // Okay we are now going to start a switch, to 'next'. We may first
1230 // have to pause the current activity, but this is an important point
1231 // where we have decided to go to 'next' so keep track of that.
Dianne Hackborn034093a42010-09-20 22:24:38 -07001232 // XXX "App Redirected" dialog is getting too many false positives
1233 // at this point, so turn off for now.
1234 if (false) {
1235 if (mLastStartedActivity != null && !mLastStartedActivity.finishing) {
1236 long now = SystemClock.uptimeMillis();
1237 final boolean inTime = mLastStartedActivity.startTime != 0
1238 && (mLastStartedActivity.startTime + START_WARN_TIME) >= now;
1239 final int lastUid = mLastStartedActivity.info.applicationInfo.uid;
1240 final int nextUid = next.info.applicationInfo.uid;
1241 if (inTime && lastUid != nextUid
1242 && lastUid != next.launchedFromUid
1243 && mService.checkPermission(
1244 android.Manifest.permission.STOP_APP_SWITCHES,
1245 -1, next.launchedFromUid)
1246 != PackageManager.PERMISSION_GRANTED) {
1247 mService.showLaunchWarningLocked(mLastStartedActivity, next);
1248 } else {
1249 next.startTime = now;
1250 mLastStartedActivity = next;
1251 }
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001252 } else {
Dianne Hackborn034093a42010-09-20 22:24:38 -07001253 next.startTime = SystemClock.uptimeMillis();
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001254 mLastStartedActivity = next;
1255 }
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001256 }
1257
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001258 // We need to start pausing the current activity so the top one
1259 // can be resumed...
1260 if (mResumedActivity != null) {
1261 if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
1262 startPausingLocked(userLeaving, false);
1263 return true;
1264 }
1265
1266 if (prev != null && prev != next) {
1267 if (!prev.waitingVisible && next != null && !next.nowVisible) {
1268 prev.waitingVisible = true;
1269 mWaitingVisibleActivities.add(prev);
1270 if (DEBUG_SWITCH) Slog.v(
1271 TAG, "Resuming top, waiting visible to hide: " + prev);
1272 } else {
1273 // The next activity is already visible, so hide the previous
1274 // activity's windows right now so we can show the new one ASAP.
1275 // We only do this if the previous is finishing, which should mean
1276 // it is on top of the one being resumed so hiding it quickly
1277 // is good. Otherwise, we want to do the normal route of allowing
1278 // the resumed activity to be shown so we can decide if the
1279 // previous should actually be hidden depending on whether the
1280 // new one is found to be full-screen or not.
1281 if (prev.finishing) {
1282 mService.mWindowManager.setAppVisibility(prev, false);
1283 if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
1284 + prev + ", waitingVisible="
1285 + (prev != null ? prev.waitingVisible : null)
1286 + ", nowVisible=" + next.nowVisible);
1287 } else {
1288 if (DEBUG_SWITCH) Slog.v(TAG, "Previous already visible but still waiting to hide: "
1289 + prev + ", waitingVisible="
1290 + (prev != null ? prev.waitingVisible : null)
1291 + ", nowVisible=" + next.nowVisible);
1292 }
1293 }
1294 }
1295
Dianne Hackborne7f97212011-02-24 14:40:20 -08001296 // Launching this app's activity, make sure the app is no longer
1297 // considered stopped.
1298 try {
1299 AppGlobals.getPackageManager().setPackageStoppedState(
1300 next.packageName, false);
1301 } catch (RemoteException e1) {
Dianne Hackborna925cd42011-03-10 13:18:20 -08001302 } catch (IllegalArgumentException e) {
1303 Slog.w(TAG, "Failed trying to unstop package "
1304 + next.packageName + ": " + e);
Dianne Hackborne7f97212011-02-24 14:40:20 -08001305 }
1306
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001307 // We are starting up the next activity, so tell the window manager
1308 // that the previous one will be hidden soon. This way it can know
1309 // to ignore it when computing the desired screen orientation.
1310 if (prev != null) {
1311 if (prev.finishing) {
1312 if (DEBUG_TRANSITION) Slog.v(TAG,
1313 "Prepare close transition: prev=" + prev);
1314 if (mNoAnimActivities.contains(prev)) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001315 mService.mWindowManager.prepareAppTransition(
1316 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001317 } else {
1318 mService.mWindowManager.prepareAppTransition(prev.task == next.task
1319 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001320 : WindowManagerPolicy.TRANSIT_TASK_CLOSE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001321 }
1322 mService.mWindowManager.setAppWillBeHidden(prev);
1323 mService.mWindowManager.setAppVisibility(prev, false);
1324 } else {
1325 if (DEBUG_TRANSITION) Slog.v(TAG,
1326 "Prepare open transition: prev=" + prev);
1327 if (mNoAnimActivities.contains(next)) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001328 mService.mWindowManager.prepareAppTransition(
1329 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001330 } else {
1331 mService.mWindowManager.prepareAppTransition(prev.task == next.task
1332 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001333 : WindowManagerPolicy.TRANSIT_TASK_OPEN, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001334 }
1335 }
1336 if (false) {
1337 mService.mWindowManager.setAppWillBeHidden(prev);
1338 mService.mWindowManager.setAppVisibility(prev, false);
1339 }
1340 } else if (mHistory.size() > 1) {
1341 if (DEBUG_TRANSITION) Slog.v(TAG,
1342 "Prepare open transition: no previous");
1343 if (mNoAnimActivities.contains(next)) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001344 mService.mWindowManager.prepareAppTransition(
1345 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001346 } else {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001347 mService.mWindowManager.prepareAppTransition(
1348 WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001349 }
1350 }
1351
1352 if (next.app != null && next.app.thread != null) {
1353 if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
1354
1355 // This activity is now becoming visible.
1356 mService.mWindowManager.setAppVisibility(next, true);
1357
1358 ActivityRecord lastResumedActivity = mResumedActivity;
1359 ActivityState lastState = next.state;
1360
1361 mService.updateCpuStats();
1362
1363 next.state = ActivityState.RESUMED;
1364 mResumedActivity = next;
1365 next.task.touchActiveTime();
Dianne Hackborn88819b22010-12-21 18:18:02 -08001366 if (mMainStack) {
1367 mService.addRecentTaskLocked(next.task);
1368 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001369 mService.updateLruProcessLocked(next.app, true, true);
1370 updateLRUListLocked(next);
1371
1372 // Have the window manager re-evaluate the orientation of
1373 // the screen based on the new activity order.
1374 boolean updated = false;
1375 if (mMainStack) {
1376 synchronized (mService) {
1377 Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
1378 mService.mConfiguration,
1379 next.mayFreezeScreenLocked(next.app) ? next : null);
1380 if (config != null) {
1381 next.frozenBeforeDestroy = true;
1382 }
1383 updated = mService.updateConfigurationLocked(config, next);
1384 }
1385 }
1386 if (!updated) {
1387 // The configuration update wasn't able to keep the existing
1388 // instance of the activity, and instead started a new one.
1389 // We should be all done, but let's just make sure our activity
1390 // is still at the top and schedule another run if something
1391 // weird happened.
1392 ActivityRecord nextNext = topRunningActivityLocked(null);
1393 if (DEBUG_SWITCH) Slog.i(TAG,
1394 "Activity config changed during resume: " + next
1395 + ", new next: " + nextNext);
1396 if (nextNext != next) {
1397 // Do over!
1398 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
1399 }
1400 if (mMainStack) {
1401 mService.setFocusedActivityLocked(next);
1402 }
1403 ensureActivitiesVisibleLocked(null, 0);
1404 mService.mWindowManager.executeAppTransition();
1405 mNoAnimActivities.clear();
1406 return true;
1407 }
1408
1409 try {
1410 // Deliver all pending results.
1411 ArrayList a = next.results;
1412 if (a != null) {
1413 final int N = a.size();
1414 if (!next.finishing && N > 0) {
1415 if (DEBUG_RESULTS) Slog.v(
1416 TAG, "Delivering results to " + next
1417 + ": " + a);
1418 next.app.thread.scheduleSendResult(next, a);
1419 }
1420 }
1421
1422 if (next.newIntents != null) {
1423 next.app.thread.scheduleNewIntent(next.newIntents, next);
1424 }
1425
1426 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
1427 System.identityHashCode(next),
1428 next.task.taskId, next.shortComponentName);
1429
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001430 next.sleeping = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001431 next.app.thread.scheduleResumeActivity(next,
1432 mService.isNextTransitionForward());
1433
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001434 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001435
1436 } catch (Exception e) {
1437 // Whoops, need to restart this activity!
1438 next.state = lastState;
1439 mResumedActivity = lastResumedActivity;
1440 Slog.i(TAG, "Restarting because process died: " + next);
1441 if (!next.hasBeenLaunched) {
1442 next.hasBeenLaunched = true;
1443 } else {
1444 if (SHOW_APP_STARTING_PREVIEW && mMainStack) {
1445 mService.mWindowManager.setAppStartingWindow(
1446 next, next.packageName, next.theme,
1447 next.nonLocalizedLabel,
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001448 next.labelRes, next.icon, next.windowFlags,
1449 null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001450 }
1451 }
1452 startSpecificActivityLocked(next, true, false);
1453 return true;
1454 }
1455
1456 // From this point on, if something goes wrong there is no way
1457 // to recover the activity.
1458 try {
1459 next.visible = true;
1460 completeResumeLocked(next);
1461 } catch (Exception e) {
1462 // If any exception gets thrown, toss away this
1463 // activity and try the next one.
1464 Slog.w(TAG, "Exception thrown during resume of " + next, e);
1465 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
1466 "resume-exception");
1467 return true;
1468 }
1469
1470 // Didn't need to use the icicle, and it is now out of date.
1471 next.icicle = null;
1472 next.haveState = false;
1473 next.stopped = false;
1474
1475 } else {
1476 // Whoops, need to restart this activity!
1477 if (!next.hasBeenLaunched) {
1478 next.hasBeenLaunched = true;
1479 } else {
1480 if (SHOW_APP_STARTING_PREVIEW) {
1481 mService.mWindowManager.setAppStartingWindow(
1482 next, next.packageName, next.theme,
1483 next.nonLocalizedLabel,
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001484 next.labelRes, next.icon, next.windowFlags,
1485 null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001486 }
1487 if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
1488 }
1489 startSpecificActivityLocked(next, true, true);
1490 }
1491
1492 return true;
1493 }
1494
1495 private final void startActivityLocked(ActivityRecord r, boolean newTask,
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001496 boolean doResume, boolean keepCurTransition) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001497 final int NH = mHistory.size();
1498
1499 int addPos = -1;
1500
1501 if (!newTask) {
1502 // If starting in an existing task, find where that is...
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001503 boolean startIt = true;
1504 for (int i = NH-1; i >= 0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001505 ActivityRecord p = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001506 if (p.finishing) {
1507 continue;
1508 }
1509 if (p.task == r.task) {
1510 // Here it is! Now, if this is not yet visible to the
1511 // user, then just add it without starting; it will
1512 // get started when the user navigates back to it.
1513 addPos = i+1;
1514 if (!startIt) {
1515 mHistory.add(addPos, r);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001516 r.putInHistory();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001517 mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
1518 r.info.screenOrientation, r.fullscreen);
1519 if (VALIDATE_TOKENS) {
1520 mService.mWindowManager.validateAppTokens(mHistory);
1521 }
1522 return;
1523 }
1524 break;
1525 }
1526 if (p.fullscreen) {
1527 startIt = false;
1528 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001529 }
1530 }
1531
1532 // Place a new activity at top of stack, so it is next to interact
1533 // with the user.
1534 if (addPos < 0) {
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001535 addPos = NH;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001536 }
1537
1538 // If we are not placing the new activity frontmost, we do not want
1539 // to deliver the onUserLeaving callback to the actual frontmost
1540 // activity
1541 if (addPos < NH) {
1542 mUserLeaving = false;
1543 if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() behind front, mUserLeaving=false");
1544 }
1545
1546 // Slot the activity into the history stack and proceed
1547 mHistory.add(addPos, r);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001548 r.putInHistory();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001549 r.frontOfTask = newTask;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001550 if (NH > 0) {
1551 // We want to show the starting preview window if we are
1552 // switching to a new task, or the next activity's process is
1553 // not currently running.
1554 boolean showStartingIcon = newTask;
1555 ProcessRecord proc = r.app;
1556 if (proc == null) {
1557 proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
1558 }
1559 if (proc == null || proc.thread == null) {
1560 showStartingIcon = true;
1561 }
1562 if (DEBUG_TRANSITION) Slog.v(TAG,
1563 "Prepare open transition: starting " + r);
1564 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001565 mService.mWindowManager.prepareAppTransition(
1566 WindowManagerPolicy.TRANSIT_NONE, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001567 mNoAnimActivities.add(r);
1568 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
1569 mService.mWindowManager.prepareAppTransition(
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001570 WindowManagerPolicy.TRANSIT_TASK_OPEN, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001571 mNoAnimActivities.remove(r);
1572 } else {
1573 mService.mWindowManager.prepareAppTransition(newTask
1574 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001575 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001576 mNoAnimActivities.remove(r);
1577 }
1578 mService.mWindowManager.addAppToken(
1579 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
1580 boolean doShow = true;
1581 if (newTask) {
1582 // Even though this activity is starting fresh, we still need
1583 // to reset it to make sure we apply affinities to move any
1584 // existing activities from other tasks in to it.
1585 // If the caller has requested that the target task be
1586 // reset, then do so.
1587 if ((r.intent.getFlags()
1588 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
1589 resetTaskIfNeededLocked(r, r);
1590 doShow = topRunningNonDelayedActivityLocked(null) == r;
1591 }
1592 }
1593 if (SHOW_APP_STARTING_PREVIEW && doShow) {
1594 // Figure out if we are transitioning from another activity that is
1595 // "has the same starting icon" as the next one. This allows the
1596 // window manager to keep the previous window it had previously
1597 // created, if it still had one.
1598 ActivityRecord prev = mResumedActivity;
1599 if (prev != null) {
1600 // We don't want to reuse the previous starting preview if:
1601 // (1) The current activity is in a different task.
1602 if (prev.task != r.task) prev = null;
1603 // (2) The current activity is already displayed.
1604 else if (prev.nowVisible) prev = null;
1605 }
1606 mService.mWindowManager.setAppStartingWindow(
1607 r, r.packageName, r.theme, r.nonLocalizedLabel,
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001608 r.labelRes, r.icon, r.windowFlags, prev, showStartingIcon);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001609 }
1610 } else {
1611 // If this is the first activity, don't do any fancy animations,
1612 // because there is nothing for it to animate on top of.
1613 mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
1614 r.info.screenOrientation, r.fullscreen);
1615 }
1616 if (VALIDATE_TOKENS) {
1617 mService.mWindowManager.validateAppTokens(mHistory);
1618 }
1619
1620 if (doResume) {
1621 resumeTopActivityLocked(null);
1622 }
1623 }
1624
1625 /**
1626 * Perform a reset of the given task, if needed as part of launching it.
1627 * Returns the new HistoryRecord at the top of the task.
1628 */
1629 private final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop,
1630 ActivityRecord newActivity) {
1631 boolean forceReset = (newActivity.info.flags
1632 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001633 if (ACTIVITY_INACTIVE_RESET_TIME > 0
1634 && taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001635 if ((newActivity.info.flags
1636 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
1637 forceReset = true;
1638 }
1639 }
1640
1641 final TaskRecord task = taskTop.task;
1642
1643 // We are going to move through the history list so that we can look
1644 // at each activity 'target' with 'below' either the interesting
1645 // activity immediately below it in the stack or null.
1646 ActivityRecord target = null;
1647 int targetI = 0;
1648 int taskTopI = -1;
1649 int replyChainEnd = -1;
1650 int lastReparentPos = -1;
1651 for (int i=mHistory.size()-1; i>=-1; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001652 ActivityRecord below = i >= 0 ? mHistory.get(i) : null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001653
1654 if (below != null && below.finishing) {
1655 continue;
1656 }
1657 if (target == null) {
1658 target = below;
1659 targetI = i;
1660 // If we were in the middle of a reply chain before this
1661 // task, it doesn't appear like the root of the chain wants
1662 // anything interesting, so drop it.
1663 replyChainEnd = -1;
1664 continue;
1665 }
1666
1667 final int flags = target.info.flags;
1668
1669 final boolean finishOnTaskLaunch =
1670 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
1671 final boolean allowTaskReparenting =
1672 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
1673
1674 if (target.task == task) {
1675 // We are inside of the task being reset... we'll either
1676 // finish this activity, push it out for another task,
1677 // or leave it as-is. We only do this
1678 // for activities that are not the root of the task (since
1679 // if we finish the root, we may no longer have the task!).
1680 if (taskTopI < 0) {
1681 taskTopI = targetI;
1682 }
1683 if (below != null && below.task == task) {
1684 final boolean clearWhenTaskReset =
1685 (target.intent.getFlags()
1686 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
1687 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
1688 // If this activity is sending a reply to a previous
1689 // activity, we can't do anything with it now until
1690 // we reach the start of the reply chain.
1691 // XXX note that we are assuming the result is always
1692 // to the previous activity, which is almost always
1693 // the case but we really shouldn't count on.
1694 if (replyChainEnd < 0) {
1695 replyChainEnd = targetI;
1696 }
1697 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
1698 && target.taskAffinity != null
1699 && !target.taskAffinity.equals(task.affinity)) {
1700 // If this activity has an affinity for another
1701 // task, then we need to move it out of here. We will
1702 // move it as far out of the way as possible, to the
1703 // bottom of the activity stack. This also keeps it
1704 // correctly ordered with any activities we previously
1705 // moved.
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001706 ActivityRecord p = mHistory.get(0);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001707 if (target.taskAffinity != null
1708 && target.taskAffinity.equals(p.task.affinity)) {
1709 // If the activity currently at the bottom has the
1710 // same task affinity as the one we are moving,
1711 // then merge it into the same task.
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001712 target.setTask(p.task, p.thumbHolder, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001713 if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
1714 + " out to bottom task " + p.task);
1715 } else {
1716 mService.mCurTask++;
1717 if (mService.mCurTask <= 0) {
1718 mService.mCurTask = 1;
1719 }
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001720 target.setTask(new TaskRecord(mService.mCurTask, target.info, null),
1721 null, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001722 target.task.affinityIntent = target.intent;
1723 if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
1724 + " out to new task " + target.task);
1725 }
1726 mService.mWindowManager.setAppGroupId(target, task.taskId);
1727 if (replyChainEnd < 0) {
1728 replyChainEnd = targetI;
1729 }
1730 int dstPos = 0;
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001731 ThumbnailHolder curThumbHolder = target.thumbHolder;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001732 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001733 p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001734 if (p.finishing) {
1735 continue;
1736 }
1737 if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
1738 + " out to target's task " + target.task);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001739 p.setTask(target.task, curThumbHolder, false);
1740 curThumbHolder = p.thumbHolder;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001741 mHistory.remove(srcPos);
1742 mHistory.add(dstPos, p);
1743 mService.mWindowManager.moveAppToken(dstPos, p);
1744 mService.mWindowManager.setAppGroupId(p, p.task.taskId);
1745 dstPos++;
1746 if (VALIDATE_TOKENS) {
1747 mService.mWindowManager.validateAppTokens(mHistory);
1748 }
1749 i++;
1750 }
1751 if (taskTop == p) {
1752 taskTop = below;
1753 }
1754 if (taskTopI == replyChainEnd) {
1755 taskTopI = -1;
1756 }
1757 replyChainEnd = -1;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001758 } else if (forceReset || finishOnTaskLaunch
1759 || clearWhenTaskReset) {
1760 // If the activity should just be removed -- either
1761 // because it asks for it, or the task should be
1762 // cleared -- then finish it and anything that is
1763 // part of its reply chain.
1764 if (clearWhenTaskReset) {
1765 // In this case, we want to finish this activity
1766 // and everything above it, so be sneaky and pretend
1767 // like these are all in the reply chain.
1768 replyChainEnd = targetI+1;
1769 while (replyChainEnd < mHistory.size() &&
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001770 (mHistory.get(
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001771 replyChainEnd)).task == task) {
1772 replyChainEnd++;
1773 }
1774 replyChainEnd--;
1775 } else if (replyChainEnd < 0) {
1776 replyChainEnd = targetI;
1777 }
1778 ActivityRecord p = null;
1779 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001780 p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001781 if (p.finishing) {
1782 continue;
1783 }
1784 if (finishActivityLocked(p, srcPos,
1785 Activity.RESULT_CANCELED, null, "reset")) {
1786 replyChainEnd--;
1787 srcPos--;
1788 }
1789 }
1790 if (taskTop == p) {
1791 taskTop = below;
1792 }
1793 if (taskTopI == replyChainEnd) {
1794 taskTopI = -1;
1795 }
1796 replyChainEnd = -1;
1797 } else {
1798 // If we were in the middle of a chain, well the
1799 // activity that started it all doesn't want anything
1800 // special, so leave it all as-is.
1801 replyChainEnd = -1;
1802 }
1803 } else {
1804 // Reached the bottom of the task -- any reply chain
1805 // should be left as-is.
1806 replyChainEnd = -1;
1807 }
1808
1809 } else if (target.resultTo != null) {
1810 // If this activity is sending a reply to a previous
1811 // activity, we can't do anything with it now until
1812 // we reach the start of the reply chain.
1813 // XXX note that we are assuming the result is always
1814 // to the previous activity, which is almost always
1815 // the case but we really shouldn't count on.
1816 if (replyChainEnd < 0) {
1817 replyChainEnd = targetI;
1818 }
1819
1820 } else if (taskTopI >= 0 && allowTaskReparenting
1821 && task.affinity != null
1822 && task.affinity.equals(target.taskAffinity)) {
1823 // We are inside of another task... if this activity has
1824 // an affinity for our task, then either remove it if we are
1825 // clearing or move it over to our task. Note that
1826 // we currently punt on the case where we are resetting a
1827 // task that is not at the top but who has activities above
1828 // with an affinity to it... this is really not a normal
1829 // case, and we will need to later pull that task to the front
1830 // and usually at that point we will do the reset and pick
1831 // up those remaining activities. (This only happens if
1832 // someone starts an activity in a new task from an activity
1833 // in a task that is not currently on top.)
1834 if (forceReset || finishOnTaskLaunch) {
1835 if (replyChainEnd < 0) {
1836 replyChainEnd = targetI;
1837 }
1838 ActivityRecord p = null;
1839 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001840 p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001841 if (p.finishing) {
1842 continue;
1843 }
1844 if (finishActivityLocked(p, srcPos,
1845 Activity.RESULT_CANCELED, null, "reset")) {
1846 taskTopI--;
1847 lastReparentPos--;
1848 replyChainEnd--;
1849 srcPos--;
1850 }
1851 }
1852 replyChainEnd = -1;
1853 } else {
1854 if (replyChainEnd < 0) {
1855 replyChainEnd = targetI;
1856 }
1857 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001858 ActivityRecord p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001859 if (p.finishing) {
1860 continue;
1861 }
1862 if (lastReparentPos < 0) {
1863 lastReparentPos = taskTopI;
1864 taskTop = p;
1865 } else {
1866 lastReparentPos--;
1867 }
1868 mHistory.remove(srcPos);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001869 p.setTask(task, null, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001870 mHistory.add(lastReparentPos, p);
1871 if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
1872 + " in to resetting task " + task);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001873 mService.mWindowManager.moveAppToken(lastReparentPos, p);
1874 mService.mWindowManager.setAppGroupId(p, p.task.taskId);
1875 if (VALIDATE_TOKENS) {
1876 mService.mWindowManager.validateAppTokens(mHistory);
1877 }
1878 }
1879 replyChainEnd = -1;
1880
1881 // Now we've moved it in to place... but what if this is
1882 // a singleTop activity and we have put it on top of another
1883 // instance of the same activity? Then we drop the instance
1884 // below so it remains singleTop.
1885 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
1886 for (int j=lastReparentPos-1; j>=0; j--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001887 ActivityRecord p = mHistory.get(j);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001888 if (p.finishing) {
1889 continue;
1890 }
1891 if (p.intent.getComponent().equals(target.intent.getComponent())) {
1892 if (finishActivityLocked(p, j,
1893 Activity.RESULT_CANCELED, null, "replace")) {
1894 taskTopI--;
1895 lastReparentPos--;
1896 }
1897 }
1898 }
1899 }
1900 }
1901 }
1902
1903 target = below;
1904 targetI = i;
1905 }
1906
1907 return taskTop;
1908 }
1909
1910 /**
1911 * Perform clear operation as requested by
1912 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
1913 * stack to the given task, then look for
1914 * an instance of that activity in the stack and, if found, finish all
1915 * activities on top of it and return the instance.
1916 *
1917 * @param newR Description of the new activity being started.
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001918 * @return Returns the old activity that should be continued to be used,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001919 * or null if none was found.
1920 */
1921 private final ActivityRecord performClearTaskLocked(int taskId,
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001922 ActivityRecord newR, int launchFlags) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001923 int i = mHistory.size();
1924
1925 // First find the requested task.
1926 while (i > 0) {
1927 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001928 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001929 if (r.task.taskId == taskId) {
1930 i++;
1931 break;
1932 }
1933 }
1934
1935 // Now clear it.
1936 while (i > 0) {
1937 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001938 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001939 if (r.finishing) {
1940 continue;
1941 }
1942 if (r.task.taskId != taskId) {
1943 return null;
1944 }
1945 if (r.realActivity.equals(newR.realActivity)) {
1946 // Here it is! Now finish everything in front...
1947 ActivityRecord ret = r;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001948 while (i < (mHistory.size()-1)) {
1949 i++;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001950 r = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001951 if (r.task.taskId != taskId) {
1952 break;
1953 }
1954 if (r.finishing) {
1955 continue;
1956 }
1957 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
1958 null, "clear")) {
1959 i--;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001960 }
1961 }
1962
1963 // Finally, if this is a normal launch mode (that is, not
1964 // expecting onNewIntent()), then we will finish the current
1965 // instance of the activity so a new fresh one can be started.
1966 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
1967 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
1968 if (!ret.finishing) {
1969 int index = indexOfTokenLocked(ret);
1970 if (index >= 0) {
1971 finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
1972 null, "clear");
1973 }
1974 return null;
1975 }
1976 }
1977
1978 return ret;
1979 }
1980 }
1981
1982 return null;
1983 }
1984
1985 /**
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001986 * Completely remove all activities associated with an existing
1987 * task starting at a specified index.
1988 */
1989 private final void performClearTaskAtIndexLocked(int taskId, int i) {
1990 while (i < (mHistory.size()-1)) {
1991 ActivityRecord r = mHistory.get(i);
1992 if (r.task.taskId != taskId) {
1993 // Whoops hit the end.
1994 return;
1995 }
1996 if (r.finishing) {
1997 i++;
1998 continue;
1999 }
2000 if (!finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2001 null, "clear")) {
2002 i++;
2003 }
2004 }
2005 }
2006
2007 /**
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002008 * Completely remove all activities associated with an existing task.
2009 */
2010 private final void performClearTaskLocked(int taskId) {
2011 int i = mHistory.size();
2012
2013 // First find the requested task.
2014 while (i > 0) {
2015 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002016 ActivityRecord r = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002017 if (r.task.taskId == taskId) {
2018 i++;
2019 break;
2020 }
2021 }
2022
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002023 // Now find the start and clear it.
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002024 while (i > 0) {
2025 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002026 ActivityRecord r = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002027 if (r.finishing) {
2028 continue;
2029 }
2030 if (r.task.taskId != taskId) {
2031 // We hit the bottom. Now finish it all...
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002032 performClearTaskAtIndexLocked(taskId, i+1);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002033 return;
2034 }
2035 }
2036 }
2037
2038 /**
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002039 * Find the activity in the history stack within the given task. Returns
2040 * the index within the history at which it's found, or < 0 if not found.
2041 */
2042 private final int findActivityInHistoryLocked(ActivityRecord r, int task) {
2043 int i = mHistory.size();
2044 while (i > 0) {
2045 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002046 ActivityRecord candidate = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002047 if (candidate.task.taskId != task) {
2048 break;
2049 }
2050 if (candidate.realActivity.equals(r.realActivity)) {
2051 return i;
2052 }
2053 }
2054
2055 return -1;
2056 }
2057
2058 /**
2059 * Reorder the history stack so that the activity at the given index is
2060 * brought to the front.
2061 */
2062 private final ActivityRecord moveActivityToFrontLocked(int where) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002063 ActivityRecord newTop = mHistory.remove(where);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002064 int top = mHistory.size();
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002065 ActivityRecord oldTop = mHistory.get(top-1);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002066 mHistory.add(top, newTop);
2067 oldTop.frontOfTask = false;
2068 newTop.frontOfTask = true;
2069 return newTop;
2070 }
2071
2072 final int startActivityLocked(IApplicationThread caller,
2073 Intent intent, String resolvedType,
2074 Uri[] grantedUriPermissions,
2075 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2076 String resultWho, int requestCode,
2077 int callingPid, int callingUid, boolean onlyIfNeeded,
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002078 boolean componentSpecified, ActivityRecord[] outActivity) {
Dianne Hackbornefb58102010-10-14 16:47:34 -07002079
2080 int err = START_SUCCESS;
2081
2082 ProcessRecord callerApp = null;
2083 if (caller != null) {
2084 callerApp = mService.getRecordForAppLocked(caller);
2085 if (callerApp != null) {
2086 callingPid = callerApp.pid;
2087 callingUid = callerApp.info.uid;
2088 } else {
2089 Slog.w(TAG, "Unable to find app for caller " + caller
2090 + " (pid=" + callingPid + ") when starting: "
2091 + intent.toString());
2092 err = START_PERMISSION_DENIED;
2093 }
2094 }
2095
2096 if (err == START_SUCCESS) {
2097 Slog.i(TAG, "Starting: " + intent + " from pid "
2098 + (callerApp != null ? callerApp.pid : callingPid));
2099 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002100
2101 ActivityRecord sourceRecord = null;
2102 ActivityRecord resultRecord = null;
2103 if (resultTo != null) {
2104 int index = indexOfTokenLocked(resultTo);
2105 if (DEBUG_RESULTS) Slog.v(
2106 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2107 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002108 sourceRecord = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002109 if (requestCode >= 0 && !sourceRecord.finishing) {
2110 resultRecord = sourceRecord;
2111 }
2112 }
2113 }
2114
2115 int launchFlags = intent.getFlags();
2116
2117 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2118 && sourceRecord != null) {
2119 // Transfer the result target from the source activity to the new
2120 // one being started, including any failures.
2121 if (requestCode >= 0) {
2122 return START_FORWARD_AND_REQUEST_CONFLICT;
2123 }
2124 resultRecord = sourceRecord.resultTo;
2125 resultWho = sourceRecord.resultWho;
2126 requestCode = sourceRecord.requestCode;
2127 sourceRecord.resultTo = null;
2128 if (resultRecord != null) {
2129 resultRecord.removeResultsLocked(
2130 sourceRecord, resultWho, requestCode);
2131 }
2132 }
2133
Dianne Hackbornefb58102010-10-14 16:47:34 -07002134 if (err == START_SUCCESS && intent.getComponent() == null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002135 // We couldn't find a class that can handle the given Intent.
2136 // That's the end of that!
2137 err = START_INTENT_NOT_RESOLVED;
2138 }
2139
2140 if (err == START_SUCCESS && aInfo == null) {
2141 // We couldn't find the specific class specified in the Intent.
2142 // Also the end of the line.
2143 err = START_CLASS_NOT_FOUND;
2144 }
2145
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002146 if (err != START_SUCCESS) {
2147 if (resultRecord != null) {
2148 sendActivityResultLocked(-1,
2149 resultRecord, resultWho, requestCode,
2150 Activity.RESULT_CANCELED, null);
2151 }
2152 return err;
2153 }
2154
2155 final int perm = mService.checkComponentPermission(aInfo.permission, callingPid,
Dianne Hackborn6c2c5fc2011-01-18 17:02:33 -08002156 callingUid, aInfo.applicationInfo.uid, aInfo.exported);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002157 if (perm != PackageManager.PERMISSION_GRANTED) {
2158 if (resultRecord != null) {
2159 sendActivityResultLocked(-1,
2160 resultRecord, resultWho, requestCode,
2161 Activity.RESULT_CANCELED, null);
2162 }
Dianne Hackborn6c2c5fc2011-01-18 17:02:33 -08002163 String msg;
2164 if (!aInfo.exported) {
2165 msg = "Permission Denial: starting " + intent.toString()
2166 + " from " + callerApp + " (pid=" + callingPid
2167 + ", uid=" + callingUid + ")"
2168 + " not exported from uid " + aInfo.applicationInfo.uid;
2169 } else {
2170 msg = "Permission Denial: starting " + intent.toString()
2171 + " from " + callerApp + " (pid=" + callingPid
2172 + ", uid=" + callingUid + ")"
2173 + " requires " + aInfo.permission;
2174 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002175 Slog.w(TAG, msg);
2176 throw new SecurityException(msg);
2177 }
2178
2179 if (mMainStack) {
2180 if (mService.mController != null) {
2181 boolean abort = false;
2182 try {
2183 // The Intent we give to the watcher has the extra data
2184 // stripped off, since it can contain private information.
2185 Intent watchIntent = intent.cloneFilter();
2186 abort = !mService.mController.activityStarting(watchIntent,
2187 aInfo.applicationInfo.packageName);
2188 } catch (RemoteException e) {
2189 mService.mController = null;
2190 }
2191
2192 if (abort) {
2193 if (resultRecord != null) {
2194 sendActivityResultLocked(-1,
2195 resultRecord, resultWho, requestCode,
2196 Activity.RESULT_CANCELED, null);
2197 }
2198 // We pretend to the caller that it was really started, but
2199 // they will just get a cancel result.
2200 return START_SUCCESS;
2201 }
2202 }
2203 }
2204
2205 ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
2206 intent, resolvedType, aInfo, mService.mConfiguration,
2207 resultRecord, resultWho, requestCode, componentSpecified);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002208 if (outActivity != null) {
2209 outActivity[0] = r;
2210 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002211
2212 if (mMainStack) {
2213 if (mResumedActivity == null
2214 || mResumedActivity.info.applicationInfo.uid != callingUid) {
2215 if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
2216 PendingActivityLaunch pal = new PendingActivityLaunch();
2217 pal.r = r;
2218 pal.sourceRecord = sourceRecord;
2219 pal.grantedUriPermissions = grantedUriPermissions;
2220 pal.grantedMode = grantedMode;
2221 pal.onlyIfNeeded = onlyIfNeeded;
2222 mService.mPendingActivityLaunches.add(pal);
2223 return START_SWITCHES_CANCELED;
2224 }
2225 }
2226
2227 if (mService.mDidAppSwitch) {
2228 // This is the second allowed switch since we stopped switches,
2229 // so now just generally allow switches. Use case: user presses
2230 // home (switches disabled, switch to home, mDidAppSwitch now true);
2231 // user taps a home icon (coming from home so allowed, we hit here
2232 // and now allow anyone to switch again).
2233 mService.mAppSwitchesAllowedTime = 0;
2234 } else {
2235 mService.mDidAppSwitch = true;
2236 }
2237
2238 mService.doPendingActivityLaunchesLocked(false);
2239 }
2240
2241 return startActivityUncheckedLocked(r, sourceRecord,
2242 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
2243 }
2244
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002245 final void moveHomeToFrontFromLaunchLocked(int launchFlags) {
2246 if ((launchFlags &
2247 (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
2248 == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
2249 // Caller wants to appear on home activity, so before starting
2250 // their own activity we will bring home to the front.
2251 moveHomeToFrontLocked();
2252 }
2253 }
2254
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002255 final int startActivityUncheckedLocked(ActivityRecord r,
2256 ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
2257 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
2258 final Intent intent = r.intent;
2259 final int callingUid = r.launchedFromUid;
2260
2261 int launchFlags = intent.getFlags();
2262
2263 // We'll invoke onUserLeaving before onPause only if the launching
2264 // activity did not explicitly state that this is an automated launch.
2265 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
2266 if (DEBUG_USER_LEAVING) Slog.v(TAG,
2267 "startActivity() => mUserLeaving=" + mUserLeaving);
2268
2269 // If the caller has asked not to resume at this point, we make note
2270 // of this in the record so that we can skip it when trying to find
2271 // the top running activity.
2272 if (!doResume) {
2273 r.delayedResume = true;
2274 }
2275
2276 ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
2277 != 0 ? r : null;
2278
2279 // If the onlyIfNeeded flag is set, then we can do this if the activity
2280 // being launched is the same as the one making the call... or, as
2281 // a special case, if we do not know the caller then we count the
2282 // current top activity as the caller.
2283 if (onlyIfNeeded) {
2284 ActivityRecord checkedCaller = sourceRecord;
2285 if (checkedCaller == null) {
2286 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
2287 }
2288 if (!checkedCaller.realActivity.equals(r.realActivity)) {
2289 // Caller is not the same as launcher, so always needed.
2290 onlyIfNeeded = false;
2291 }
2292 }
2293
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002294 if (sourceRecord == null) {
2295 // This activity is not being started from another... in this
2296 // case we -always- start a new task.
2297 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
2298 Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
2299 + intent);
2300 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2301 }
2302 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2303 // The original activity who is starting us is running as a single
2304 // instance... this new activity it is starting must go on its
2305 // own task.
2306 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2307 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
2308 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
2309 // The activity being started is a single instance... it always
2310 // gets launched into its own task.
2311 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2312 }
2313
2314 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
2315 // For whatever reason this activity is being launched into a new
2316 // task... yet the caller has requested a result back. Well, that
2317 // is pretty messed up, so instead immediately send back a cancel
2318 // and let the new task continue launched as normal without a
2319 // dependency on its originator.
2320 Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
2321 sendActivityResultLocked(-1,
2322 r.resultTo, r.resultWho, r.requestCode,
2323 Activity.RESULT_CANCELED, null);
2324 r.resultTo = null;
2325 }
2326
2327 boolean addingToTask = false;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002328 TaskRecord reuseTask = null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002329 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
2330 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
2331 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
2332 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2333 // If bring to front is requested, and no result is requested, and
2334 // we can find a task that was started with this same
2335 // component, then instead of launching bring that one to the front.
2336 if (r.resultTo == null) {
2337 // See if there is a task to bring to the front. If this is
2338 // a SINGLE_INSTANCE activity, there can be one and only one
2339 // instance of it in the history, and it is always in its own
2340 // unique task, so we do a special search.
2341 ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
2342 ? findTaskLocked(intent, r.info)
2343 : findActivityLocked(intent, r.info);
2344 if (taskTop != null) {
2345 if (taskTop.task.intent == null) {
2346 // This task was started because of movement of
2347 // the activity based on affinity... now that we
2348 // are actually launching it, we can assign the
2349 // base intent.
2350 taskTop.task.setIntent(intent, r.info);
2351 }
2352 // If the target task is not in the front, then we need
2353 // to bring it to the front... except... well, with
2354 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
2355 // to have the same behavior as if a new instance was
2356 // being started, which means not bringing it to the front
2357 // if the caller is not itself in the front.
2358 ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
Jean-Baptiste Queru66a5d692010-10-25 17:27:16 -07002359 if (curTop != null && curTop.task != taskTop.task) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002360 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
2361 boolean callerAtFront = sourceRecord == null
2362 || curTop.task == sourceRecord.task;
2363 if (callerAtFront) {
2364 // We really do want to push this one into the
2365 // user's face, right now.
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002366 moveHomeToFrontFromLaunchLocked(launchFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002367 moveTaskToFrontLocked(taskTop.task, r);
2368 }
2369 }
2370 // If the caller has requested that the target task be
2371 // reset, then do so.
2372 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2373 taskTop = resetTaskIfNeededLocked(taskTop, r);
2374 }
2375 if (onlyIfNeeded) {
2376 // We don't need to start a new activity, and
2377 // the client said not to do anything if that
2378 // is the case, so this is it! And for paranoia, make
2379 // sure we have correctly resumed the top activity.
2380 if (doResume) {
2381 resumeTopActivityLocked(null);
2382 }
2383 return START_RETURN_INTENT_TO_CALLER;
2384 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002385 if ((launchFlags &
2386 (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
2387 == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
2388 // The caller has requested to completely replace any
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002389 // existing task with its new activity. Well that should
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002390 // not be too hard...
2391 reuseTask = taskTop.task;
2392 performClearTaskLocked(taskTop.task.taskId);
2393 reuseTask.setIntent(r.intent, r.info);
2394 } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002395 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
2396 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2397 // In this situation we want to remove all activities
2398 // from the task up to the one being started. In most
2399 // cases this means we are resetting the task to its
2400 // initial state.
2401 ActivityRecord top = performClearTaskLocked(
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002402 taskTop.task.taskId, r, launchFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002403 if (top != null) {
2404 if (top.frontOfTask) {
2405 // Activity aliases may mean we use different
2406 // intents for the top activity, so make sure
2407 // the task now has the identity of the new
2408 // intent.
2409 top.task.setIntent(r.intent, r.info);
2410 }
2411 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002412 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002413 } else {
2414 // A special case: we need to
2415 // start the activity because it is not currently
2416 // running, and the caller has asked to clear the
2417 // current task to have this activity at the top.
2418 addingToTask = true;
2419 // Now pretend like this activity is being started
2420 // by the top of its task, so it is put in the
2421 // right place.
2422 sourceRecord = taskTop;
2423 }
2424 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
2425 // In this case the top activity on the task is the
2426 // same as the one being launched, so we take that
2427 // as a request to bring the task to the foreground.
2428 // If the top activity in the task is the root
2429 // activity, deliver this new intent to it if it
2430 // desires.
2431 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
2432 && taskTop.realActivity.equals(r.realActivity)) {
2433 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
2434 if (taskTop.frontOfTask) {
2435 taskTop.task.setIntent(r.intent, r.info);
2436 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002437 taskTop.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002438 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
2439 // In this case we are launching the root activity
2440 // of the task, but with a different intent. We
2441 // should start a new instance on top.
2442 addingToTask = true;
2443 sourceRecord = taskTop;
2444 }
2445 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
2446 // In this case an activity is being launched in to an
2447 // existing task, without resetting that task. This
2448 // is typically the situation of launching an activity
2449 // from a notification or shortcut. We want to place
2450 // the new activity on top of the current task.
2451 addingToTask = true;
2452 sourceRecord = taskTop;
2453 } else if (!taskTop.task.rootWasReset) {
2454 // In this case we are launching in to an existing task
2455 // that has not yet been started from its front door.
2456 // The current task has been brought to the front.
2457 // Ideally, we'd probably like to place this new task
2458 // at the bottom of its stack, but that's a little hard
2459 // to do with the current organization of the code so
2460 // for now we'll just drop it.
2461 taskTop.task.setIntent(r.intent, r.info);
2462 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002463 if (!addingToTask && reuseTask == null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002464 // We didn't do anything... but it was needed (a.k.a., client
2465 // don't use that intent!) And for paranoia, make
2466 // sure we have correctly resumed the top activity.
2467 if (doResume) {
2468 resumeTopActivityLocked(null);
2469 }
2470 return START_TASK_TO_FRONT;
2471 }
2472 }
2473 }
2474 }
2475
2476 //String uri = r.intent.toURI();
2477 //Intent intent2 = new Intent(uri);
2478 //Slog.i(TAG, "Given intent: " + r.intent);
2479 //Slog.i(TAG, "URI is: " + uri);
2480 //Slog.i(TAG, "To intent: " + intent2);
2481
2482 if (r.packageName != null) {
2483 // If the activity being launched is the same as the one currently
2484 // at the top, then we need to check if it should only be launched
2485 // once.
2486 ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
2487 if (top != null && r.resultTo == null) {
2488 if (top.realActivity.equals(r.realActivity)) {
2489 if (top.app != null && top.app.thread != null) {
2490 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
2491 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
2492 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
2493 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
2494 // For paranoia, make sure we have correctly
2495 // resumed the top activity.
2496 if (doResume) {
2497 resumeTopActivityLocked(null);
2498 }
2499 if (onlyIfNeeded) {
2500 // We don't need to start a new activity, and
2501 // the client said not to do anything if that
2502 // is the case, so this is it!
2503 return START_RETURN_INTENT_TO_CALLER;
2504 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002505 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002506 return START_DELIVERED_TO_TOP;
2507 }
2508 }
2509 }
2510 }
2511
2512 } else {
2513 if (r.resultTo != null) {
2514 sendActivityResultLocked(-1,
2515 r.resultTo, r.resultWho, r.requestCode,
2516 Activity.RESULT_CANCELED, null);
2517 }
2518 return START_CLASS_NOT_FOUND;
2519 }
2520
2521 boolean newTask = false;
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002522 boolean keepCurTransition = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002523
2524 // Should this be considered a new task?
2525 if (r.resultTo == null && !addingToTask
2526 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002527 if (reuseTask == null) {
2528 // todo: should do better management of integers.
2529 mService.mCurTask++;
2530 if (mService.mCurTask <= 0) {
2531 mService.mCurTask = 1;
2532 }
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002533 r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002534 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2535 + " in new task " + r.task);
2536 } else {
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002537 r.setTask(reuseTask, reuseTask, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002538 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002539 newTask = true;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002540 moveHomeToFrontFromLaunchLocked(launchFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002541
2542 } else if (sourceRecord != null) {
2543 if (!addingToTask &&
2544 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
2545 // In this case, we are adding the activity to an existing
2546 // task, but the caller has asked to clear that task if the
2547 // activity is already running.
2548 ActivityRecord top = performClearTaskLocked(
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002549 sourceRecord.task.taskId, r, launchFlags);
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002550 keepCurTransition = true;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002551 if (top != null) {
2552 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002553 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002554 // For paranoia, make sure we have correctly
2555 // resumed the top activity.
2556 if (doResume) {
2557 resumeTopActivityLocked(null);
2558 }
2559 return START_DELIVERED_TO_TOP;
2560 }
2561 } else if (!addingToTask &&
2562 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
2563 // In this case, we are launching an activity in our own task
2564 // that may already be running somewhere in the history, and
2565 // we want to shuffle it to the front of the stack if so.
2566 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
2567 if (where >= 0) {
2568 ActivityRecord top = moveActivityToFrontLocked(where);
2569 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002570 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002571 if (doResume) {
2572 resumeTopActivityLocked(null);
2573 }
2574 return START_DELIVERED_TO_TOP;
2575 }
2576 }
2577 // An existing activity is starting this new activity, so we want
2578 // to keep the new one in the same task as the one that is starting
2579 // it.
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002580 r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002581 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2582 + " in existing task " + r.task);
2583
2584 } else {
2585 // This not being started from an existing activity, and not part
2586 // of a new task... just put it in the top task, though these days
2587 // this case should never happen.
2588 final int N = mHistory.size();
2589 ActivityRecord prev =
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002590 N > 0 ? mHistory.get(N-1) : null;
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002591 r.setTask(prev != null
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002592 ? prev.task
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002593 : new TaskRecord(mService.mCurTask, r.info, intent), null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002594 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2595 + " in new guessed " + r.task);
2596 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002597
2598 if (grantedUriPermissions != null && callingUid > 0) {
2599 for (int i=0; i<grantedUriPermissions.length; i++) {
2600 mService.grantUriPermissionLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002601 grantedUriPermissions[i], grantedMode, r.getUriPermissionsLocked());
Dianne Hackborn39792d22010-08-19 18:01:52 -07002602 }
2603 }
2604
2605 mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002606 intent, r.getUriPermissionsLocked());
Dianne Hackborn39792d22010-08-19 18:01:52 -07002607
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002608 if (newTask) {
2609 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
2610 }
2611 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002612 startActivityLocked(r, newTask, doResume, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002613 return START_SUCCESS;
2614 }
2615
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002616 ActivityInfo resolveActivity(Intent intent, String resolvedType, boolean debug) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002617 // Collect information about the target of the Intent.
2618 ActivityInfo aInfo;
2619 try {
2620 ResolveInfo rInfo =
2621 AppGlobals.getPackageManager().resolveIntent(
2622 intent, resolvedType,
2623 PackageManager.MATCH_DEFAULT_ONLY
2624 | ActivityManagerService.STOCK_PM_FLAGS);
2625 aInfo = rInfo != null ? rInfo.activityInfo : null;
2626 } catch (RemoteException e) {
2627 aInfo = null;
2628 }
2629
2630 if (aInfo != null) {
2631 // Store the found target back into the intent, because now that
2632 // we have it we never want to do this again. For example, if the
2633 // user navigates back to this point in the history, we should
2634 // always restart the exact same activity.
2635 intent.setComponent(new ComponentName(
2636 aInfo.applicationInfo.packageName, aInfo.name));
2637
2638 // Don't debug things in the system process
2639 if (debug) {
2640 if (!aInfo.processName.equals("system")) {
2641 mService.setDebugApp(aInfo.processName, true, false);
2642 }
2643 }
2644 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002645 return aInfo;
2646 }
2647
2648 final int startActivityMayWait(IApplicationThread caller, int callingUid,
2649 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
2650 int grantedMode, IBinder resultTo,
2651 String resultWho, int requestCode, boolean onlyIfNeeded,
2652 boolean debug, WaitResult outResult, Configuration config) {
2653 // Refuse possible leaked file descriptors
2654 if (intent != null && intent.hasFileDescriptors()) {
2655 throw new IllegalArgumentException("File descriptors passed in Intent");
2656 }
2657
2658 boolean componentSpecified = intent.getComponent() != null;
2659
2660 // Don't modify the client's object!
2661 intent = new Intent(intent);
2662
2663 // Collect information about the target of the Intent.
2664 ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002665
2666 synchronized (mService) {
2667 int callingPid;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002668 if (callingUid >= 0) {
2669 callingPid = -1;
2670 } else if (caller == null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002671 callingPid = Binder.getCallingPid();
2672 callingUid = Binder.getCallingUid();
2673 } else {
2674 callingPid = callingUid = -1;
2675 }
2676
2677 mConfigWillChange = config != null
2678 && mService.mConfiguration.diff(config) != 0;
2679 if (DEBUG_CONFIGURATION) Slog.v(TAG,
2680 "Starting activity when config will change = " + mConfigWillChange);
2681
2682 final long origId = Binder.clearCallingIdentity();
2683
2684 if (mMainStack && aInfo != null &&
Dianne Hackborn54e570f2010-10-04 18:32:32 -07002685 (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002686 // This may be a heavy-weight process! Check to see if we already
2687 // have another, different heavy-weight process running.
2688 if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
2689 if (mService.mHeavyWeightProcess != null &&
2690 (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
2691 !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
2692 int realCallingPid = callingPid;
2693 int realCallingUid = callingUid;
2694 if (caller != null) {
2695 ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
2696 if (callerApp != null) {
2697 realCallingPid = callerApp.pid;
2698 realCallingUid = callerApp.info.uid;
2699 } else {
2700 Slog.w(TAG, "Unable to find app for caller " + caller
2701 + " (pid=" + realCallingPid + ") when starting: "
2702 + intent.toString());
2703 return START_PERMISSION_DENIED;
2704 }
2705 }
2706
2707 IIntentSender target = mService.getIntentSenderLocked(
2708 IActivityManager.INTENT_SENDER_ACTIVITY, "android",
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002709 realCallingUid, null, null, 0, new Intent[] { intent },
2710 new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002711 | PendingIntent.FLAG_ONE_SHOT);
2712
2713 Intent newIntent = new Intent();
2714 if (requestCode >= 0) {
2715 // Caller is requesting a result.
2716 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
2717 }
2718 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
2719 new IntentSender(target));
2720 if (mService.mHeavyWeightProcess.activities.size() > 0) {
2721 ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
2722 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
2723 hist.packageName);
2724 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
2725 hist.task.taskId);
2726 }
2727 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
2728 aInfo.packageName);
2729 newIntent.setFlags(intent.getFlags());
2730 newIntent.setClassName("android",
2731 HeavyWeightSwitcherActivity.class.getName());
2732 intent = newIntent;
2733 resolvedType = null;
2734 caller = null;
2735 callingUid = Binder.getCallingUid();
2736 callingPid = Binder.getCallingPid();
2737 componentSpecified = true;
2738 try {
2739 ResolveInfo rInfo =
2740 AppGlobals.getPackageManager().resolveIntent(
2741 intent, null,
2742 PackageManager.MATCH_DEFAULT_ONLY
2743 | ActivityManagerService.STOCK_PM_FLAGS);
2744 aInfo = rInfo != null ? rInfo.activityInfo : null;
2745 } catch (RemoteException e) {
2746 aInfo = null;
2747 }
2748 }
2749 }
2750 }
2751
2752 int res = startActivityLocked(caller, intent, resolvedType,
2753 grantedUriPermissions, grantedMode, aInfo,
2754 resultTo, resultWho, requestCode, callingPid, callingUid,
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002755 onlyIfNeeded, componentSpecified, null);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002756
2757 if (mConfigWillChange && mMainStack) {
2758 // If the caller also wants to switch to a new configuration,
2759 // do so now. This allows a clean switch, as we are waiting
2760 // for the current activity to pause (so we will not destroy
2761 // it), and have not yet started the next activity.
2762 mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
2763 "updateConfiguration()");
2764 mConfigWillChange = false;
2765 if (DEBUG_CONFIGURATION) Slog.v(TAG,
2766 "Updating to new configuration after starting activity.");
2767 mService.updateConfigurationLocked(config, null);
2768 }
2769
2770 Binder.restoreCallingIdentity(origId);
2771
2772 if (outResult != null) {
2773 outResult.result = res;
2774 if (res == IActivityManager.START_SUCCESS) {
2775 mWaitingActivityLaunched.add(outResult);
2776 do {
2777 try {
Dianne Hackbornba0492d2010-10-12 19:01:46 -07002778 mService.wait();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002779 } catch (InterruptedException e) {
2780 }
2781 } while (!outResult.timeout && outResult.who == null);
2782 } else if (res == IActivityManager.START_TASK_TO_FRONT) {
2783 ActivityRecord r = this.topRunningActivityLocked(null);
2784 if (r.nowVisible) {
2785 outResult.timeout = false;
2786 outResult.who = new ComponentName(r.info.packageName, r.info.name);
2787 outResult.totalTime = 0;
2788 outResult.thisTime = 0;
2789 } else {
2790 outResult.thisTime = SystemClock.uptimeMillis();
2791 mWaitingActivityVisible.add(outResult);
2792 do {
2793 try {
Dianne Hackbornba0492d2010-10-12 19:01:46 -07002794 mService.wait();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002795 } catch (InterruptedException e) {
2796 }
2797 } while (!outResult.timeout && outResult.who == null);
2798 }
2799 }
2800 }
2801
2802 return res;
2803 }
2804 }
2805
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002806 final int startActivities(IApplicationThread caller, int callingUid,
2807 Intent[] intents, String[] resolvedTypes, IBinder resultTo) {
2808 if (intents == null) {
2809 throw new NullPointerException("intents is null");
2810 }
2811 if (resolvedTypes == null) {
2812 throw new NullPointerException("resolvedTypes is null");
2813 }
2814 if (intents.length != resolvedTypes.length) {
2815 throw new IllegalArgumentException("intents are length different than resolvedTypes");
2816 }
2817
2818 ActivityRecord[] outActivity = new ActivityRecord[1];
2819
2820 int callingPid;
2821 if (callingUid >= 0) {
2822 callingPid = -1;
2823 } else if (caller == null) {
2824 callingPid = Binder.getCallingPid();
2825 callingUid = Binder.getCallingUid();
2826 } else {
2827 callingPid = callingUid = -1;
2828 }
2829 final long origId = Binder.clearCallingIdentity();
2830 try {
2831 synchronized (mService) {
2832
2833 for (int i=0; i<intents.length; i++) {
2834 Intent intent = intents[i];
2835 if (intent == null) {
2836 continue;
2837 }
2838
2839 // Refuse possible leaked file descriptors
2840 if (intent != null && intent.hasFileDescriptors()) {
2841 throw new IllegalArgumentException("File descriptors passed in Intent");
2842 }
2843
2844 boolean componentSpecified = intent.getComponent() != null;
2845
2846 // Don't modify the client's object!
2847 intent = new Intent(intent);
2848
2849 // Collect information about the target of the Intent.
2850 ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], false);
2851
2852 if (mMainStack && aInfo != null && (aInfo.applicationInfo.flags
2853 & ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
2854 throw new IllegalArgumentException(
2855 "FLAG_CANT_SAVE_STATE not supported here");
2856 }
2857
2858 int res = startActivityLocked(caller, intent, resolvedTypes[i],
2859 null, 0, aInfo, resultTo, null, -1, callingPid, callingUid,
2860 false, componentSpecified, outActivity);
2861 if (res < 0) {
2862 return res;
2863 }
2864
2865 resultTo = outActivity[0];
2866 }
2867 }
2868 } finally {
2869 Binder.restoreCallingIdentity(origId);
2870 }
2871
2872 return IActivityManager.START_SUCCESS;
2873 }
2874
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002875 void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r,
2876 long thisTime, long totalTime) {
2877 for (int i=mWaitingActivityLaunched.size()-1; i>=0; i--) {
2878 WaitResult w = mWaitingActivityLaunched.get(i);
2879 w.timeout = timeout;
2880 if (r != null) {
2881 w.who = new ComponentName(r.info.packageName, r.info.name);
2882 }
2883 w.thisTime = thisTime;
2884 w.totalTime = totalTime;
2885 }
2886 mService.notifyAll();
2887 }
2888
2889 void reportActivityVisibleLocked(ActivityRecord r) {
2890 for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
2891 WaitResult w = mWaitingActivityVisible.get(i);
2892 w.timeout = false;
2893 if (r != null) {
2894 w.who = new ComponentName(r.info.packageName, r.info.name);
2895 }
2896 w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
2897 w.thisTime = w.totalTime;
2898 }
2899 mService.notifyAll();
2900 }
2901
2902 void sendActivityResultLocked(int callingUid, ActivityRecord r,
2903 String resultWho, int requestCode, int resultCode, Intent data) {
2904
2905 if (callingUid > 0) {
2906 mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002907 data, r.getUriPermissionsLocked());
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002908 }
2909
2910 if (DEBUG_RESULTS) Slog.v(TAG, "Send activity result to " + r
2911 + " : who=" + resultWho + " req=" + requestCode
2912 + " res=" + resultCode + " data=" + data);
2913 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
2914 try {
2915 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
2916 list.add(new ResultInfo(resultWho, requestCode,
2917 resultCode, data));
2918 r.app.thread.scheduleSendResult(r, list);
2919 return;
2920 } catch (Exception e) {
2921 Slog.w(TAG, "Exception thrown sending result to " + r, e);
2922 }
2923 }
2924
2925 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
2926 }
2927
2928 private final void stopActivityLocked(ActivityRecord r) {
2929 if (DEBUG_SWITCH) Slog.d(TAG, "Stopping: " + r);
2930 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
2931 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
2932 if (!r.finishing) {
2933 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
2934 "no-history");
2935 }
2936 } else if (r.app != null && r.app.thread != null) {
2937 if (mMainStack) {
2938 if (mService.mFocusedActivity == r) {
2939 mService.setFocusedActivityLocked(topRunningActivityLocked(null));
2940 }
2941 }
2942 r.resumeKeyDispatchingLocked();
2943 try {
2944 r.stopped = false;
2945 r.state = ActivityState.STOPPING;
2946 if (DEBUG_VISBILITY) Slog.v(
2947 TAG, "Stopping visible=" + r.visible + " for " + r);
2948 if (!r.visible) {
2949 mService.mWindowManager.setAppVisibility(r, false);
2950 }
2951 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08002952 if (mService.isSleeping()) {
2953 r.setSleeping(true);
2954 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002955 } catch (Exception e) {
2956 // Maybe just ignore exceptions here... if the process
2957 // has crashed, our death notification will clean things
2958 // up.
2959 Slog.w(TAG, "Exception thrown during pause", e);
2960 // Just in case, assume it to be stopped.
2961 r.stopped = true;
2962 r.state = ActivityState.STOPPED;
2963 if (r.configDestroy) {
2964 destroyActivityLocked(r, true);
2965 }
2966 }
2967 }
2968 }
2969
2970 final ArrayList<ActivityRecord> processStoppingActivitiesLocked(
2971 boolean remove) {
2972 int N = mStoppingActivities.size();
2973 if (N <= 0) return null;
2974
2975 ArrayList<ActivityRecord> stops = null;
2976
2977 final boolean nowVisible = mResumedActivity != null
2978 && mResumedActivity.nowVisible
2979 && !mResumedActivity.waitingVisible;
2980 for (int i=0; i<N; i++) {
2981 ActivityRecord s = mStoppingActivities.get(i);
2982 if (localLOGV) Slog.v(TAG, "Stopping " + s + ": nowVisible="
2983 + nowVisible + " waitingVisible=" + s.waitingVisible
2984 + " finishing=" + s.finishing);
2985 if (s.waitingVisible && nowVisible) {
2986 mWaitingVisibleActivities.remove(s);
2987 s.waitingVisible = false;
2988 if (s.finishing) {
2989 // If this activity is finishing, it is sitting on top of
2990 // everyone else but we now know it is no longer needed...
2991 // so get rid of it. Otherwise, we need to go through the
2992 // normal flow and hide it once we determine that it is
2993 // hidden by the activities in front of it.
2994 if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
2995 mService.mWindowManager.setAppVisibility(s, false);
2996 }
2997 }
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08002998 if ((!s.waitingVisible || mService.isSleeping()) && remove) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002999 if (localLOGV) Slog.v(TAG, "Ready to stop: " + s);
3000 if (stops == null) {
3001 stops = new ArrayList<ActivityRecord>();
3002 }
3003 stops.add(s);
3004 mStoppingActivities.remove(i);
3005 N--;
3006 i--;
3007 }
3008 }
3009
3010 return stops;
3011 }
3012
3013 final void activityIdleInternal(IBinder token, boolean fromTimeout,
3014 Configuration config) {
3015 if (localLOGV) Slog.v(TAG, "Activity idle: " + token);
3016
3017 ArrayList<ActivityRecord> stops = null;
3018 ArrayList<ActivityRecord> finishes = null;
3019 ArrayList<ActivityRecord> thumbnails = null;
3020 int NS = 0;
3021 int NF = 0;
3022 int NT = 0;
3023 IApplicationThread sendThumbnail = null;
3024 boolean booting = false;
3025 boolean enableScreen = false;
3026
3027 synchronized (mService) {
3028 if (token != null) {
3029 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
3030 }
3031
3032 // Get the activity record.
3033 int index = indexOfTokenLocked(token);
3034 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003035 ActivityRecord r = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003036
3037 if (fromTimeout) {
3038 reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
3039 }
3040
3041 // This is a hack to semi-deal with a race condition
3042 // in the client where it can be constructed with a
3043 // newer configuration from when we asked it to launch.
3044 // We'll update with whatever configuration it now says
3045 // it used to launch.
3046 if (config != null) {
3047 r.configuration = config;
3048 }
3049
3050 // No longer need to keep the device awake.
3051 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
3052 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
3053 mLaunchingActivity.release();
3054 }
3055
3056 // We are now idle. If someone is waiting for a thumbnail from
3057 // us, we can now deliver.
3058 r.idle = true;
3059 mService.scheduleAppGcsLocked();
3060 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
3061 sendThumbnail = r.app.thread;
3062 r.thumbnailNeeded = false;
3063 }
3064
3065 // If this activity is fullscreen, set up to hide those under it.
3066
3067 if (DEBUG_VISBILITY) Slog.v(TAG, "Idle activity for " + r);
3068 ensureActivitiesVisibleLocked(null, 0);
3069
3070 //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
3071 if (mMainStack) {
3072 if (!mService.mBooted && !fromTimeout) {
3073 mService.mBooted = true;
3074 enableScreen = true;
3075 }
3076 }
3077
3078 } else if (fromTimeout) {
3079 reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
3080 }
3081
3082 // Atomically retrieve all of the other things to do.
3083 stops = processStoppingActivitiesLocked(true);
3084 NS = stops != null ? stops.size() : 0;
3085 if ((NF=mFinishingActivities.size()) > 0) {
3086 finishes = new ArrayList<ActivityRecord>(mFinishingActivities);
3087 mFinishingActivities.clear();
3088 }
3089 if ((NT=mService.mCancelledThumbnails.size()) > 0) {
3090 thumbnails = new ArrayList<ActivityRecord>(mService.mCancelledThumbnails);
3091 mService.mCancelledThumbnails.clear();
3092 }
3093
3094 if (mMainStack) {
3095 booting = mService.mBooting;
3096 mService.mBooting = false;
3097 }
3098 }
3099
3100 int i;
3101
3102 // Send thumbnail if requested.
3103 if (sendThumbnail != null) {
3104 try {
3105 sendThumbnail.requestThumbnail(token);
3106 } catch (Exception e) {
3107 Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
3108 mService.sendPendingThumbnail(null, token, null, null, true);
3109 }
3110 }
3111
3112 // Stop any activities that are scheduled to do so but have been
3113 // waiting for the next one to start.
3114 for (i=0; i<NS; i++) {
3115 ActivityRecord r = (ActivityRecord)stops.get(i);
3116 synchronized (mService) {
3117 if (r.finishing) {
3118 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
3119 } else {
3120 stopActivityLocked(r);
3121 }
3122 }
3123 }
3124
3125 // Finish any activities that are scheduled to do so but have been
3126 // waiting for the next one to start.
3127 for (i=0; i<NF; i++) {
3128 ActivityRecord r = (ActivityRecord)finishes.get(i);
3129 synchronized (mService) {
3130 destroyActivityLocked(r, true);
3131 }
3132 }
3133
3134 // Report back to any thumbnail receivers.
3135 for (i=0; i<NT; i++) {
3136 ActivityRecord r = (ActivityRecord)thumbnails.get(i);
3137 mService.sendPendingThumbnail(r, null, null, null, true);
3138 }
3139
3140 if (booting) {
3141 mService.finishBooting();
3142 }
3143
3144 mService.trimApplications();
3145 //dump();
3146 //mWindowManager.dump();
3147
3148 if (enableScreen) {
3149 mService.enableScreenAfterBoot();
3150 }
3151 }
3152
3153 /**
3154 * @return Returns true if the activity is being finished, false if for
3155 * some reason it is being left as-is.
3156 */
3157 final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3158 Intent resultData, String reason) {
3159 if (DEBUG_RESULTS) Slog.v(
3160 TAG, "Finishing activity: token=" + token
3161 + ", result=" + resultCode + ", data=" + resultData);
3162
3163 int index = indexOfTokenLocked(token);
3164 if (index < 0) {
3165 return false;
3166 }
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003167 ActivityRecord r = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003168
3169 // Is this the last activity left?
3170 boolean lastActivity = true;
3171 for (int i=mHistory.size()-1; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003172 ActivityRecord p = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003173 if (!p.finishing && p != r) {
3174 lastActivity = false;
3175 break;
3176 }
3177 }
3178
3179 // If this is the last activity, but it is the home activity, then
3180 // just don't finish it.
3181 if (lastActivity) {
3182 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3183 return false;
3184 }
3185 }
3186
3187 finishActivityLocked(r, index, resultCode, resultData, reason);
3188 return true;
3189 }
3190
3191 /**
3192 * @return Returns true if this activity has been removed from the history
3193 * list, or false if it is still in the list and will be removed later.
3194 */
3195 final boolean finishActivityLocked(ActivityRecord r, int index,
3196 int resultCode, Intent resultData, String reason) {
3197 if (r.finishing) {
3198 Slog.w(TAG, "Duplicate finish request for " + r);
3199 return false;
3200 }
3201
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -08003202 r.makeFinishing();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003203 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
3204 System.identityHashCode(r),
3205 r.task.taskId, r.shortComponentName, reason);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003206 if (index < (mHistory.size()-1)) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003207 ActivityRecord next = mHistory.get(index+1);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003208 if (next.task == r.task) {
3209 if (r.frontOfTask) {
3210 // The next activity is now the front of the task.
3211 next.frontOfTask = true;
3212 }
3213 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
3214 // If the caller asked that this activity (and all above it)
3215 // be cleared when the task is reset, don't lose that information,
3216 // but propagate it up to the next activity.
3217 next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
3218 }
3219 }
3220 }
3221
3222 r.pauseKeyDispatchingLocked();
3223 if (mMainStack) {
3224 if (mService.mFocusedActivity == r) {
3225 mService.setFocusedActivityLocked(topRunningActivityLocked(null));
3226 }
3227 }
3228
3229 // send the result
3230 ActivityRecord resultTo = r.resultTo;
3231 if (resultTo != null) {
3232 if (DEBUG_RESULTS) Slog.v(TAG, "Adding result to " + resultTo
3233 + " who=" + r.resultWho + " req=" + r.requestCode
3234 + " res=" + resultCode + " data=" + resultData);
3235 if (r.info.applicationInfo.uid > 0) {
3236 mService.grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
Dianne Hackborna1c69e02010-09-01 22:55:02 -07003237 resultTo.packageName, resultData,
3238 resultTo.getUriPermissionsLocked());
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003239 }
3240 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3241 resultData);
3242 r.resultTo = null;
3243 }
3244 else if (DEBUG_RESULTS) Slog.v(TAG, "No result destination from " + r);
3245
3246 // Make sure this HistoryRecord is not holding on to other resources,
3247 // because clients have remote IPC references to this object so we
3248 // can't assume that will go away and want to avoid circular IPC refs.
3249 r.results = null;
3250 r.pendingResults = null;
3251 r.newIntents = null;
3252 r.icicle = null;
3253
3254 if (mService.mPendingThumbnails.size() > 0) {
3255 // There are clients waiting to receive thumbnails so, in case
3256 // this is an activity that someone is waiting for, add it
3257 // to the pending list so we can correctly update the clients.
3258 mService.mCancelledThumbnails.add(r);
3259 }
3260
3261 if (mResumedActivity == r) {
3262 boolean endTask = index <= 0
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003263 || (mHistory.get(index-1)).task != r.task;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003264 if (DEBUG_TRANSITION) Slog.v(TAG,
3265 "Prepare close transition: finishing " + r);
3266 mService.mWindowManager.prepareAppTransition(endTask
3267 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003268 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003269
3270 // Tell window manager to prepare for this one to be removed.
3271 mService.mWindowManager.setAppVisibility(r, false);
3272
3273 if (mPausingActivity == null) {
3274 if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
3275 if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
3276 startPausingLocked(false, false);
3277 }
3278
3279 } else if (r.state != ActivityState.PAUSING) {
3280 // If the activity is PAUSING, we will complete the finish once
3281 // it is done pausing; else we can just directly finish it here.
3282 if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
3283 return finishCurrentActivityLocked(r, index,
3284 FINISH_AFTER_PAUSE) == null;
3285 } else {
3286 if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
3287 }
3288
3289 return false;
3290 }
3291
3292 private static final int FINISH_IMMEDIATELY = 0;
3293 private static final int FINISH_AFTER_PAUSE = 1;
3294 private static final int FINISH_AFTER_VISIBLE = 2;
3295
3296 private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
3297 int mode) {
3298 final int index = indexOfTokenLocked(r);
3299 if (index < 0) {
3300 return null;
3301 }
3302
3303 return finishCurrentActivityLocked(r, index, mode);
3304 }
3305
3306 private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
3307 int index, int mode) {
3308 // First things first: if this activity is currently visible,
3309 // and the resumed activity is not yet visible, then hold off on
3310 // finishing until the resumed one becomes visible.
3311 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3312 if (!mStoppingActivities.contains(r)) {
3313 mStoppingActivities.add(r);
3314 if (mStoppingActivities.size() > 3) {
3315 // If we already have a few activities waiting to stop,
3316 // then give up on things going idle and start clearing
3317 // them out.
3318 Message msg = Message.obtain();
3319 msg.what = IDLE_NOW_MSG;
3320 mHandler.sendMessage(msg);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003321 } else {
3322 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003323 }
3324 }
3325 r.state = ActivityState.STOPPING;
3326 mService.updateOomAdjLocked();
3327 return r;
3328 }
3329
3330 // make sure the record is cleaned out of other places.
3331 mStoppingActivities.remove(r);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003332 mGoingToSleepActivities.remove(r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003333 mWaitingVisibleActivities.remove(r);
3334 if (mResumedActivity == r) {
3335 mResumedActivity = null;
3336 }
3337 final ActivityState prevState = r.state;
3338 r.state = ActivityState.FINISHING;
3339
3340 if (mode == FINISH_IMMEDIATELY
3341 || prevState == ActivityState.STOPPED
3342 || prevState == ActivityState.INITIALIZING) {
3343 // If this activity is already stopped, we can just finish
3344 // it right now.
3345 return destroyActivityLocked(r, true) ? null : r;
3346 } else {
3347 // Need to go through the full pause cycle to get this
3348 // activity into the stopped state and then finish it.
3349 if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
3350 mFinishingActivities.add(r);
3351 resumeTopActivityLocked(null);
3352 }
3353 return r;
3354 }
3355
3356 /**
3357 * Perform the common clean-up of an activity record. This is called both
3358 * as part of destroyActivityLocked() (when destroying the client-side
3359 * representation) and cleaning things up as a result of its hosting
3360 * processing going away, in which case there is no remaining client-side
3361 * state to destroy so only the cleanup here is needed.
3362 */
3363 final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices) {
3364 if (mResumedActivity == r) {
3365 mResumedActivity = null;
3366 }
3367 if (mService.mFocusedActivity == r) {
3368 mService.mFocusedActivity = null;
3369 }
3370
3371 r.configDestroy = false;
3372 r.frozenBeforeDestroy = false;
3373
3374 // Make sure this record is no longer in the pending finishes list.
3375 // This could happen, for example, if we are trimming activities
3376 // down to the max limit while they are still waiting to finish.
3377 mFinishingActivities.remove(r);
3378 mWaitingVisibleActivities.remove(r);
3379
3380 // Remove any pending results.
3381 if (r.finishing && r.pendingResults != null) {
3382 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
3383 PendingIntentRecord rec = apr.get();
3384 if (rec != null) {
3385 mService.cancelIntentSenderLocked(rec, false);
3386 }
3387 }
3388 r.pendingResults = null;
3389 }
3390
3391 if (cleanServices) {
3392 cleanUpActivityServicesLocked(r);
3393 }
3394
3395 if (mService.mPendingThumbnails.size() > 0) {
3396 // There are clients waiting to receive thumbnails so, in case
3397 // this is an activity that someone is waiting for, add it
3398 // to the pending list so we can correctly update the clients.
3399 mService.mCancelledThumbnails.add(r);
3400 }
3401
3402 // Get rid of any pending idle timeouts.
3403 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
3404 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003405 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003406 }
3407
3408 private final void removeActivityFromHistoryLocked(ActivityRecord r) {
3409 if (r.state != ActivityState.DESTROYED) {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -08003410 r.makeFinishing();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003411 mHistory.remove(r);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07003412 r.takeFromHistory();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003413 r.state = ActivityState.DESTROYED;
3414 mService.mWindowManager.removeAppToken(r);
3415 if (VALIDATE_TOKENS) {
3416 mService.mWindowManager.validateAppTokens(mHistory);
3417 }
3418 cleanUpActivityServicesLocked(r);
3419 r.removeUriPermissionsLocked();
3420 }
3421 }
3422
3423 /**
3424 * Perform clean-up of service connections in an activity record.
3425 */
3426 final void cleanUpActivityServicesLocked(ActivityRecord r) {
3427 // Throw away any services that have been bound by this activity.
3428 if (r.connections != null) {
3429 Iterator<ConnectionRecord> it = r.connections.iterator();
3430 while (it.hasNext()) {
3431 ConnectionRecord c = it.next();
3432 mService.removeConnectionLocked(c, null, r);
3433 }
3434 r.connections = null;
3435 }
3436 }
3437
3438 /**
3439 * Destroy the current CLIENT SIDE instance of an activity. This may be
3440 * called both when actually finishing an activity, or when performing
3441 * a configuration switch where we destroy the current client-side object
3442 * but then create a new client-side object for this same HistoryRecord.
3443 */
3444 final boolean destroyActivityLocked(ActivityRecord r,
3445 boolean removeFromApp) {
3446 if (DEBUG_SWITCH) Slog.v(
3447 TAG, "Removing activity: token=" + r
3448 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
3449 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
3450 System.identityHashCode(r),
3451 r.task.taskId, r.shortComponentName);
3452
3453 boolean removedFromHistory = false;
3454
3455 cleanUpActivityLocked(r, false);
3456
3457 final boolean hadApp = r.app != null;
3458
3459 if (hadApp) {
3460 if (removeFromApp) {
3461 int idx = r.app.activities.indexOf(r);
3462 if (idx >= 0) {
3463 r.app.activities.remove(idx);
3464 }
3465 if (mService.mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) {
3466 mService.mHeavyWeightProcess = null;
3467 mService.mHandler.sendEmptyMessage(
3468 ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
3469 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003470 if (r.app.activities.size() == 0) {
3471 // No longer have activities, so update location in
3472 // LRU list.
3473 mService.updateLruProcessLocked(r.app, true, false);
3474 }
3475 }
3476
3477 boolean skipDestroy = false;
3478
3479 try {
3480 if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
3481 r.app.thread.scheduleDestroyActivity(r, r.finishing,
3482 r.configChangeFlags);
3483 } catch (Exception e) {
3484 // We can just ignore exceptions here... if the process
3485 // has crashed, our death notification will clean things
3486 // up.
3487 //Slog.w(TAG, "Exception thrown during finish", e);
3488 if (r.finishing) {
3489 removeActivityFromHistoryLocked(r);
3490 removedFromHistory = true;
3491 skipDestroy = true;
3492 }
3493 }
3494
3495 r.app = null;
3496 r.nowVisible = false;
3497
3498 if (r.finishing && !skipDestroy) {
3499 r.state = ActivityState.DESTROYING;
3500 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
3501 msg.obj = r;
3502 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
3503 } else {
3504 r.state = ActivityState.DESTROYED;
3505 }
3506 } else {
3507 // remove this record from the history.
3508 if (r.finishing) {
3509 removeActivityFromHistoryLocked(r);
3510 removedFromHistory = true;
3511 } else {
3512 r.state = ActivityState.DESTROYED;
3513 }
3514 }
3515
3516 r.configChangeFlags = 0;
3517
3518 if (!mLRUActivities.remove(r) && hadApp) {
3519 Slog.w(TAG, "Activity " + r + " being finished, but not in LRU list");
3520 }
3521
3522 return removedFromHistory;
3523 }
3524
3525 final void activityDestroyed(IBinder token) {
3526 synchronized (mService) {
3527 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
3528
3529 int index = indexOfTokenLocked(token);
3530 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003531 ActivityRecord r = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003532 if (r.state == ActivityState.DESTROYING) {
3533 final long origId = Binder.clearCallingIdentity();
3534 removeActivityFromHistoryLocked(r);
3535 Binder.restoreCallingIdentity(origId);
3536 }
3537 }
3538 }
3539 }
3540
3541 private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
3542 int i = list.size();
3543 if (localLOGV) Slog.v(
3544 TAG, "Removing app " + app + " from list " + list
3545 + " with " + i + " entries");
3546 while (i > 0) {
3547 i--;
3548 ActivityRecord r = (ActivityRecord)list.get(i);
3549 if (localLOGV) Slog.v(
3550 TAG, "Record #" + i + " " + r + ": app=" + r.app);
3551 if (r.app == app) {
3552 if (localLOGV) Slog.v(TAG, "Removing this entry!");
3553 list.remove(i);
3554 }
3555 }
3556 }
3557
3558 void removeHistoryRecordsForAppLocked(ProcessRecord app) {
3559 removeHistoryRecordsForAppLocked(mLRUActivities, app);
3560 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003561 removeHistoryRecordsForAppLocked(mGoingToSleepActivities, app);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003562 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
3563 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
3564 }
3565
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003566 /**
3567 * Move the current home activity's task (if one exists) to the front
3568 * of the stack.
3569 */
3570 final void moveHomeToFrontLocked() {
3571 TaskRecord homeTask = null;
3572 for (int i=mHistory.size()-1; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003573 ActivityRecord hr = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003574 if (hr.isHomeActivity) {
3575 homeTask = hr.task;
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -08003576 break;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003577 }
3578 }
3579 if (homeTask != null) {
3580 moveTaskToFrontLocked(homeTask, null);
3581 }
3582 }
3583
3584
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003585 final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason) {
3586 if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
3587
3588 final int task = tr.taskId;
3589 int top = mHistory.size()-1;
3590
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003591 if (top < 0 || (mHistory.get(top)).task.taskId == task) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003592 // nothing to do!
3593 return;
3594 }
3595
3596 ArrayList moved = new ArrayList();
3597
3598 // Applying the affinities may have removed entries from the history,
3599 // so get the size again.
3600 top = mHistory.size()-1;
3601 int pos = top;
3602
3603 // Shift all activities with this task up to the top
3604 // of the stack, keeping them in the same internal order.
3605 while (pos >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003606 ActivityRecord r = mHistory.get(pos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003607 if (localLOGV) Slog.v(
3608 TAG, "At " + pos + " ckp " + r.task + ": " + r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003609 if (r.task.taskId == task) {
3610 if (localLOGV) Slog.v(TAG, "Removing and adding at " + top);
3611 mHistory.remove(pos);
3612 mHistory.add(top, r);
3613 moved.add(0, r);
3614 top--;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003615 }
3616 pos--;
3617 }
3618
3619 if (DEBUG_TRANSITION) Slog.v(TAG,
3620 "Prepare to front transition: task=" + tr);
3621 if (reason != null &&
3622 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003623 mService.mWindowManager.prepareAppTransition(
3624 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003625 ActivityRecord r = topRunningActivityLocked(null);
3626 if (r != null) {
3627 mNoAnimActivities.add(r);
3628 }
3629 } else {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003630 mService.mWindowManager.prepareAppTransition(
3631 WindowManagerPolicy.TRANSIT_TASK_TO_FRONT, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003632 }
3633
3634 mService.mWindowManager.moveAppTokensToTop(moved);
3635 if (VALIDATE_TOKENS) {
3636 mService.mWindowManager.validateAppTokens(mHistory);
3637 }
3638
3639 finishTaskMoveLocked(task);
3640 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
3641 }
3642
3643 private final void finishTaskMoveLocked(int task) {
3644 resumeTopActivityLocked(null);
3645 }
3646
3647 /**
3648 * Worker method for rearranging history stack. Implements the function of moving all
3649 * activities for a specific task (gathering them if disjoint) into a single group at the
3650 * bottom of the stack.
3651 *
3652 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
3653 * to premeptively cancel the move.
3654 *
3655 * @param task The taskId to collect and move to the bottom.
3656 * @return Returns true if the move completed, false if not.
3657 */
3658 final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
3659 Slog.i(TAG, "moveTaskToBack: " + task);
3660
3661 // If we have a watcher, preflight the move before committing to it. First check
3662 // for *other* available tasks, but if none are available, then try again allowing the
3663 // current task to be selected.
3664 if (mMainStack && mService.mController != null) {
3665 ActivityRecord next = topRunningActivityLocked(null, task);
3666 if (next == null) {
3667 next = topRunningActivityLocked(null, 0);
3668 }
3669 if (next != null) {
3670 // ask watcher if this is allowed
3671 boolean moveOK = true;
3672 try {
3673 moveOK = mService.mController.activityResuming(next.packageName);
3674 } catch (RemoteException e) {
3675 mService.mController = null;
3676 }
3677 if (!moveOK) {
3678 return false;
3679 }
3680 }
3681 }
3682
3683 ArrayList moved = new ArrayList();
3684
3685 if (DEBUG_TRANSITION) Slog.v(TAG,
3686 "Prepare to back transition: task=" + task);
3687
3688 final int N = mHistory.size();
3689 int bottom = 0;
3690 int pos = 0;
3691
3692 // Shift all activities with this task down to the bottom
3693 // of the stack, keeping them in the same internal order.
3694 while (pos < N) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003695 ActivityRecord r = mHistory.get(pos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003696 if (localLOGV) Slog.v(
3697 TAG, "At " + pos + " ckp " + r.task + ": " + r);
3698 if (r.task.taskId == task) {
3699 if (localLOGV) Slog.v(TAG, "Removing and adding at " + (N-1));
3700 mHistory.remove(pos);
3701 mHistory.add(bottom, r);
3702 moved.add(r);
3703 bottom++;
3704 }
3705 pos++;
3706 }
3707
3708 if (reason != null &&
3709 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003710 mService.mWindowManager.prepareAppTransition(
3711 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003712 ActivityRecord r = topRunningActivityLocked(null);
3713 if (r != null) {
3714 mNoAnimActivities.add(r);
3715 }
3716 } else {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003717 mService.mWindowManager.prepareAppTransition(
3718 WindowManagerPolicy.TRANSIT_TASK_TO_BACK, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003719 }
3720 mService.mWindowManager.moveAppTokensToBottom(moved);
3721 if (VALIDATE_TOKENS) {
3722 mService.mWindowManager.validateAppTokens(mHistory);
3723 }
3724
3725 finishTaskMoveLocked(task);
3726 return true;
3727 }
3728
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003729 public ActivityManager.TaskThumbnails getTaskThumbnailsLocked(TaskRecord tr) {
3730 TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
3731 ActivityRecord resumed = mResumedActivity;
3732 if (resumed != null && resumed.thumbHolder == tr) {
3733 info.mainThumbnail = resumed.stack.screenshotActivities(resumed);
3734 } else {
3735 info.mainThumbnail = tr.lastThumbnail;
3736 }
3737 return info;
3738 }
3739
3740 public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex) {
3741 TaskAccessInfo info = getTaskAccessInfoLocked(taskId, false);
3742 if (info.root == null) {
3743 Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId);
3744 return null;
3745 }
3746
3747 if (subTaskIndex < 0) {
3748 // Just remove the entire task.
3749 performClearTaskAtIndexLocked(taskId, info.rootIndex);
3750 return info.root;
3751 }
3752
3753 if (subTaskIndex >= info.subtasks.size()) {
3754 Slog.w(TAG, "removeTaskLocked: unknown subTaskIndex " + subTaskIndex);
3755 return null;
3756 }
3757
3758 // Remove all of this task's activies starting at the sub task.
3759 TaskAccessInfo.SubTask subtask = info.subtasks.get(subTaskIndex);
3760 performClearTaskAtIndexLocked(taskId, subtask.index);
3761 return subtask.activity;
3762 }
3763
3764 public TaskAccessInfo getTaskAccessInfoLocked(int taskId, boolean inclThumbs) {
3765 ActivityRecord resumed = mResumedActivity;
3766 final TaskAccessInfo thumbs = new TaskAccessInfo();
3767 // How many different sub-thumbnails?
3768 final int NA = mHistory.size();
3769 int j = 0;
3770 ThumbnailHolder holder = null;
3771 while (j < NA) {
3772 ActivityRecord ar = mHistory.get(j);
3773 if (!ar.finishing && ar.task.taskId == taskId) {
3774 holder = ar.thumbHolder;
3775 break;
3776 }
3777 j++;
3778 }
3779
3780 if (j >= NA) {
3781 return thumbs;
3782 }
3783
3784 thumbs.root = mHistory.get(j);
3785 thumbs.rootIndex = j;
3786
3787 ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>();
3788 thumbs.subtasks = subtasks;
3789 ActivityRecord lastActivity = null;
3790 while (j < NA) {
3791 ActivityRecord ar = mHistory.get(j);
3792 j++;
3793 if (ar.finishing) {
3794 continue;
3795 }
3796 if (ar.task.taskId != taskId) {
3797 break;
3798 }
3799 lastActivity = ar;
3800 if (ar.thumbHolder != holder && holder != null) {
3801 thumbs.numSubThumbbails++;
3802 holder = ar.thumbHolder;
3803 TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask();
3804 sub.thumbnail = holder.lastThumbnail;
3805 sub.activity = ar;
3806 sub.index = j-1;
3807 subtasks.add(sub);
3808 }
3809 }
3810 if (lastActivity != null && subtasks.size() > 0) {
3811 if (resumed == lastActivity) {
3812 TaskAccessInfo.SubTask sub = subtasks.get(subtasks.size()-1);
3813 sub.thumbnail = lastActivity.stack.screenshotActivities(lastActivity);
3814 }
3815 }
3816 if (thumbs.numSubThumbbails > 0) {
3817 thumbs.retriever = new IThumbnailRetriever.Stub() {
3818 public Bitmap getThumbnail(int index) {
3819 if (index < 0 || index >= thumbs.subtasks.size()) {
3820 return null;
3821 }
3822 return thumbs.subtasks.get(index).thumbnail;
3823 }
3824 };
3825 }
3826 return thumbs;
3827 }
3828
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003829 private final void logStartActivity(int tag, ActivityRecord r,
3830 TaskRecord task) {
3831 EventLog.writeEvent(tag,
3832 System.identityHashCode(r), task.taskId,
3833 r.shortComponentName, r.intent.getAction(),
3834 r.intent.getType(), r.intent.getDataString(),
3835 r.intent.getFlags());
3836 }
3837
3838 /**
3839 * Make sure the given activity matches the current configuration. Returns
3840 * false if the activity had to be destroyed. Returns true if the
3841 * configuration is the same, or the activity will remain running as-is
3842 * for whatever reason. Ensures the HistoryRecord is updated with the
3843 * correct configuration and all other bookkeeping is handled.
3844 */
3845 final boolean ensureActivityConfigurationLocked(ActivityRecord r,
3846 int globalChanges) {
3847 if (mConfigWillChange) {
3848 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3849 "Skipping config check (will change): " + r);
3850 return true;
3851 }
3852
3853 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3854 "Ensuring correct configuration: " + r);
3855
3856 // Short circuit: if the two configurations are the exact same
3857 // object (the common case), then there is nothing to do.
3858 Configuration newConfig = mService.mConfiguration;
3859 if (r.configuration == newConfig) {
3860 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3861 "Configuration unchanged in " + r);
3862 return true;
3863 }
3864
3865 // We don't worry about activities that are finishing.
3866 if (r.finishing) {
3867 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3868 "Configuration doesn't matter in finishing " + r);
3869 r.stopFreezingScreenLocked(false);
3870 return true;
3871 }
3872
3873 // Okay we now are going to make this activity have the new config.
3874 // But then we need to figure out how it needs to deal with that.
3875 Configuration oldConfig = r.configuration;
3876 r.configuration = newConfig;
3877
3878 // If the activity isn't currently running, just leave the new
3879 // configuration and it will pick that up next time it starts.
3880 if (r.app == null || r.app.thread == null) {
3881 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3882 "Configuration doesn't matter not running " + r);
3883 r.stopFreezingScreenLocked(false);
3884 return true;
3885 }
3886
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07003887 // Figure out what has changed between the two configurations.
3888 int changes = oldConfig.diff(newConfig);
3889 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
3890 Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
3891 + Integer.toHexString(changes) + ", handles=0x"
3892 + Integer.toHexString(r.info.configChanges)
3893 + ", newConfig=" + newConfig);
3894 }
3895 if ((changes&(~r.info.configChanges)) != 0) {
3896 // Aha, the activity isn't handling the change, so DIE DIE DIE.
3897 r.configChangeFlags |= changes;
3898 r.startFreezingScreenLocked(r.app, globalChanges);
3899 if (r.app == null || r.app.thread == null) {
3900 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3901 "Switch is destroying non-running " + r);
3902 destroyActivityLocked(r, true);
3903 } else if (r.state == ActivityState.PAUSING) {
3904 // A little annoying: we are waiting for this activity to
3905 // finish pausing. Let's not do anything now, but just
3906 // flag that it needs to be restarted when done pausing.
3907 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3908 "Switch is skipping already pausing " + r);
3909 r.configDestroy = true;
3910 return true;
3911 } else if (r.state == ActivityState.RESUMED) {
3912 // Try to optimize this case: the configuration is changing
3913 // and we need to restart the top, resumed activity.
3914 // Instead of doing the normal handshaking, just say
3915 // "restart!".
3916 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3917 "Switch is restarting resumed " + r);
3918 relaunchActivityLocked(r, r.configChangeFlags, true);
3919 r.configChangeFlags = 0;
3920 } else {
3921 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3922 "Switch is restarting non-resumed " + r);
3923 relaunchActivityLocked(r, r.configChangeFlags, false);
3924 r.configChangeFlags = 0;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003925 }
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07003926
3927 // All done... tell the caller we weren't able to keep this
3928 // activity around.
3929 return false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003930 }
3931
3932 // Default case: the activity can handle this new configuration, so
3933 // hand it over. Note that we don't need to give it the new
3934 // configuration, since we always send configuration changes to all
3935 // process when they happen so it can just use whatever configuration
3936 // it last got.
3937 if (r.app != null && r.app.thread != null) {
3938 try {
3939 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
3940 r.app.thread.scheduleActivityConfigurationChanged(r);
3941 } catch (RemoteException e) {
3942 // If process died, whatever.
3943 }
3944 }
3945 r.stopFreezingScreenLocked(false);
3946
3947 return true;
3948 }
3949
3950 private final boolean relaunchActivityLocked(ActivityRecord r,
3951 int changes, boolean andResume) {
3952 List<ResultInfo> results = null;
3953 List<Intent> newIntents = null;
3954 if (andResume) {
3955 results = r.results;
3956 newIntents = r.newIntents;
3957 }
3958 if (DEBUG_SWITCH) Slog.v(TAG, "Relaunching: " + r
3959 + " with results=" + results + " newIntents=" + newIntents
3960 + " andResume=" + andResume);
3961 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
3962 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
3963 r.task.taskId, r.shortComponentName);
3964
3965 r.startFreezingScreenLocked(r.app, 0);
3966
3967 try {
3968 if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
3969 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
3970 changes, !andResume, mService.mConfiguration);
3971 // Note: don't need to call pauseIfSleepingLocked() here, because
3972 // the caller will only pass in 'andResume' if this activity is
3973 // currently resumed, which implies we aren't sleeping.
3974 } catch (RemoteException e) {
3975 return false;
3976 }
3977
3978 if (andResume) {
3979 r.results = null;
3980 r.newIntents = null;
3981 if (mMainStack) {
3982 mService.reportResumedActivityLocked(r);
3983 }
3984 }
3985
3986 return true;
3987 }
3988}