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