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