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