blob: a99b48c02135a231430b73739b3a73732f43d87f [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;
24import android.app.AppGlobals;
25import android.app.IActivityManager;
26import static android.app.IActivityManager.START_CLASS_NOT_FOUND;
27import static android.app.IActivityManager.START_DELIVERED_TO_TOP;
28import static android.app.IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
29import static android.app.IActivityManager.START_INTENT_NOT_RESOLVED;
30import static android.app.IActivityManager.START_PERMISSION_DENIED;
31import static android.app.IActivityManager.START_RETURN_INTENT_TO_CALLER;
32import static android.app.IActivityManager.START_SUCCESS;
33import static android.app.IActivityManager.START_SWITCHES_CANCELED;
34import static android.app.IActivityManager.START_TASK_TO_FRONT;
35import android.app.IApplicationThread;
36import android.app.PendingIntent;
37import android.app.ResultInfo;
38import android.app.IActivityManager.WaitResult;
39import android.content.ComponentName;
40import android.content.Context;
41import android.content.IIntentSender;
42import android.content.Intent;
43import android.content.IntentSender;
44import android.content.pm.ActivityInfo;
45import android.content.pm.ApplicationInfo;
46import android.content.pm.PackageManager;
47import android.content.pm.ResolveInfo;
48import android.content.res.Configuration;
49import android.net.Uri;
50import android.os.Binder;
51import android.os.Bundle;
52import android.os.Handler;
53import android.os.IBinder;
54import android.os.Message;
55import android.os.PowerManager;
56import android.os.RemoteException;
57import android.os.SystemClock;
58import android.util.EventLog;
59import android.util.Log;
60import android.util.Slog;
61import android.view.WindowManagerPolicy;
62
63import java.lang.ref.WeakReference;
64import java.util.ArrayList;
65import java.util.Iterator;
66import java.util.List;
67
68/**
69 * State and management of a single stack of activities.
70 */
71public class ActivityStack {
72 static final String TAG = ActivityManagerService.TAG;
73 static final boolean localLOGV = ActivityManagerService.localLOGV;
74 static final boolean DEBUG_SWITCH = ActivityManagerService.DEBUG_SWITCH;
75 static final boolean DEBUG_PAUSE = ActivityManagerService.DEBUG_PAUSE;
76 static final boolean DEBUG_VISBILITY = ActivityManagerService.DEBUG_VISBILITY;
77 static final boolean DEBUG_USER_LEAVING = ActivityManagerService.DEBUG_USER_LEAVING;
78 static final boolean DEBUG_TRANSITION = ActivityManagerService.DEBUG_TRANSITION;
79 static final boolean DEBUG_RESULTS = ActivityManagerService.DEBUG_RESULTS;
80 static final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
81 static final boolean DEBUG_TASKS = ActivityManagerService.DEBUG_TASKS;
82
83 static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
84
85 // How long we wait until giving up on the last activity telling us it
86 // is idle.
87 static final int IDLE_TIMEOUT = 10*1000;
88
89 // How long we wait until giving up on the last activity to pause. This
90 // is short because it directly impacts the responsiveness of starting the
91 // next activity.
92 static final int PAUSE_TIMEOUT = 500;
93
94 // How long we can hold the launch wake lock before giving up.
95 static final int LAUNCH_TIMEOUT = 10*1000;
96
97 // How long we wait until giving up on an activity telling us it has
98 // finished destroying itself.
99 static final int DESTROY_TIMEOUT = 10*1000;
100
101 // How long until we reset a task when the user returns to it. Currently
102 // 30 minutes.
103 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
104
105 // Set to false to disable the preview that is shown while a new activity
106 // is being started.
107 static final boolean SHOW_APP_STARTING_PREVIEW = true;
108
109 enum ActivityState {
110 INITIALIZING,
111 RESUMED,
112 PAUSING,
113 PAUSED,
114 STOPPING,
115 STOPPED,
116 FINISHING,
117 DESTROYING,
118 DESTROYED
119 }
120
121 final ActivityManagerService mService;
122 final boolean mMainStack;
123
124 final Context mContext;
125
126 /**
127 * The back history of all previous (and possibly still
128 * running) activities. It contains HistoryRecord objects.
129 */
130 final ArrayList mHistory = new ArrayList();
131
132 /**
133 * List of running activities, sorted by recent usage.
134 * The first entry in the list is the least recently used.
135 * It contains HistoryRecord objects.
136 */
137 final ArrayList mLRUActivities = new ArrayList();
138
139 /**
140 * List of activities that are waiting for a new activity
141 * to become visible before completing whatever operation they are
142 * supposed to do.
143 */
144 final ArrayList<ActivityRecord> mWaitingVisibleActivities
145 = new ArrayList<ActivityRecord>();
146
147 /**
148 * List of activities that are ready to be stopped, but waiting
149 * for the next activity to settle down before doing so. It contains
150 * HistoryRecord objects.
151 */
152 final ArrayList<ActivityRecord> mStoppingActivities
153 = new ArrayList<ActivityRecord>();
154
155 /**
156 * Animations that for the current transition have requested not to
157 * be considered for the transition animation.
158 */
159 final ArrayList<ActivityRecord> mNoAnimActivities
160 = new ArrayList<ActivityRecord>();
161
162 /**
163 * List of activities that are ready to be finished, but waiting
164 * for the previous activity to settle down before doing so. It contains
165 * HistoryRecord objects.
166 */
167 final ArrayList<ActivityRecord> mFinishingActivities
168 = new ArrayList<ActivityRecord>();
169
170 /**
171 * List of people waiting to find out about the next launched activity.
172 */
173 final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched
174 = new ArrayList<IActivityManager.WaitResult>();
175
176 /**
177 * List of people waiting to find out about the next visible activity.
178 */
179 final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible
180 = new ArrayList<IActivityManager.WaitResult>();
181
182 /**
183 * Set when the system is going to sleep, until we have
184 * successfully paused the current activity and released our wake lock.
185 * At that point the system is allowed to actually sleep.
186 */
187 final PowerManager.WakeLock mGoingToSleep;
188
189 /**
190 * We don't want to allow the device to go to sleep while in the process
191 * of launching an activity. This is primarily to allow alarm intent
192 * receivers to launch an activity and get that to run before the device
193 * goes back to sleep.
194 */
195 final PowerManager.WakeLock mLaunchingActivity;
196
197 /**
198 * When we are in the process of pausing an activity, before starting the
199 * next one, this variable holds the activity that is currently being paused.
200 */
201 ActivityRecord mPausingActivity = null;
202
203 /**
204 * This is the last activity that we put into the paused state. This is
205 * used to determine if we need to do an activity transition while sleeping,
206 * when we normally hold the top activity paused.
207 */
208 ActivityRecord mLastPausedActivity = null;
209
210 /**
211 * Current activity that is resumed, or null if there is none.
212 */
213 ActivityRecord mResumedActivity = null;
214
215 /**
216 * Set when we know we are going to be calling updateConfiguration()
217 * soon, so want to skip intermediate config checks.
218 */
219 boolean mConfigWillChange;
220
221 /**
222 * Set to indicate whether to issue an onUserLeaving callback when a
223 * newly launched activity is being brought in front of us.
224 */
225 boolean mUserLeaving = false;
226
227 long mInitialStartTime = 0;
228
229 static final int PAUSE_TIMEOUT_MSG = 9;
230 static final int IDLE_TIMEOUT_MSG = 10;
231 static final int IDLE_NOW_MSG = 11;
232 static final int LAUNCH_TIMEOUT_MSG = 16;
233 static final int DESTROY_TIMEOUT_MSG = 17;
234 static final int RESUME_TOP_ACTIVITY_MSG = 19;
235
236 final Handler mHandler = new Handler() {
237 //public Handler() {
238 // if (localLOGV) Slog.v(TAG, "Handler started!");
239 //}
240
241 public void handleMessage(Message msg) {
242 switch (msg.what) {
243 case PAUSE_TIMEOUT_MSG: {
244 IBinder token = (IBinder)msg.obj;
245 // We don't at this point know if the activity is fullscreen,
246 // so we need to be conservative and assume it isn't.
247 Slog.w(TAG, "Activity pause timeout for " + token);
248 activityPaused(token, null, true);
249 } break;
250 case IDLE_TIMEOUT_MSG: {
251 if (mService.mDidDexOpt) {
252 mService.mDidDexOpt = false;
253 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
254 nmsg.obj = msg.obj;
255 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
256 return;
257 }
258 // We don't at this point know if the activity is fullscreen,
259 // so we need to be conservative and assume it isn't.
260 IBinder token = (IBinder)msg.obj;
261 Slog.w(TAG, "Activity idle timeout for " + token);
262 activityIdleInternal(token, true, null);
263 } break;
264 case DESTROY_TIMEOUT_MSG: {
265 IBinder token = (IBinder)msg.obj;
266 // We don't at this point know if the activity is fullscreen,
267 // so we need to be conservative and assume it isn't.
268 Slog.w(TAG, "Activity destroy timeout for " + token);
269 activityDestroyed(token);
270 } break;
271 case IDLE_NOW_MSG: {
272 IBinder token = (IBinder)msg.obj;
273 activityIdleInternal(token, false, null);
274 } break;
275 case LAUNCH_TIMEOUT_MSG: {
276 if (mService.mDidDexOpt) {
277 mService.mDidDexOpt = false;
278 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
279 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
280 return;
281 }
282 synchronized (mService) {
283 if (mLaunchingActivity.isHeld()) {
284 Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
285 mLaunchingActivity.release();
286 }
287 }
288 } break;
289 case RESUME_TOP_ACTIVITY_MSG: {
290 synchronized (mService) {
291 resumeTopActivityLocked(null);
292 }
293 } break;
294 }
295 }
296 };
297
298 ActivityStack(ActivityManagerService service, Context context, boolean mainStack) {
299 mService = service;
300 mContext = context;
301 mMainStack = mainStack;
302 PowerManager pm =
303 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
304 mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
305 mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
306 mLaunchingActivity.setReferenceCounted(false);
307 }
308
309 final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
310 int i = mHistory.size()-1;
311 while (i >= 0) {
312 ActivityRecord r = (ActivityRecord)mHistory.get(i);
313 if (!r.finishing && r != notTop) {
314 return r;
315 }
316 i--;
317 }
318 return null;
319 }
320
321 final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
322 int i = mHistory.size()-1;
323 while (i >= 0) {
324 ActivityRecord r = (ActivityRecord)mHistory.get(i);
325 if (!r.finishing && !r.delayedResume && r != notTop) {
326 return r;
327 }
328 i--;
329 }
330 return null;
331 }
332
333 /**
334 * This is a simplified version of topRunningActivityLocked that provides a number of
335 * optional skip-over modes. It is intended for use with the ActivityController hook only.
336 *
337 * @param token If non-null, any history records matching this token will be skipped.
338 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
339 *
340 * @return Returns the HistoryRecord of the next activity on the stack.
341 */
342 final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
343 int i = mHistory.size()-1;
344 while (i >= 0) {
345 ActivityRecord r = (ActivityRecord)mHistory.get(i);
346 // Note: the taskId check depends on real taskId fields being non-zero
347 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
348 return r;
349 }
350 i--;
351 }
352 return null;
353 }
354
355 final int indexOfTokenLocked(IBinder token) {
356 int count = mHistory.size();
357
358 // convert the token to an entry in the history.
359 int index = -1;
360 for (int i=count-1; i>=0; i--) {
361 Object o = mHistory.get(i);
362 if (o == token) {
363 index = i;
364 break;
365 }
366 }
367
368 return index;
369 }
370
371 private final boolean updateLRUListLocked(ActivityRecord r) {
372 final boolean hadit = mLRUActivities.remove(r);
373 mLRUActivities.add(r);
374 return hadit;
375 }
376
377 /**
378 * Returns the top activity in any existing task matching the given
379 * Intent. Returns null if no such task is found.
380 */
381 private ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) {
382 ComponentName cls = intent.getComponent();
383 if (info.targetActivity != null) {
384 cls = new ComponentName(info.packageName, info.targetActivity);
385 }
386
387 TaskRecord cp = null;
388
389 final int N = mHistory.size();
390 for (int i=(N-1); i>=0; i--) {
391 ActivityRecord r = (ActivityRecord)mHistory.get(i);
392 if (!r.finishing && r.task != cp
393 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
394 cp = r.task;
395 //Slog.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
396 // + "/aff=" + r.task.affinity + " to new cls="
397 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
398 if (r.task.affinity != null) {
399 if (r.task.affinity.equals(info.taskAffinity)) {
400 //Slog.i(TAG, "Found matching affinity!");
401 return r;
402 }
403 } else if (r.task.intent != null
404 && r.task.intent.getComponent().equals(cls)) {
405 //Slog.i(TAG, "Found matching class!");
406 //dump();
407 //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
408 return r;
409 } else if (r.task.affinityIntent != null
410 && r.task.affinityIntent.getComponent().equals(cls)) {
411 //Slog.i(TAG, "Found matching class!");
412 //dump();
413 //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
414 return r;
415 }
416 }
417 }
418
419 return null;
420 }
421
422 /**
423 * Returns the first activity (starting from the top of the stack) that
424 * is the same as the given activity. Returns null if no such activity
425 * is found.
426 */
427 private ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
428 ComponentName cls = intent.getComponent();
429 if (info.targetActivity != null) {
430 cls = new ComponentName(info.packageName, info.targetActivity);
431 }
432
433 final int N = mHistory.size();
434 for (int i=(N-1); i>=0; i--) {
435 ActivityRecord r = (ActivityRecord)mHistory.get(i);
436 if (!r.finishing) {
437 if (r.intent.getComponent().equals(cls)) {
438 //Slog.i(TAG, "Found matching class!");
439 //dump();
440 //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
441 return r;
442 }
443 }
444 }
445
446 return null;
447 }
448
449 final boolean realStartActivityLocked(ActivityRecord r,
450 ProcessRecord app, boolean andResume, boolean checkConfig)
451 throws RemoteException {
452
453 r.startFreezingScreenLocked(app, 0);
454 mService.mWindowManager.setAppVisibility(r, true);
455
456 // Have the window manager re-evaluate the orientation of
457 // the screen based on the new activity order. Note that
458 // as a result of this, it can call back into the activity
459 // manager with a new orientation. We don't care about that,
460 // because the activity is not currently running so we are
461 // just restarting it anyway.
462 if (checkConfig) {
463 Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
464 mService.mConfiguration,
465 r.mayFreezeScreenLocked(app) ? r : null);
466 mService.updateConfigurationLocked(config, r);
467 }
468
469 r.app = app;
470
471 if (localLOGV) Slog.v(TAG, "Launching: " + r);
472
473 int idx = app.activities.indexOf(r);
474 if (idx < 0) {
475 app.activities.add(r);
476 }
477 mService.updateLruProcessLocked(app, true, true);
478
479 try {
480 if (app.thread == null) {
481 throw new RemoteException();
482 }
483 List<ResultInfo> results = null;
484 List<Intent> newIntents = null;
485 if (andResume) {
486 results = r.results;
487 newIntents = r.newIntents;
488 }
489 if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
490 + " icicle=" + r.icicle
491 + " with results=" + results + " newIntents=" + newIntents
492 + " andResume=" + andResume);
493 if (andResume) {
494 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
495 System.identityHashCode(r),
496 r.task.taskId, r.shortComponentName);
497 }
498 if (r.isHomeActivity) {
499 mService.mHomeProcess = app;
500 }
501 mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
502 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
503 System.identityHashCode(r),
504 r.info, r.icicle, results, newIntents, !andResume,
505 mService.isNextTransitionForward());
506
507 if ((app.info.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
508 // This may be a heavy-weight process! Note that the package
509 // manager will ensure that only activity can run in the main
510 // process of the .apk, which is the only thing that will be
511 // considered heavy-weight.
512 if (app.processName.equals(app.info.packageName)) {
513 if (mService.mHeavyWeightProcess != null
514 && mService.mHeavyWeightProcess != app) {
515 Log.w(TAG, "Starting new heavy weight process " + app
516 + " when already running "
517 + mService.mHeavyWeightProcess);
518 }
519 mService.mHeavyWeightProcess = app;
520 Message msg = mService.mHandler.obtainMessage(
521 ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
522 msg.obj = r;
523 mService.mHandler.sendMessage(msg);
524 }
525 }
526
527 } catch (RemoteException e) {
528 if (r.launchFailed) {
529 // This is the second time we failed -- finish activity
530 // and give up.
531 Slog.e(TAG, "Second failure launching "
532 + r.intent.getComponent().flattenToShortString()
533 + ", giving up", e);
534 mService.appDiedLocked(app, app.pid, app.thread);
535 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
536 "2nd-crash");
537 return false;
538 }
539
540 // This is the first time we failed -- restart process and
541 // retry.
542 app.activities.remove(r);
543 throw e;
544 }
545
546 r.launchFailed = false;
547 if (updateLRUListLocked(r)) {
548 Slog.w(TAG, "Activity " + r
549 + " being launched, but already in LRU list");
550 }
551
552 if (andResume) {
553 // As part of the process of launching, ActivityThread also performs
554 // a resume.
555 r.state = ActivityState.RESUMED;
556 r.icicle = null;
557 r.haveState = false;
558 r.stopped = false;
559 mResumedActivity = r;
560 r.task.touchActiveTime();
561 completeResumeLocked(r);
562 pauseIfSleepingLocked();
563 } else {
564 // This activity is not starting in the resumed state... which
565 // should look like we asked it to pause+stop (but remain visible),
566 // and it has done so and reported back the current icicle and
567 // other state.
568 r.state = ActivityState.STOPPED;
569 r.stopped = true;
570 }
571
572 // Launch the new version setup screen if needed. We do this -after-
573 // launching the initial activity (that is, home), so that it can have
574 // a chance to initialize itself while in the background, making the
575 // switch back to it faster and look better.
576 if (mMainStack) {
577 mService.startSetupActivityLocked();
578 }
579
580 return true;
581 }
582
583 private final void startSpecificActivityLocked(ActivityRecord r,
584 boolean andResume, boolean checkConfig) {
585 // Is this activity's application already running?
586 ProcessRecord app = mService.getProcessRecordLocked(r.processName,
587 r.info.applicationInfo.uid);
588
589 if (r.startTime == 0) {
590 r.startTime = SystemClock.uptimeMillis();
591 if (mInitialStartTime == 0) {
592 mInitialStartTime = r.startTime;
593 }
594 } else if (mInitialStartTime == 0) {
595 mInitialStartTime = SystemClock.uptimeMillis();
596 }
597
598 if (app != null && app.thread != null) {
599 try {
600 realStartActivityLocked(r, app, andResume, checkConfig);
601 return;
602 } catch (RemoteException e) {
603 Slog.w(TAG, "Exception when starting activity "
604 + r.intent.getComponent().flattenToShortString(), e);
605 }
606
607 // If a dead object exception was thrown -- fall through to
608 // restart the application.
609 }
610
611 mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
612 "activity", r.intent.getComponent(), false);
613 }
614
615 void pauseIfSleepingLocked() {
616 if (mService.mSleeping || mService.mShuttingDown) {
617 if (!mGoingToSleep.isHeld()) {
618 mGoingToSleep.acquire();
619 if (mLaunchingActivity.isHeld()) {
620 mLaunchingActivity.release();
621 mService.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
622 }
623 }
624
625 // If we are not currently pausing an activity, get the current
626 // one to pause. If we are pausing one, we will just let that stuff
627 // run and release the wake lock when all done.
628 if (mPausingActivity == null) {
629 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause...");
630 if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false");
631 startPausingLocked(false, true);
632 }
633 }
634 }
635
636 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
637 if (mPausingActivity != null) {
638 RuntimeException e = new RuntimeException();
639 Slog.e(TAG, "Trying to pause when pause is already pending for "
640 + mPausingActivity, e);
641 }
642 ActivityRecord prev = mResumedActivity;
643 if (prev == null) {
644 RuntimeException e = new RuntimeException();
645 Slog.e(TAG, "Trying to pause when nothing is resumed", e);
646 resumeTopActivityLocked(null);
647 return;
648 }
649 if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
650 mResumedActivity = null;
651 mPausingActivity = prev;
652 mLastPausedActivity = prev;
653 prev.state = ActivityState.PAUSING;
654 prev.task.touchActiveTime();
655
656 mService.updateCpuStats();
657
658 if (prev.app != null && prev.app.thread != null) {
659 if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
660 try {
661 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
662 System.identityHashCode(prev),
663 prev.shortComponentName);
664 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
665 prev.configChangeFlags);
666 if (mMainStack) {
667 mService.updateUsageStats(prev, false);
668 }
669 } catch (Exception e) {
670 // Ignore exception, if process died other code will cleanup.
671 Slog.w(TAG, "Exception thrown during pause", e);
672 mPausingActivity = null;
673 mLastPausedActivity = null;
674 }
675 } else {
676 mPausingActivity = null;
677 mLastPausedActivity = null;
678 }
679
680 // If we are not going to sleep, we want to ensure the device is
681 // awake until the next activity is started.
682 if (!mService.mSleeping && !mService.mShuttingDown) {
683 mLaunchingActivity.acquire();
684 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
685 // To be safe, don't allow the wake lock to be held for too long.
686 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
687 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
688 }
689 }
690
691
692 if (mPausingActivity != null) {
693 // Have the window manager pause its key dispatching until the new
694 // activity has started. If we're pausing the activity just because
695 // the screen is being turned off and the UI is sleeping, don't interrupt
696 // key dispatch; the same activity will pick it up again on wakeup.
697 if (!uiSleeping) {
698 prev.pauseKeyDispatchingLocked();
699 } else {
700 if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
701 }
702
703 // Schedule a pause timeout in case the app doesn't respond.
704 // We don't give it much time because this directly impacts the
705 // responsiveness seen by the user.
706 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
707 msg.obj = prev;
708 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
709 if (DEBUG_PAUSE) Slog.v(TAG, "Waiting for pause to complete...");
710 } else {
711 // This activity failed to schedule the
712 // pause, so just treat it as being paused now.
713 if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
714 resumeTopActivityLocked(null);
715 }
716 }
717
718 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
719 if (DEBUG_PAUSE) Slog.v(
720 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
721 + ", timeout=" + timeout);
722
723 ActivityRecord r = null;
724
725 synchronized (mService) {
726 int index = indexOfTokenLocked(token);
727 if (index >= 0) {
728 r = (ActivityRecord)mHistory.get(index);
729 if (!timeout) {
730 r.icicle = icicle;
731 r.haveState = true;
732 }
733 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
734 if (mPausingActivity == r) {
735 r.state = ActivityState.PAUSED;
736 completePauseLocked();
737 } else {
738 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
739 System.identityHashCode(r), r.shortComponentName,
740 mPausingActivity != null
741 ? mPausingActivity.shortComponentName : "(none)");
742 }
743 }
744 }
745 }
746
747 private final void completePauseLocked() {
748 ActivityRecord prev = mPausingActivity;
749 if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
750
751 if (prev != null) {
752 if (prev.finishing) {
753 if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
754 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
755 } else if (prev.app != null) {
756 if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
757 if (prev.waitingVisible) {
758 prev.waitingVisible = false;
759 mWaitingVisibleActivities.remove(prev);
760 if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
761 TAG, "Complete pause, no longer waiting: " + prev);
762 }
763 if (prev.configDestroy) {
764 // The previous is being paused because the configuration
765 // is changing, which means it is actually stopping...
766 // To juggle the fact that we are also starting a new
767 // instance right now, we need to first completely stop
768 // the current instance before starting the new one.
769 if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
770 destroyActivityLocked(prev, true);
771 } else {
772 mStoppingActivities.add(prev);
773 if (mStoppingActivities.size() > 3) {
774 // If we already have a few activities waiting to stop,
775 // then give up on things going idle and start clearing
776 // them out.
777 if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
778 Message msg = Message.obtain();
779 msg.what = IDLE_NOW_MSG;
780 mHandler.sendMessage(msg);
781 }
782 }
783 } else {
784 if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
785 prev = null;
786 }
787 mPausingActivity = null;
788 }
789
790 if (!mService.mSleeping && !mService.mShuttingDown) {
791 resumeTopActivityLocked(prev);
792 } else {
793 if (mGoingToSleep.isHeld()) {
794 mGoingToSleep.release();
795 }
796 if (mService.mShuttingDown) {
797 mService.notifyAll();
798 }
799 }
800
801 if (prev != null) {
802 prev.resumeKeyDispatchingLocked();
803 }
804
805 if (prev.app != null && prev.cpuTimeAtResume > 0
806 && mService.mBatteryStatsService.isOnBattery()) {
807 long diff = 0;
808 synchronized (mService.mProcessStatsThread) {
809 diff = mService.mProcessStats.getCpuTimeForPid(prev.app.pid)
810 - prev.cpuTimeAtResume;
811 }
812 if (diff > 0) {
813 BatteryStatsImpl bsi = mService.mBatteryStatsService.getActiveStatistics();
814 synchronized (bsi) {
815 BatteryStatsImpl.Uid.Proc ps =
816 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
817 prev.info.packageName);
818 if (ps != null) {
819 ps.addForegroundTimeLocked(diff);
820 }
821 }
822 }
823 }
824 prev.cpuTimeAtResume = 0; // reset it
825 }
826
827 /**
828 * Once we know that we have asked an application to put an activity in
829 * the resumed state (either by launching it or explicitly telling it),
830 * this function updates the rest of our state to match that fact.
831 */
832 private final void completeResumeLocked(ActivityRecord next) {
833 next.idle = false;
834 next.results = null;
835 next.newIntents = null;
836
837 // schedule an idle timeout in case the app doesn't do it for us.
838 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
839 msg.obj = next;
840 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
841
842 if (false) {
843 // The activity was never told to pause, so just keep
844 // things going as-is. To maintain our own state,
845 // we need to emulate it coming back and saying it is
846 // idle.
847 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
848 msg.obj = next;
849 mHandler.sendMessage(msg);
850 }
851
852 if (mMainStack) {
853 mService.reportResumedActivityLocked(next);
854 }
855
856 next.thumbnail = null;
857 if (mMainStack) {
858 mService.setFocusedActivityLocked(next);
859 }
860 next.resumeKeyDispatchingLocked();
861 ensureActivitiesVisibleLocked(null, 0);
862 mService.mWindowManager.executeAppTransition();
863 mNoAnimActivities.clear();
864
865 // Mark the point when the activity is resuming
866 // TODO: To be more accurate, the mark should be before the onCreate,
867 // not after the onResume. But for subsequent starts, onResume is fine.
868 if (next.app != null) {
869 synchronized (mService.mProcessStatsThread) {
870 next.cpuTimeAtResume = mService.mProcessStats.getCpuTimeForPid(next.app.pid);
871 }
872 } else {
873 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
874 }
875 }
876
877 /**
878 * Make sure that all activities that need to be visible (that is, they
879 * currently can be seen by the user) actually are.
880 */
881 final void ensureActivitiesVisibleLocked(ActivityRecord top,
882 ActivityRecord starting, String onlyThisProcess, int configChanges) {
883 if (DEBUG_VISBILITY) Slog.v(
884 TAG, "ensureActivitiesVisible behind " + top
885 + " configChanges=0x" + Integer.toHexString(configChanges));
886
887 // If the top activity is not fullscreen, then we need to
888 // make sure any activities under it are now visible.
889 final int count = mHistory.size();
890 int i = count-1;
891 while (mHistory.get(i) != top) {
892 i--;
893 }
894 ActivityRecord r;
895 boolean behindFullscreen = false;
896 for (; i>=0; i--) {
897 r = (ActivityRecord)mHistory.get(i);
898 if (DEBUG_VISBILITY) Slog.v(
899 TAG, "Make visible? " + r + " finishing=" + r.finishing
900 + " state=" + r.state);
901 if (r.finishing) {
902 continue;
903 }
904
905 final boolean doThisProcess = onlyThisProcess == null
906 || onlyThisProcess.equals(r.processName);
907
908 // First: if this is not the current activity being started, make
909 // sure it matches the current configuration.
910 if (r != starting && doThisProcess) {
911 ensureActivityConfigurationLocked(r, 0);
912 }
913
914 if (r.app == null || r.app.thread == null) {
915 if (onlyThisProcess == null
916 || onlyThisProcess.equals(r.processName)) {
917 // This activity needs to be visible, but isn't even
918 // running... get it started, but don't resume it
919 // at this point.
920 if (DEBUG_VISBILITY) Slog.v(
921 TAG, "Start and freeze screen for " + r);
922 if (r != starting) {
923 r.startFreezingScreenLocked(r.app, configChanges);
924 }
925 if (!r.visible) {
926 if (DEBUG_VISBILITY) Slog.v(
927 TAG, "Starting and making visible: " + r);
928 mService.mWindowManager.setAppVisibility(r, true);
929 }
930 if (r != starting) {
931 startSpecificActivityLocked(r, false, false);
932 }
933 }
934
935 } else if (r.visible) {
936 // If this activity is already visible, then there is nothing
937 // else to do here.
938 if (DEBUG_VISBILITY) Slog.v(
939 TAG, "Skipping: already visible at " + r);
940 r.stopFreezingScreenLocked(false);
941
942 } else if (onlyThisProcess == null) {
943 // This activity is not currently visible, but is running.
944 // Tell it to become visible.
945 r.visible = true;
946 if (r.state != ActivityState.RESUMED && r != starting) {
947 // If this activity is paused, tell it
948 // to now show its window.
949 if (DEBUG_VISBILITY) Slog.v(
950 TAG, "Making visible and scheduling visibility: " + r);
951 try {
952 mService.mWindowManager.setAppVisibility(r, true);
953 r.app.thread.scheduleWindowVisibility(r, true);
954 r.stopFreezingScreenLocked(false);
955 } catch (Exception e) {
956 // Just skip on any failure; we'll make it
957 // visible when it next restarts.
958 Slog.w(TAG, "Exception thrown making visibile: "
959 + r.intent.getComponent(), e);
960 }
961 }
962 }
963
964 // Aggregate current change flags.
965 configChanges |= r.configChangeFlags;
966
967 if (r.fullscreen) {
968 // At this point, nothing else needs to be shown
969 if (DEBUG_VISBILITY) Slog.v(
970 TAG, "Stopping: fullscreen at " + r);
971 behindFullscreen = true;
972 i--;
973 break;
974 }
975 }
976
977 // Now for any activities that aren't visible to the user, make
978 // sure they no longer are keeping the screen frozen.
979 while (i >= 0) {
980 r = (ActivityRecord)mHistory.get(i);
981 if (DEBUG_VISBILITY) Slog.v(
982 TAG, "Make invisible? " + r + " finishing=" + r.finishing
983 + " state=" + r.state
984 + " behindFullscreen=" + behindFullscreen);
985 if (!r.finishing) {
986 if (behindFullscreen) {
987 if (r.visible) {
988 if (DEBUG_VISBILITY) Slog.v(
989 TAG, "Making invisible: " + r);
990 r.visible = false;
991 try {
992 mService.mWindowManager.setAppVisibility(r, false);
993 if ((r.state == ActivityState.STOPPING
994 || r.state == ActivityState.STOPPED)
995 && r.app != null && r.app.thread != null) {
996 if (DEBUG_VISBILITY) Slog.v(
997 TAG, "Scheduling invisibility: " + r);
998 r.app.thread.scheduleWindowVisibility(r, false);
999 }
1000 } catch (Exception e) {
1001 // Just skip on any failure; we'll make it
1002 // visible when it next restarts.
1003 Slog.w(TAG, "Exception thrown making hidden: "
1004 + r.intent.getComponent(), e);
1005 }
1006 } else {
1007 if (DEBUG_VISBILITY) Slog.v(
1008 TAG, "Already invisible: " + r);
1009 }
1010 } else if (r.fullscreen) {
1011 if (DEBUG_VISBILITY) Slog.v(
1012 TAG, "Now behindFullscreen: " + r);
1013 behindFullscreen = true;
1014 }
1015 }
1016 i--;
1017 }
1018 }
1019
1020 /**
1021 * Version of ensureActivitiesVisible that can easily be called anywhere.
1022 */
1023 final void ensureActivitiesVisibleLocked(ActivityRecord starting,
1024 int configChanges) {
1025 ActivityRecord r = topRunningActivityLocked(null);
1026 if (r != null) {
1027 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
1028 }
1029 }
1030
1031 /**
1032 * Ensure that the top activity in the stack is resumed.
1033 *
1034 * @param prev The previously resumed activity, for when in the process
1035 * of pausing; can be null to call from elsewhere.
1036 *
1037 * @return Returns true if something is being resumed, or false if
1038 * nothing happened.
1039 */
1040 final boolean resumeTopActivityLocked(ActivityRecord prev) {
1041 // Find the first activity that is not finishing.
1042 ActivityRecord next = topRunningActivityLocked(null);
1043
1044 // Remember how we'll process this pause/resume situation, and ensure
1045 // that the state is reset however we wind up proceeding.
1046 final boolean userLeaving = mUserLeaving;
1047 mUserLeaving = false;
1048
1049 if (next == null) {
1050 // There are no more activities! Let's just start up the
1051 // Launcher...
1052 if (mMainStack) {
1053 return mService.startHomeActivityLocked();
1054 }
1055 }
1056
1057 next.delayedResume = false;
1058
1059 // If the top activity is the resumed one, nothing to do.
1060 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
1061 // Make sure we have executed any pending transitions, since there
1062 // should be nothing left to do at this point.
1063 mService.mWindowManager.executeAppTransition();
1064 mNoAnimActivities.clear();
1065 return false;
1066 }
1067
1068 // If we are sleeping, and there is no resumed activity, and the top
1069 // activity is paused, well that is the state we want.
1070 if ((mService.mSleeping || mService.mShuttingDown)
1071 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
1072 // Make sure we have executed any pending transitions, since there
1073 // should be nothing left to do at this point.
1074 mService.mWindowManager.executeAppTransition();
1075 mNoAnimActivities.clear();
1076 return false;
1077 }
1078
1079 // The activity may be waiting for stop, but that is no longer
1080 // appropriate for it.
1081 mStoppingActivities.remove(next);
1082 mWaitingVisibleActivities.remove(next);
1083
1084 if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
1085
1086 // If we are currently pausing an activity, then don't do anything
1087 // until that is done.
1088 if (mPausingActivity != null) {
1089 if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity);
1090 return false;
1091 }
1092
1093 // We need to start pausing the current activity so the top one
1094 // can be resumed...
1095 if (mResumedActivity != null) {
1096 if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
1097 startPausingLocked(userLeaving, false);
1098 return true;
1099 }
1100
1101 if (prev != null && prev != next) {
1102 if (!prev.waitingVisible && next != null && !next.nowVisible) {
1103 prev.waitingVisible = true;
1104 mWaitingVisibleActivities.add(prev);
1105 if (DEBUG_SWITCH) Slog.v(
1106 TAG, "Resuming top, waiting visible to hide: " + prev);
1107 } else {
1108 // The next activity is already visible, so hide the previous
1109 // activity's windows right now so we can show the new one ASAP.
1110 // We only do this if the previous is finishing, which should mean
1111 // it is on top of the one being resumed so hiding it quickly
1112 // is good. Otherwise, we want to do the normal route of allowing
1113 // the resumed activity to be shown so we can decide if the
1114 // previous should actually be hidden depending on whether the
1115 // new one is found to be full-screen or not.
1116 if (prev.finishing) {
1117 mService.mWindowManager.setAppVisibility(prev, false);
1118 if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
1119 + prev + ", waitingVisible="
1120 + (prev != null ? prev.waitingVisible : null)
1121 + ", nowVisible=" + next.nowVisible);
1122 } else {
1123 if (DEBUG_SWITCH) Slog.v(TAG, "Previous already visible but still waiting to hide: "
1124 + prev + ", waitingVisible="
1125 + (prev != null ? prev.waitingVisible : null)
1126 + ", nowVisible=" + next.nowVisible);
1127 }
1128 }
1129 }
1130
1131 // We are starting up the next activity, so tell the window manager
1132 // that the previous one will be hidden soon. This way it can know
1133 // to ignore it when computing the desired screen orientation.
1134 if (prev != null) {
1135 if (prev.finishing) {
1136 if (DEBUG_TRANSITION) Slog.v(TAG,
1137 "Prepare close transition: prev=" + prev);
1138 if (mNoAnimActivities.contains(prev)) {
1139 mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
1140 } else {
1141 mService.mWindowManager.prepareAppTransition(prev.task == next.task
1142 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
1143 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
1144 }
1145 mService.mWindowManager.setAppWillBeHidden(prev);
1146 mService.mWindowManager.setAppVisibility(prev, false);
1147 } else {
1148 if (DEBUG_TRANSITION) Slog.v(TAG,
1149 "Prepare open transition: prev=" + prev);
1150 if (mNoAnimActivities.contains(next)) {
1151 mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
1152 } else {
1153 mService.mWindowManager.prepareAppTransition(prev.task == next.task
1154 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1155 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
1156 }
1157 }
1158 if (false) {
1159 mService.mWindowManager.setAppWillBeHidden(prev);
1160 mService.mWindowManager.setAppVisibility(prev, false);
1161 }
1162 } else if (mHistory.size() > 1) {
1163 if (DEBUG_TRANSITION) Slog.v(TAG,
1164 "Prepare open transition: no previous");
1165 if (mNoAnimActivities.contains(next)) {
1166 mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
1167 } else {
1168 mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
1169 }
1170 }
1171
1172 if (next.app != null && next.app.thread != null) {
1173 if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
1174
1175 // This activity is now becoming visible.
1176 mService.mWindowManager.setAppVisibility(next, true);
1177
1178 ActivityRecord lastResumedActivity = mResumedActivity;
1179 ActivityState lastState = next.state;
1180
1181 mService.updateCpuStats();
1182
1183 next.state = ActivityState.RESUMED;
1184 mResumedActivity = next;
1185 next.task.touchActiveTime();
1186 mService.updateLruProcessLocked(next.app, true, true);
1187 updateLRUListLocked(next);
1188
1189 // Have the window manager re-evaluate the orientation of
1190 // the screen based on the new activity order.
1191 boolean updated = false;
1192 if (mMainStack) {
1193 synchronized (mService) {
1194 Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
1195 mService.mConfiguration,
1196 next.mayFreezeScreenLocked(next.app) ? next : null);
1197 if (config != null) {
1198 next.frozenBeforeDestroy = true;
1199 }
1200 updated = mService.updateConfigurationLocked(config, next);
1201 }
1202 }
1203 if (!updated) {
1204 // The configuration update wasn't able to keep the existing
1205 // instance of the activity, and instead started a new one.
1206 // We should be all done, but let's just make sure our activity
1207 // is still at the top and schedule another run if something
1208 // weird happened.
1209 ActivityRecord nextNext = topRunningActivityLocked(null);
1210 if (DEBUG_SWITCH) Slog.i(TAG,
1211 "Activity config changed during resume: " + next
1212 + ", new next: " + nextNext);
1213 if (nextNext != next) {
1214 // Do over!
1215 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
1216 }
1217 if (mMainStack) {
1218 mService.setFocusedActivityLocked(next);
1219 }
1220 ensureActivitiesVisibleLocked(null, 0);
1221 mService.mWindowManager.executeAppTransition();
1222 mNoAnimActivities.clear();
1223 return true;
1224 }
1225
1226 try {
1227 // Deliver all pending results.
1228 ArrayList a = next.results;
1229 if (a != null) {
1230 final int N = a.size();
1231 if (!next.finishing && N > 0) {
1232 if (DEBUG_RESULTS) Slog.v(
1233 TAG, "Delivering results to " + next
1234 + ": " + a);
1235 next.app.thread.scheduleSendResult(next, a);
1236 }
1237 }
1238
1239 if (next.newIntents != null) {
1240 next.app.thread.scheduleNewIntent(next.newIntents, next);
1241 }
1242
1243 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
1244 System.identityHashCode(next),
1245 next.task.taskId, next.shortComponentName);
1246
1247 next.app.thread.scheduleResumeActivity(next,
1248 mService.isNextTransitionForward());
1249
1250 pauseIfSleepingLocked();
1251
1252 } catch (Exception e) {
1253 // Whoops, need to restart this activity!
1254 next.state = lastState;
1255 mResumedActivity = lastResumedActivity;
1256 Slog.i(TAG, "Restarting because process died: " + next);
1257 if (!next.hasBeenLaunched) {
1258 next.hasBeenLaunched = true;
1259 } else {
1260 if (SHOW_APP_STARTING_PREVIEW && mMainStack) {
1261 mService.mWindowManager.setAppStartingWindow(
1262 next, next.packageName, next.theme,
1263 next.nonLocalizedLabel,
1264 next.labelRes, next.icon, null, true);
1265 }
1266 }
1267 startSpecificActivityLocked(next, true, false);
1268 return true;
1269 }
1270
1271 // From this point on, if something goes wrong there is no way
1272 // to recover the activity.
1273 try {
1274 next.visible = true;
1275 completeResumeLocked(next);
1276 } catch (Exception e) {
1277 // If any exception gets thrown, toss away this
1278 // activity and try the next one.
1279 Slog.w(TAG, "Exception thrown during resume of " + next, e);
1280 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
1281 "resume-exception");
1282 return true;
1283 }
1284
1285 // Didn't need to use the icicle, and it is now out of date.
1286 next.icicle = null;
1287 next.haveState = false;
1288 next.stopped = false;
1289
1290 } else {
1291 // Whoops, need to restart this activity!
1292 if (!next.hasBeenLaunched) {
1293 next.hasBeenLaunched = true;
1294 } else {
1295 if (SHOW_APP_STARTING_PREVIEW) {
1296 mService.mWindowManager.setAppStartingWindow(
1297 next, next.packageName, next.theme,
1298 next.nonLocalizedLabel,
1299 next.labelRes, next.icon, null, true);
1300 }
1301 if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
1302 }
1303 startSpecificActivityLocked(next, true, true);
1304 }
1305
1306 return true;
1307 }
1308
1309 private final void startActivityLocked(ActivityRecord r, boolean newTask,
1310 boolean doResume) {
1311 final int NH = mHistory.size();
1312
1313 int addPos = -1;
1314
1315 if (!newTask) {
1316 // If starting in an existing task, find where that is...
1317 ActivityRecord next = null;
1318 boolean startIt = true;
1319 for (int i = NH-1; i >= 0; i--) {
1320 ActivityRecord p = (ActivityRecord)mHistory.get(i);
1321 if (p.finishing) {
1322 continue;
1323 }
1324 if (p.task == r.task) {
1325 // Here it is! Now, if this is not yet visible to the
1326 // user, then just add it without starting; it will
1327 // get started when the user navigates back to it.
1328 addPos = i+1;
1329 if (!startIt) {
1330 mHistory.add(addPos, r);
1331 r.inHistory = true;
1332 r.task.numActivities++;
1333 mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
1334 r.info.screenOrientation, r.fullscreen);
1335 if (VALIDATE_TOKENS) {
1336 mService.mWindowManager.validateAppTokens(mHistory);
1337 }
1338 return;
1339 }
1340 break;
1341 }
1342 if (p.fullscreen) {
1343 startIt = false;
1344 }
1345 next = p;
1346 }
1347 }
1348
1349 // Place a new activity at top of stack, so it is next to interact
1350 // with the user.
1351 if (addPos < 0) {
1352 addPos = mHistory.size();
1353 }
1354
1355 // If we are not placing the new activity frontmost, we do not want
1356 // to deliver the onUserLeaving callback to the actual frontmost
1357 // activity
1358 if (addPos < NH) {
1359 mUserLeaving = false;
1360 if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() behind front, mUserLeaving=false");
1361 }
1362
1363 // Slot the activity into the history stack and proceed
1364 mHistory.add(addPos, r);
1365 r.inHistory = true;
1366 r.frontOfTask = newTask;
1367 r.task.numActivities++;
1368 if (NH > 0) {
1369 // We want to show the starting preview window if we are
1370 // switching to a new task, or the next activity's process is
1371 // not currently running.
1372 boolean showStartingIcon = newTask;
1373 ProcessRecord proc = r.app;
1374 if (proc == null) {
1375 proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
1376 }
1377 if (proc == null || proc.thread == null) {
1378 showStartingIcon = true;
1379 }
1380 if (DEBUG_TRANSITION) Slog.v(TAG,
1381 "Prepare open transition: starting " + r);
1382 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
1383 mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
1384 mNoAnimActivities.add(r);
1385 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
1386 mService.mWindowManager.prepareAppTransition(
1387 WindowManagerPolicy.TRANSIT_TASK_OPEN);
1388 mNoAnimActivities.remove(r);
1389 } else {
1390 mService.mWindowManager.prepareAppTransition(newTask
1391 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
1392 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
1393 mNoAnimActivities.remove(r);
1394 }
1395 mService.mWindowManager.addAppToken(
1396 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
1397 boolean doShow = true;
1398 if (newTask) {
1399 // Even though this activity is starting fresh, we still need
1400 // to reset it to make sure we apply affinities to move any
1401 // existing activities from other tasks in to it.
1402 // If the caller has requested that the target task be
1403 // reset, then do so.
1404 if ((r.intent.getFlags()
1405 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
1406 resetTaskIfNeededLocked(r, r);
1407 doShow = topRunningNonDelayedActivityLocked(null) == r;
1408 }
1409 }
1410 if (SHOW_APP_STARTING_PREVIEW && doShow) {
1411 // Figure out if we are transitioning from another activity that is
1412 // "has the same starting icon" as the next one. This allows the
1413 // window manager to keep the previous window it had previously
1414 // created, if it still had one.
1415 ActivityRecord prev = mResumedActivity;
1416 if (prev != null) {
1417 // We don't want to reuse the previous starting preview if:
1418 // (1) The current activity is in a different task.
1419 if (prev.task != r.task) prev = null;
1420 // (2) The current activity is already displayed.
1421 else if (prev.nowVisible) prev = null;
1422 }
1423 mService.mWindowManager.setAppStartingWindow(
1424 r, r.packageName, r.theme, r.nonLocalizedLabel,
1425 r.labelRes, r.icon, prev, showStartingIcon);
1426 }
1427 } else {
1428 // If this is the first activity, don't do any fancy animations,
1429 // because there is nothing for it to animate on top of.
1430 mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
1431 r.info.screenOrientation, r.fullscreen);
1432 }
1433 if (VALIDATE_TOKENS) {
1434 mService.mWindowManager.validateAppTokens(mHistory);
1435 }
1436
1437 if (doResume) {
1438 resumeTopActivityLocked(null);
1439 }
1440 }
1441
1442 /**
1443 * Perform a reset of the given task, if needed as part of launching it.
1444 * Returns the new HistoryRecord at the top of the task.
1445 */
1446 private final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop,
1447 ActivityRecord newActivity) {
1448 boolean forceReset = (newActivity.info.flags
1449 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
1450 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
1451 if ((newActivity.info.flags
1452 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
1453 forceReset = true;
1454 }
1455 }
1456
1457 final TaskRecord task = taskTop.task;
1458
1459 // We are going to move through the history list so that we can look
1460 // at each activity 'target' with 'below' either the interesting
1461 // activity immediately below it in the stack or null.
1462 ActivityRecord target = null;
1463 int targetI = 0;
1464 int taskTopI = -1;
1465 int replyChainEnd = -1;
1466 int lastReparentPos = -1;
1467 for (int i=mHistory.size()-1; i>=-1; i--) {
1468 ActivityRecord below = i >= 0 ? (ActivityRecord)mHistory.get(i) : null;
1469
1470 if (below != null && below.finishing) {
1471 continue;
1472 }
1473 if (target == null) {
1474 target = below;
1475 targetI = i;
1476 // If we were in the middle of a reply chain before this
1477 // task, it doesn't appear like the root of the chain wants
1478 // anything interesting, so drop it.
1479 replyChainEnd = -1;
1480 continue;
1481 }
1482
1483 final int flags = target.info.flags;
1484
1485 final boolean finishOnTaskLaunch =
1486 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
1487 final boolean allowTaskReparenting =
1488 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
1489
1490 if (target.task == task) {
1491 // We are inside of the task being reset... we'll either
1492 // finish this activity, push it out for another task,
1493 // or leave it as-is. We only do this
1494 // for activities that are not the root of the task (since
1495 // if we finish the root, we may no longer have the task!).
1496 if (taskTopI < 0) {
1497 taskTopI = targetI;
1498 }
1499 if (below != null && below.task == task) {
1500 final boolean clearWhenTaskReset =
1501 (target.intent.getFlags()
1502 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
1503 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
1504 // If this activity is sending a reply to a previous
1505 // activity, we can't do anything with it now until
1506 // we reach the start of the reply chain.
1507 // XXX note that we are assuming the result is always
1508 // to the previous activity, which is almost always
1509 // the case but we really shouldn't count on.
1510 if (replyChainEnd < 0) {
1511 replyChainEnd = targetI;
1512 }
1513 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
1514 && target.taskAffinity != null
1515 && !target.taskAffinity.equals(task.affinity)) {
1516 // If this activity has an affinity for another
1517 // task, then we need to move it out of here. We will
1518 // move it as far out of the way as possible, to the
1519 // bottom of the activity stack. This also keeps it
1520 // correctly ordered with any activities we previously
1521 // moved.
1522 ActivityRecord p = (ActivityRecord)mHistory.get(0);
1523 if (target.taskAffinity != null
1524 && target.taskAffinity.equals(p.task.affinity)) {
1525 // If the activity currently at the bottom has the
1526 // same task affinity as the one we are moving,
1527 // then merge it into the same task.
1528 target.task = p.task;
1529 if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
1530 + " out to bottom task " + p.task);
1531 } else {
1532 mService.mCurTask++;
1533 if (mService.mCurTask <= 0) {
1534 mService.mCurTask = 1;
1535 }
1536 target.task = new TaskRecord(mService.mCurTask, target.info, null,
1537 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
1538 target.task.affinityIntent = target.intent;
1539 if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
1540 + " out to new task " + target.task);
1541 }
1542 mService.mWindowManager.setAppGroupId(target, task.taskId);
1543 if (replyChainEnd < 0) {
1544 replyChainEnd = targetI;
1545 }
1546 int dstPos = 0;
1547 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
1548 p = (ActivityRecord)mHistory.get(srcPos);
1549 if (p.finishing) {
1550 continue;
1551 }
1552 if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
1553 + " out to target's task " + target.task);
1554 task.numActivities--;
1555 p.task = target.task;
1556 target.task.numActivities++;
1557 mHistory.remove(srcPos);
1558 mHistory.add(dstPos, p);
1559 mService.mWindowManager.moveAppToken(dstPos, p);
1560 mService.mWindowManager.setAppGroupId(p, p.task.taskId);
1561 dstPos++;
1562 if (VALIDATE_TOKENS) {
1563 mService.mWindowManager.validateAppTokens(mHistory);
1564 }
1565 i++;
1566 }
1567 if (taskTop == p) {
1568 taskTop = below;
1569 }
1570 if (taskTopI == replyChainEnd) {
1571 taskTopI = -1;
1572 }
1573 replyChainEnd = -1;
1574 if (mMainStack) {
1575 mService.addRecentTaskLocked(target.task);
1576 }
1577 } else if (forceReset || finishOnTaskLaunch
1578 || clearWhenTaskReset) {
1579 // If the activity should just be removed -- either
1580 // because it asks for it, or the task should be
1581 // cleared -- then finish it and anything that is
1582 // part of its reply chain.
1583 if (clearWhenTaskReset) {
1584 // In this case, we want to finish this activity
1585 // and everything above it, so be sneaky and pretend
1586 // like these are all in the reply chain.
1587 replyChainEnd = targetI+1;
1588 while (replyChainEnd < mHistory.size() &&
1589 ((ActivityRecord)mHistory.get(
1590 replyChainEnd)).task == task) {
1591 replyChainEnd++;
1592 }
1593 replyChainEnd--;
1594 } else if (replyChainEnd < 0) {
1595 replyChainEnd = targetI;
1596 }
1597 ActivityRecord p = null;
1598 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
1599 p = (ActivityRecord)mHistory.get(srcPos);
1600 if (p.finishing) {
1601 continue;
1602 }
1603 if (finishActivityLocked(p, srcPos,
1604 Activity.RESULT_CANCELED, null, "reset")) {
1605 replyChainEnd--;
1606 srcPos--;
1607 }
1608 }
1609 if (taskTop == p) {
1610 taskTop = below;
1611 }
1612 if (taskTopI == replyChainEnd) {
1613 taskTopI = -1;
1614 }
1615 replyChainEnd = -1;
1616 } else {
1617 // If we were in the middle of a chain, well the
1618 // activity that started it all doesn't want anything
1619 // special, so leave it all as-is.
1620 replyChainEnd = -1;
1621 }
1622 } else {
1623 // Reached the bottom of the task -- any reply chain
1624 // should be left as-is.
1625 replyChainEnd = -1;
1626 }
1627
1628 } else if (target.resultTo != null) {
1629 // If this activity is sending a reply to a previous
1630 // activity, we can't do anything with it now until
1631 // we reach the start of the reply chain.
1632 // XXX note that we are assuming the result is always
1633 // to the previous activity, which is almost always
1634 // the case but we really shouldn't count on.
1635 if (replyChainEnd < 0) {
1636 replyChainEnd = targetI;
1637 }
1638
1639 } else if (taskTopI >= 0 && allowTaskReparenting
1640 && task.affinity != null
1641 && task.affinity.equals(target.taskAffinity)) {
1642 // We are inside of another task... if this activity has
1643 // an affinity for our task, then either remove it if we are
1644 // clearing or move it over to our task. Note that
1645 // we currently punt on the case where we are resetting a
1646 // task that is not at the top but who has activities above
1647 // with an affinity to it... this is really not a normal
1648 // case, and we will need to later pull that task to the front
1649 // and usually at that point we will do the reset and pick
1650 // up those remaining activities. (This only happens if
1651 // someone starts an activity in a new task from an activity
1652 // in a task that is not currently on top.)
1653 if (forceReset || finishOnTaskLaunch) {
1654 if (replyChainEnd < 0) {
1655 replyChainEnd = targetI;
1656 }
1657 ActivityRecord p = null;
1658 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
1659 p = (ActivityRecord)mHistory.get(srcPos);
1660 if (p.finishing) {
1661 continue;
1662 }
1663 if (finishActivityLocked(p, srcPos,
1664 Activity.RESULT_CANCELED, null, "reset")) {
1665 taskTopI--;
1666 lastReparentPos--;
1667 replyChainEnd--;
1668 srcPos--;
1669 }
1670 }
1671 replyChainEnd = -1;
1672 } else {
1673 if (replyChainEnd < 0) {
1674 replyChainEnd = targetI;
1675 }
1676 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
1677 ActivityRecord p = (ActivityRecord)mHistory.get(srcPos);
1678 if (p.finishing) {
1679 continue;
1680 }
1681 if (lastReparentPos < 0) {
1682 lastReparentPos = taskTopI;
1683 taskTop = p;
1684 } else {
1685 lastReparentPos--;
1686 }
1687 mHistory.remove(srcPos);
1688 p.task.numActivities--;
1689 p.task = task;
1690 mHistory.add(lastReparentPos, p);
1691 if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
1692 + " in to resetting task " + task);
1693 task.numActivities++;
1694 mService.mWindowManager.moveAppToken(lastReparentPos, p);
1695 mService.mWindowManager.setAppGroupId(p, p.task.taskId);
1696 if (VALIDATE_TOKENS) {
1697 mService.mWindowManager.validateAppTokens(mHistory);
1698 }
1699 }
1700 replyChainEnd = -1;
1701
1702 // Now we've moved it in to place... but what if this is
1703 // a singleTop activity and we have put it on top of another
1704 // instance of the same activity? Then we drop the instance
1705 // below so it remains singleTop.
1706 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
1707 for (int j=lastReparentPos-1; j>=0; j--) {
1708 ActivityRecord p = (ActivityRecord)mHistory.get(j);
1709 if (p.finishing) {
1710 continue;
1711 }
1712 if (p.intent.getComponent().equals(target.intent.getComponent())) {
1713 if (finishActivityLocked(p, j,
1714 Activity.RESULT_CANCELED, null, "replace")) {
1715 taskTopI--;
1716 lastReparentPos--;
1717 }
1718 }
1719 }
1720 }
1721 }
1722 }
1723
1724 target = below;
1725 targetI = i;
1726 }
1727
1728 return taskTop;
1729 }
1730
1731 /**
1732 * Perform clear operation as requested by
1733 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
1734 * stack to the given task, then look for
1735 * an instance of that activity in the stack and, if found, finish all
1736 * activities on top of it and return the instance.
1737 *
1738 * @param newR Description of the new activity being started.
1739 * @return Returns the old activity that should be continue to be used,
1740 * or null if none was found.
1741 */
1742 private final ActivityRecord performClearTaskLocked(int taskId,
1743 ActivityRecord newR, int launchFlags, boolean doClear) {
1744 int i = mHistory.size();
1745
1746 // First find the requested task.
1747 while (i > 0) {
1748 i--;
1749 ActivityRecord r = (ActivityRecord)mHistory.get(i);
1750 if (r.task.taskId == taskId) {
1751 i++;
1752 break;
1753 }
1754 }
1755
1756 // Now clear it.
1757 while (i > 0) {
1758 i--;
1759 ActivityRecord r = (ActivityRecord)mHistory.get(i);
1760 if (r.finishing) {
1761 continue;
1762 }
1763 if (r.task.taskId != taskId) {
1764 return null;
1765 }
1766 if (r.realActivity.equals(newR.realActivity)) {
1767 // Here it is! Now finish everything in front...
1768 ActivityRecord ret = r;
1769 if (doClear) {
1770 while (i < (mHistory.size()-1)) {
1771 i++;
1772 r = (ActivityRecord)mHistory.get(i);
1773 if (r.finishing) {
1774 continue;
1775 }
1776 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
1777 null, "clear")) {
1778 i--;
1779 }
1780 }
1781 }
1782
1783 // Finally, if this is a normal launch mode (that is, not
1784 // expecting onNewIntent()), then we will finish the current
1785 // instance of the activity so a new fresh one can be started.
1786 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
1787 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
1788 if (!ret.finishing) {
1789 int index = indexOfTokenLocked(ret);
1790 if (index >= 0) {
1791 finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
1792 null, "clear");
1793 }
1794 return null;
1795 }
1796 }
1797
1798 return ret;
1799 }
1800 }
1801
1802 return null;
1803 }
1804
1805 /**
1806 * Find the activity in the history stack within the given task. Returns
1807 * the index within the history at which it's found, or < 0 if not found.
1808 */
1809 private final int findActivityInHistoryLocked(ActivityRecord r, int task) {
1810 int i = mHistory.size();
1811 while (i > 0) {
1812 i--;
1813 ActivityRecord candidate = (ActivityRecord)mHistory.get(i);
1814 if (candidate.task.taskId != task) {
1815 break;
1816 }
1817 if (candidate.realActivity.equals(r.realActivity)) {
1818 return i;
1819 }
1820 }
1821
1822 return -1;
1823 }
1824
1825 /**
1826 * Reorder the history stack so that the activity at the given index is
1827 * brought to the front.
1828 */
1829 private final ActivityRecord moveActivityToFrontLocked(int where) {
1830 ActivityRecord newTop = (ActivityRecord)mHistory.remove(where);
1831 int top = mHistory.size();
1832 ActivityRecord oldTop = (ActivityRecord)mHistory.get(top-1);
1833 mHistory.add(top, newTop);
1834 oldTop.frontOfTask = false;
1835 newTop.frontOfTask = true;
1836 return newTop;
1837 }
1838
1839 final int startActivityLocked(IApplicationThread caller,
1840 Intent intent, String resolvedType,
1841 Uri[] grantedUriPermissions,
1842 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
1843 String resultWho, int requestCode,
1844 int callingPid, int callingUid, boolean onlyIfNeeded,
1845 boolean componentSpecified) {
1846 Slog.i(TAG, "Starting activity: " + intent);
1847
1848 ActivityRecord sourceRecord = null;
1849 ActivityRecord resultRecord = null;
1850 if (resultTo != null) {
1851 int index = indexOfTokenLocked(resultTo);
1852 if (DEBUG_RESULTS) Slog.v(
1853 TAG, "Sending result to " + resultTo + " (index " + index + ")");
1854 if (index >= 0) {
1855 sourceRecord = (ActivityRecord)mHistory.get(index);
1856 if (requestCode >= 0 && !sourceRecord.finishing) {
1857 resultRecord = sourceRecord;
1858 }
1859 }
1860 }
1861
1862 int launchFlags = intent.getFlags();
1863
1864 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
1865 && sourceRecord != null) {
1866 // Transfer the result target from the source activity to the new
1867 // one being started, including any failures.
1868 if (requestCode >= 0) {
1869 return START_FORWARD_AND_REQUEST_CONFLICT;
1870 }
1871 resultRecord = sourceRecord.resultTo;
1872 resultWho = sourceRecord.resultWho;
1873 requestCode = sourceRecord.requestCode;
1874 sourceRecord.resultTo = null;
1875 if (resultRecord != null) {
1876 resultRecord.removeResultsLocked(
1877 sourceRecord, resultWho, requestCode);
1878 }
1879 }
1880
1881 int err = START_SUCCESS;
1882
1883 if (intent.getComponent() == null) {
1884 // We couldn't find a class that can handle the given Intent.
1885 // That's the end of that!
1886 err = START_INTENT_NOT_RESOLVED;
1887 }
1888
1889 if (err == START_SUCCESS && aInfo == null) {
1890 // We couldn't find the specific class specified in the Intent.
1891 // Also the end of the line.
1892 err = START_CLASS_NOT_FOUND;
1893 }
1894
1895 ProcessRecord callerApp = null;
1896 if (err == START_SUCCESS && caller != null) {
1897 callerApp = mService.getRecordForAppLocked(caller);
1898 if (callerApp != null) {
1899 callingPid = callerApp.pid;
1900 callingUid = callerApp.info.uid;
1901 } else {
1902 Slog.w(TAG, "Unable to find app for caller " + caller
1903 + " (pid=" + callingPid + ") when starting: "
1904 + intent.toString());
1905 err = START_PERMISSION_DENIED;
1906 }
1907 }
1908
1909 if (err != START_SUCCESS) {
1910 if (resultRecord != null) {
1911 sendActivityResultLocked(-1,
1912 resultRecord, resultWho, requestCode,
1913 Activity.RESULT_CANCELED, null);
1914 }
1915 return err;
1916 }
1917
1918 final int perm = mService.checkComponentPermission(aInfo.permission, callingPid,
1919 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
1920 if (perm != PackageManager.PERMISSION_GRANTED) {
1921 if (resultRecord != null) {
1922 sendActivityResultLocked(-1,
1923 resultRecord, resultWho, requestCode,
1924 Activity.RESULT_CANCELED, null);
1925 }
1926 String msg = "Permission Denial: starting " + intent.toString()
1927 + " from " + callerApp + " (pid=" + callingPid
1928 + ", uid=" + callingUid + ")"
1929 + " requires " + aInfo.permission;
1930 Slog.w(TAG, msg);
1931 throw new SecurityException(msg);
1932 }
1933
1934 if (mMainStack) {
1935 if (mService.mController != null) {
1936 boolean abort = false;
1937 try {
1938 // The Intent we give to the watcher has the extra data
1939 // stripped off, since it can contain private information.
1940 Intent watchIntent = intent.cloneFilter();
1941 abort = !mService.mController.activityStarting(watchIntent,
1942 aInfo.applicationInfo.packageName);
1943 } catch (RemoteException e) {
1944 mService.mController = null;
1945 }
1946
1947 if (abort) {
1948 if (resultRecord != null) {
1949 sendActivityResultLocked(-1,
1950 resultRecord, resultWho, requestCode,
1951 Activity.RESULT_CANCELED, null);
1952 }
1953 // We pretend to the caller that it was really started, but
1954 // they will just get a cancel result.
1955 return START_SUCCESS;
1956 }
1957 }
1958 }
1959
1960 ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
1961 intent, resolvedType, aInfo, mService.mConfiguration,
1962 resultRecord, resultWho, requestCode, componentSpecified);
1963
1964 if (mMainStack) {
1965 if (mResumedActivity == null
1966 || mResumedActivity.info.applicationInfo.uid != callingUid) {
1967 if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
1968 PendingActivityLaunch pal = new PendingActivityLaunch();
1969 pal.r = r;
1970 pal.sourceRecord = sourceRecord;
1971 pal.grantedUriPermissions = grantedUriPermissions;
1972 pal.grantedMode = grantedMode;
1973 pal.onlyIfNeeded = onlyIfNeeded;
1974 mService.mPendingActivityLaunches.add(pal);
1975 return START_SWITCHES_CANCELED;
1976 }
1977 }
1978
1979 if (mService.mDidAppSwitch) {
1980 // This is the second allowed switch since we stopped switches,
1981 // so now just generally allow switches. Use case: user presses
1982 // home (switches disabled, switch to home, mDidAppSwitch now true);
1983 // user taps a home icon (coming from home so allowed, we hit here
1984 // and now allow anyone to switch again).
1985 mService.mAppSwitchesAllowedTime = 0;
1986 } else {
1987 mService.mDidAppSwitch = true;
1988 }
1989
1990 mService.doPendingActivityLaunchesLocked(false);
1991 }
1992
1993 return startActivityUncheckedLocked(r, sourceRecord,
1994 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
1995 }
1996
1997 final int startActivityUncheckedLocked(ActivityRecord r,
1998 ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
1999 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
2000 final Intent intent = r.intent;
2001 final int callingUid = r.launchedFromUid;
2002
2003 int launchFlags = intent.getFlags();
2004
2005 // We'll invoke onUserLeaving before onPause only if the launching
2006 // activity did not explicitly state that this is an automated launch.
2007 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
2008 if (DEBUG_USER_LEAVING) Slog.v(TAG,
2009 "startActivity() => mUserLeaving=" + mUserLeaving);
2010
2011 // If the caller has asked not to resume at this point, we make note
2012 // of this in the record so that we can skip it when trying to find
2013 // the top running activity.
2014 if (!doResume) {
2015 r.delayedResume = true;
2016 }
2017
2018 ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
2019 != 0 ? r : null;
2020
2021 // If the onlyIfNeeded flag is set, then we can do this if the activity
2022 // being launched is the same as the one making the call... or, as
2023 // a special case, if we do not know the caller then we count the
2024 // current top activity as the caller.
2025 if (onlyIfNeeded) {
2026 ActivityRecord checkedCaller = sourceRecord;
2027 if (checkedCaller == null) {
2028 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
2029 }
2030 if (!checkedCaller.realActivity.equals(r.realActivity)) {
2031 // Caller is not the same as launcher, so always needed.
2032 onlyIfNeeded = false;
2033 }
2034 }
2035
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002036 if (sourceRecord == null) {
2037 // This activity is not being started from another... in this
2038 // case we -always- start a new task.
2039 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
2040 Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
2041 + intent);
2042 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2043 }
2044 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2045 // The original activity who is starting us is running as a single
2046 // instance... this new activity it is starting must go on its
2047 // own task.
2048 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2049 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
2050 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
2051 // The activity being started is a single instance... it always
2052 // gets launched into its own task.
2053 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2054 }
2055
2056 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
2057 // For whatever reason this activity is being launched into a new
2058 // task... yet the caller has requested a result back. Well, that
2059 // is pretty messed up, so instead immediately send back a cancel
2060 // and let the new task continue launched as normal without a
2061 // dependency on its originator.
2062 Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
2063 sendActivityResultLocked(-1,
2064 r.resultTo, r.resultWho, r.requestCode,
2065 Activity.RESULT_CANCELED, null);
2066 r.resultTo = null;
2067 }
2068
2069 boolean addingToTask = false;
2070 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
2071 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
2072 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
2073 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2074 // If bring to front is requested, and no result is requested, and
2075 // we can find a task that was started with this same
2076 // component, then instead of launching bring that one to the front.
2077 if (r.resultTo == null) {
2078 // See if there is a task to bring to the front. If this is
2079 // a SINGLE_INSTANCE activity, there can be one and only one
2080 // instance of it in the history, and it is always in its own
2081 // unique task, so we do a special search.
2082 ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
2083 ? findTaskLocked(intent, r.info)
2084 : findActivityLocked(intent, r.info);
2085 if (taskTop != null) {
2086 if (taskTop.task.intent == null) {
2087 // This task was started because of movement of
2088 // the activity based on affinity... now that we
2089 // are actually launching it, we can assign the
2090 // base intent.
2091 taskTop.task.setIntent(intent, r.info);
2092 }
2093 // If the target task is not in the front, then we need
2094 // to bring it to the front... except... well, with
2095 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
2096 // to have the same behavior as if a new instance was
2097 // being started, which means not bringing it to the front
2098 // if the caller is not itself in the front.
2099 ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
2100 if (curTop.task != taskTop.task) {
2101 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
2102 boolean callerAtFront = sourceRecord == null
2103 || curTop.task == sourceRecord.task;
2104 if (callerAtFront) {
2105 // We really do want to push this one into the
2106 // user's face, right now.
2107 moveTaskToFrontLocked(taskTop.task, r);
2108 }
2109 }
2110 // If the caller has requested that the target task be
2111 // reset, then do so.
2112 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2113 taskTop = resetTaskIfNeededLocked(taskTop, r);
2114 }
2115 if (onlyIfNeeded) {
2116 // We don't need to start a new activity, and
2117 // the client said not to do anything if that
2118 // is the case, so this is it! And for paranoia, make
2119 // sure we have correctly resumed the top activity.
2120 if (doResume) {
2121 resumeTopActivityLocked(null);
2122 }
2123 return START_RETURN_INTENT_TO_CALLER;
2124 }
2125 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
2126 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
2127 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2128 // In this situation we want to remove all activities
2129 // from the task up to the one being started. In most
2130 // cases this means we are resetting the task to its
2131 // initial state.
2132 ActivityRecord top = performClearTaskLocked(
2133 taskTop.task.taskId, r, launchFlags, true);
2134 if (top != null) {
2135 if (top.frontOfTask) {
2136 // Activity aliases may mean we use different
2137 // intents for the top activity, so make sure
2138 // the task now has the identity of the new
2139 // intent.
2140 top.task.setIntent(r.intent, r.info);
2141 }
2142 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002143 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002144 } else {
2145 // A special case: we need to
2146 // start the activity because it is not currently
2147 // running, and the caller has asked to clear the
2148 // current task to have this activity at the top.
2149 addingToTask = true;
2150 // Now pretend like this activity is being started
2151 // by the top of its task, so it is put in the
2152 // right place.
2153 sourceRecord = taskTop;
2154 }
2155 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
2156 // In this case the top activity on the task is the
2157 // same as the one being launched, so we take that
2158 // as a request to bring the task to the foreground.
2159 // If the top activity in the task is the root
2160 // activity, deliver this new intent to it if it
2161 // desires.
2162 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
2163 && taskTop.realActivity.equals(r.realActivity)) {
2164 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
2165 if (taskTop.frontOfTask) {
2166 taskTop.task.setIntent(r.intent, r.info);
2167 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002168 taskTop.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002169 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
2170 // In this case we are launching the root activity
2171 // of the task, but with a different intent. We
2172 // should start a new instance on top.
2173 addingToTask = true;
2174 sourceRecord = taskTop;
2175 }
2176 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
2177 // In this case an activity is being launched in to an
2178 // existing task, without resetting that task. This
2179 // is typically the situation of launching an activity
2180 // from a notification or shortcut. We want to place
2181 // the new activity on top of the current task.
2182 addingToTask = true;
2183 sourceRecord = taskTop;
2184 } else if (!taskTop.task.rootWasReset) {
2185 // In this case we are launching in to an existing task
2186 // that has not yet been started from its front door.
2187 // The current task has been brought to the front.
2188 // Ideally, we'd probably like to place this new task
2189 // at the bottom of its stack, but that's a little hard
2190 // to do with the current organization of the code so
2191 // for now we'll just drop it.
2192 taskTop.task.setIntent(r.intent, r.info);
2193 }
2194 if (!addingToTask) {
2195 // We didn't do anything... but it was needed (a.k.a., client
2196 // don't use that intent!) And for paranoia, make
2197 // sure we have correctly resumed the top activity.
2198 if (doResume) {
2199 resumeTopActivityLocked(null);
2200 }
2201 return START_TASK_TO_FRONT;
2202 }
2203 }
2204 }
2205 }
2206
2207 //String uri = r.intent.toURI();
2208 //Intent intent2 = new Intent(uri);
2209 //Slog.i(TAG, "Given intent: " + r.intent);
2210 //Slog.i(TAG, "URI is: " + uri);
2211 //Slog.i(TAG, "To intent: " + intent2);
2212
2213 if (r.packageName != null) {
2214 // If the activity being launched is the same as the one currently
2215 // at the top, then we need to check if it should only be launched
2216 // once.
2217 ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
2218 if (top != null && r.resultTo == null) {
2219 if (top.realActivity.equals(r.realActivity)) {
2220 if (top.app != null && top.app.thread != null) {
2221 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
2222 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
2223 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
2224 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
2225 // For paranoia, make sure we have correctly
2226 // resumed the top activity.
2227 if (doResume) {
2228 resumeTopActivityLocked(null);
2229 }
2230 if (onlyIfNeeded) {
2231 // We don't need to start a new activity, and
2232 // the client said not to do anything if that
2233 // is the case, so this is it!
2234 return START_RETURN_INTENT_TO_CALLER;
2235 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002236 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002237 return START_DELIVERED_TO_TOP;
2238 }
2239 }
2240 }
2241 }
2242
2243 } else {
2244 if (r.resultTo != null) {
2245 sendActivityResultLocked(-1,
2246 r.resultTo, r.resultWho, r.requestCode,
2247 Activity.RESULT_CANCELED, null);
2248 }
2249 return START_CLASS_NOT_FOUND;
2250 }
2251
2252 boolean newTask = false;
2253
2254 // Should this be considered a new task?
2255 if (r.resultTo == null && !addingToTask
2256 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
2257 // todo: should do better management of integers.
2258 mService.mCurTask++;
2259 if (mService.mCurTask <= 0) {
2260 mService.mCurTask = 1;
2261 }
2262 r.task = new TaskRecord(mService.mCurTask, r.info, intent,
2263 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
2264 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2265 + " in new task " + r.task);
2266 newTask = true;
2267 if (mMainStack) {
2268 mService.addRecentTaskLocked(r.task);
2269 }
2270
2271 } else if (sourceRecord != null) {
2272 if (!addingToTask &&
2273 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
2274 // In this case, we are adding the activity to an existing
2275 // task, but the caller has asked to clear that task if the
2276 // activity is already running.
2277 ActivityRecord top = performClearTaskLocked(
2278 sourceRecord.task.taskId, r, launchFlags, true);
2279 if (top != null) {
2280 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002281 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002282 // For paranoia, make sure we have correctly
2283 // resumed the top activity.
2284 if (doResume) {
2285 resumeTopActivityLocked(null);
2286 }
2287 return START_DELIVERED_TO_TOP;
2288 }
2289 } else if (!addingToTask &&
2290 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
2291 // In this case, we are launching an activity in our own task
2292 // that may already be running somewhere in the history, and
2293 // we want to shuffle it to the front of the stack if so.
2294 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
2295 if (where >= 0) {
2296 ActivityRecord top = moveActivityToFrontLocked(where);
2297 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002298 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002299 if (doResume) {
2300 resumeTopActivityLocked(null);
2301 }
2302 return START_DELIVERED_TO_TOP;
2303 }
2304 }
2305 // An existing activity is starting this new activity, so we want
2306 // to keep the new one in the same task as the one that is starting
2307 // it.
2308 r.task = sourceRecord.task;
2309 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2310 + " in existing task " + r.task);
2311
2312 } else {
2313 // This not being started from an existing activity, and not part
2314 // of a new task... just put it in the top task, though these days
2315 // this case should never happen.
2316 final int N = mHistory.size();
2317 ActivityRecord prev =
2318 N > 0 ? (ActivityRecord)mHistory.get(N-1) : null;
2319 r.task = prev != null
2320 ? prev.task
2321 : new TaskRecord(mService.mCurTask, r.info, intent,
2322 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
2323 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2324 + " in new guessed " + r.task);
2325 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002326
2327 if (grantedUriPermissions != null && callingUid > 0) {
2328 for (int i=0; i<grantedUriPermissions.length; i++) {
2329 mService.grantUriPermissionLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002330 grantedUriPermissions[i], grantedMode, r.getUriPermissionsLocked());
Dianne Hackborn39792d22010-08-19 18:01:52 -07002331 }
2332 }
2333
2334 mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002335 intent, r.getUriPermissionsLocked());
Dianne Hackborn39792d22010-08-19 18:01:52 -07002336
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002337 if (newTask) {
2338 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
2339 }
2340 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
2341 startActivityLocked(r, newTask, doResume);
2342 return START_SUCCESS;
2343 }
2344
2345 final int startActivityMayWait(IApplicationThread caller,
2346 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
2347 int grantedMode, IBinder resultTo,
2348 String resultWho, int requestCode, boolean onlyIfNeeded,
2349 boolean debug, WaitResult outResult, Configuration config) {
2350 // Refuse possible leaked file descriptors
2351 if (intent != null && intent.hasFileDescriptors()) {
2352 throw new IllegalArgumentException("File descriptors passed in Intent");
2353 }
2354
2355 boolean componentSpecified = intent.getComponent() != null;
2356
2357 // Don't modify the client's object!
2358 intent = new Intent(intent);
2359
2360 // Collect information about the target of the Intent.
2361 ActivityInfo aInfo;
2362 try {
2363 ResolveInfo rInfo =
2364 AppGlobals.getPackageManager().resolveIntent(
2365 intent, resolvedType,
2366 PackageManager.MATCH_DEFAULT_ONLY
2367 | ActivityManagerService.STOCK_PM_FLAGS);
2368 aInfo = rInfo != null ? rInfo.activityInfo : null;
2369 } catch (RemoteException e) {
2370 aInfo = null;
2371 }
2372
2373 if (aInfo != null) {
2374 // Store the found target back into the intent, because now that
2375 // we have it we never want to do this again. For example, if the
2376 // user navigates back to this point in the history, we should
2377 // always restart the exact same activity.
2378 intent.setComponent(new ComponentName(
2379 aInfo.applicationInfo.packageName, aInfo.name));
2380
2381 // Don't debug things in the system process
2382 if (debug) {
2383 if (!aInfo.processName.equals("system")) {
2384 mService.setDebugApp(aInfo.processName, true, false);
2385 }
2386 }
2387 }
2388
2389 synchronized (mService) {
2390 int callingPid;
2391 int callingUid;
2392 if (caller == null) {
2393 callingPid = Binder.getCallingPid();
2394 callingUid = Binder.getCallingUid();
2395 } else {
2396 callingPid = callingUid = -1;
2397 }
2398
2399 mConfigWillChange = config != null
2400 && mService.mConfiguration.diff(config) != 0;
2401 if (DEBUG_CONFIGURATION) Slog.v(TAG,
2402 "Starting activity when config will change = " + mConfigWillChange);
2403
2404 final long origId = Binder.clearCallingIdentity();
2405
2406 if (mMainStack && aInfo != null &&
2407 (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
2408 // This may be a heavy-weight process! Check to see if we already
2409 // have another, different heavy-weight process running.
2410 if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
2411 if (mService.mHeavyWeightProcess != null &&
2412 (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
2413 !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
2414 int realCallingPid = callingPid;
2415 int realCallingUid = callingUid;
2416 if (caller != null) {
2417 ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
2418 if (callerApp != null) {
2419 realCallingPid = callerApp.pid;
2420 realCallingUid = callerApp.info.uid;
2421 } else {
2422 Slog.w(TAG, "Unable to find app for caller " + caller
2423 + " (pid=" + realCallingPid + ") when starting: "
2424 + intent.toString());
2425 return START_PERMISSION_DENIED;
2426 }
2427 }
2428
2429 IIntentSender target = mService.getIntentSenderLocked(
2430 IActivityManager.INTENT_SENDER_ACTIVITY, "android",
2431 realCallingUid, null, null, 0, intent,
2432 resolvedType, PendingIntent.FLAG_CANCEL_CURRENT
2433 | PendingIntent.FLAG_ONE_SHOT);
2434
2435 Intent newIntent = new Intent();
2436 if (requestCode >= 0) {
2437 // Caller is requesting a result.
2438 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
2439 }
2440 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
2441 new IntentSender(target));
2442 if (mService.mHeavyWeightProcess.activities.size() > 0) {
2443 ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
2444 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
2445 hist.packageName);
2446 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
2447 hist.task.taskId);
2448 }
2449 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
2450 aInfo.packageName);
2451 newIntent.setFlags(intent.getFlags());
2452 newIntent.setClassName("android",
2453 HeavyWeightSwitcherActivity.class.getName());
2454 intent = newIntent;
2455 resolvedType = null;
2456 caller = null;
2457 callingUid = Binder.getCallingUid();
2458 callingPid = Binder.getCallingPid();
2459 componentSpecified = true;
2460 try {
2461 ResolveInfo rInfo =
2462 AppGlobals.getPackageManager().resolveIntent(
2463 intent, null,
2464 PackageManager.MATCH_DEFAULT_ONLY
2465 | ActivityManagerService.STOCK_PM_FLAGS);
2466 aInfo = rInfo != null ? rInfo.activityInfo : null;
2467 } catch (RemoteException e) {
2468 aInfo = null;
2469 }
2470 }
2471 }
2472 }
2473
2474 int res = startActivityLocked(caller, intent, resolvedType,
2475 grantedUriPermissions, grantedMode, aInfo,
2476 resultTo, resultWho, requestCode, callingPid, callingUid,
2477 onlyIfNeeded, componentSpecified);
2478
2479 if (mConfigWillChange && mMainStack) {
2480 // If the caller also wants to switch to a new configuration,
2481 // do so now. This allows a clean switch, as we are waiting
2482 // for the current activity to pause (so we will not destroy
2483 // it), and have not yet started the next activity.
2484 mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
2485 "updateConfiguration()");
2486 mConfigWillChange = false;
2487 if (DEBUG_CONFIGURATION) Slog.v(TAG,
2488 "Updating to new configuration after starting activity.");
2489 mService.updateConfigurationLocked(config, null);
2490 }
2491
2492 Binder.restoreCallingIdentity(origId);
2493
2494 if (outResult != null) {
2495 outResult.result = res;
2496 if (res == IActivityManager.START_SUCCESS) {
2497 mWaitingActivityLaunched.add(outResult);
2498 do {
2499 try {
2500 wait();
2501 } catch (InterruptedException e) {
2502 }
2503 } while (!outResult.timeout && outResult.who == null);
2504 } else if (res == IActivityManager.START_TASK_TO_FRONT) {
2505 ActivityRecord r = this.topRunningActivityLocked(null);
2506 if (r.nowVisible) {
2507 outResult.timeout = false;
2508 outResult.who = new ComponentName(r.info.packageName, r.info.name);
2509 outResult.totalTime = 0;
2510 outResult.thisTime = 0;
2511 } else {
2512 outResult.thisTime = SystemClock.uptimeMillis();
2513 mWaitingActivityVisible.add(outResult);
2514 do {
2515 try {
2516 wait();
2517 } catch (InterruptedException e) {
2518 }
2519 } while (!outResult.timeout && outResult.who == null);
2520 }
2521 }
2522 }
2523
2524 return res;
2525 }
2526 }
2527
2528 void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r,
2529 long thisTime, long totalTime) {
2530 for (int i=mWaitingActivityLaunched.size()-1; i>=0; i--) {
2531 WaitResult w = mWaitingActivityLaunched.get(i);
2532 w.timeout = timeout;
2533 if (r != null) {
2534 w.who = new ComponentName(r.info.packageName, r.info.name);
2535 }
2536 w.thisTime = thisTime;
2537 w.totalTime = totalTime;
2538 }
2539 mService.notifyAll();
2540 }
2541
2542 void reportActivityVisibleLocked(ActivityRecord r) {
2543 for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
2544 WaitResult w = mWaitingActivityVisible.get(i);
2545 w.timeout = false;
2546 if (r != null) {
2547 w.who = new ComponentName(r.info.packageName, r.info.name);
2548 }
2549 w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
2550 w.thisTime = w.totalTime;
2551 }
2552 mService.notifyAll();
2553 }
2554
2555 void sendActivityResultLocked(int callingUid, ActivityRecord r,
2556 String resultWho, int requestCode, int resultCode, Intent data) {
2557
2558 if (callingUid > 0) {
2559 mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002560 data, r.getUriPermissionsLocked());
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002561 }
2562
2563 if (DEBUG_RESULTS) Slog.v(TAG, "Send activity result to " + r
2564 + " : who=" + resultWho + " req=" + requestCode
2565 + " res=" + resultCode + " data=" + data);
2566 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
2567 try {
2568 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
2569 list.add(new ResultInfo(resultWho, requestCode,
2570 resultCode, data));
2571 r.app.thread.scheduleSendResult(r, list);
2572 return;
2573 } catch (Exception e) {
2574 Slog.w(TAG, "Exception thrown sending result to " + r, e);
2575 }
2576 }
2577
2578 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
2579 }
2580
2581 private final void stopActivityLocked(ActivityRecord r) {
2582 if (DEBUG_SWITCH) Slog.d(TAG, "Stopping: " + r);
2583 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
2584 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
2585 if (!r.finishing) {
2586 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
2587 "no-history");
2588 }
2589 } else if (r.app != null && r.app.thread != null) {
2590 if (mMainStack) {
2591 if (mService.mFocusedActivity == r) {
2592 mService.setFocusedActivityLocked(topRunningActivityLocked(null));
2593 }
2594 }
2595 r.resumeKeyDispatchingLocked();
2596 try {
2597 r.stopped = false;
2598 r.state = ActivityState.STOPPING;
2599 if (DEBUG_VISBILITY) Slog.v(
2600 TAG, "Stopping visible=" + r.visible + " for " + r);
2601 if (!r.visible) {
2602 mService.mWindowManager.setAppVisibility(r, false);
2603 }
2604 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
2605 } catch (Exception e) {
2606 // Maybe just ignore exceptions here... if the process
2607 // has crashed, our death notification will clean things
2608 // up.
2609 Slog.w(TAG, "Exception thrown during pause", e);
2610 // Just in case, assume it to be stopped.
2611 r.stopped = true;
2612 r.state = ActivityState.STOPPED;
2613 if (r.configDestroy) {
2614 destroyActivityLocked(r, true);
2615 }
2616 }
2617 }
2618 }
2619
2620 final ArrayList<ActivityRecord> processStoppingActivitiesLocked(
2621 boolean remove) {
2622 int N = mStoppingActivities.size();
2623 if (N <= 0) return null;
2624
2625 ArrayList<ActivityRecord> stops = null;
2626
2627 final boolean nowVisible = mResumedActivity != null
2628 && mResumedActivity.nowVisible
2629 && !mResumedActivity.waitingVisible;
2630 for (int i=0; i<N; i++) {
2631 ActivityRecord s = mStoppingActivities.get(i);
2632 if (localLOGV) Slog.v(TAG, "Stopping " + s + ": nowVisible="
2633 + nowVisible + " waitingVisible=" + s.waitingVisible
2634 + " finishing=" + s.finishing);
2635 if (s.waitingVisible && nowVisible) {
2636 mWaitingVisibleActivities.remove(s);
2637 s.waitingVisible = false;
2638 if (s.finishing) {
2639 // If this activity is finishing, it is sitting on top of
2640 // everyone else but we now know it is no longer needed...
2641 // so get rid of it. Otherwise, we need to go through the
2642 // normal flow and hide it once we determine that it is
2643 // hidden by the activities in front of it.
2644 if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
2645 mService.mWindowManager.setAppVisibility(s, false);
2646 }
2647 }
2648 if (!s.waitingVisible && remove) {
2649 if (localLOGV) Slog.v(TAG, "Ready to stop: " + s);
2650 if (stops == null) {
2651 stops = new ArrayList<ActivityRecord>();
2652 }
2653 stops.add(s);
2654 mStoppingActivities.remove(i);
2655 N--;
2656 i--;
2657 }
2658 }
2659
2660 return stops;
2661 }
2662
2663 final void activityIdleInternal(IBinder token, boolean fromTimeout,
2664 Configuration config) {
2665 if (localLOGV) Slog.v(TAG, "Activity idle: " + token);
2666
2667 ArrayList<ActivityRecord> stops = null;
2668 ArrayList<ActivityRecord> finishes = null;
2669 ArrayList<ActivityRecord> thumbnails = null;
2670 int NS = 0;
2671 int NF = 0;
2672 int NT = 0;
2673 IApplicationThread sendThumbnail = null;
2674 boolean booting = false;
2675 boolean enableScreen = false;
2676
2677 synchronized (mService) {
2678 if (token != null) {
2679 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
2680 }
2681
2682 // Get the activity record.
2683 int index = indexOfTokenLocked(token);
2684 if (index >= 0) {
2685 ActivityRecord r = (ActivityRecord)mHistory.get(index);
2686
2687 if (fromTimeout) {
2688 reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
2689 }
2690
2691 // This is a hack to semi-deal with a race condition
2692 // in the client where it can be constructed with a
2693 // newer configuration from when we asked it to launch.
2694 // We'll update with whatever configuration it now says
2695 // it used to launch.
2696 if (config != null) {
2697 r.configuration = config;
2698 }
2699
2700 // No longer need to keep the device awake.
2701 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
2702 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
2703 mLaunchingActivity.release();
2704 }
2705
2706 // We are now idle. If someone is waiting for a thumbnail from
2707 // us, we can now deliver.
2708 r.idle = true;
2709 mService.scheduleAppGcsLocked();
2710 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
2711 sendThumbnail = r.app.thread;
2712 r.thumbnailNeeded = false;
2713 }
2714
2715 // If this activity is fullscreen, set up to hide those under it.
2716
2717 if (DEBUG_VISBILITY) Slog.v(TAG, "Idle activity for " + r);
2718 ensureActivitiesVisibleLocked(null, 0);
2719
2720 //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
2721 if (mMainStack) {
2722 if (!mService.mBooted && !fromTimeout) {
2723 mService.mBooted = true;
2724 enableScreen = true;
2725 }
2726 }
2727
2728 } else if (fromTimeout) {
2729 reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
2730 }
2731
2732 // Atomically retrieve all of the other things to do.
2733 stops = processStoppingActivitiesLocked(true);
2734 NS = stops != null ? stops.size() : 0;
2735 if ((NF=mFinishingActivities.size()) > 0) {
2736 finishes = new ArrayList<ActivityRecord>(mFinishingActivities);
2737 mFinishingActivities.clear();
2738 }
2739 if ((NT=mService.mCancelledThumbnails.size()) > 0) {
2740 thumbnails = new ArrayList<ActivityRecord>(mService.mCancelledThumbnails);
2741 mService.mCancelledThumbnails.clear();
2742 }
2743
2744 if (mMainStack) {
2745 booting = mService.mBooting;
2746 mService.mBooting = false;
2747 }
2748 }
2749
2750 int i;
2751
2752 // Send thumbnail if requested.
2753 if (sendThumbnail != null) {
2754 try {
2755 sendThumbnail.requestThumbnail(token);
2756 } catch (Exception e) {
2757 Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
2758 mService.sendPendingThumbnail(null, token, null, null, true);
2759 }
2760 }
2761
2762 // Stop any activities that are scheduled to do so but have been
2763 // waiting for the next one to start.
2764 for (i=0; i<NS; i++) {
2765 ActivityRecord r = (ActivityRecord)stops.get(i);
2766 synchronized (mService) {
2767 if (r.finishing) {
2768 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
2769 } else {
2770 stopActivityLocked(r);
2771 }
2772 }
2773 }
2774
2775 // Finish any activities that are scheduled to do so but have been
2776 // waiting for the next one to start.
2777 for (i=0; i<NF; i++) {
2778 ActivityRecord r = (ActivityRecord)finishes.get(i);
2779 synchronized (mService) {
2780 destroyActivityLocked(r, true);
2781 }
2782 }
2783
2784 // Report back to any thumbnail receivers.
2785 for (i=0; i<NT; i++) {
2786 ActivityRecord r = (ActivityRecord)thumbnails.get(i);
2787 mService.sendPendingThumbnail(r, null, null, null, true);
2788 }
2789
2790 if (booting) {
2791 mService.finishBooting();
2792 }
2793
2794 mService.trimApplications();
2795 //dump();
2796 //mWindowManager.dump();
2797
2798 if (enableScreen) {
2799 mService.enableScreenAfterBoot();
2800 }
2801 }
2802
2803 /**
2804 * @return Returns true if the activity is being finished, false if for
2805 * some reason it is being left as-is.
2806 */
2807 final boolean requestFinishActivityLocked(IBinder token, int resultCode,
2808 Intent resultData, String reason) {
2809 if (DEBUG_RESULTS) Slog.v(
2810 TAG, "Finishing activity: token=" + token
2811 + ", result=" + resultCode + ", data=" + resultData);
2812
2813 int index = indexOfTokenLocked(token);
2814 if (index < 0) {
2815 return false;
2816 }
2817 ActivityRecord r = (ActivityRecord)mHistory.get(index);
2818
2819 // Is this the last activity left?
2820 boolean lastActivity = true;
2821 for (int i=mHistory.size()-1; i>=0; i--) {
2822 ActivityRecord p = (ActivityRecord)mHistory.get(i);
2823 if (!p.finishing && p != r) {
2824 lastActivity = false;
2825 break;
2826 }
2827 }
2828
2829 // If this is the last activity, but it is the home activity, then
2830 // just don't finish it.
2831 if (lastActivity) {
2832 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
2833 return false;
2834 }
2835 }
2836
2837 finishActivityLocked(r, index, resultCode, resultData, reason);
2838 return true;
2839 }
2840
2841 /**
2842 * @return Returns true if this activity has been removed from the history
2843 * list, or false if it is still in the list and will be removed later.
2844 */
2845 final boolean finishActivityLocked(ActivityRecord r, int index,
2846 int resultCode, Intent resultData, String reason) {
2847 if (r.finishing) {
2848 Slog.w(TAG, "Duplicate finish request for " + r);
2849 return false;
2850 }
2851
2852 r.finishing = true;
2853 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
2854 System.identityHashCode(r),
2855 r.task.taskId, r.shortComponentName, reason);
2856 r.task.numActivities--;
2857 if (index < (mHistory.size()-1)) {
2858 ActivityRecord next = (ActivityRecord)mHistory.get(index+1);
2859 if (next.task == r.task) {
2860 if (r.frontOfTask) {
2861 // The next activity is now the front of the task.
2862 next.frontOfTask = true;
2863 }
2864 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2865 // If the caller asked that this activity (and all above it)
2866 // be cleared when the task is reset, don't lose that information,
2867 // but propagate it up to the next activity.
2868 next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
2869 }
2870 }
2871 }
2872
2873 r.pauseKeyDispatchingLocked();
2874 if (mMainStack) {
2875 if (mService.mFocusedActivity == r) {
2876 mService.setFocusedActivityLocked(topRunningActivityLocked(null));
2877 }
2878 }
2879
2880 // send the result
2881 ActivityRecord resultTo = r.resultTo;
2882 if (resultTo != null) {
2883 if (DEBUG_RESULTS) Slog.v(TAG, "Adding result to " + resultTo
2884 + " who=" + r.resultWho + " req=" + r.requestCode
2885 + " res=" + resultCode + " data=" + resultData);
2886 if (r.info.applicationInfo.uid > 0) {
2887 mService.grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002888 r.packageName, resultData, r.getUriPermissionsLocked());
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002889 }
2890 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
2891 resultData);
2892 r.resultTo = null;
2893 }
2894 else if (DEBUG_RESULTS) Slog.v(TAG, "No result destination from " + r);
2895
2896 // Make sure this HistoryRecord is not holding on to other resources,
2897 // because clients have remote IPC references to this object so we
2898 // can't assume that will go away and want to avoid circular IPC refs.
2899 r.results = null;
2900 r.pendingResults = null;
2901 r.newIntents = null;
2902 r.icicle = null;
2903
2904 if (mService.mPendingThumbnails.size() > 0) {
2905 // There are clients waiting to receive thumbnails so, in case
2906 // this is an activity that someone is waiting for, add it
2907 // to the pending list so we can correctly update the clients.
2908 mService.mCancelledThumbnails.add(r);
2909 }
2910
2911 if (mResumedActivity == r) {
2912 boolean endTask = index <= 0
2913 || ((ActivityRecord)mHistory.get(index-1)).task != r.task;
2914 if (DEBUG_TRANSITION) Slog.v(TAG,
2915 "Prepare close transition: finishing " + r);
2916 mService.mWindowManager.prepareAppTransition(endTask
2917 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
2918 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
2919
2920 // Tell window manager to prepare for this one to be removed.
2921 mService.mWindowManager.setAppVisibility(r, false);
2922
2923 if (mPausingActivity == null) {
2924 if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
2925 if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
2926 startPausingLocked(false, false);
2927 }
2928
2929 } else if (r.state != ActivityState.PAUSING) {
2930 // If the activity is PAUSING, we will complete the finish once
2931 // it is done pausing; else we can just directly finish it here.
2932 if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
2933 return finishCurrentActivityLocked(r, index,
2934 FINISH_AFTER_PAUSE) == null;
2935 } else {
2936 if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
2937 }
2938
2939 return false;
2940 }
2941
2942 private static final int FINISH_IMMEDIATELY = 0;
2943 private static final int FINISH_AFTER_PAUSE = 1;
2944 private static final int FINISH_AFTER_VISIBLE = 2;
2945
2946 private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
2947 int mode) {
2948 final int index = indexOfTokenLocked(r);
2949 if (index < 0) {
2950 return null;
2951 }
2952
2953 return finishCurrentActivityLocked(r, index, mode);
2954 }
2955
2956 private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
2957 int index, int mode) {
2958 // First things first: if this activity is currently visible,
2959 // and the resumed activity is not yet visible, then hold off on
2960 // finishing until the resumed one becomes visible.
2961 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
2962 if (!mStoppingActivities.contains(r)) {
2963 mStoppingActivities.add(r);
2964 if (mStoppingActivities.size() > 3) {
2965 // If we already have a few activities waiting to stop,
2966 // then give up on things going idle and start clearing
2967 // them out.
2968 Message msg = Message.obtain();
2969 msg.what = IDLE_NOW_MSG;
2970 mHandler.sendMessage(msg);
2971 }
2972 }
2973 r.state = ActivityState.STOPPING;
2974 mService.updateOomAdjLocked();
2975 return r;
2976 }
2977
2978 // make sure the record is cleaned out of other places.
2979 mStoppingActivities.remove(r);
2980 mWaitingVisibleActivities.remove(r);
2981 if (mResumedActivity == r) {
2982 mResumedActivity = null;
2983 }
2984 final ActivityState prevState = r.state;
2985 r.state = ActivityState.FINISHING;
2986
2987 if (mode == FINISH_IMMEDIATELY
2988 || prevState == ActivityState.STOPPED
2989 || prevState == ActivityState.INITIALIZING) {
2990 // If this activity is already stopped, we can just finish
2991 // it right now.
2992 return destroyActivityLocked(r, true) ? null : r;
2993 } else {
2994 // Need to go through the full pause cycle to get this
2995 // activity into the stopped state and then finish it.
2996 if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
2997 mFinishingActivities.add(r);
2998 resumeTopActivityLocked(null);
2999 }
3000 return r;
3001 }
3002
3003 /**
3004 * Perform the common clean-up of an activity record. This is called both
3005 * as part of destroyActivityLocked() (when destroying the client-side
3006 * representation) and cleaning things up as a result of its hosting
3007 * processing going away, in which case there is no remaining client-side
3008 * state to destroy so only the cleanup here is needed.
3009 */
3010 final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices) {
3011 if (mResumedActivity == r) {
3012 mResumedActivity = null;
3013 }
3014 if (mService.mFocusedActivity == r) {
3015 mService.mFocusedActivity = null;
3016 }
3017
3018 r.configDestroy = false;
3019 r.frozenBeforeDestroy = false;
3020
3021 // Make sure this record is no longer in the pending finishes list.
3022 // This could happen, for example, if we are trimming activities
3023 // down to the max limit while they are still waiting to finish.
3024 mFinishingActivities.remove(r);
3025 mWaitingVisibleActivities.remove(r);
3026
3027 // Remove any pending results.
3028 if (r.finishing && r.pendingResults != null) {
3029 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
3030 PendingIntentRecord rec = apr.get();
3031 if (rec != null) {
3032 mService.cancelIntentSenderLocked(rec, false);
3033 }
3034 }
3035 r.pendingResults = null;
3036 }
3037
3038 if (cleanServices) {
3039 cleanUpActivityServicesLocked(r);
3040 }
3041
3042 if (mService.mPendingThumbnails.size() > 0) {
3043 // There are clients waiting to receive thumbnails so, in case
3044 // this is an activity that someone is waiting for, add it
3045 // to the pending list so we can correctly update the clients.
3046 mService.mCancelledThumbnails.add(r);
3047 }
3048
3049 // Get rid of any pending idle timeouts.
3050 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
3051 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
3052 }
3053
3054 private final void removeActivityFromHistoryLocked(ActivityRecord r) {
3055 if (r.state != ActivityState.DESTROYED) {
3056 mHistory.remove(r);
3057 r.inHistory = false;
3058 r.state = ActivityState.DESTROYED;
3059 mService.mWindowManager.removeAppToken(r);
3060 if (VALIDATE_TOKENS) {
3061 mService.mWindowManager.validateAppTokens(mHistory);
3062 }
3063 cleanUpActivityServicesLocked(r);
3064 r.removeUriPermissionsLocked();
3065 }
3066 }
3067
3068 /**
3069 * Perform clean-up of service connections in an activity record.
3070 */
3071 final void cleanUpActivityServicesLocked(ActivityRecord r) {
3072 // Throw away any services that have been bound by this activity.
3073 if (r.connections != null) {
3074 Iterator<ConnectionRecord> it = r.connections.iterator();
3075 while (it.hasNext()) {
3076 ConnectionRecord c = it.next();
3077 mService.removeConnectionLocked(c, null, r);
3078 }
3079 r.connections = null;
3080 }
3081 }
3082
3083 /**
3084 * Destroy the current CLIENT SIDE instance of an activity. This may be
3085 * called both when actually finishing an activity, or when performing
3086 * a configuration switch where we destroy the current client-side object
3087 * but then create a new client-side object for this same HistoryRecord.
3088 */
3089 final boolean destroyActivityLocked(ActivityRecord r,
3090 boolean removeFromApp) {
3091 if (DEBUG_SWITCH) Slog.v(
3092 TAG, "Removing activity: token=" + r
3093 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
3094 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
3095 System.identityHashCode(r),
3096 r.task.taskId, r.shortComponentName);
3097
3098 boolean removedFromHistory = false;
3099
3100 cleanUpActivityLocked(r, false);
3101
3102 final boolean hadApp = r.app != null;
3103
3104 if (hadApp) {
3105 if (removeFromApp) {
3106 int idx = r.app.activities.indexOf(r);
3107 if (idx >= 0) {
3108 r.app.activities.remove(idx);
3109 }
3110 if (mService.mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) {
3111 mService.mHeavyWeightProcess = null;
3112 mService.mHandler.sendEmptyMessage(
3113 ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
3114 }
3115 if (r.persistent) {
3116 mService.decPersistentCountLocked(r.app);
3117 }
3118 if (r.app.activities.size() == 0) {
3119 // No longer have activities, so update location in
3120 // LRU list.
3121 mService.updateLruProcessLocked(r.app, true, false);
3122 }
3123 }
3124
3125 boolean skipDestroy = false;
3126
3127 try {
3128 if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
3129 r.app.thread.scheduleDestroyActivity(r, r.finishing,
3130 r.configChangeFlags);
3131 } catch (Exception e) {
3132 // We can just ignore exceptions here... if the process
3133 // has crashed, our death notification will clean things
3134 // up.
3135 //Slog.w(TAG, "Exception thrown during finish", e);
3136 if (r.finishing) {
3137 removeActivityFromHistoryLocked(r);
3138 removedFromHistory = true;
3139 skipDestroy = true;
3140 }
3141 }
3142
3143 r.app = null;
3144 r.nowVisible = false;
3145
3146 if (r.finishing && !skipDestroy) {
3147 r.state = ActivityState.DESTROYING;
3148 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
3149 msg.obj = r;
3150 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
3151 } else {
3152 r.state = ActivityState.DESTROYED;
3153 }
3154 } else {
3155 // remove this record from the history.
3156 if (r.finishing) {
3157 removeActivityFromHistoryLocked(r);
3158 removedFromHistory = true;
3159 } else {
3160 r.state = ActivityState.DESTROYED;
3161 }
3162 }
3163
3164 r.configChangeFlags = 0;
3165
3166 if (!mLRUActivities.remove(r) && hadApp) {
3167 Slog.w(TAG, "Activity " + r + " being finished, but not in LRU list");
3168 }
3169
3170 return removedFromHistory;
3171 }
3172
3173 final void activityDestroyed(IBinder token) {
3174 synchronized (mService) {
3175 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
3176
3177 int index = indexOfTokenLocked(token);
3178 if (index >= 0) {
3179 ActivityRecord r = (ActivityRecord)mHistory.get(index);
3180 if (r.state == ActivityState.DESTROYING) {
3181 final long origId = Binder.clearCallingIdentity();
3182 removeActivityFromHistoryLocked(r);
3183 Binder.restoreCallingIdentity(origId);
3184 }
3185 }
3186 }
3187 }
3188
3189 private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
3190 int i = list.size();
3191 if (localLOGV) Slog.v(
3192 TAG, "Removing app " + app + " from list " + list
3193 + " with " + i + " entries");
3194 while (i > 0) {
3195 i--;
3196 ActivityRecord r = (ActivityRecord)list.get(i);
3197 if (localLOGV) Slog.v(
3198 TAG, "Record #" + i + " " + r + ": app=" + r.app);
3199 if (r.app == app) {
3200 if (localLOGV) Slog.v(TAG, "Removing this entry!");
3201 list.remove(i);
3202 }
3203 }
3204 }
3205
3206 void removeHistoryRecordsForAppLocked(ProcessRecord app) {
3207 removeHistoryRecordsForAppLocked(mLRUActivities, app);
3208 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
3209 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
3210 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
3211 }
3212
3213 final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason) {
3214 if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
3215
3216 final int task = tr.taskId;
3217 int top = mHistory.size()-1;
3218
3219 if (top < 0 || ((ActivityRecord)mHistory.get(top)).task.taskId == task) {
3220 // nothing to do!
3221 return;
3222 }
3223
3224 ArrayList moved = new ArrayList();
3225
3226 // Applying the affinities may have removed entries from the history,
3227 // so get the size again.
3228 top = mHistory.size()-1;
3229 int pos = top;
3230
3231 // Shift all activities with this task up to the top
3232 // of the stack, keeping them in the same internal order.
3233 while (pos >= 0) {
3234 ActivityRecord r = (ActivityRecord)mHistory.get(pos);
3235 if (localLOGV) Slog.v(
3236 TAG, "At " + pos + " ckp " + r.task + ": " + r);
3237 boolean first = true;
3238 if (r.task.taskId == task) {
3239 if (localLOGV) Slog.v(TAG, "Removing and adding at " + top);
3240 mHistory.remove(pos);
3241 mHistory.add(top, r);
3242 moved.add(0, r);
3243 top--;
3244 if (first && mMainStack) {
3245 mService.addRecentTaskLocked(r.task);
3246 first = false;
3247 }
3248 }
3249 pos--;
3250 }
3251
3252 if (DEBUG_TRANSITION) Slog.v(TAG,
3253 "Prepare to front transition: task=" + tr);
3254 if (reason != null &&
3255 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
3256 mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
3257 ActivityRecord r = topRunningActivityLocked(null);
3258 if (r != null) {
3259 mNoAnimActivities.add(r);
3260 }
3261 } else {
3262 mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
3263 }
3264
3265 mService.mWindowManager.moveAppTokensToTop(moved);
3266 if (VALIDATE_TOKENS) {
3267 mService.mWindowManager.validateAppTokens(mHistory);
3268 }
3269
3270 finishTaskMoveLocked(task);
3271 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
3272 }
3273
3274 private final void finishTaskMoveLocked(int task) {
3275 resumeTopActivityLocked(null);
3276 }
3277
3278 /**
3279 * Worker method for rearranging history stack. Implements the function of moving all
3280 * activities for a specific task (gathering them if disjoint) into a single group at the
3281 * bottom of the stack.
3282 *
3283 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
3284 * to premeptively cancel the move.
3285 *
3286 * @param task The taskId to collect and move to the bottom.
3287 * @return Returns true if the move completed, false if not.
3288 */
3289 final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
3290 Slog.i(TAG, "moveTaskToBack: " + task);
3291
3292 // If we have a watcher, preflight the move before committing to it. First check
3293 // for *other* available tasks, but if none are available, then try again allowing the
3294 // current task to be selected.
3295 if (mMainStack && mService.mController != null) {
3296 ActivityRecord next = topRunningActivityLocked(null, task);
3297 if (next == null) {
3298 next = topRunningActivityLocked(null, 0);
3299 }
3300 if (next != null) {
3301 // ask watcher if this is allowed
3302 boolean moveOK = true;
3303 try {
3304 moveOK = mService.mController.activityResuming(next.packageName);
3305 } catch (RemoteException e) {
3306 mService.mController = null;
3307 }
3308 if (!moveOK) {
3309 return false;
3310 }
3311 }
3312 }
3313
3314 ArrayList moved = new ArrayList();
3315
3316 if (DEBUG_TRANSITION) Slog.v(TAG,
3317 "Prepare to back transition: task=" + task);
3318
3319 final int N = mHistory.size();
3320 int bottom = 0;
3321 int pos = 0;
3322
3323 // Shift all activities with this task down to the bottom
3324 // of the stack, keeping them in the same internal order.
3325 while (pos < N) {
3326 ActivityRecord r = (ActivityRecord)mHistory.get(pos);
3327 if (localLOGV) Slog.v(
3328 TAG, "At " + pos + " ckp " + r.task + ": " + r);
3329 if (r.task.taskId == task) {
3330 if (localLOGV) Slog.v(TAG, "Removing and adding at " + (N-1));
3331 mHistory.remove(pos);
3332 mHistory.add(bottom, r);
3333 moved.add(r);
3334 bottom++;
3335 }
3336 pos++;
3337 }
3338
3339 if (reason != null &&
3340 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
3341 mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
3342 ActivityRecord r = topRunningActivityLocked(null);
3343 if (r != null) {
3344 mNoAnimActivities.add(r);
3345 }
3346 } else {
3347 mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
3348 }
3349 mService.mWindowManager.moveAppTokensToBottom(moved);
3350 if (VALIDATE_TOKENS) {
3351 mService.mWindowManager.validateAppTokens(mHistory);
3352 }
3353
3354 finishTaskMoveLocked(task);
3355 return true;
3356 }
3357
3358 private final void logStartActivity(int tag, ActivityRecord r,
3359 TaskRecord task) {
3360 EventLog.writeEvent(tag,
3361 System.identityHashCode(r), task.taskId,
3362 r.shortComponentName, r.intent.getAction(),
3363 r.intent.getType(), r.intent.getDataString(),
3364 r.intent.getFlags());
3365 }
3366
3367 /**
3368 * Make sure the given activity matches the current configuration. Returns
3369 * false if the activity had to be destroyed. Returns true if the
3370 * configuration is the same, or the activity will remain running as-is
3371 * for whatever reason. Ensures the HistoryRecord is updated with the
3372 * correct configuration and all other bookkeeping is handled.
3373 */
3374 final boolean ensureActivityConfigurationLocked(ActivityRecord r,
3375 int globalChanges) {
3376 if (mConfigWillChange) {
3377 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3378 "Skipping config check (will change): " + r);
3379 return true;
3380 }
3381
3382 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3383 "Ensuring correct configuration: " + r);
3384
3385 // Short circuit: if the two configurations are the exact same
3386 // object (the common case), then there is nothing to do.
3387 Configuration newConfig = mService.mConfiguration;
3388 if (r.configuration == newConfig) {
3389 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3390 "Configuration unchanged in " + r);
3391 return true;
3392 }
3393
3394 // We don't worry about activities that are finishing.
3395 if (r.finishing) {
3396 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3397 "Configuration doesn't matter in finishing " + r);
3398 r.stopFreezingScreenLocked(false);
3399 return true;
3400 }
3401
3402 // Okay we now are going to make this activity have the new config.
3403 // But then we need to figure out how it needs to deal with that.
3404 Configuration oldConfig = r.configuration;
3405 r.configuration = newConfig;
3406
3407 // If the activity isn't currently running, just leave the new
3408 // configuration and it will pick that up next time it starts.
3409 if (r.app == null || r.app.thread == null) {
3410 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3411 "Configuration doesn't matter not running " + r);
3412 r.stopFreezingScreenLocked(false);
3413 return true;
3414 }
3415
3416 // If the activity isn't persistent, there is a chance we will
3417 // need to restart it.
3418 if (!r.persistent) {
3419
3420 // Figure out what has changed between the two configurations.
3421 int changes = oldConfig.diff(newConfig);
3422 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
3423 Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
3424 + Integer.toHexString(changes) + ", handles=0x"
3425 + Integer.toHexString(r.info.configChanges)
3426 + ", newConfig=" + newConfig);
3427 }
3428 if ((changes&(~r.info.configChanges)) != 0) {
3429 // Aha, the activity isn't handling the change, so DIE DIE DIE.
3430 r.configChangeFlags |= changes;
3431 r.startFreezingScreenLocked(r.app, globalChanges);
3432 if (r.app == null || r.app.thread == null) {
3433 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3434 "Switch is destroying non-running " + r);
3435 destroyActivityLocked(r, true);
3436 } else if (r.state == ActivityState.PAUSING) {
3437 // A little annoying: we are waiting for this activity to
3438 // finish pausing. Let's not do anything now, but just
3439 // flag that it needs to be restarted when done pausing.
3440 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3441 "Switch is skipping already pausing " + r);
3442 r.configDestroy = true;
3443 return true;
3444 } else if (r.state == ActivityState.RESUMED) {
3445 // Try to optimize this case: the configuration is changing
3446 // and we need to restart the top, resumed activity.
3447 // Instead of doing the normal handshaking, just say
3448 // "restart!".
3449 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3450 "Switch is restarting resumed " + r);
3451 relaunchActivityLocked(r, r.configChangeFlags, true);
3452 r.configChangeFlags = 0;
3453 } else {
3454 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
3455 "Switch is restarting non-resumed " + r);
3456 relaunchActivityLocked(r, r.configChangeFlags, false);
3457 r.configChangeFlags = 0;
3458 }
3459
3460 // All done... tell the caller we weren't able to keep this
3461 // activity around.
3462 return false;
3463 }
3464 }
3465
3466 // Default case: the activity can handle this new configuration, so
3467 // hand it over. Note that we don't need to give it the new
3468 // configuration, since we always send configuration changes to all
3469 // process when they happen so it can just use whatever configuration
3470 // it last got.
3471 if (r.app != null && r.app.thread != null) {
3472 try {
3473 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
3474 r.app.thread.scheduleActivityConfigurationChanged(r);
3475 } catch (RemoteException e) {
3476 // If process died, whatever.
3477 }
3478 }
3479 r.stopFreezingScreenLocked(false);
3480
3481 return true;
3482 }
3483
3484 private final boolean relaunchActivityLocked(ActivityRecord r,
3485 int changes, boolean andResume) {
3486 List<ResultInfo> results = null;
3487 List<Intent> newIntents = null;
3488 if (andResume) {
3489 results = r.results;
3490 newIntents = r.newIntents;
3491 }
3492 if (DEBUG_SWITCH) Slog.v(TAG, "Relaunching: " + r
3493 + " with results=" + results + " newIntents=" + newIntents
3494 + " andResume=" + andResume);
3495 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
3496 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
3497 r.task.taskId, r.shortComponentName);
3498
3499 r.startFreezingScreenLocked(r.app, 0);
3500
3501 try {
3502 if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
3503 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
3504 changes, !andResume, mService.mConfiguration);
3505 // Note: don't need to call pauseIfSleepingLocked() here, because
3506 // the caller will only pass in 'andResume' if this activity is
3507 // currently resumed, which implies we aren't sleeping.
3508 } catch (RemoteException e) {
3509 return false;
3510 }
3511
3512 if (andResume) {
3513 r.results = null;
3514 r.newIntents = null;
3515 if (mMainStack) {
3516 mService.reportResumedActivityLocked(r);
3517 }
3518 }
3519
3520 return true;
3521 }
3522}