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