blob: f59f0c1a9055b844f7eed1f6cabbb99fbdcb3c57 [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;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -070024import android.app.ActivityManager;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070025import android.app.AppGlobals;
26import android.app.IActivityManager;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -070027import android.app.IThumbnailRetriever;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070028import static android.app.IActivityManager.START_CLASS_NOT_FOUND;
29import static android.app.IActivityManager.START_DELIVERED_TO_TOP;
30import static android.app.IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
31import static android.app.IActivityManager.START_INTENT_NOT_RESOLVED;
32import static android.app.IActivityManager.START_PERMISSION_DENIED;
33import static android.app.IActivityManager.START_RETURN_INTENT_TO_CALLER;
34import static android.app.IActivityManager.START_SUCCESS;
35import static android.app.IActivityManager.START_SWITCHES_CANCELED;
36import static android.app.IActivityManager.START_TASK_TO_FRONT;
37import android.app.IApplicationThread;
38import android.app.PendingIntent;
39import android.app.ResultInfo;
40import android.app.IActivityManager.WaitResult;
41import android.content.ComponentName;
42import android.content.Context;
43import android.content.IIntentSender;
44import android.content.Intent;
45import android.content.IntentSender;
46import android.content.pm.ActivityInfo;
47import android.content.pm.ApplicationInfo;
48import android.content.pm.PackageManager;
49import android.content.pm.ResolveInfo;
50import android.content.res.Configuration;
Dianne Hackborn0aae2d42010-12-07 23:51:29 -080051import android.content.res.Resources;
52import android.graphics.Bitmap;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070053import android.net.Uri;
54import android.os.Binder;
Dianne Hackbornce86ba82011-07-13 19:33:41 -070055import android.os.Bundle;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070056import android.os.Handler;
57import android.os.IBinder;
58import android.os.Message;
Dianne Hackborn62f20ec2011-08-15 17:40:28 -070059import android.os.ParcelFileDescriptor;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070060import android.os.PowerManager;
61import android.os.RemoteException;
62import android.os.SystemClock;
Amith Yamasani742a6712011-05-04 14:49:28 -070063import android.os.UserId;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070064import android.util.EventLog;
65import android.util.Log;
66import android.util.Slog;
67import android.view.WindowManagerPolicy;
68
Dianne Hackborn62f20ec2011-08-15 17:40:28 -070069import java.io.IOException;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070070import java.lang.ref.WeakReference;
71import java.util.ArrayList;
72import java.util.Iterator;
73import java.util.List;
74
75/**
76 * State and management of a single stack of activities.
77 */
Dianne Hackborn0c5001d2011-04-12 18:16:08 -070078final class ActivityStack {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070079 static final String TAG = ActivityManagerService.TAG;
Dianne Hackbornb961cd22011-06-21 12:13:37 -070080 static final boolean localLOGV = ActivityManagerService.localLOGV;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070081 static final boolean DEBUG_SWITCH = ActivityManagerService.DEBUG_SWITCH;
82 static final boolean DEBUG_PAUSE = ActivityManagerService.DEBUG_PAUSE;
83 static final boolean DEBUG_VISBILITY = ActivityManagerService.DEBUG_VISBILITY;
84 static final boolean DEBUG_USER_LEAVING = ActivityManagerService.DEBUG_USER_LEAVING;
85 static final boolean DEBUG_TRANSITION = ActivityManagerService.DEBUG_TRANSITION;
86 static final boolean DEBUG_RESULTS = ActivityManagerService.DEBUG_RESULTS;
87 static final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
88 static final boolean DEBUG_TASKS = ActivityManagerService.DEBUG_TASKS;
89
Dianne Hackbornce86ba82011-07-13 19:33:41 -070090 static final boolean DEBUG_STATES = false;
Dianne Hackborn98cfebc2011-10-18 13:17:33 -070091 static final boolean DEBUG_ADD_REMOVE = false;
92 static final boolean DEBUG_SAVED_STATE = false;
Dianne Hackbornce86ba82011-07-13 19:33:41 -070093
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -070094 static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
95
96 // How long we wait until giving up on the last activity telling us it
97 // is idle.
98 static final int IDLE_TIMEOUT = 10*1000;
99
100 // How long we wait until giving up on the last activity to pause. This
101 // is short because it directly impacts the responsiveness of starting the
102 // next activity.
103 static final int PAUSE_TIMEOUT = 500;
104
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800105 // How long we can hold the sleep wake lock before giving up.
106 static final int SLEEP_TIMEOUT = 5*1000;
107
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700108 // How long we can hold the launch wake lock before giving up.
109 static final int LAUNCH_TIMEOUT = 10*1000;
110
111 // How long we wait until giving up on an activity telling us it has
112 // finished destroying itself.
113 static final int DESTROY_TIMEOUT = 10*1000;
114
115 // How long until we reset a task when the user returns to it. Currently
Dianne Hackborn621e17d2010-11-22 15:59:56 -0800116 // disabled.
117 static final long ACTIVITY_INACTIVE_RESET_TIME = 0;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700118
Dianne Hackborn0dad3642010-09-09 21:25:35 -0700119 // How long between activity launches that we consider safe to not warn
120 // the user about an unexpected activity being launched on top.
121 static final long START_WARN_TIME = 5*1000;
122
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700123 // Set to false to disable the preview that is shown while a new activity
124 // is being started.
125 static final boolean SHOW_APP_STARTING_PREVIEW = true;
126
127 enum ActivityState {
128 INITIALIZING,
129 RESUMED,
130 PAUSING,
131 PAUSED,
132 STOPPING,
133 STOPPED,
134 FINISHING,
135 DESTROYING,
136 DESTROYED
137 }
138
139 final ActivityManagerService mService;
140 final boolean mMainStack;
141
142 final Context mContext;
143
144 /**
145 * The back history of all previous (and possibly still
146 * running) activities. It contains HistoryRecord objects.
147 */
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700148 final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
Dianne Hackbornbe707852011-11-11 14:32:10 -0800149
150 /**
151 * Used for validating app tokens with window manager.
152 */
153 final ArrayList<IBinder> mValidateAppTokens = new ArrayList<IBinder>();
154
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700155 /**
156 * List of running activities, sorted by recent usage.
157 * The first entry in the list is the least recently used.
158 * It contains HistoryRecord objects.
159 */
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700160 final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<ActivityRecord>();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700161
162 /**
163 * List of activities that are waiting for a new activity
164 * to become visible before completing whatever operation they are
165 * supposed to do.
166 */
167 final ArrayList<ActivityRecord> mWaitingVisibleActivities
168 = new ArrayList<ActivityRecord>();
169
170 /**
171 * List of activities that are ready to be stopped, but waiting
172 * for the next activity to settle down before doing so. It contains
173 * HistoryRecord objects.
174 */
175 final ArrayList<ActivityRecord> mStoppingActivities
176 = new ArrayList<ActivityRecord>();
177
178 /**
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800179 * List of activities that are in the process of going to sleep.
180 */
181 final ArrayList<ActivityRecord> mGoingToSleepActivities
182 = new ArrayList<ActivityRecord>();
183
184 /**
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700185 * Animations that for the current transition have requested not to
186 * be considered for the transition animation.
187 */
188 final ArrayList<ActivityRecord> mNoAnimActivities
189 = new ArrayList<ActivityRecord>();
190
191 /**
192 * List of activities that are ready to be finished, but waiting
193 * for the previous activity to settle down before doing so. It contains
194 * HistoryRecord objects.
195 */
196 final ArrayList<ActivityRecord> mFinishingActivities
197 = new ArrayList<ActivityRecord>();
198
199 /**
200 * List of people waiting to find out about the next launched activity.
201 */
202 final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched
203 = new ArrayList<IActivityManager.WaitResult>();
204
205 /**
206 * List of people waiting to find out about the next visible activity.
207 */
208 final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible
209 = new ArrayList<IActivityManager.WaitResult>();
210
211 /**
212 * Set when the system is going to sleep, until we have
213 * successfully paused the current activity and released our wake lock.
214 * At that point the system is allowed to actually sleep.
215 */
216 final PowerManager.WakeLock mGoingToSleep;
217
218 /**
219 * We don't want to allow the device to go to sleep while in the process
220 * of launching an activity. This is primarily to allow alarm intent
221 * receivers to launch an activity and get that to run before the device
222 * goes back to sleep.
223 */
224 final PowerManager.WakeLock mLaunchingActivity;
225
226 /**
227 * When we are in the process of pausing an activity, before starting the
228 * next one, this variable holds the activity that is currently being paused.
229 */
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800230 final ArrayList<ActivityRecord> mPausingActivities = new ArrayList<ActivityRecord>();
231
232 /**
233 * These activities currently have their input paused, as they want for
234 * the next top activity to have its windows visible.
235 */
236 final ArrayList<ActivityRecord> mInputPausedActivities = new ArrayList<ActivityRecord>();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700237
238 /**
239 * This is the last activity that we put into the paused state. This is
240 * used to determine if we need to do an activity transition while sleeping,
241 * when we normally hold the top activity paused.
242 */
243 ActivityRecord mLastPausedActivity = null;
244
245 /**
246 * Current activity that is resumed, or null if there is none.
247 */
248 ActivityRecord mResumedActivity = null;
249
250 /**
Dianne Hackborn0dad3642010-09-09 21:25:35 -0700251 * This is the last activity that has been started. It is only used to
252 * identify when multiple activities are started at once so that the user
253 * can be warned they may not be in the activity they think they are.
254 */
255 ActivityRecord mLastStartedActivity = null;
256
257 /**
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700258 * Set when we know we are going to be calling updateConfiguration()
259 * soon, so want to skip intermediate config checks.
260 */
261 boolean mConfigWillChange;
262
263 /**
264 * Set to indicate whether to issue an onUserLeaving callback when a
265 * newly launched activity is being brought in front of us.
266 */
267 boolean mUserLeaving = false;
268
269 long mInitialStartTime = 0;
270
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800271 /**
272 * Set when we have taken too long waiting to go to sleep.
273 */
274 boolean mSleepTimeout = false;
275
Dianne Hackborn90c52de2011-09-23 12:57:44 -0700276 /**
277 * Dismiss the keyguard after the next activity is displayed?
278 */
279 boolean mDismissKeyguardOnNextActivity = false;
280
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800281 int mThumbnailWidth = -1;
282 int mThumbnailHeight = -1;
283
Amith Yamasani742a6712011-05-04 14:49:28 -0700284 private int mCurrentUser;
285
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800286 static final int SLEEP_TIMEOUT_MSG = 8;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700287 static final int PAUSE_TIMEOUT_MSG = 9;
288 static final int IDLE_TIMEOUT_MSG = 10;
289 static final int IDLE_NOW_MSG = 11;
290 static final int LAUNCH_TIMEOUT_MSG = 16;
291 static final int DESTROY_TIMEOUT_MSG = 17;
292 static final int RESUME_TOP_ACTIVITY_MSG = 19;
293
294 final Handler mHandler = new Handler() {
295 //public Handler() {
296 // if (localLOGV) Slog.v(TAG, "Handler started!");
297 //}
298
299 public void handleMessage(Message msg) {
300 switch (msg.what) {
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800301 case SLEEP_TIMEOUT_MSG: {
Dianne Hackborn8e8d65f2011-08-11 19:36:18 -0700302 synchronized (mService) {
303 if (mService.isSleeping()) {
304 Slog.w(TAG, "Sleep timeout! Sleeping now.");
305 mSleepTimeout = true;
306 checkReadyForSleepLocked();
307 }
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800308 }
309 } break;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700310 case PAUSE_TIMEOUT_MSG: {
Dianne Hackbornbe707852011-11-11 14:32:10 -0800311 ActivityRecord r = (ActivityRecord)msg.obj;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700312 // We don't at this point know if the activity is fullscreen,
313 // so we need to be conservative and assume it isn't.
Dianne Hackbornbe707852011-11-11 14:32:10 -0800314 Slog.w(TAG, "Activity pause timeout for " + r);
315 activityPaused(r != null ? r.appToken : null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700316 } break;
317 case IDLE_TIMEOUT_MSG: {
318 if (mService.mDidDexOpt) {
319 mService.mDidDexOpt = false;
320 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
321 nmsg.obj = msg.obj;
322 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
323 return;
324 }
325 // We don't at this point know if the activity is fullscreen,
326 // so we need to be conservative and assume it isn't.
Dianne Hackbornbe707852011-11-11 14:32:10 -0800327 ActivityRecord r = (ActivityRecord)msg.obj;
328 Slog.w(TAG, "Activity idle timeout for " + r);
329 activityIdleInternal(r != null ? r.appToken : null, true, null);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700330 } break;
331 case DESTROY_TIMEOUT_MSG: {
Dianne Hackbornbe707852011-11-11 14:32:10 -0800332 ActivityRecord r = (ActivityRecord)msg.obj;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700333 // We don't at this point know if the activity is fullscreen,
334 // so we need to be conservative and assume it isn't.
Dianne Hackbornbe707852011-11-11 14:32:10 -0800335 Slog.w(TAG, "Activity destroy timeout for " + r);
336 activityDestroyed(r != null ? r.appToken : null);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700337 } break;
338 case IDLE_NOW_MSG: {
Dianne Hackbornbe707852011-11-11 14:32:10 -0800339 ActivityRecord r = (ActivityRecord)msg.obj;
340 activityIdleInternal(r != null ? r.appToken : null, false, null);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700341 } break;
342 case LAUNCH_TIMEOUT_MSG: {
343 if (mService.mDidDexOpt) {
344 mService.mDidDexOpt = false;
345 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
346 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
347 return;
348 }
349 synchronized (mService) {
350 if (mLaunchingActivity.isHeld()) {
351 Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
352 mLaunchingActivity.release();
353 }
354 }
355 } break;
356 case RESUME_TOP_ACTIVITY_MSG: {
357 synchronized (mService) {
358 resumeTopActivityLocked(null);
359 }
360 } break;
361 }
362 }
363 };
364
365 ActivityStack(ActivityManagerService service, Context context, boolean mainStack) {
366 mService = service;
367 mContext = context;
368 mMainStack = mainStack;
369 PowerManager pm =
370 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
371 mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
372 mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
373 mLaunchingActivity.setReferenceCounted(false);
374 }
375
376 final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700377 // TODO: Don't look for any tasks from other users
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700378 int i = mHistory.size()-1;
379 while (i >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700380 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700381 if (!r.finishing && r != notTop) {
382 return r;
383 }
384 i--;
385 }
386 return null;
387 }
388
389 final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700390 // TODO: Don't look for any tasks from other users
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700391 int i = mHistory.size()-1;
392 while (i >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700393 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700394 if (!r.finishing && !r.delayedResume && r != notTop) {
395 return r;
396 }
397 i--;
398 }
399 return null;
400 }
401
402 /**
403 * This is a simplified version of topRunningActivityLocked that provides a number of
404 * optional skip-over modes. It is intended for use with the ActivityController hook only.
405 *
406 * @param token If non-null, any history records matching this token will be skipped.
407 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
408 *
409 * @return Returns the HistoryRecord of the next activity on the stack.
410 */
411 final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700412 // TODO: Don't look for any tasks from other users
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700413 int i = mHistory.size()-1;
414 while (i >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700415 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700416 // Note: the taskId check depends on real taskId fields being non-zero
Dianne Hackbornbe707852011-11-11 14:32:10 -0800417 if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700418 return r;
419 }
420 i--;
421 }
422 return null;
423 }
424
425 final int indexOfTokenLocked(IBinder token) {
Dianne Hackbornbe707852011-11-11 14:32:10 -0800426 return mHistory.indexOf(ActivityRecord.forToken(token));
427 }
428
429 final int indexOfActivityLocked(ActivityRecord r) {
430 return mHistory.indexOf(r);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700431 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700432
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700433 final ActivityRecord isInStackLocked(IBinder token) {
Dianne Hackbornbe707852011-11-11 14:32:10 -0800434 ActivityRecord r = ActivityRecord.forToken(token);
435 if (mHistory.contains(r)) {
436 return r;
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700437 }
438 return null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700439 }
440
441 private final boolean updateLRUListLocked(ActivityRecord r) {
442 final boolean hadit = mLRUActivities.remove(r);
443 mLRUActivities.add(r);
444 return hadit;
445 }
446
447 /**
448 * Returns the top activity in any existing task matching the given
449 * Intent. Returns null if no such task is found.
450 */
451 private ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) {
452 ComponentName cls = intent.getComponent();
453 if (info.targetActivity != null) {
454 cls = new ComponentName(info.packageName, info.targetActivity);
455 }
456
457 TaskRecord cp = null;
458
Amith Yamasani742a6712011-05-04 14:49:28 -0700459 final int userId = UserId.getUserId(info.applicationInfo.uid);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700460 final int N = mHistory.size();
461 for (int i=(N-1); i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700462 ActivityRecord r = mHistory.get(i);
Amith Yamasani742a6712011-05-04 14:49:28 -0700463 if (!r.finishing && r.task != cp && r.userId == userId
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700464 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
465 cp = r.task;
466 //Slog.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
467 // + "/aff=" + r.task.affinity + " to new cls="
468 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
469 if (r.task.affinity != null) {
470 if (r.task.affinity.equals(info.taskAffinity)) {
471 //Slog.i(TAG, "Found matching affinity!");
472 return r;
473 }
474 } else if (r.task.intent != null
475 && r.task.intent.getComponent().equals(cls)) {
476 //Slog.i(TAG, "Found matching class!");
477 //dump();
478 //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
479 return r;
480 } else if (r.task.affinityIntent != null
481 && r.task.affinityIntent.getComponent().equals(cls)) {
482 //Slog.i(TAG, "Found matching class!");
483 //dump();
484 //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
485 return r;
486 }
487 }
488 }
489
490 return null;
491 }
492
493 /**
494 * Returns the first activity (starting from the top of the stack) that
495 * is the same as the given activity. Returns null if no such activity
496 * is found.
497 */
498 private ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
499 ComponentName cls = intent.getComponent();
500 if (info.targetActivity != null) {
501 cls = new ComponentName(info.packageName, info.targetActivity);
502 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700503 final int userId = UserId.getUserId(info.applicationInfo.uid);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700504
505 final int N = mHistory.size();
506 for (int i=(N-1); i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700507 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700508 if (!r.finishing) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700509 if (r.intent.getComponent().equals(cls) && r.userId == userId) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700510 //Slog.i(TAG, "Found matching class!");
511 //dump();
512 //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
513 return r;
514 }
515 }
516 }
517
518 return null;
519 }
520
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700521 final void showAskCompatModeDialogLocked(ActivityRecord r) {
522 Message msg = Message.obtain();
523 msg.what = ActivityManagerService.SHOW_COMPAT_MODE_DIALOG_MSG;
524 msg.obj = r.task.askedCompatMode ? null : r;
525 mService.mHandler.sendMessage(msg);
526 }
527
Amith Yamasani742a6712011-05-04 14:49:28 -0700528 /*
529 * Move the activities around in the stack to bring a user to the foreground.
530 * @return whether there are any activities for the specified user.
531 */
532 final boolean switchUser(int userId) {
533 synchronized (mService) {
534 mCurrentUser = userId;
535
536 // Only one activity? Nothing to do...
537 if (mHistory.size() < 2)
538 return false;
539
540 boolean haveActivities = false;
541 // Check if the top activity is from the new user.
542 ActivityRecord top = mHistory.get(mHistory.size() - 1);
543 if (top.userId == userId) return true;
544 // Otherwise, move the user's activities to the top.
545 int N = mHistory.size();
546 int i = 0;
547 while (i < N) {
548 ActivityRecord r = mHistory.get(i);
549 if (r.userId == userId) {
550 ActivityRecord moveToTop = mHistory.remove(i);
551 mHistory.add(moveToTop);
552 // No need to check the top one now
553 N--;
554 haveActivities = true;
555 } else {
556 i++;
557 }
558 }
559 // Transition from the old top to the new top
560 resumeTopActivityLocked(top);
561 return haveActivities;
562 }
563 }
564
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700565 final boolean realStartActivityLocked(ActivityRecord r,
566 ProcessRecord app, boolean andResume, boolean checkConfig)
567 throws RemoteException {
568
569 r.startFreezingScreenLocked(app, 0);
Dianne Hackbornbe707852011-11-11 14:32:10 -0800570 mService.mWindowManager.setAppVisibility(r.appToken, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700571
572 // Have the window manager re-evaluate the orientation of
573 // the screen based on the new activity order. Note that
574 // as a result of this, it can call back into the activity
575 // manager with a new orientation. We don't care about that,
576 // because the activity is not currently running so we are
577 // just restarting it anyway.
578 if (checkConfig) {
579 Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
580 mService.mConfiguration,
Dianne Hackbornbe707852011-11-11 14:32:10 -0800581 r.mayFreezeScreenLocked(app) ? r.appToken : null);
Dianne Hackborn813075a62011-11-14 17:45:19 -0800582 mService.updateConfigurationLocked(config, r, false, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700583 }
584
585 r.app = app;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700586 app.waitingToKill = null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700587
588 if (localLOGV) Slog.v(TAG, "Launching: " + r);
589
590 int idx = app.activities.indexOf(r);
591 if (idx < 0) {
592 app.activities.add(r);
593 }
594 mService.updateLruProcessLocked(app, true, true);
595
596 try {
597 if (app.thread == null) {
598 throw new RemoteException();
599 }
600 List<ResultInfo> results = null;
601 List<Intent> newIntents = null;
602 if (andResume) {
603 results = r.results;
604 newIntents = r.newIntents;
605 }
606 if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
607 + " icicle=" + r.icicle
608 + " with results=" + results + " newIntents=" + newIntents
609 + " andResume=" + andResume);
610 if (andResume) {
611 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
612 System.identityHashCode(r),
613 r.task.taskId, r.shortComponentName);
614 }
615 if (r.isHomeActivity) {
616 mService.mHomeProcess = app;
617 }
618 mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800619 r.sleeping = false;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400620 r.forceNewConfig = false;
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700621 showAskCompatModeDialogLocked(r);
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700622 r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700623 String profileFile = null;
624 ParcelFileDescriptor profileFd = null;
625 boolean profileAutoStop = false;
626 if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) {
627 if (mService.mProfileProc == null || mService.mProfileProc == app) {
628 mService.mProfileProc = app;
629 profileFile = mService.mProfileFile;
630 profileFd = mService.mProfileFd;
631 profileAutoStop = mService.mAutoStopProfiler;
632 }
633 }
Dianne Hackbornf0754f5b2011-07-21 16:02:07 -0700634 app.hasShownUi = true;
Dianne Hackbornc68c9132011-07-29 01:25:18 -0700635 app.pendingUiClean = true;
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700636 if (profileFd != null) {
637 try {
638 profileFd = profileFd.dup();
639 } catch (IOException e) {
640 profileFd = null;
641 }
642 }
Dianne Hackbornbe707852011-11-11 14:32:10 -0800643 app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
Dianne Hackborn813075a62011-11-14 17:45:19 -0800644 System.identityHashCode(r), r.info,
645 new Configuration(mService.mConfiguration),
Dianne Hackborn58f42a52011-10-10 13:46:34 -0700646 r.compat, r.icicle, results, newIntents, !andResume,
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700647 mService.isNextTransitionForward(), profileFile, profileFd,
648 profileAutoStop);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700649
Dianne Hackborn54e570f2010-10-04 18:32:32 -0700650 if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700651 // This may be a heavy-weight process! Note that the package
652 // manager will ensure that only activity can run in the main
653 // process of the .apk, which is the only thing that will be
654 // considered heavy-weight.
655 if (app.processName.equals(app.info.packageName)) {
656 if (mService.mHeavyWeightProcess != null
657 && mService.mHeavyWeightProcess != app) {
658 Log.w(TAG, "Starting new heavy weight process " + app
659 + " when already running "
660 + mService.mHeavyWeightProcess);
661 }
662 mService.mHeavyWeightProcess = app;
663 Message msg = mService.mHandler.obtainMessage(
664 ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
665 msg.obj = r;
666 mService.mHandler.sendMessage(msg);
667 }
668 }
669
670 } catch (RemoteException e) {
671 if (r.launchFailed) {
672 // This is the second time we failed -- finish activity
673 // and give up.
674 Slog.e(TAG, "Second failure launching "
675 + r.intent.getComponent().flattenToShortString()
676 + ", giving up", e);
677 mService.appDiedLocked(app, app.pid, app.thread);
Dianne Hackbornbe707852011-11-11 14:32:10 -0800678 requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700679 "2nd-crash");
680 return false;
681 }
682
683 // This is the first time we failed -- restart process and
684 // retry.
685 app.activities.remove(r);
686 throw e;
687 }
688
689 r.launchFailed = false;
690 if (updateLRUListLocked(r)) {
691 Slog.w(TAG, "Activity " + r
692 + " being launched, but already in LRU list");
693 }
694
695 if (andResume) {
696 // As part of the process of launching, ActivityThread also performs
697 // a resume.
698 r.state = ActivityState.RESUMED;
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700699 if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + r
700 + " (starting new instance)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700701 r.stopped = false;
702 mResumedActivity = r;
703 r.task.touchActiveTime();
Dianne Hackborn88819b22010-12-21 18:18:02 -0800704 if (mMainStack) {
705 mService.addRecentTaskLocked(r.task);
706 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700707 completeResumeLocked(r);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800708 checkReadyForSleepLocked();
Dianne Hackborn98cfebc2011-10-18 13:17:33 -0700709 if (DEBUG_SAVED_STATE) Slog.i(TAG, "Launch completed; removing icicle of " + r.icicle);
710 r.icicle = null;
711 r.haveState = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700712 } else {
713 // This activity is not starting in the resumed state... which
714 // should look like we asked it to pause+stop (but remain visible),
715 // and it has done so and reported back the current icicle and
716 // other state.
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700717 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r
718 + " (starting in stopped state)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700719 r.state = ActivityState.STOPPED;
720 r.stopped = true;
721 }
722
723 // Launch the new version setup screen if needed. We do this -after-
724 // launching the initial activity (that is, home), so that it can have
725 // a chance to initialize itself while in the background, making the
726 // switch back to it faster and look better.
727 if (mMainStack) {
728 mService.startSetupActivityLocked();
729 }
730
731 return true;
732 }
733
734 private final void startSpecificActivityLocked(ActivityRecord r,
735 boolean andResume, boolean checkConfig) {
736 // Is this activity's application already running?
737 ProcessRecord app = mService.getProcessRecordLocked(r.processName,
738 r.info.applicationInfo.uid);
739
Dianne Hackborn0dad3642010-09-09 21:25:35 -0700740 if (r.launchTime == 0) {
741 r.launchTime = SystemClock.uptimeMillis();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700742 if (mInitialStartTime == 0) {
Dianne Hackborn0dad3642010-09-09 21:25:35 -0700743 mInitialStartTime = r.launchTime;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700744 }
745 } else if (mInitialStartTime == 0) {
746 mInitialStartTime = SystemClock.uptimeMillis();
747 }
748
749 if (app != null && app.thread != null) {
750 try {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700751 app.addPackage(r.info.packageName);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700752 realStartActivityLocked(r, app, andResume, checkConfig);
753 return;
754 } catch (RemoteException e) {
755 Slog.w(TAG, "Exception when starting activity "
756 + r.intent.getComponent().flattenToShortString(), e);
757 }
758
759 // If a dead object exception was thrown -- fall through to
760 // restart the application.
761 }
762
763 mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborna0c283e2012-02-09 10:47:01 -0800764 "activity", r.intent.getComponent(), false, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700765 }
766
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800767 void stopIfSleepingLocked() {
768 if (mService.isSleeping()) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700769 if (!mGoingToSleep.isHeld()) {
770 mGoingToSleep.acquire();
771 if (mLaunchingActivity.isHeld()) {
772 mLaunchingActivity.release();
773 mService.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
774 }
775 }
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800776 mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
777 Message msg = mHandler.obtainMessage(SLEEP_TIMEOUT_MSG);
778 mHandler.sendMessageDelayed(msg, SLEEP_TIMEOUT);
779 checkReadyForSleepLocked();
780 }
781 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700782
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800783 void awakeFromSleepingLocked() {
784 mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
785 mSleepTimeout = false;
786 if (mGoingToSleep.isHeld()) {
787 mGoingToSleep.release();
788 }
789 // Ensure activities are no longer sleeping.
790 for (int i=mHistory.size()-1; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700791 ActivityRecord r = mHistory.get(i);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800792 r.setSleeping(false);
793 }
794 mGoingToSleepActivities.clear();
795 }
796
797 void activitySleptLocked(ActivityRecord r) {
798 mGoingToSleepActivities.remove(r);
799 checkReadyForSleepLocked();
800 }
801
802 void checkReadyForSleepLocked() {
803 if (!mService.isSleeping()) {
804 // Do not care.
805 return;
806 }
807
808 if (!mSleepTimeout) {
809 if (mResumedActivity != null) {
810 // Still have something resumed; can't sleep until it is paused.
811 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause " + mResumedActivity);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700812 if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false");
813 startPausingLocked(false, true);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800814 return;
815 }
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800816 if (mPausingActivities.size() > 0) {
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800817 // Still waiting for something to pause; can't sleep yet.
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800818 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivities);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800819 return;
820 }
821
822 if (mStoppingActivities.size() > 0) {
823 // Still need to tell some activities to stop; can't sleep yet.
824 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to stop "
825 + mStoppingActivities.size() + " activities");
Dianne Hackborn80a7ac12011-09-22 18:32:52 -0700826 scheduleIdleLocked();
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800827 return;
828 }
829
830 ensureActivitiesVisibleLocked(null, 0);
831
832 // Make sure any stopped but visible activities are now sleeping.
833 // This ensures that the activity's onStop() is called.
834 for (int i=mHistory.size()-1; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700835 ActivityRecord r = mHistory.get(i);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800836 if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) {
837 r.setSleeping(true);
838 }
839 }
840
841 if (mGoingToSleepActivities.size() > 0) {
842 // Still need to tell some activities to sleep; can't sleep yet.
843 if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to sleep "
844 + mGoingToSleepActivities.size() + " activities");
845 return;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700846 }
847 }
Dianne Hackborn4eba96b2011-01-21 13:34:36 -0800848
849 mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
850
851 if (mGoingToSleep.isHeld()) {
852 mGoingToSleep.release();
853 }
854 if (mService.mShuttingDown) {
855 mService.notifyAll();
856 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700857 }
858
Dianne Hackbornd2835932010-12-13 16:28:46 -0800859 public final Bitmap screenshotActivities(ActivityRecord who) {
Dianne Hackbornff801ec2011-01-22 18:05:38 -0800860 if (who.noDisplay) {
861 return null;
862 }
863
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800864 Resources res = mService.mContext.getResources();
865 int w = mThumbnailWidth;
866 int h = mThumbnailHeight;
867 if (w < 0) {
868 mThumbnailWidth = w =
869 res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
870 mThumbnailHeight = h =
871 res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
872 }
873
874 if (w > 0) {
Dianne Hackbornbe707852011-11-11 14:32:10 -0800875 return mService.mWindowManager.screenshotApplications(who.appToken, w, h);
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800876 }
877 return null;
878 }
879
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700880 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700881 ActivityRecord prev = mResumedActivity;
882 if (prev == null) {
883 RuntimeException e = new RuntimeException();
884 Slog.e(TAG, "Trying to pause when nothing is resumed", e);
885 resumeTopActivityLocked(null);
886 return;
887 }
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800888 if (mPausingActivities.contains(prev)) {
889 RuntimeException e = new RuntimeException();
890 Slog.e(TAG, "Trying to pause when pause when already pausing " + prev, e);
891 }
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700892 if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
893 else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700894 mResumedActivity = null;
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800895 mPausingActivities.add(prev);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700896 mLastPausedActivity = prev;
897 prev.state = ActivityState.PAUSING;
898 prev.task.touchActiveTime();
Dianne Hackbornf26fd992011-04-08 18:14:09 -0700899 prev.updateThumbnail(screenshotActivities(prev), null);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700900
901 mService.updateCpuStats();
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800902 ActivityRecord pausing;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700903
904 if (prev.app != null && prev.app.thread != null) {
905 if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800906 pausing = prev;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700907 try {
908 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
909 System.identityHashCode(prev),
910 prev.shortComponentName);
Dianne Hackbornbe707852011-11-11 14:32:10 -0800911 prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
912 userLeaving, prev.configChangeFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700913 if (mMainStack) {
914 mService.updateUsageStats(prev, false);
915 }
916 } catch (Exception e) {
917 // Ignore exception, if process died other code will cleanup.
918 Slog.w(TAG, "Exception thrown during pause", e);
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800919 mPausingActivities.remove(prev);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700920 mLastPausedActivity = null;
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800921 pausing = null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700922 }
923 } else {
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800924 mPausingActivities.remove(prev);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700925 mLastPausedActivity = null;
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800926 pausing = null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700927 }
928
929 // If we are not going to sleep, we want to ensure the device is
930 // awake until the next activity is started.
931 if (!mService.mSleeping && !mService.mShuttingDown) {
932 mLaunchingActivity.acquire();
933 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
934 // To be safe, don't allow the wake lock to be held for too long.
935 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
936 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
937 }
938 }
939
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800940 if (pausing != null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700941 // Have the window manager pause its key dispatching until the new
942 // activity has started. If we're pausing the activity just because
943 // the screen is being turned off and the UI is sleeping, don't interrupt
944 // key dispatch; the same activity will pick it up again on wakeup.
945 if (!uiSleeping) {
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800946 pausing.pauseKeyDispatchingLocked();
947 mInputPausedActivities.add(prev);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700948 } else {
949 if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
950 }
951
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800952 if (pausing.configDestroy) {
953 // The previous is being paused because the configuration
954 // is changing, which means it is actually stopping...
955 // To juggle the fact that we are also starting a new
956 // instance right now, we need to first completely stop
957 // the current instance before starting the new one.
958 if (DEBUG_PAUSE) Slog.v(TAG, "Destroying at pause: " + prev);
959 destroyActivityLocked(pausing, true, false, "pause-config");
960 }
961
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700962 // Schedule a pause timeout in case the app doesn't respond.
963 // We don't give it much time because this directly impacts the
964 // responsiveness seen by the user.
965 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
966 msg.obj = prev;
967 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
968 if (DEBUG_PAUSE) Slog.v(TAG, "Waiting for pause to complete...");
969 } else {
970 // This activity failed to schedule the
971 // pause, so just treat it as being paused now.
972 if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800973 }
974
975 if (!mService.isSleeping()) {
976 resumeTopActivityLocked(pausing);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700977 }
978 }
979
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800980 final void activityPaused(IBinder token, boolean timeout) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700981 if (DEBUG_PAUSE) Slog.v(
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800982 TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700983
984 ActivityRecord r = null;
985
986 synchronized (mService) {
987 int index = indexOfTokenLocked(token);
988 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -0700989 r = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700990 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800991 if (mPausingActivities.contains(r)) {
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700992 if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
993 + (timeout ? " (due to timeout)" : " (pause complete)"));
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700994 r.state = ActivityState.PAUSED;
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800995 completePauseLocked(r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700996 } else {
Dianne Hackborncbb722e2012-02-07 18:33:49 -0800997 ActivityRecord old = mPausingActivities.size() > 0
998 ? mPausingActivities.get(0) : null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -0700999 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
1000 System.identityHashCode(r), r.shortComponentName,
Dianne Hackborncbb722e2012-02-07 18:33:49 -08001001 old != null ? old.shortComponentName : "(none)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001002 }
1003 }
1004 }
1005 }
1006
Dianne Hackbornce86ba82011-07-13 19:33:41 -07001007 final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
1008 CharSequence description) {
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001009 if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
Dianne Hackbornce86ba82011-07-13 19:33:41 -07001010 r.icicle = icicle;
1011 r.haveState = true;
1012 r.updateThumbnail(thumbnail, description);
1013 r.stopped = true;
1014 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
1015 r.state = ActivityState.STOPPED;
1016 if (!r.finishing) {
1017 if (r.configDestroy) {
Dianne Hackborn28695e02011-11-02 21:59:51 -07001018 destroyActivityLocked(r, true, false, "stop-config");
Dianne Hackbornce86ba82011-07-13 19:33:41 -07001019 resumeTopActivityLocked(null);
Dianne Hackborn50685602011-12-01 12:23:37 -08001020 } else {
1021 // Now that this process has stopped, we may want to consider
1022 // it to be the previous app to try to keep around in case
1023 // the user wants to return to it.
1024 ProcessRecord fgApp = null;
1025 if (mResumedActivity != null) {
1026 fgApp = mResumedActivity.app;
Dianne Hackborncbb722e2012-02-07 18:33:49 -08001027 } else {
1028 for (int i=mPausingActivities.size()-1; i>=0; i--) {
1029 ActivityRecord pausing = mPausingActivities.get(i);
1030 if (pausing.app == r.app) {
1031 fgApp = pausing.app;
1032 break;
1033 }
1034 }
Dianne Hackborn50685602011-12-01 12:23:37 -08001035 }
1036 if (r.app != null && fgApp != null && r.app != fgApp
1037 && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
1038 && r.app != mService.mHomeProcess) {
1039 mService.mPreviousProcess = r.app;
1040 mService.mPreviousProcessVisibleTime = r.lastVisibleTime;
1041 }
Dianne Hackbornce86ba82011-07-13 19:33:41 -07001042 }
1043 }
1044 }
1045
Dianne Hackborncbb722e2012-02-07 18:33:49 -08001046 private final void completePauseLocked(ActivityRecord prev) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001047 if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
1048
Dianne Hackborncbb722e2012-02-07 18:33:49 -08001049 if (prev.finishing) {
1050 if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
1051 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
1052 } else if (prev.app != null) {
1053 if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
1054 if (prev.waitingVisible) {
1055 prev.waitingVisible = false;
1056 mWaitingVisibleActivities.remove(prev);
1057 if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
1058 TAG, "Complete pause, no longer waiting: " + prev);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001059 }
Dianne Hackborncbb722e2012-02-07 18:33:49 -08001060 if (prev.configDestroy) {
1061 // The previous is being paused because the configuration
1062 // is changing, which means it is actually stopping...
1063 // To juggle the fact that we are also starting a new
1064 // instance right now, we need to first completely stop
1065 // the current instance before starting the new one.
1066 if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
1067 destroyActivityLocked(prev, true, false, "pause-config");
1068 } else {
1069 mStoppingActivities.add(prev);
1070 if (mStoppingActivities.size() > 3) {
1071 // If we already have a few activities waiting to stop,
1072 // then give up on things going idle and start clearing
1073 // them out.
1074 if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
1075 scheduleIdleLocked();
1076 } else {
1077 checkReadyForSleepLocked();
1078 }
1079 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001080 } else {
Dianne Hackborncbb722e2012-02-07 18:33:49 -08001081 if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
1082 prev = null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001083 }
Dianne Hackborncbb722e2012-02-07 18:33:49 -08001084 mPausingActivities.remove(prev);
1085
1086 if (mService.isSleeping()) {
1087 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001088 }
1089
1090 if (prev.app != null && prev.cpuTimeAtResume > 0
1091 && mService.mBatteryStatsService.isOnBattery()) {
1092 long diff = 0;
1093 synchronized (mService.mProcessStatsThread) {
1094 diff = mService.mProcessStats.getCpuTimeForPid(prev.app.pid)
1095 - prev.cpuTimeAtResume;
1096 }
1097 if (diff > 0) {
1098 BatteryStatsImpl bsi = mService.mBatteryStatsService.getActiveStatistics();
1099 synchronized (bsi) {
1100 BatteryStatsImpl.Uid.Proc ps =
1101 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
1102 prev.info.packageName);
1103 if (ps != null) {
1104 ps.addForegroundTimeLocked(diff);
1105 }
1106 }
1107 }
1108 }
1109 prev.cpuTimeAtResume = 0; // reset it
1110 }
1111
1112 /**
1113 * Once we know that we have asked an application to put an activity in
1114 * the resumed state (either by launching it or explicitly telling it),
1115 * this function updates the rest of our state to match that fact.
1116 */
1117 private final void completeResumeLocked(ActivityRecord next) {
1118 next.idle = false;
1119 next.results = null;
1120 next.newIntents = null;
1121
1122 // schedule an idle timeout in case the app doesn't do it for us.
1123 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1124 msg.obj = next;
1125 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
1126
1127 if (false) {
1128 // The activity was never told to pause, so just keep
1129 // things going as-is. To maintain our own state,
1130 // we need to emulate it coming back and saying it is
1131 // idle.
1132 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
1133 msg.obj = next;
1134 mHandler.sendMessage(msg);
1135 }
1136
1137 if (mMainStack) {
1138 mService.reportResumedActivityLocked(next);
1139 }
1140
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001141 next.clearThumbnail();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001142 if (mMainStack) {
1143 mService.setFocusedActivityLocked(next);
1144 }
Dianne Hackborncbb722e2012-02-07 18:33:49 -08001145 if (mInputPausedActivities.remove(next)) {
1146 next.resumeKeyDispatchingLocked();
1147 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001148 ensureActivitiesVisibleLocked(null, 0);
1149 mService.mWindowManager.executeAppTransition();
1150 mNoAnimActivities.clear();
1151
1152 // Mark the point when the activity is resuming
1153 // TODO: To be more accurate, the mark should be before the onCreate,
1154 // not after the onResume. But for subsequent starts, onResume is fine.
1155 if (next.app != null) {
1156 synchronized (mService.mProcessStatsThread) {
1157 next.cpuTimeAtResume = mService.mProcessStats.getCpuTimeForPid(next.app.pid);
1158 }
1159 } else {
1160 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
1161 }
1162 }
1163
1164 /**
1165 * Make sure that all activities that need to be visible (that is, they
1166 * currently can be seen by the user) actually are.
1167 */
1168 final void ensureActivitiesVisibleLocked(ActivityRecord top,
1169 ActivityRecord starting, String onlyThisProcess, int configChanges) {
1170 if (DEBUG_VISBILITY) Slog.v(
1171 TAG, "ensureActivitiesVisible behind " + top
1172 + " configChanges=0x" + Integer.toHexString(configChanges));
1173
1174 // If the top activity is not fullscreen, then we need to
1175 // make sure any activities under it are now visible.
1176 final int count = mHistory.size();
1177 int i = count-1;
1178 while (mHistory.get(i) != top) {
1179 i--;
1180 }
1181 ActivityRecord r;
1182 boolean behindFullscreen = false;
1183 for (; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001184 r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001185 if (DEBUG_VISBILITY) Slog.v(
1186 TAG, "Make visible? " + r + " finishing=" + r.finishing
1187 + " state=" + r.state);
1188 if (r.finishing) {
1189 continue;
1190 }
1191
1192 final boolean doThisProcess = onlyThisProcess == null
1193 || onlyThisProcess.equals(r.processName);
1194
1195 // First: if this is not the current activity being started, make
1196 // sure it matches the current configuration.
1197 if (r != starting && doThisProcess) {
1198 ensureActivityConfigurationLocked(r, 0);
1199 }
1200
1201 if (r.app == null || r.app.thread == null) {
1202 if (onlyThisProcess == null
1203 || onlyThisProcess.equals(r.processName)) {
1204 // This activity needs to be visible, but isn't even
1205 // running... get it started, but don't resume it
1206 // at this point.
1207 if (DEBUG_VISBILITY) Slog.v(
1208 TAG, "Start and freeze screen for " + r);
1209 if (r != starting) {
1210 r.startFreezingScreenLocked(r.app, configChanges);
1211 }
1212 if (!r.visible) {
1213 if (DEBUG_VISBILITY) Slog.v(
1214 TAG, "Starting and making visible: " + r);
Dianne Hackbornbe707852011-11-11 14:32:10 -08001215 mService.mWindowManager.setAppVisibility(r.appToken, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001216 }
1217 if (r != starting) {
1218 startSpecificActivityLocked(r, false, false);
1219 }
1220 }
1221
1222 } else if (r.visible) {
1223 // If this activity is already visible, then there is nothing
1224 // else to do here.
1225 if (DEBUG_VISBILITY) Slog.v(
1226 TAG, "Skipping: already visible at " + r);
1227 r.stopFreezingScreenLocked(false);
1228
1229 } else if (onlyThisProcess == null) {
1230 // This activity is not currently visible, but is running.
1231 // Tell it to become visible.
1232 r.visible = true;
1233 if (r.state != ActivityState.RESUMED && r != starting) {
1234 // If this activity is paused, tell it
1235 // to now show its window.
1236 if (DEBUG_VISBILITY) Slog.v(
1237 TAG, "Making visible and scheduling visibility: " + r);
1238 try {
Dianne Hackbornbe707852011-11-11 14:32:10 -08001239 mService.mWindowManager.setAppVisibility(r.appToken, true);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001240 r.sleeping = false;
Dianne Hackborn905577f2011-09-07 18:31:28 -07001241 r.app.pendingUiClean = true;
Dianne Hackbornbe707852011-11-11 14:32:10 -08001242 r.app.thread.scheduleWindowVisibility(r.appToken, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001243 r.stopFreezingScreenLocked(false);
1244 } catch (Exception e) {
1245 // Just skip on any failure; we'll make it
1246 // visible when it next restarts.
1247 Slog.w(TAG, "Exception thrown making visibile: "
1248 + r.intent.getComponent(), e);
1249 }
1250 }
1251 }
1252
1253 // Aggregate current change flags.
1254 configChanges |= r.configChangeFlags;
1255
1256 if (r.fullscreen) {
1257 // At this point, nothing else needs to be shown
1258 if (DEBUG_VISBILITY) Slog.v(
1259 TAG, "Stopping: fullscreen at " + r);
1260 behindFullscreen = true;
1261 i--;
1262 break;
1263 }
1264 }
1265
1266 // Now for any activities that aren't visible to the user, make
1267 // sure they no longer are keeping the screen frozen.
1268 while (i >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001269 r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001270 if (DEBUG_VISBILITY) Slog.v(
1271 TAG, "Make invisible? " + r + " finishing=" + r.finishing
1272 + " state=" + r.state
1273 + " behindFullscreen=" + behindFullscreen);
1274 if (!r.finishing) {
1275 if (behindFullscreen) {
1276 if (r.visible) {
1277 if (DEBUG_VISBILITY) Slog.v(
1278 TAG, "Making invisible: " + r);
1279 r.visible = false;
1280 try {
Dianne Hackbornbe707852011-11-11 14:32:10 -08001281 mService.mWindowManager.setAppVisibility(r.appToken, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001282 if ((r.state == ActivityState.STOPPING
1283 || r.state == ActivityState.STOPPED)
1284 && r.app != null && r.app.thread != null) {
1285 if (DEBUG_VISBILITY) Slog.v(
1286 TAG, "Scheduling invisibility: " + r);
Dianne Hackbornbe707852011-11-11 14:32:10 -08001287 r.app.thread.scheduleWindowVisibility(r.appToken, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001288 }
1289 } catch (Exception e) {
1290 // Just skip on any failure; we'll make it
1291 // visible when it next restarts.
1292 Slog.w(TAG, "Exception thrown making hidden: "
1293 + r.intent.getComponent(), e);
1294 }
1295 } else {
1296 if (DEBUG_VISBILITY) Slog.v(
1297 TAG, "Already invisible: " + r);
1298 }
1299 } else if (r.fullscreen) {
1300 if (DEBUG_VISBILITY) Slog.v(
1301 TAG, "Now behindFullscreen: " + r);
1302 behindFullscreen = true;
1303 }
1304 }
1305 i--;
1306 }
1307 }
1308
1309 /**
1310 * Version of ensureActivitiesVisible that can easily be called anywhere.
1311 */
1312 final void ensureActivitiesVisibleLocked(ActivityRecord starting,
1313 int configChanges) {
1314 ActivityRecord r = topRunningActivityLocked(null);
1315 if (r != null) {
1316 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
1317 }
1318 }
1319
1320 /**
1321 * Ensure that the top activity in the stack is resumed.
1322 *
1323 * @param prev The previously resumed activity, for when in the process
1324 * of pausing; can be null to call from elsewhere.
1325 *
1326 * @return Returns true if something is being resumed, or false if
1327 * nothing happened.
1328 */
1329 final boolean resumeTopActivityLocked(ActivityRecord prev) {
1330 // Find the first activity that is not finishing.
1331 ActivityRecord next = topRunningActivityLocked(null);
1332
1333 // Remember how we'll process this pause/resume situation, and ensure
1334 // that the state is reset however we wind up proceeding.
1335 final boolean userLeaving = mUserLeaving;
1336 mUserLeaving = false;
1337
1338 if (next == null) {
1339 // There are no more activities! Let's just start up the
1340 // Launcher...
1341 if (mMainStack) {
Amith Yamasani742a6712011-05-04 14:49:28 -07001342 return mService.startHomeActivityLocked(0);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001343 }
1344 }
1345
1346 next.delayedResume = false;
1347
1348 // If the top activity is the resumed one, nothing to do.
1349 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
1350 // Make sure we have executed any pending transitions, since there
1351 // should be nothing left to do at this point.
1352 mService.mWindowManager.executeAppTransition();
1353 mNoAnimActivities.clear();
1354 return false;
1355 }
1356
1357 // If we are sleeping, and there is no resumed activity, and the top
1358 // activity is paused, well that is the state we want.
1359 if ((mService.mSleeping || mService.mShuttingDown)
1360 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
1361 // Make sure we have executed any pending transitions, since there
1362 // should be nothing left to do at this point.
1363 mService.mWindowManager.executeAppTransition();
1364 mNoAnimActivities.clear();
1365 return false;
1366 }
1367
1368 // The activity may be waiting for stop, but that is no longer
1369 // appropriate for it.
1370 mStoppingActivities.remove(next);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001371 mGoingToSleepActivities.remove(next);
1372 next.sleeping = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001373 mWaitingVisibleActivities.remove(next);
1374
1375 if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
1376
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001377 // Okay we are now going to start a switch, to 'next'. We may first
1378 // have to pause the current activity, but this is an important point
1379 // where we have decided to go to 'next' so keep track of that.
Dianne Hackborn034093a42010-09-20 22:24:38 -07001380 // XXX "App Redirected" dialog is getting too many false positives
1381 // at this point, so turn off for now.
1382 if (false) {
1383 if (mLastStartedActivity != null && !mLastStartedActivity.finishing) {
1384 long now = SystemClock.uptimeMillis();
1385 final boolean inTime = mLastStartedActivity.startTime != 0
1386 && (mLastStartedActivity.startTime + START_WARN_TIME) >= now;
1387 final int lastUid = mLastStartedActivity.info.applicationInfo.uid;
1388 final int nextUid = next.info.applicationInfo.uid;
1389 if (inTime && lastUid != nextUid
1390 && lastUid != next.launchedFromUid
1391 && mService.checkPermission(
1392 android.Manifest.permission.STOP_APP_SWITCHES,
1393 -1, next.launchedFromUid)
1394 != PackageManager.PERMISSION_GRANTED) {
1395 mService.showLaunchWarningLocked(mLastStartedActivity, next);
1396 } else {
1397 next.startTime = now;
1398 mLastStartedActivity = next;
1399 }
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001400 } else {
Dianne Hackborn034093a42010-09-20 22:24:38 -07001401 next.startTime = SystemClock.uptimeMillis();
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001402 mLastStartedActivity = next;
1403 }
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001404 }
1405
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001406 // We need to start pausing the current activity so the top one
1407 // can be resumed...
1408 if (mResumedActivity != null) {
1409 if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
1410 startPausingLocked(userLeaving, false);
1411 return true;
1412 }
1413
1414 if (prev != null && prev != next) {
1415 if (!prev.waitingVisible && next != null && !next.nowVisible) {
1416 prev.waitingVisible = true;
1417 mWaitingVisibleActivities.add(prev);
1418 if (DEBUG_SWITCH) Slog.v(
1419 TAG, "Resuming top, waiting visible to hide: " + prev);
1420 } else {
1421 // The next activity is already visible, so hide the previous
1422 // activity's windows right now so we can show the new one ASAP.
1423 // We only do this if the previous is finishing, which should mean
1424 // it is on top of the one being resumed so hiding it quickly
1425 // is good. Otherwise, we want to do the normal route of allowing
1426 // the resumed activity to be shown so we can decide if the
1427 // previous should actually be hidden depending on whether the
1428 // new one is found to be full-screen or not.
1429 if (prev.finishing) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08001430 mService.mWindowManager.setAppVisibility(prev.appToken, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001431 if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
1432 + prev + ", waitingVisible="
1433 + (prev != null ? prev.waitingVisible : null)
1434 + ", nowVisible=" + next.nowVisible);
1435 } else {
1436 if (DEBUG_SWITCH) Slog.v(TAG, "Previous already visible but still waiting to hide: "
1437 + prev + ", waitingVisible="
1438 + (prev != null ? prev.waitingVisible : null)
1439 + ", nowVisible=" + next.nowVisible);
1440 }
1441 }
1442 }
1443
Dianne Hackborne7f97212011-02-24 14:40:20 -08001444 // Launching this app's activity, make sure the app is no longer
1445 // considered stopped.
1446 try {
Amith Yamasani742a6712011-05-04 14:49:28 -07001447 // TODO: Apply to the correct userId
Dianne Hackborne7f97212011-02-24 14:40:20 -08001448 AppGlobals.getPackageManager().setPackageStoppedState(
1449 next.packageName, false);
1450 } catch (RemoteException e1) {
Dianne Hackborna925cd42011-03-10 13:18:20 -08001451 } catch (IllegalArgumentException e) {
1452 Slog.w(TAG, "Failed trying to unstop package "
1453 + next.packageName + ": " + e);
Dianne Hackborne7f97212011-02-24 14:40:20 -08001454 }
1455
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001456 // We are starting up the next activity, so tell the window manager
1457 // that the previous one will be hidden soon. This way it can know
1458 // to ignore it when computing the desired screen orientation.
1459 if (prev != null) {
1460 if (prev.finishing) {
1461 if (DEBUG_TRANSITION) Slog.v(TAG,
1462 "Prepare close transition: prev=" + prev);
1463 if (mNoAnimActivities.contains(prev)) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001464 mService.mWindowManager.prepareAppTransition(
1465 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001466 } else {
1467 mService.mWindowManager.prepareAppTransition(prev.task == next.task
1468 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001469 : WindowManagerPolicy.TRANSIT_TASK_CLOSE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001470 }
Dianne Hackbornbe707852011-11-11 14:32:10 -08001471 mService.mWindowManager.setAppWillBeHidden(prev.appToken);
1472 mService.mWindowManager.setAppVisibility(prev.appToken, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001473 } else {
1474 if (DEBUG_TRANSITION) Slog.v(TAG,
1475 "Prepare open transition: prev=" + prev);
1476 if (mNoAnimActivities.contains(next)) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001477 mService.mWindowManager.prepareAppTransition(
1478 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001479 } else {
1480 mService.mWindowManager.prepareAppTransition(prev.task == next.task
1481 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001482 : WindowManagerPolicy.TRANSIT_TASK_OPEN, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001483 }
1484 }
1485 if (false) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08001486 mService.mWindowManager.setAppWillBeHidden(prev.appToken);
1487 mService.mWindowManager.setAppVisibility(prev.appToken, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001488 }
1489 } else if (mHistory.size() > 1) {
1490 if (DEBUG_TRANSITION) Slog.v(TAG,
1491 "Prepare open transition: no previous");
1492 if (mNoAnimActivities.contains(next)) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001493 mService.mWindowManager.prepareAppTransition(
1494 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001495 } else {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001496 mService.mWindowManager.prepareAppTransition(
1497 WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001498 }
1499 }
1500
1501 if (next.app != null && next.app.thread != null) {
1502 if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
1503
1504 // This activity is now becoming visible.
Dianne Hackbornbe707852011-11-11 14:32:10 -08001505 mService.mWindowManager.setAppVisibility(next.appToken, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001506
1507 ActivityRecord lastResumedActivity = mResumedActivity;
1508 ActivityState lastState = next.state;
1509
1510 mService.updateCpuStats();
1511
Dianne Hackbornce86ba82011-07-13 19:33:41 -07001512 if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + next + " (in existing)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001513 next.state = ActivityState.RESUMED;
1514 mResumedActivity = next;
1515 next.task.touchActiveTime();
Dianne Hackborn88819b22010-12-21 18:18:02 -08001516 if (mMainStack) {
1517 mService.addRecentTaskLocked(next.task);
1518 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001519 mService.updateLruProcessLocked(next.app, true, true);
1520 updateLRUListLocked(next);
1521
1522 // Have the window manager re-evaluate the orientation of
1523 // the screen based on the new activity order.
1524 boolean updated = false;
1525 if (mMainStack) {
1526 synchronized (mService) {
1527 Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
1528 mService.mConfiguration,
Dianne Hackbornbe707852011-11-11 14:32:10 -08001529 next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001530 if (config != null) {
1531 next.frozenBeforeDestroy = true;
1532 }
Dianne Hackborn813075a62011-11-14 17:45:19 -08001533 updated = mService.updateConfigurationLocked(config, next, false, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001534 }
1535 }
1536 if (!updated) {
1537 // The configuration update wasn't able to keep the existing
1538 // instance of the activity, and instead started a new one.
1539 // We should be all done, but let's just make sure our activity
1540 // is still at the top and schedule another run if something
1541 // weird happened.
1542 ActivityRecord nextNext = topRunningActivityLocked(null);
1543 if (DEBUG_SWITCH) Slog.i(TAG,
1544 "Activity config changed during resume: " + next
1545 + ", new next: " + nextNext);
1546 if (nextNext != next) {
1547 // Do over!
1548 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
1549 }
1550 if (mMainStack) {
1551 mService.setFocusedActivityLocked(next);
1552 }
1553 ensureActivitiesVisibleLocked(null, 0);
1554 mService.mWindowManager.executeAppTransition();
1555 mNoAnimActivities.clear();
1556 return true;
1557 }
1558
1559 try {
1560 // Deliver all pending results.
1561 ArrayList a = next.results;
1562 if (a != null) {
1563 final int N = a.size();
1564 if (!next.finishing && N > 0) {
1565 if (DEBUG_RESULTS) Slog.v(
1566 TAG, "Delivering results to " + next
1567 + ": " + a);
Dianne Hackbornbe707852011-11-11 14:32:10 -08001568 next.app.thread.scheduleSendResult(next.appToken, a);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001569 }
1570 }
1571
1572 if (next.newIntents != null) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08001573 next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001574 }
1575
1576 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
1577 System.identityHashCode(next),
1578 next.task.taskId, next.shortComponentName);
1579
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001580 next.sleeping = false;
Dianne Hackborn36cd41f2011-05-25 21:00:46 -07001581 showAskCompatModeDialogLocked(next);
Dianne Hackborn905577f2011-09-07 18:31:28 -07001582 next.app.pendingUiClean = true;
Dianne Hackbornbe707852011-11-11 14:32:10 -08001583 next.app.thread.scheduleResumeActivity(next.appToken,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001584 mService.isNextTransitionForward());
1585
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08001586 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001587
1588 } catch (Exception e) {
1589 // Whoops, need to restart this activity!
Dianne Hackbornce86ba82011-07-13 19:33:41 -07001590 if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to "
1591 + lastState + ": " + next);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001592 next.state = lastState;
1593 mResumedActivity = lastResumedActivity;
1594 Slog.i(TAG, "Restarting because process died: " + next);
1595 if (!next.hasBeenLaunched) {
1596 next.hasBeenLaunched = true;
1597 } else {
1598 if (SHOW_APP_STARTING_PREVIEW && mMainStack) {
1599 mService.mWindowManager.setAppStartingWindow(
Dianne Hackbornbe707852011-11-11 14:32:10 -08001600 next.appToken, next.packageName, next.theme,
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001601 mService.compatibilityInfoForPackageLocked(
1602 next.info.applicationInfo),
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001603 next.nonLocalizedLabel,
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001604 next.labelRes, next.icon, next.windowFlags,
1605 null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001606 }
1607 }
1608 startSpecificActivityLocked(next, true, false);
1609 return true;
1610 }
1611
1612 // From this point on, if something goes wrong there is no way
1613 // to recover the activity.
1614 try {
1615 next.visible = true;
1616 completeResumeLocked(next);
1617 } catch (Exception e) {
1618 // If any exception gets thrown, toss away this
1619 // activity and try the next one.
1620 Slog.w(TAG, "Exception thrown during resume of " + next, e);
Dianne Hackbornbe707852011-11-11 14:32:10 -08001621 requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001622 "resume-exception");
1623 return true;
1624 }
1625
1626 // Didn't need to use the icicle, and it is now out of date.
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001627 if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; didn't need icicle of: " + next);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001628 next.icicle = null;
1629 next.haveState = false;
1630 next.stopped = false;
1631
1632 } else {
1633 // Whoops, need to restart this activity!
1634 if (!next.hasBeenLaunched) {
1635 next.hasBeenLaunched = true;
1636 } else {
1637 if (SHOW_APP_STARTING_PREVIEW) {
1638 mService.mWindowManager.setAppStartingWindow(
Dianne Hackbornbe707852011-11-11 14:32:10 -08001639 next.appToken, next.packageName, next.theme,
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001640 mService.compatibilityInfoForPackageLocked(
1641 next.info.applicationInfo),
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001642 next.nonLocalizedLabel,
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001643 next.labelRes, next.icon, next.windowFlags,
1644 null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001645 }
1646 if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
1647 }
1648 startSpecificActivityLocked(next, true, true);
1649 }
1650
1651 return true;
1652 }
1653
1654 private final void startActivityLocked(ActivityRecord r, boolean newTask,
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001655 boolean doResume, boolean keepCurTransition) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001656 final int NH = mHistory.size();
1657
1658 int addPos = -1;
1659
1660 if (!newTask) {
1661 // If starting in an existing task, find where that is...
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001662 boolean startIt = true;
1663 for (int i = NH-1; i >= 0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001664 ActivityRecord p = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001665 if (p.finishing) {
1666 continue;
1667 }
1668 if (p.task == r.task) {
1669 // Here it is! Now, if this is not yet visible to the
1670 // user, then just add it without starting; it will
1671 // get started when the user navigates back to it.
1672 addPos = i+1;
1673 if (!startIt) {
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001674 if (DEBUG_ADD_REMOVE) {
1675 RuntimeException here = new RuntimeException("here");
1676 here.fillInStackTrace();
1677 Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos,
1678 here);
1679 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001680 mHistory.add(addPos, r);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001681 r.putInHistory();
Dianne Hackbornbe707852011-11-11 14:32:10 -08001682 mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001683 r.info.screenOrientation, r.fullscreen);
1684 if (VALIDATE_TOKENS) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08001685 validateAppTokensLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001686 }
1687 return;
1688 }
1689 break;
1690 }
1691 if (p.fullscreen) {
1692 startIt = false;
1693 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001694 }
1695 }
1696
1697 // Place a new activity at top of stack, so it is next to interact
1698 // with the user.
1699 if (addPos < 0) {
Dianne Hackborn0dad3642010-09-09 21:25:35 -07001700 addPos = NH;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001701 }
1702
1703 // If we are not placing the new activity frontmost, we do not want
1704 // to deliver the onUserLeaving callback to the actual frontmost
1705 // activity
1706 if (addPos < NH) {
1707 mUserLeaving = false;
1708 if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() behind front, mUserLeaving=false");
1709 }
1710
1711 // Slot the activity into the history stack and proceed
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001712 if (DEBUG_ADD_REMOVE) {
1713 RuntimeException here = new RuntimeException("here");
1714 here.fillInStackTrace();
1715 Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos, here);
1716 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001717 mHistory.add(addPos, r);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001718 r.putInHistory();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001719 r.frontOfTask = newTask;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001720 if (NH > 0) {
1721 // We want to show the starting preview window if we are
1722 // switching to a new task, or the next activity's process is
1723 // not currently running.
1724 boolean showStartingIcon = newTask;
1725 ProcessRecord proc = r.app;
1726 if (proc == null) {
1727 proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
1728 }
1729 if (proc == null || proc.thread == null) {
1730 showStartingIcon = true;
1731 }
1732 if (DEBUG_TRANSITION) Slog.v(TAG,
1733 "Prepare open transition: starting " + r);
1734 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001735 mService.mWindowManager.prepareAppTransition(
1736 WindowManagerPolicy.TRANSIT_NONE, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001737 mNoAnimActivities.add(r);
1738 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
1739 mService.mWindowManager.prepareAppTransition(
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001740 WindowManagerPolicy.TRANSIT_TASK_OPEN, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001741 mNoAnimActivities.remove(r);
1742 } else {
1743 mService.mWindowManager.prepareAppTransition(newTask
1744 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08001745 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001746 mNoAnimActivities.remove(r);
1747 }
1748 mService.mWindowManager.addAppToken(
Dianne Hackbornbe707852011-11-11 14:32:10 -08001749 addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001750 boolean doShow = true;
1751 if (newTask) {
1752 // Even though this activity is starting fresh, we still need
1753 // to reset it to make sure we apply affinities to move any
1754 // existing activities from other tasks in to it.
1755 // If the caller has requested that the target task be
1756 // reset, then do so.
1757 if ((r.intent.getFlags()
1758 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
1759 resetTaskIfNeededLocked(r, r);
1760 doShow = topRunningNonDelayedActivityLocked(null) == r;
1761 }
1762 }
1763 if (SHOW_APP_STARTING_PREVIEW && doShow) {
1764 // Figure out if we are transitioning from another activity that is
1765 // "has the same starting icon" as the next one. This allows the
1766 // window manager to keep the previous window it had previously
1767 // created, if it still had one.
1768 ActivityRecord prev = mResumedActivity;
1769 if (prev != null) {
1770 // We don't want to reuse the previous starting preview if:
1771 // (1) The current activity is in a different task.
1772 if (prev.task != r.task) prev = null;
1773 // (2) The current activity is already displayed.
1774 else if (prev.nowVisible) prev = null;
1775 }
1776 mService.mWindowManager.setAppStartingWindow(
Dianne Hackbornbe707852011-11-11 14:32:10 -08001777 r.appToken, r.packageName, r.theme,
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001778 mService.compatibilityInfoForPackageLocked(
1779 r.info.applicationInfo), r.nonLocalizedLabel,
Dianne Hackbornbe707852011-11-11 14:32:10 -08001780 r.labelRes, r.icon, r.windowFlags,
1781 prev != null ? prev.appToken : null, showStartingIcon);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001782 }
1783 } else {
1784 // If this is the first activity, don't do any fancy animations,
1785 // because there is nothing for it to animate on top of.
Dianne Hackbornbe707852011-11-11 14:32:10 -08001786 mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001787 r.info.screenOrientation, r.fullscreen);
1788 }
1789 if (VALIDATE_TOKENS) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08001790 validateAppTokensLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001791 }
1792
1793 if (doResume) {
1794 resumeTopActivityLocked(null);
1795 }
1796 }
1797
Dianne Hackbornbe707852011-11-11 14:32:10 -08001798 final void validateAppTokensLocked() {
1799 mValidateAppTokens.clear();
1800 mValidateAppTokens.ensureCapacity(mHistory.size());
1801 for (int i=0; i<mHistory.size(); i++) {
1802 mValidateAppTokens.add(mHistory.get(i).appToken);
1803 }
1804 mService.mWindowManager.validateAppTokens(mValidateAppTokens);
1805 }
1806
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001807 /**
1808 * Perform a reset of the given task, if needed as part of launching it.
1809 * Returns the new HistoryRecord at the top of the task.
1810 */
1811 private final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop,
1812 ActivityRecord newActivity) {
1813 boolean forceReset = (newActivity.info.flags
1814 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001815 if (ACTIVITY_INACTIVE_RESET_TIME > 0
1816 && taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001817 if ((newActivity.info.flags
1818 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
1819 forceReset = true;
1820 }
1821 }
1822
1823 final TaskRecord task = taskTop.task;
1824
1825 // We are going to move through the history list so that we can look
1826 // at each activity 'target' with 'below' either the interesting
1827 // activity immediately below it in the stack or null.
1828 ActivityRecord target = null;
1829 int targetI = 0;
1830 int taskTopI = -1;
1831 int replyChainEnd = -1;
1832 int lastReparentPos = -1;
1833 for (int i=mHistory.size()-1; i>=-1; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001834 ActivityRecord below = i >= 0 ? mHistory.get(i) : null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001835
1836 if (below != null && below.finishing) {
1837 continue;
1838 }
1839 if (target == null) {
1840 target = below;
1841 targetI = i;
1842 // If we were in the middle of a reply chain before this
1843 // task, it doesn't appear like the root of the chain wants
1844 // anything interesting, so drop it.
1845 replyChainEnd = -1;
1846 continue;
1847 }
1848
1849 final int flags = target.info.flags;
1850
1851 final boolean finishOnTaskLaunch =
1852 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
1853 final boolean allowTaskReparenting =
1854 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
1855
1856 if (target.task == task) {
1857 // We are inside of the task being reset... we'll either
1858 // finish this activity, push it out for another task,
1859 // or leave it as-is. We only do this
1860 // for activities that are not the root of the task (since
1861 // if we finish the root, we may no longer have the task!).
1862 if (taskTopI < 0) {
1863 taskTopI = targetI;
1864 }
1865 if (below != null && below.task == task) {
1866 final boolean clearWhenTaskReset =
1867 (target.intent.getFlags()
1868 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
1869 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
1870 // If this activity is sending a reply to a previous
1871 // activity, we can't do anything with it now until
1872 // we reach the start of the reply chain.
1873 // XXX note that we are assuming the result is always
1874 // to the previous activity, which is almost always
1875 // the case but we really shouldn't count on.
1876 if (replyChainEnd < 0) {
1877 replyChainEnd = targetI;
1878 }
1879 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
1880 && target.taskAffinity != null
1881 && !target.taskAffinity.equals(task.affinity)) {
1882 // If this activity has an affinity for another
1883 // task, then we need to move it out of here. We will
1884 // move it as far out of the way as possible, to the
1885 // bottom of the activity stack. This also keeps it
1886 // correctly ordered with any activities we previously
1887 // moved.
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001888 ActivityRecord p = mHistory.get(0);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001889 if (target.taskAffinity != null
1890 && target.taskAffinity.equals(p.task.affinity)) {
1891 // If the activity currently at the bottom has the
1892 // same task affinity as the one we are moving,
1893 // then merge it into the same task.
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001894 target.setTask(p.task, p.thumbHolder, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001895 if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
1896 + " out to bottom task " + p.task);
1897 } else {
1898 mService.mCurTask++;
1899 if (mService.mCurTask <= 0) {
1900 mService.mCurTask = 1;
1901 }
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001902 target.setTask(new TaskRecord(mService.mCurTask, target.info, null),
1903 null, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001904 target.task.affinityIntent = target.intent;
1905 if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
1906 + " out to new task " + target.task);
1907 }
Dianne Hackbornbe707852011-11-11 14:32:10 -08001908 mService.mWindowManager.setAppGroupId(target.appToken, task.taskId);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001909 if (replyChainEnd < 0) {
1910 replyChainEnd = targetI;
1911 }
1912 int dstPos = 0;
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001913 ThumbnailHolder curThumbHolder = target.thumbHolder;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001914 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001915 p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001916 if (p.finishing) {
1917 continue;
1918 }
1919 if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
1920 + " out to target's task " + target.task);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07001921 p.setTask(target.task, curThumbHolder, false);
1922 curThumbHolder = p.thumbHolder;
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07001923 if (DEBUG_ADD_REMOVE) {
1924 RuntimeException here = new RuntimeException("here");
1925 here.fillInStackTrace();
1926 Slog.i(TAG, "Removing and adding activity " + p + " to stack at "
1927 + dstPos, here);
1928 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001929 mHistory.remove(srcPos);
1930 mHistory.add(dstPos, p);
Dianne Hackbornbe707852011-11-11 14:32:10 -08001931 mService.mWindowManager.moveAppToken(dstPos, p.appToken);
1932 mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001933 dstPos++;
1934 if (VALIDATE_TOKENS) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08001935 validateAppTokensLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001936 }
1937 i++;
1938 }
1939 if (taskTop == p) {
1940 taskTop = below;
1941 }
1942 if (taskTopI == replyChainEnd) {
1943 taskTopI = -1;
1944 }
1945 replyChainEnd = -1;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001946 } else if (forceReset || finishOnTaskLaunch
1947 || clearWhenTaskReset) {
1948 // If the activity should just be removed -- either
1949 // because it asks for it, or the task should be
1950 // cleared -- then finish it and anything that is
1951 // part of its reply chain.
1952 if (clearWhenTaskReset) {
1953 // In this case, we want to finish this activity
1954 // and everything above it, so be sneaky and pretend
1955 // like these are all in the reply chain.
1956 replyChainEnd = targetI+1;
1957 while (replyChainEnd < mHistory.size() &&
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001958 (mHistory.get(
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001959 replyChainEnd)).task == task) {
1960 replyChainEnd++;
1961 }
1962 replyChainEnd--;
1963 } else if (replyChainEnd < 0) {
1964 replyChainEnd = targetI;
1965 }
1966 ActivityRecord p = null;
1967 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07001968 p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001969 if (p.finishing) {
1970 continue;
1971 }
1972 if (finishActivityLocked(p, srcPos,
1973 Activity.RESULT_CANCELED, null, "reset")) {
1974 replyChainEnd--;
1975 srcPos--;
1976 }
1977 }
1978 if (taskTop == p) {
1979 taskTop = below;
1980 }
1981 if (taskTopI == replyChainEnd) {
1982 taskTopI = -1;
1983 }
1984 replyChainEnd = -1;
1985 } else {
1986 // If we were in the middle of a chain, well the
1987 // activity that started it all doesn't want anything
1988 // special, so leave it all as-is.
1989 replyChainEnd = -1;
1990 }
1991 } else {
1992 // Reached the bottom of the task -- any reply chain
1993 // should be left as-is.
1994 replyChainEnd = -1;
1995 }
Dianne Hackbornae0a0a82011-12-07 14:03:01 -08001996
1997 } else if (target.resultTo != null && (below == null
1998 || below.task == target.task)) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07001999 // If this activity is sending a reply to a previous
2000 // activity, we can't do anything with it now until
2001 // we reach the start of the reply chain.
2002 // XXX note that we are assuming the result is always
2003 // to the previous activity, which is almost always
2004 // the case but we really shouldn't count on.
2005 if (replyChainEnd < 0) {
2006 replyChainEnd = targetI;
2007 }
2008
2009 } else if (taskTopI >= 0 && allowTaskReparenting
2010 && task.affinity != null
2011 && task.affinity.equals(target.taskAffinity)) {
2012 // We are inside of another task... if this activity has
2013 // an affinity for our task, then either remove it if we are
2014 // clearing or move it over to our task. Note that
2015 // we currently punt on the case where we are resetting a
2016 // task that is not at the top but who has activities above
2017 // with an affinity to it... this is really not a normal
2018 // case, and we will need to later pull that task to the front
2019 // and usually at that point we will do the reset and pick
2020 // up those remaining activities. (This only happens if
2021 // someone starts an activity in a new task from an activity
2022 // in a task that is not currently on top.)
2023 if (forceReset || finishOnTaskLaunch) {
2024 if (replyChainEnd < 0) {
2025 replyChainEnd = targetI;
2026 }
2027 ActivityRecord p = null;
Dianne Hackbornae0a0a82011-12-07 14:03:01 -08002028 if (DEBUG_TASKS) Slog.v(TAG, "Finishing task at index "
2029 + targetI + " to " + replyChainEnd);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002030 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002031 p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002032 if (p.finishing) {
2033 continue;
2034 }
2035 if (finishActivityLocked(p, srcPos,
2036 Activity.RESULT_CANCELED, null, "reset")) {
2037 taskTopI--;
2038 lastReparentPos--;
2039 replyChainEnd--;
2040 srcPos--;
2041 }
2042 }
2043 replyChainEnd = -1;
2044 } else {
2045 if (replyChainEnd < 0) {
2046 replyChainEnd = targetI;
2047 }
Dianne Hackbornae0a0a82011-12-07 14:03:01 -08002048 if (DEBUG_TASKS) Slog.v(TAG, "Reparenting task at index "
2049 + targetI + " to " + replyChainEnd);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002050 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002051 ActivityRecord p = mHistory.get(srcPos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002052 if (p.finishing) {
2053 continue;
2054 }
2055 if (lastReparentPos < 0) {
2056 lastReparentPos = taskTopI;
2057 taskTop = p;
2058 } else {
2059 lastReparentPos--;
2060 }
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07002061 if (DEBUG_ADD_REMOVE) {
2062 RuntimeException here = new RuntimeException("here");
2063 here.fillInStackTrace();
2064 Slog.i(TAG, "Removing and adding activity " + p + " to stack at "
2065 + lastReparentPos, here);
2066 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002067 mHistory.remove(srcPos);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002068 p.setTask(task, null, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002069 mHistory.add(lastReparentPos, p);
2070 if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
Dianne Hackbornae0a0a82011-12-07 14:03:01 -08002071 + " from " + srcPos + " to " + lastReparentPos
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002072 + " in to resetting task " + task);
Dianne Hackbornbe707852011-11-11 14:32:10 -08002073 mService.mWindowManager.moveAppToken(lastReparentPos, p.appToken);
2074 mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002075 if (VALIDATE_TOKENS) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08002076 validateAppTokensLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002077 }
2078 }
2079 replyChainEnd = -1;
2080
2081 // Now we've moved it in to place... but what if this is
2082 // a singleTop activity and we have put it on top of another
2083 // instance of the same activity? Then we drop the instance
2084 // below so it remains singleTop.
2085 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
2086 for (int j=lastReparentPos-1; j>=0; j--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002087 ActivityRecord p = mHistory.get(j);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002088 if (p.finishing) {
2089 continue;
2090 }
2091 if (p.intent.getComponent().equals(target.intent.getComponent())) {
2092 if (finishActivityLocked(p, j,
2093 Activity.RESULT_CANCELED, null, "replace")) {
2094 taskTopI--;
2095 lastReparentPos--;
2096 }
2097 }
2098 }
2099 }
2100 }
Dianne Hackbornae0a0a82011-12-07 14:03:01 -08002101
2102 } else if (below != null && below.task != target.task) {
2103 // We hit the botton of a task; the reply chain can't
2104 // pass through it.
2105 replyChainEnd = -1;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002106 }
2107
2108 target = below;
2109 targetI = i;
2110 }
2111
2112 return taskTop;
2113 }
2114
2115 /**
2116 * Perform clear operation as requested by
2117 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2118 * stack to the given task, then look for
2119 * an instance of that activity in the stack and, if found, finish all
2120 * activities on top of it and return the instance.
2121 *
2122 * @param newR Description of the new activity being started.
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002123 * @return Returns the old activity that should be continued to be used,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002124 * or null if none was found.
2125 */
2126 private final ActivityRecord performClearTaskLocked(int taskId,
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002127 ActivityRecord newR, int launchFlags) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002128 int i = mHistory.size();
2129
2130 // First find the requested task.
2131 while (i > 0) {
2132 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002133 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002134 if (r.task.taskId == taskId) {
2135 i++;
2136 break;
2137 }
2138 }
2139
2140 // Now clear it.
2141 while (i > 0) {
2142 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002143 ActivityRecord r = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002144 if (r.finishing) {
2145 continue;
2146 }
2147 if (r.task.taskId != taskId) {
2148 return null;
2149 }
2150 if (r.realActivity.equals(newR.realActivity)) {
2151 // Here it is! Now finish everything in front...
2152 ActivityRecord ret = r;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002153 while (i < (mHistory.size()-1)) {
2154 i++;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002155 r = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002156 if (r.task.taskId != taskId) {
2157 break;
2158 }
2159 if (r.finishing) {
2160 continue;
2161 }
2162 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2163 null, "clear")) {
2164 i--;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002165 }
2166 }
2167
2168 // Finally, if this is a normal launch mode (that is, not
2169 // expecting onNewIntent()), then we will finish the current
2170 // instance of the activity so a new fresh one can be started.
2171 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2172 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
2173 if (!ret.finishing) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08002174 int index = indexOfTokenLocked(ret.appToken);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002175 if (index >= 0) {
2176 finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
2177 null, "clear");
2178 }
2179 return null;
2180 }
2181 }
2182
2183 return ret;
2184 }
2185 }
2186
2187 return null;
2188 }
2189
2190 /**
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002191 * Completely remove all activities associated with an existing
2192 * task starting at a specified index.
2193 */
2194 private final void performClearTaskAtIndexLocked(int taskId, int i) {
Dianne Hackborneabd3282011-10-13 16:26:49 -07002195 while (i < mHistory.size()) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002196 ActivityRecord r = mHistory.get(i);
2197 if (r.task.taskId != taskId) {
2198 // Whoops hit the end.
2199 return;
2200 }
2201 if (r.finishing) {
2202 i++;
2203 continue;
2204 }
2205 if (!finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2206 null, "clear")) {
2207 i++;
2208 }
2209 }
2210 }
2211
2212 /**
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002213 * Completely remove all activities associated with an existing task.
2214 */
2215 private final void performClearTaskLocked(int taskId) {
2216 int i = mHistory.size();
2217
2218 // First find the requested task.
2219 while (i > 0) {
2220 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002221 ActivityRecord r = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002222 if (r.task.taskId == taskId) {
2223 i++;
2224 break;
2225 }
2226 }
2227
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002228 // Now find the start and clear it.
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002229 while (i > 0) {
2230 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002231 ActivityRecord r = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002232 if (r.finishing) {
2233 continue;
2234 }
2235 if (r.task.taskId != taskId) {
2236 // We hit the bottom. Now finish it all...
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002237 performClearTaskAtIndexLocked(taskId, i+1);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002238 return;
2239 }
2240 }
2241 }
2242
2243 /**
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002244 * Find the activity in the history stack within the given task. Returns
2245 * the index within the history at which it's found, or < 0 if not found.
2246 */
2247 private final int findActivityInHistoryLocked(ActivityRecord r, int task) {
2248 int i = mHistory.size();
2249 while (i > 0) {
2250 i--;
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002251 ActivityRecord candidate = mHistory.get(i);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002252 if (candidate.task.taskId != task) {
2253 break;
2254 }
2255 if (candidate.realActivity.equals(r.realActivity)) {
2256 return i;
2257 }
2258 }
2259
2260 return -1;
2261 }
2262
2263 /**
2264 * Reorder the history stack so that the activity at the given index is
2265 * brought to the front.
2266 */
2267 private final ActivityRecord moveActivityToFrontLocked(int where) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002268 ActivityRecord newTop = mHistory.remove(where);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002269 int top = mHistory.size();
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002270 ActivityRecord oldTop = mHistory.get(top-1);
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07002271 if (DEBUG_ADD_REMOVE) {
2272 RuntimeException here = new RuntimeException("here");
2273 here.fillInStackTrace();
2274 Slog.i(TAG, "Removing and adding activity " + newTop + " to stack at "
2275 + top, here);
2276 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002277 mHistory.add(top, newTop);
2278 oldTop.frontOfTask = false;
2279 newTop.frontOfTask = true;
2280 return newTop;
2281 }
2282
2283 final int startActivityLocked(IApplicationThread caller,
2284 Intent intent, String resolvedType,
2285 Uri[] grantedUriPermissions,
2286 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2287 String resultWho, int requestCode,
2288 int callingPid, int callingUid, boolean onlyIfNeeded,
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002289 boolean componentSpecified, ActivityRecord[] outActivity) {
Dianne Hackbornefb58102010-10-14 16:47:34 -07002290
2291 int err = START_SUCCESS;
2292
2293 ProcessRecord callerApp = null;
2294 if (caller != null) {
2295 callerApp = mService.getRecordForAppLocked(caller);
2296 if (callerApp != null) {
2297 callingPid = callerApp.pid;
2298 callingUid = callerApp.info.uid;
2299 } else {
2300 Slog.w(TAG, "Unable to find app for caller " + caller
2301 + " (pid=" + callingPid + ") when starting: "
2302 + intent.toString());
2303 err = START_PERMISSION_DENIED;
2304 }
2305 }
2306
2307 if (err == START_SUCCESS) {
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002308 Slog.i(TAG, "START {" + intent.toShortString(true, true, true) + "} from pid "
Dianne Hackbornefb58102010-10-14 16:47:34 -07002309 + (callerApp != null ? callerApp.pid : callingPid));
2310 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002311
2312 ActivityRecord sourceRecord = null;
2313 ActivityRecord resultRecord = null;
2314 if (resultTo != null) {
2315 int index = indexOfTokenLocked(resultTo);
2316 if (DEBUG_RESULTS) Slog.v(
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07002317 TAG, "Will send result to " + resultTo + " (index " + index + ")");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002318 if (index >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002319 sourceRecord = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002320 if (requestCode >= 0 && !sourceRecord.finishing) {
2321 resultRecord = sourceRecord;
2322 }
2323 }
2324 }
2325
2326 int launchFlags = intent.getFlags();
2327
2328 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2329 && sourceRecord != null) {
2330 // Transfer the result target from the source activity to the new
2331 // one being started, including any failures.
2332 if (requestCode >= 0) {
2333 return START_FORWARD_AND_REQUEST_CONFLICT;
2334 }
2335 resultRecord = sourceRecord.resultTo;
2336 resultWho = sourceRecord.resultWho;
2337 requestCode = sourceRecord.requestCode;
2338 sourceRecord.resultTo = null;
2339 if (resultRecord != null) {
2340 resultRecord.removeResultsLocked(
2341 sourceRecord, resultWho, requestCode);
2342 }
2343 }
2344
Dianne Hackbornefb58102010-10-14 16:47:34 -07002345 if (err == START_SUCCESS && intent.getComponent() == null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002346 // We couldn't find a class that can handle the given Intent.
2347 // That's the end of that!
2348 err = START_INTENT_NOT_RESOLVED;
2349 }
2350
2351 if (err == START_SUCCESS && aInfo == null) {
2352 // We couldn't find the specific class specified in the Intent.
2353 // Also the end of the line.
2354 err = START_CLASS_NOT_FOUND;
2355 }
2356
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002357 if (err != START_SUCCESS) {
2358 if (resultRecord != null) {
2359 sendActivityResultLocked(-1,
2360 resultRecord, resultWho, requestCode,
2361 Activity.RESULT_CANCELED, null);
2362 }
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002363 mDismissKeyguardOnNextActivity = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002364 return err;
2365 }
2366
2367 final int perm = mService.checkComponentPermission(aInfo.permission, callingPid,
Dianne Hackborn6c2c5fc2011-01-18 17:02:33 -08002368 callingUid, aInfo.applicationInfo.uid, aInfo.exported);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002369 if (perm != PackageManager.PERMISSION_GRANTED) {
2370 if (resultRecord != null) {
2371 sendActivityResultLocked(-1,
2372 resultRecord, resultWho, requestCode,
2373 Activity.RESULT_CANCELED, null);
2374 }
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002375 mDismissKeyguardOnNextActivity = false;
Dianne Hackborn6c2c5fc2011-01-18 17:02:33 -08002376 String msg;
2377 if (!aInfo.exported) {
2378 msg = "Permission Denial: starting " + intent.toString()
2379 + " from " + callerApp + " (pid=" + callingPid
2380 + ", uid=" + callingUid + ")"
2381 + " not exported from uid " + aInfo.applicationInfo.uid;
2382 } else {
2383 msg = "Permission Denial: starting " + intent.toString()
2384 + " from " + callerApp + " (pid=" + callingPid
2385 + ", uid=" + callingUid + ")"
2386 + " requires " + aInfo.permission;
2387 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002388 Slog.w(TAG, msg);
2389 throw new SecurityException(msg);
2390 }
2391
2392 if (mMainStack) {
2393 if (mService.mController != null) {
2394 boolean abort = false;
2395 try {
2396 // The Intent we give to the watcher has the extra data
2397 // stripped off, since it can contain private information.
2398 Intent watchIntent = intent.cloneFilter();
2399 abort = !mService.mController.activityStarting(watchIntent,
2400 aInfo.applicationInfo.packageName);
2401 } catch (RemoteException e) {
2402 mService.mController = null;
2403 }
2404
2405 if (abort) {
2406 if (resultRecord != null) {
2407 sendActivityResultLocked(-1,
2408 resultRecord, resultWho, requestCode,
2409 Activity.RESULT_CANCELED, null);
2410 }
2411 // We pretend to the caller that it was really started, but
2412 // they will just get a cancel result.
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002413 mDismissKeyguardOnNextActivity = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002414 return START_SUCCESS;
2415 }
2416 }
2417 }
Amith Yamasani742a6712011-05-04 14:49:28 -07002418
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002419 ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
2420 intent, resolvedType, aInfo, mService.mConfiguration,
2421 resultRecord, resultWho, requestCode, componentSpecified);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002422 if (outActivity != null) {
2423 outActivity[0] = r;
2424 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002425
2426 if (mMainStack) {
2427 if (mResumedActivity == null
2428 || mResumedActivity.info.applicationInfo.uid != callingUid) {
2429 if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
2430 PendingActivityLaunch pal = new PendingActivityLaunch();
2431 pal.r = r;
2432 pal.sourceRecord = sourceRecord;
2433 pal.grantedUriPermissions = grantedUriPermissions;
2434 pal.grantedMode = grantedMode;
2435 pal.onlyIfNeeded = onlyIfNeeded;
2436 mService.mPendingActivityLaunches.add(pal);
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002437 mDismissKeyguardOnNextActivity = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002438 return START_SWITCHES_CANCELED;
2439 }
2440 }
2441
2442 if (mService.mDidAppSwitch) {
2443 // This is the second allowed switch since we stopped switches,
2444 // so now just generally allow switches. Use case: user presses
2445 // home (switches disabled, switch to home, mDidAppSwitch now true);
2446 // user taps a home icon (coming from home so allowed, we hit here
2447 // and now allow anyone to switch again).
2448 mService.mAppSwitchesAllowedTime = 0;
2449 } else {
2450 mService.mDidAppSwitch = true;
2451 }
2452
2453 mService.doPendingActivityLaunchesLocked(false);
2454 }
2455
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002456 err = startActivityUncheckedLocked(r, sourceRecord,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002457 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
Dianne Hackborncbb722e2012-02-07 18:33:49 -08002458 if (mDismissKeyguardOnNextActivity && mPausingActivities.size() == 0) {
Dianne Hackborn90c52de2011-09-23 12:57:44 -07002459 // Someone asked to have the keyguard dismissed on the next
2460 // activity start, but we are not actually doing an activity
2461 // switch... just dismiss the keyguard now, because we
2462 // probably want to see whatever is behind it.
2463 mDismissKeyguardOnNextActivity = false;
2464 mService.mWindowManager.dismissKeyguard();
2465 }
2466 return err;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002467 }
2468
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002469 final void moveHomeToFrontFromLaunchLocked(int launchFlags) {
2470 if ((launchFlags &
2471 (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
2472 == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
2473 // Caller wants to appear on home activity, so before starting
2474 // their own activity we will bring home to the front.
2475 moveHomeToFrontLocked();
2476 }
2477 }
2478
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002479 final int startActivityUncheckedLocked(ActivityRecord r,
2480 ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
2481 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
2482 final Intent intent = r.intent;
2483 final int callingUid = r.launchedFromUid;
Amith Yamasani742a6712011-05-04 14:49:28 -07002484 final int userId = r.userId;
2485
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002486 int launchFlags = intent.getFlags();
2487
2488 // We'll invoke onUserLeaving before onPause only if the launching
2489 // activity did not explicitly state that this is an automated launch.
2490 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
2491 if (DEBUG_USER_LEAVING) Slog.v(TAG,
2492 "startActivity() => mUserLeaving=" + mUserLeaving);
2493
2494 // If the caller has asked not to resume at this point, we make note
2495 // of this in the record so that we can skip it when trying to find
2496 // the top running activity.
2497 if (!doResume) {
2498 r.delayedResume = true;
2499 }
2500
2501 ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
2502 != 0 ? r : null;
2503
2504 // If the onlyIfNeeded flag is set, then we can do this if the activity
2505 // being launched is the same as the one making the call... or, as
2506 // a special case, if we do not know the caller then we count the
2507 // current top activity as the caller.
2508 if (onlyIfNeeded) {
2509 ActivityRecord checkedCaller = sourceRecord;
2510 if (checkedCaller == null) {
2511 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
2512 }
2513 if (!checkedCaller.realActivity.equals(r.realActivity)) {
2514 // Caller is not the same as launcher, so always needed.
2515 onlyIfNeeded = false;
2516 }
2517 }
2518
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002519 if (sourceRecord == null) {
2520 // This activity is not being started from another... in this
2521 // case we -always- start a new task.
2522 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
2523 Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
2524 + intent);
2525 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2526 }
2527 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2528 // The original activity who is starting us is running as a single
2529 // instance... this new activity it is starting must go on its
2530 // own task.
2531 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2532 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
2533 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
2534 // The activity being started is a single instance... it always
2535 // gets launched into its own task.
2536 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2537 }
2538
2539 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
2540 // For whatever reason this activity is being launched into a new
2541 // task... yet the caller has requested a result back. Well, that
2542 // is pretty messed up, so instead immediately send back a cancel
2543 // and let the new task continue launched as normal without a
2544 // dependency on its originator.
2545 Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
2546 sendActivityResultLocked(-1,
2547 r.resultTo, r.resultWho, r.requestCode,
2548 Activity.RESULT_CANCELED, null);
2549 r.resultTo = null;
2550 }
2551
2552 boolean addingToTask = false;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002553 TaskRecord reuseTask = null;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002554 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
2555 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
2556 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
2557 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2558 // If bring to front is requested, and no result is requested, and
2559 // we can find a task that was started with this same
2560 // component, then instead of launching bring that one to the front.
2561 if (r.resultTo == null) {
2562 // See if there is a task to bring to the front. If this is
2563 // a SINGLE_INSTANCE activity, there can be one and only one
2564 // instance of it in the history, and it is always in its own
2565 // unique task, so we do a special search.
2566 ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
2567 ? findTaskLocked(intent, r.info)
2568 : findActivityLocked(intent, r.info);
2569 if (taskTop != null) {
2570 if (taskTop.task.intent == null) {
2571 // This task was started because of movement of
2572 // the activity based on affinity... now that we
2573 // are actually launching it, we can assign the
2574 // base intent.
2575 taskTop.task.setIntent(intent, r.info);
2576 }
2577 // If the target task is not in the front, then we need
2578 // to bring it to the front... except... well, with
2579 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
2580 // to have the same behavior as if a new instance was
2581 // being started, which means not bringing it to the front
2582 // if the caller is not itself in the front.
2583 ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
Jean-Baptiste Queru66a5d692010-10-25 17:27:16 -07002584 if (curTop != null && curTop.task != taskTop.task) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002585 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
2586 boolean callerAtFront = sourceRecord == null
2587 || curTop.task == sourceRecord.task;
2588 if (callerAtFront) {
2589 // We really do want to push this one into the
2590 // user's face, right now.
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002591 moveHomeToFrontFromLaunchLocked(launchFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002592 moveTaskToFrontLocked(taskTop.task, r);
2593 }
2594 }
2595 // If the caller has requested that the target task be
2596 // reset, then do so.
2597 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2598 taskTop = resetTaskIfNeededLocked(taskTop, r);
2599 }
2600 if (onlyIfNeeded) {
2601 // We don't need to start a new activity, and
2602 // the client said not to do anything if that
2603 // is the case, so this is it! And for paranoia, make
2604 // sure we have correctly resumed the top activity.
2605 if (doResume) {
2606 resumeTopActivityLocked(null);
2607 }
2608 return START_RETURN_INTENT_TO_CALLER;
2609 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002610 if ((launchFlags &
2611 (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
2612 == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
2613 // The caller has requested to completely replace any
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002614 // existing task with its new activity. Well that should
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002615 // not be too hard...
2616 reuseTask = taskTop.task;
2617 performClearTaskLocked(taskTop.task.taskId);
2618 reuseTask.setIntent(r.intent, r.info);
2619 } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002620 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
2621 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
2622 // In this situation we want to remove all activities
2623 // from the task up to the one being started. In most
2624 // cases this means we are resetting the task to its
2625 // initial state.
2626 ActivityRecord top = performClearTaskLocked(
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002627 taskTop.task.taskId, r, launchFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002628 if (top != null) {
2629 if (top.frontOfTask) {
2630 // Activity aliases may mean we use different
2631 // intents for the top activity, so make sure
2632 // the task now has the identity of the new
2633 // intent.
2634 top.task.setIntent(r.intent, r.info);
2635 }
2636 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002637 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002638 } else {
2639 // A special case: we need to
2640 // start the activity because it is not currently
2641 // running, and the caller has asked to clear the
2642 // current task to have this activity at the top.
2643 addingToTask = true;
2644 // Now pretend like this activity is being started
2645 // by the top of its task, so it is put in the
2646 // right place.
2647 sourceRecord = taskTop;
2648 }
2649 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
2650 // In this case the top activity on the task is the
2651 // same as the one being launched, so we take that
2652 // as a request to bring the task to the foreground.
2653 // If the top activity in the task is the root
2654 // activity, deliver this new intent to it if it
2655 // desires.
2656 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
2657 && taskTop.realActivity.equals(r.realActivity)) {
2658 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
2659 if (taskTop.frontOfTask) {
2660 taskTop.task.setIntent(r.intent, r.info);
2661 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002662 taskTop.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002663 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
2664 // In this case we are launching the root activity
2665 // of the task, but with a different intent. We
2666 // should start a new instance on top.
2667 addingToTask = true;
2668 sourceRecord = taskTop;
2669 }
2670 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
2671 // In this case an activity is being launched in to an
2672 // existing task, without resetting that task. This
2673 // is typically the situation of launching an activity
2674 // from a notification or shortcut. We want to place
2675 // the new activity on top of the current task.
2676 addingToTask = true;
2677 sourceRecord = taskTop;
2678 } else if (!taskTop.task.rootWasReset) {
2679 // In this case we are launching in to an existing task
2680 // that has not yet been started from its front door.
2681 // The current task has been brought to the front.
2682 // Ideally, we'd probably like to place this new task
2683 // at the bottom of its stack, but that's a little hard
2684 // to do with the current organization of the code so
2685 // for now we'll just drop it.
2686 taskTop.task.setIntent(r.intent, r.info);
2687 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002688 if (!addingToTask && reuseTask == null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002689 // We didn't do anything... but it was needed (a.k.a., client
2690 // don't use that intent!) And for paranoia, make
2691 // sure we have correctly resumed the top activity.
2692 if (doResume) {
2693 resumeTopActivityLocked(null);
2694 }
2695 return START_TASK_TO_FRONT;
2696 }
2697 }
2698 }
2699 }
2700
2701 //String uri = r.intent.toURI();
2702 //Intent intent2 = new Intent(uri);
2703 //Slog.i(TAG, "Given intent: " + r.intent);
2704 //Slog.i(TAG, "URI is: " + uri);
2705 //Slog.i(TAG, "To intent: " + intent2);
2706
2707 if (r.packageName != null) {
2708 // If the activity being launched is the same as the one currently
2709 // at the top, then we need to check if it should only be launched
2710 // once.
2711 ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
2712 if (top != null && r.resultTo == null) {
Amith Yamasani742a6712011-05-04 14:49:28 -07002713 if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002714 if (top.app != null && top.app.thread != null) {
2715 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
2716 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
2717 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
2718 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
2719 // For paranoia, make sure we have correctly
2720 // resumed the top activity.
2721 if (doResume) {
2722 resumeTopActivityLocked(null);
2723 }
2724 if (onlyIfNeeded) {
2725 // We don't need to start a new activity, and
2726 // the client said not to do anything if that
2727 // is the case, so this is it!
2728 return START_RETURN_INTENT_TO_CALLER;
2729 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002730 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002731 return START_DELIVERED_TO_TOP;
2732 }
2733 }
2734 }
2735 }
2736
2737 } else {
2738 if (r.resultTo != null) {
2739 sendActivityResultLocked(-1,
2740 r.resultTo, r.resultWho, r.requestCode,
2741 Activity.RESULT_CANCELED, null);
2742 }
2743 return START_CLASS_NOT_FOUND;
2744 }
2745
2746 boolean newTask = false;
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002747 boolean keepCurTransition = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002748
2749 // Should this be considered a new task?
2750 if (r.resultTo == null && !addingToTask
2751 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002752 if (reuseTask == null) {
2753 // todo: should do better management of integers.
2754 mService.mCurTask++;
2755 if (mService.mCurTask <= 0) {
2756 mService.mCurTask = 1;
2757 }
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002758 r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002759 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2760 + " in new task " + r.task);
2761 } else {
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002762 r.setTask(reuseTask, reuseTask, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002763 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002764 newTask = true;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002765 moveHomeToFrontFromLaunchLocked(launchFlags);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002766
2767 } else if (sourceRecord != null) {
2768 if (!addingToTask &&
2769 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
2770 // In this case, we are adding the activity to an existing
2771 // task, but the caller has asked to clear that task if the
2772 // activity is already running.
2773 ActivityRecord top = performClearTaskLocked(
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002774 sourceRecord.task.taskId, r, launchFlags);
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002775 keepCurTransition = true;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002776 if (top != null) {
2777 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002778 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002779 // For paranoia, make sure we have correctly
2780 // resumed the top activity.
2781 if (doResume) {
2782 resumeTopActivityLocked(null);
2783 }
2784 return START_DELIVERED_TO_TOP;
2785 }
2786 } else if (!addingToTask &&
2787 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
2788 // In this case, we are launching an activity in our own task
2789 // that may already be running somewhere in the history, and
2790 // we want to shuffle it to the front of the stack if so.
2791 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
2792 if (where >= 0) {
2793 ActivityRecord top = moveActivityToFrontLocked(where);
2794 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
Dianne Hackborn39792d22010-08-19 18:01:52 -07002795 top.deliverNewIntentLocked(callingUid, r.intent);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002796 if (doResume) {
2797 resumeTopActivityLocked(null);
2798 }
2799 return START_DELIVERED_TO_TOP;
2800 }
2801 }
2802 // An existing activity is starting this new activity, so we want
2803 // to keep the new one in the same task as the one that is starting
2804 // it.
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002805 r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002806 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2807 + " in existing task " + r.task);
2808
2809 } else {
2810 // This not being started from an existing activity, and not part
2811 // of a new task... just put it in the top task, though these days
2812 // this case should never happen.
2813 final int N = mHistory.size();
2814 ActivityRecord prev =
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07002815 N > 0 ? mHistory.get(N-1) : null;
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002816 r.setTask(prev != null
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002817 ? prev.task
Dianne Hackbornf26fd992011-04-08 18:14:09 -07002818 : new TaskRecord(mService.mCurTask, r.info, intent), null, true);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002819 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
2820 + " in new guessed " + r.task);
2821 }
Dianne Hackborn39792d22010-08-19 18:01:52 -07002822
2823 if (grantedUriPermissions != null && callingUid > 0) {
2824 for (int i=0; i<grantedUriPermissions.length; i++) {
2825 mService.grantUriPermissionLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002826 grantedUriPermissions[i], grantedMode, r.getUriPermissionsLocked());
Dianne Hackborn39792d22010-08-19 18:01:52 -07002827 }
2828 }
2829
2830 mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07002831 intent, r.getUriPermissionsLocked());
Dianne Hackborn39792d22010-08-19 18:01:52 -07002832
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002833 if (newTask) {
2834 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
2835 }
2836 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08002837 startActivityLocked(r, newTask, doResume, keepCurTransition);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002838 return START_SUCCESS;
2839 }
2840
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002841 ActivityInfo resolveActivity(Intent intent, String resolvedType, boolean debug,
2842 String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002843 // Collect information about the target of the Intent.
2844 ActivityInfo aInfo;
2845 try {
2846 ResolveInfo rInfo =
2847 AppGlobals.getPackageManager().resolveIntent(
2848 intent, resolvedType,
2849 PackageManager.MATCH_DEFAULT_ONLY
2850 | ActivityManagerService.STOCK_PM_FLAGS);
2851 aInfo = rInfo != null ? rInfo.activityInfo : null;
2852 } catch (RemoteException e) {
2853 aInfo = null;
2854 }
2855
2856 if (aInfo != null) {
2857 // Store the found target back into the intent, because now that
2858 // we have it we never want to do this again. For example, if the
2859 // user navigates back to this point in the history, we should
2860 // always restart the exact same activity.
2861 intent.setComponent(new ComponentName(
2862 aInfo.applicationInfo.packageName, aInfo.name));
2863
2864 // Don't debug things in the system process
2865 if (debug) {
2866 if (!aInfo.processName.equals("system")) {
2867 mService.setDebugApp(aInfo.processName, true, false);
2868 }
2869 }
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002870
2871 if (profileFile != null) {
2872 if (!aInfo.processName.equals("system")) {
2873 mService.setProfileApp(aInfo.applicationInfo, aInfo.processName,
2874 profileFile, profileFd, autoStopProfiler);
2875 }
2876 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002877 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002878 return aInfo;
2879 }
2880
2881 final int startActivityMayWait(IApplicationThread caller, int callingUid,
2882 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
2883 int grantedMode, IBinder resultTo,
2884 String resultWho, int requestCode, boolean onlyIfNeeded,
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002885 boolean debug, String profileFile, ParcelFileDescriptor profileFd,
Amith Yamasani742a6712011-05-04 14:49:28 -07002886 boolean autoStopProfiler,
2887 WaitResult outResult, Configuration config, int userId) {
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002888 // Refuse possible leaked file descriptors
2889 if (intent != null && intent.hasFileDescriptors()) {
2890 throw new IllegalArgumentException("File descriptors passed in Intent");
2891 }
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002892 boolean componentSpecified = intent.getComponent() != null;
2893
2894 // Don't modify the client's object!
2895 intent = new Intent(intent);
2896
2897 // Collect information about the target of the Intent.
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07002898 ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug,
2899 profileFile, profileFd, autoStopProfiler);
Amith Yamasani742a6712011-05-04 14:49:28 -07002900 aInfo = mService.getActivityInfoForUser(aInfo, userId);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002901
2902 synchronized (mService) {
2903 int callingPid;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002904 if (callingUid >= 0) {
2905 callingPid = -1;
2906 } else if (caller == null) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002907 callingPid = Binder.getCallingPid();
2908 callingUid = Binder.getCallingUid();
2909 } else {
2910 callingPid = callingUid = -1;
2911 }
2912
2913 mConfigWillChange = config != null
2914 && mService.mConfiguration.diff(config) != 0;
2915 if (DEBUG_CONFIGURATION) Slog.v(TAG,
2916 "Starting activity when config will change = " + mConfigWillChange);
2917
2918 final long origId = Binder.clearCallingIdentity();
2919
2920 if (mMainStack && aInfo != null &&
Dianne Hackborn54e570f2010-10-04 18:32:32 -07002921 (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002922 // This may be a heavy-weight process! Check to see if we already
2923 // have another, different heavy-weight process running.
2924 if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
2925 if (mService.mHeavyWeightProcess != null &&
2926 (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
2927 !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
2928 int realCallingPid = callingPid;
2929 int realCallingUid = callingUid;
2930 if (caller != null) {
2931 ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
2932 if (callerApp != null) {
2933 realCallingPid = callerApp.pid;
2934 realCallingUid = callerApp.info.uid;
2935 } else {
2936 Slog.w(TAG, "Unable to find app for caller " + caller
2937 + " (pid=" + realCallingPid + ") when starting: "
2938 + intent.toString());
2939 return START_PERMISSION_DENIED;
2940 }
2941 }
2942
2943 IIntentSender target = mService.getIntentSenderLocked(
2944 IActivityManager.INTENT_SENDER_ACTIVITY, "android",
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002945 realCallingUid, null, null, 0, new Intent[] { intent },
2946 new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002947 | PendingIntent.FLAG_ONE_SHOT);
2948
2949 Intent newIntent = new Intent();
2950 if (requestCode >= 0) {
2951 // Caller is requesting a result.
2952 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
2953 }
2954 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
2955 new IntentSender(target));
2956 if (mService.mHeavyWeightProcess.activities.size() > 0) {
2957 ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
2958 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
2959 hist.packageName);
2960 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
2961 hist.task.taskId);
2962 }
2963 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
2964 aInfo.packageName);
2965 newIntent.setFlags(intent.getFlags());
2966 newIntent.setClassName("android",
2967 HeavyWeightSwitcherActivity.class.getName());
2968 intent = newIntent;
2969 resolvedType = null;
2970 caller = null;
2971 callingUid = Binder.getCallingUid();
2972 callingPid = Binder.getCallingPid();
2973 componentSpecified = true;
2974 try {
2975 ResolveInfo rInfo =
2976 AppGlobals.getPackageManager().resolveIntent(
2977 intent, null,
2978 PackageManager.MATCH_DEFAULT_ONLY
2979 | ActivityManagerService.STOCK_PM_FLAGS);
2980 aInfo = rInfo != null ? rInfo.activityInfo : null;
Amith Yamasani742a6712011-05-04 14:49:28 -07002981 aInfo = mService.getActivityInfoForUser(aInfo, userId);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002982 } catch (RemoteException e) {
2983 aInfo = null;
2984 }
2985 }
2986 }
2987 }
2988
2989 int res = startActivityLocked(caller, intent, resolvedType,
2990 grantedUriPermissions, grantedMode, aInfo,
2991 resultTo, resultWho, requestCode, callingPid, callingUid,
Dianne Hackborn621e17d2010-11-22 15:59:56 -08002992 onlyIfNeeded, componentSpecified, null);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07002993
2994 if (mConfigWillChange && mMainStack) {
2995 // If the caller also wants to switch to a new configuration,
2996 // do so now. This allows a clean switch, as we are waiting
2997 // for the current activity to pause (so we will not destroy
2998 // it), and have not yet started the next activity.
2999 mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
3000 "updateConfiguration()");
3001 mConfigWillChange = false;
3002 if (DEBUG_CONFIGURATION) Slog.v(TAG,
3003 "Updating to new configuration after starting activity.");
Dianne Hackborn813075a62011-11-14 17:45:19 -08003004 mService.updateConfigurationLocked(config, null, false, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003005 }
3006
3007 Binder.restoreCallingIdentity(origId);
3008
3009 if (outResult != null) {
3010 outResult.result = res;
3011 if (res == IActivityManager.START_SUCCESS) {
3012 mWaitingActivityLaunched.add(outResult);
3013 do {
3014 try {
Dianne Hackbornba0492d2010-10-12 19:01:46 -07003015 mService.wait();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003016 } catch (InterruptedException e) {
3017 }
3018 } while (!outResult.timeout && outResult.who == null);
3019 } else if (res == IActivityManager.START_TASK_TO_FRONT) {
3020 ActivityRecord r = this.topRunningActivityLocked(null);
3021 if (r.nowVisible) {
3022 outResult.timeout = false;
3023 outResult.who = new ComponentName(r.info.packageName, r.info.name);
3024 outResult.totalTime = 0;
3025 outResult.thisTime = 0;
3026 } else {
3027 outResult.thisTime = SystemClock.uptimeMillis();
3028 mWaitingActivityVisible.add(outResult);
3029 do {
3030 try {
Dianne Hackbornba0492d2010-10-12 19:01:46 -07003031 mService.wait();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003032 } catch (InterruptedException e) {
3033 }
3034 } while (!outResult.timeout && outResult.who == null);
3035 }
3036 }
3037 }
3038
3039 return res;
3040 }
3041 }
3042
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003043 final int startActivities(IApplicationThread caller, int callingUid,
Amith Yamasani742a6712011-05-04 14:49:28 -07003044 Intent[] intents,
3045 String[] resolvedTypes, IBinder resultTo, int userId) {
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003046 if (intents == null) {
3047 throw new NullPointerException("intents is null");
3048 }
3049 if (resolvedTypes == null) {
3050 throw new NullPointerException("resolvedTypes is null");
3051 }
3052 if (intents.length != resolvedTypes.length) {
3053 throw new IllegalArgumentException("intents are length different than resolvedTypes");
3054 }
3055
3056 ActivityRecord[] outActivity = new ActivityRecord[1];
3057
3058 int callingPid;
3059 if (callingUid >= 0) {
3060 callingPid = -1;
3061 } else if (caller == null) {
3062 callingPid = Binder.getCallingPid();
3063 callingUid = Binder.getCallingUid();
3064 } else {
3065 callingPid = callingUid = -1;
3066 }
3067 final long origId = Binder.clearCallingIdentity();
3068 try {
3069 synchronized (mService) {
3070
3071 for (int i=0; i<intents.length; i++) {
3072 Intent intent = intents[i];
3073 if (intent == null) {
3074 continue;
3075 }
3076
3077 // Refuse possible leaked file descriptors
3078 if (intent != null && intent.hasFileDescriptors()) {
3079 throw new IllegalArgumentException("File descriptors passed in Intent");
3080 }
3081
3082 boolean componentSpecified = intent.getComponent() != null;
3083
3084 // Don't modify the client's object!
3085 intent = new Intent(intent);
3086
3087 // Collect information about the target of the Intent.
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003088 ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], false,
3089 null, null, false);
Amith Yamasani742a6712011-05-04 14:49:28 -07003090 // TODO: New, check if this is correct
3091 aInfo = mService.getActivityInfoForUser(aInfo, userId);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003092
3093 if (mMainStack && aInfo != null && (aInfo.applicationInfo.flags
3094 & ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
3095 throw new IllegalArgumentException(
3096 "FLAG_CANT_SAVE_STATE not supported here");
3097 }
3098
3099 int res = startActivityLocked(caller, intent, resolvedTypes[i],
3100 null, 0, aInfo, resultTo, null, -1, callingPid, callingUid,
3101 false, componentSpecified, outActivity);
3102 if (res < 0) {
3103 return res;
3104 }
3105
Dianne Hackbornbe707852011-11-11 14:32:10 -08003106 resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003107 }
3108 }
3109 } finally {
3110 Binder.restoreCallingIdentity(origId);
3111 }
3112
3113 return IActivityManager.START_SUCCESS;
3114 }
3115
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003116 void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r,
3117 long thisTime, long totalTime) {
3118 for (int i=mWaitingActivityLaunched.size()-1; i>=0; i--) {
3119 WaitResult w = mWaitingActivityLaunched.get(i);
3120 w.timeout = timeout;
3121 if (r != null) {
3122 w.who = new ComponentName(r.info.packageName, r.info.name);
3123 }
3124 w.thisTime = thisTime;
3125 w.totalTime = totalTime;
3126 }
3127 mService.notifyAll();
3128 }
Dianne Hackborncbb722e2012-02-07 18:33:49 -08003129
3130 void reportActivityDrawnLocked(ActivityRecord r) {
3131 if (mResumedActivity == r) {
3132 // Once the resumed activity has been drawn, we can stop
3133 // pausing input on all other activities.
3134 for (int i=mInputPausedActivities.size()-1; i>=0; i--) {
3135 mInputPausedActivities.get(i).resumeKeyDispatchingLocked();
3136 }
3137 mInputPausedActivities.clear();
3138 }
3139 }
3140
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003141 void reportActivityVisibleLocked(ActivityRecord r) {
3142 for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
3143 WaitResult w = mWaitingActivityVisible.get(i);
3144 w.timeout = false;
3145 if (r != null) {
3146 w.who = new ComponentName(r.info.packageName, r.info.name);
3147 }
3148 w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
3149 w.thisTime = w.totalTime;
3150 }
3151 mService.notifyAll();
Dianne Hackborn90c52de2011-09-23 12:57:44 -07003152
3153 if (mDismissKeyguardOnNextActivity) {
3154 mDismissKeyguardOnNextActivity = false;
3155 mService.mWindowManager.dismissKeyguard();
3156 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003157 }
3158
3159 void sendActivityResultLocked(int callingUid, ActivityRecord r,
3160 String resultWho, int requestCode, int resultCode, Intent data) {
3161
3162 if (callingUid > 0) {
3163 mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
Dianne Hackborn7e269642010-08-25 19:50:20 -07003164 data, r.getUriPermissionsLocked());
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003165 }
3166
3167 if (DEBUG_RESULTS) Slog.v(TAG, "Send activity result to " + r
3168 + " : who=" + resultWho + " req=" + requestCode
3169 + " res=" + resultCode + " data=" + data);
3170 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3171 try {
3172 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3173 list.add(new ResultInfo(resultWho, requestCode,
3174 resultCode, data));
Dianne Hackbornbe707852011-11-11 14:32:10 -08003175 r.app.thread.scheduleSendResult(r.appToken, list);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003176 return;
3177 } catch (Exception e) {
3178 Slog.w(TAG, "Exception thrown sending result to " + r, e);
3179 }
3180 }
3181
3182 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3183 }
3184
3185 private final void stopActivityLocked(ActivityRecord r) {
3186 if (DEBUG_SWITCH) Slog.d(TAG, "Stopping: " + r);
3187 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3188 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3189 if (!r.finishing) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08003190 requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003191 "no-history");
3192 }
3193 } else if (r.app != null && r.app.thread != null) {
3194 if (mMainStack) {
3195 if (mService.mFocusedActivity == r) {
3196 mService.setFocusedActivityLocked(topRunningActivityLocked(null));
3197 }
3198 }
Dianne Hackborncbb722e2012-02-07 18:33:49 -08003199 if (mInputPausedActivities.remove(r)) {
3200 r.resumeKeyDispatchingLocked();
3201 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003202 try {
3203 r.stopped = false;
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003204 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
3205 + " (stop requested)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003206 r.state = ActivityState.STOPPING;
3207 if (DEBUG_VISBILITY) Slog.v(
3208 TAG, "Stopping visible=" + r.visible + " for " + r);
3209 if (!r.visible) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08003210 mService.mWindowManager.setAppVisibility(r.appToken, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003211 }
Dianne Hackbornbe707852011-11-11 14:32:10 -08003212 r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003213 if (mService.isSleeping()) {
3214 r.setSleeping(true);
3215 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003216 } catch (Exception e) {
3217 // Maybe just ignore exceptions here... if the process
3218 // has crashed, our death notification will clean things
3219 // up.
3220 Slog.w(TAG, "Exception thrown during pause", e);
3221 // Just in case, assume it to be stopped.
3222 r.stopped = true;
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003223 if (DEBUG_STATES) Slog.v(TAG, "Stop failed; moving to STOPPED: " + r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003224 r.state = ActivityState.STOPPED;
3225 if (r.configDestroy) {
Dianne Hackborn28695e02011-11-02 21:59:51 -07003226 destroyActivityLocked(r, true, false, "stop-except");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003227 }
3228 }
3229 }
3230 }
3231
3232 final ArrayList<ActivityRecord> processStoppingActivitiesLocked(
3233 boolean remove) {
3234 int N = mStoppingActivities.size();
3235 if (N <= 0) return null;
3236
3237 ArrayList<ActivityRecord> stops = null;
3238
3239 final boolean nowVisible = mResumedActivity != null
3240 && mResumedActivity.nowVisible
3241 && !mResumedActivity.waitingVisible;
3242 for (int i=0; i<N; i++) {
3243 ActivityRecord s = mStoppingActivities.get(i);
3244 if (localLOGV) Slog.v(TAG, "Stopping " + s + ": nowVisible="
3245 + nowVisible + " waitingVisible=" + s.waitingVisible
3246 + " finishing=" + s.finishing);
3247 if (s.waitingVisible && nowVisible) {
3248 mWaitingVisibleActivities.remove(s);
3249 s.waitingVisible = false;
3250 if (s.finishing) {
3251 // If this activity is finishing, it is sitting on top of
3252 // everyone else but we now know it is no longer needed...
3253 // so get rid of it. Otherwise, we need to go through the
3254 // normal flow and hide it once we determine that it is
3255 // hidden by the activities in front of it.
3256 if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
Dianne Hackbornbe707852011-11-11 14:32:10 -08003257 mService.mWindowManager.setAppVisibility(s.appToken, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003258 }
3259 }
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003260 if ((!s.waitingVisible || mService.isSleeping()) && remove) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003261 if (localLOGV) Slog.v(TAG, "Ready to stop: " + s);
3262 if (stops == null) {
3263 stops = new ArrayList<ActivityRecord>();
3264 }
3265 stops.add(s);
3266 mStoppingActivities.remove(i);
3267 N--;
3268 i--;
3269 }
3270 }
3271
3272 return stops;
3273 }
3274
Dianne Hackborn80a7ac12011-09-22 18:32:52 -07003275 final void scheduleIdleLocked() {
3276 Message msg = Message.obtain();
3277 msg.what = IDLE_NOW_MSG;
3278 mHandler.sendMessage(msg);
3279 }
3280
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003281 final ActivityRecord activityIdleInternal(IBinder token, boolean fromTimeout,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003282 Configuration config) {
3283 if (localLOGV) Slog.v(TAG, "Activity idle: " + token);
3284
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003285 ActivityRecord res = null;
3286
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003287 ArrayList<ActivityRecord> stops = null;
3288 ArrayList<ActivityRecord> finishes = null;
3289 ArrayList<ActivityRecord> thumbnails = null;
3290 int NS = 0;
3291 int NF = 0;
3292 int NT = 0;
3293 IApplicationThread sendThumbnail = null;
3294 boolean booting = false;
3295 boolean enableScreen = false;
3296
3297 synchronized (mService) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08003298 ActivityRecord r = ActivityRecord.forToken(token);
3299 if (r != null) {
3300 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003301 }
3302
3303 // Get the activity record.
Dianne Hackbornbe707852011-11-11 14:32:10 -08003304 int index = indexOfActivityLocked(r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003305 if (index >= 0) {
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003306 res = r;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003307
3308 if (fromTimeout) {
3309 reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
3310 }
3311
3312 // This is a hack to semi-deal with a race condition
3313 // in the client where it can be constructed with a
3314 // newer configuration from when we asked it to launch.
3315 // We'll update with whatever configuration it now says
3316 // it used to launch.
3317 if (config != null) {
3318 r.configuration = config;
3319 }
3320
3321 // No longer need to keep the device awake.
3322 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
3323 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
3324 mLaunchingActivity.release();
3325 }
3326
3327 // We are now idle. If someone is waiting for a thumbnail from
3328 // us, we can now deliver.
3329 r.idle = true;
3330 mService.scheduleAppGcsLocked();
3331 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
3332 sendThumbnail = r.app.thread;
3333 r.thumbnailNeeded = false;
3334 }
3335
3336 // If this activity is fullscreen, set up to hide those under it.
3337
3338 if (DEBUG_VISBILITY) Slog.v(TAG, "Idle activity for " + r);
3339 ensureActivitiesVisibleLocked(null, 0);
3340
3341 //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
3342 if (mMainStack) {
Dianne Hackborn29aae6f2011-08-18 18:30:09 -07003343 if (!mService.mBooted) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003344 mService.mBooted = true;
3345 enableScreen = true;
3346 }
3347 }
3348
3349 } else if (fromTimeout) {
3350 reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
3351 }
3352
3353 // Atomically retrieve all of the other things to do.
3354 stops = processStoppingActivitiesLocked(true);
3355 NS = stops != null ? stops.size() : 0;
3356 if ((NF=mFinishingActivities.size()) > 0) {
3357 finishes = new ArrayList<ActivityRecord>(mFinishingActivities);
3358 mFinishingActivities.clear();
3359 }
3360 if ((NT=mService.mCancelledThumbnails.size()) > 0) {
3361 thumbnails = new ArrayList<ActivityRecord>(mService.mCancelledThumbnails);
3362 mService.mCancelledThumbnails.clear();
3363 }
3364
3365 if (mMainStack) {
3366 booting = mService.mBooting;
3367 mService.mBooting = false;
3368 }
3369 }
3370
3371 int i;
3372
3373 // Send thumbnail if requested.
3374 if (sendThumbnail != null) {
3375 try {
3376 sendThumbnail.requestThumbnail(token);
3377 } catch (Exception e) {
3378 Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
3379 mService.sendPendingThumbnail(null, token, null, null, true);
3380 }
3381 }
3382
3383 // Stop any activities that are scheduled to do so but have been
3384 // waiting for the next one to start.
3385 for (i=0; i<NS; i++) {
3386 ActivityRecord r = (ActivityRecord)stops.get(i);
3387 synchronized (mService) {
3388 if (r.finishing) {
3389 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
3390 } else {
3391 stopActivityLocked(r);
3392 }
3393 }
3394 }
3395
3396 // Finish any activities that are scheduled to do so but have been
3397 // waiting for the next one to start.
3398 for (i=0; i<NF; i++) {
3399 ActivityRecord r = (ActivityRecord)finishes.get(i);
3400 synchronized (mService) {
Dianne Hackborn28695e02011-11-02 21:59:51 -07003401 destroyActivityLocked(r, true, false, "finish-idle");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003402 }
3403 }
3404
3405 // Report back to any thumbnail receivers.
3406 for (i=0; i<NT; i++) {
3407 ActivityRecord r = (ActivityRecord)thumbnails.get(i);
3408 mService.sendPendingThumbnail(r, null, null, null, true);
3409 }
3410
3411 if (booting) {
3412 mService.finishBooting();
3413 }
3414
3415 mService.trimApplications();
3416 //dump();
3417 //mWindowManager.dump();
3418
3419 if (enableScreen) {
3420 mService.enableScreenAfterBoot();
3421 }
Dianne Hackborn62f20ec2011-08-15 17:40:28 -07003422
3423 return res;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003424 }
3425
3426 /**
3427 * @return Returns true if the activity is being finished, false if for
3428 * some reason it is being left as-is.
3429 */
3430 final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3431 Intent resultData, String reason) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003432 int index = indexOfTokenLocked(token);
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07003433 if (DEBUG_RESULTS) Slog.v(
3434 TAG, "Finishing activity @" + index + ": token=" + token
3435 + ", result=" + resultCode + ", data=" + resultData);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003436 if (index < 0) {
3437 return false;
3438 }
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003439 ActivityRecord r = mHistory.get(index);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003440
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003441 finishActivityLocked(r, index, resultCode, resultData, reason);
3442 return true;
3443 }
3444
3445 /**
3446 * @return Returns true if this activity has been removed from the history
3447 * list, or false if it is still in the list and will be removed later.
3448 */
3449 final boolean finishActivityLocked(ActivityRecord r, int index,
3450 int resultCode, Intent resultData, String reason) {
3451 if (r.finishing) {
3452 Slog.w(TAG, "Duplicate finish request for " + r);
3453 return false;
3454 }
3455
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -08003456 r.makeFinishing();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003457 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
3458 System.identityHashCode(r),
3459 r.task.taskId, r.shortComponentName, reason);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003460 if (index < (mHistory.size()-1)) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003461 ActivityRecord next = mHistory.get(index+1);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003462 if (next.task == r.task) {
3463 if (r.frontOfTask) {
3464 // The next activity is now the front of the task.
3465 next.frontOfTask = true;
3466 }
3467 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
3468 // If the caller asked that this activity (and all above it)
3469 // be cleared when the task is reset, don't lose that information,
3470 // but propagate it up to the next activity.
3471 next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
3472 }
3473 }
3474 }
3475
3476 r.pauseKeyDispatchingLocked();
3477 if (mMainStack) {
3478 if (mService.mFocusedActivity == r) {
3479 mService.setFocusedActivityLocked(topRunningActivityLocked(null));
3480 }
3481 }
3482
3483 // send the result
3484 ActivityRecord resultTo = r.resultTo;
3485 if (resultTo != null) {
3486 if (DEBUG_RESULTS) Slog.v(TAG, "Adding result to " + resultTo
3487 + " who=" + r.resultWho + " req=" + r.requestCode
3488 + " res=" + resultCode + " data=" + resultData);
3489 if (r.info.applicationInfo.uid > 0) {
3490 mService.grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
Dianne Hackborna1c69e02010-09-01 22:55:02 -07003491 resultTo.packageName, resultData,
3492 resultTo.getUriPermissionsLocked());
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003493 }
3494 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3495 resultData);
3496 r.resultTo = null;
3497 }
3498 else if (DEBUG_RESULTS) Slog.v(TAG, "No result destination from " + r);
3499
3500 // Make sure this HistoryRecord is not holding on to other resources,
3501 // because clients have remote IPC references to this object so we
3502 // can't assume that will go away and want to avoid circular IPC refs.
3503 r.results = null;
3504 r.pendingResults = null;
3505 r.newIntents = null;
3506 r.icicle = null;
3507
3508 if (mService.mPendingThumbnails.size() > 0) {
3509 // There are clients waiting to receive thumbnails so, in case
3510 // this is an activity that someone is waiting for, add it
3511 // to the pending list so we can correctly update the clients.
3512 mService.mCancelledThumbnails.add(r);
3513 }
3514
3515 if (mResumedActivity == r) {
3516 boolean endTask = index <= 0
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003517 || (mHistory.get(index-1)).task != r.task;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003518 if (DEBUG_TRANSITION) Slog.v(TAG,
3519 "Prepare close transition: finishing " + r);
3520 mService.mWindowManager.prepareAppTransition(endTask
3521 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003522 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003523
3524 // Tell window manager to prepare for this one to be removed.
Dianne Hackbornbe707852011-11-11 14:32:10 -08003525 mService.mWindowManager.setAppVisibility(r.appToken, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003526
Dianne Hackborncbb722e2012-02-07 18:33:49 -08003527 if (!mPausingActivities.contains(r)) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003528 if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
3529 if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
3530 startPausingLocked(false, false);
3531 }
3532
3533 } else if (r.state != ActivityState.PAUSING) {
3534 // If the activity is PAUSING, we will complete the finish once
3535 // it is done pausing; else we can just directly finish it here.
3536 if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
3537 return finishCurrentActivityLocked(r, index,
3538 FINISH_AFTER_PAUSE) == null;
3539 } else {
3540 if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
3541 }
3542
3543 return false;
3544 }
3545
3546 private static final int FINISH_IMMEDIATELY = 0;
3547 private static final int FINISH_AFTER_PAUSE = 1;
3548 private static final int FINISH_AFTER_VISIBLE = 2;
3549
3550 private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
3551 int mode) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08003552 final int index = indexOfActivityLocked(r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003553 if (index < 0) {
3554 return null;
3555 }
3556
3557 return finishCurrentActivityLocked(r, index, mode);
3558 }
3559
3560 private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
3561 int index, int mode) {
3562 // First things first: if this activity is currently visible,
3563 // and the resumed activity is not yet visible, then hold off on
3564 // finishing until the resumed one becomes visible.
3565 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3566 if (!mStoppingActivities.contains(r)) {
3567 mStoppingActivities.add(r);
3568 if (mStoppingActivities.size() > 3) {
3569 // If we already have a few activities waiting to stop,
3570 // then give up on things going idle and start clearing
3571 // them out.
Dianne Hackborn80a7ac12011-09-22 18:32:52 -07003572 scheduleIdleLocked();
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003573 } else {
3574 checkReadyForSleepLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003575 }
3576 }
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003577 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
3578 + " (finish requested)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003579 r.state = ActivityState.STOPPING;
3580 mService.updateOomAdjLocked();
3581 return r;
3582 }
3583
3584 // make sure the record is cleaned out of other places.
3585 mStoppingActivities.remove(r);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003586 mGoingToSleepActivities.remove(r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003587 mWaitingVisibleActivities.remove(r);
3588 if (mResumedActivity == r) {
3589 mResumedActivity = null;
3590 }
3591 final ActivityState prevState = r.state;
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003592 if (DEBUG_STATES) Slog.v(TAG, "Moving to FINISHING: " + r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003593 r.state = ActivityState.FINISHING;
3594
3595 if (mode == FINISH_IMMEDIATELY
3596 || prevState == ActivityState.STOPPED
3597 || prevState == ActivityState.INITIALIZING) {
3598 // If this activity is already stopped, we can just finish
3599 // it right now.
Dianne Hackborn28695e02011-11-02 21:59:51 -07003600 return destroyActivityLocked(r, true, true, "finish-imm") ? null : r;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003601 } else {
3602 // Need to go through the full pause cycle to get this
3603 // activity into the stopped state and then finish it.
3604 if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
3605 mFinishingActivities.add(r);
3606 resumeTopActivityLocked(null);
3607 }
3608 return r;
3609 }
3610
Dianne Hackborncbb722e2012-02-07 18:33:49 -08003611 final void appDiedLocked(ProcessRecord app) {
3612 for (int i=mPausingActivities.size()-1; i>=0; i--) {
3613 ActivityRecord r = mPausingActivities.get(i);
3614 if (r.app == app) {
3615 if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " + r);
3616 mPausingActivities.remove(i);
3617 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
3618 }
3619 }
3620 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
3621 mLastPausedActivity = null;
3622 }
3623 }
3624
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003625 /**
3626 * Perform the common clean-up of an activity record. This is called both
3627 * as part of destroyActivityLocked() (when destroying the client-side
3628 * representation) and cleaning things up as a result of its hosting
3629 * processing going away, in which case there is no remaining client-side
3630 * state to destroy so only the cleanup here is needed.
3631 */
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003632 final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices,
3633 boolean setState) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003634 if (mResumedActivity == r) {
3635 mResumedActivity = null;
3636 }
3637 if (mService.mFocusedActivity == r) {
3638 mService.mFocusedActivity = null;
3639 }
3640
3641 r.configDestroy = false;
3642 r.frozenBeforeDestroy = false;
3643
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003644 if (setState) {
3645 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (cleaning up)");
3646 r.state = ActivityState.DESTROYED;
3647 }
3648
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003649 // Make sure this record is no longer in the pending finishes list.
3650 // This could happen, for example, if we are trimming activities
3651 // down to the max limit while they are still waiting to finish.
3652 mFinishingActivities.remove(r);
3653 mWaitingVisibleActivities.remove(r);
3654
3655 // Remove any pending results.
3656 if (r.finishing && r.pendingResults != null) {
3657 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
3658 PendingIntentRecord rec = apr.get();
3659 if (rec != null) {
3660 mService.cancelIntentSenderLocked(rec, false);
3661 }
3662 }
3663 r.pendingResults = null;
3664 }
3665
3666 if (cleanServices) {
3667 cleanUpActivityServicesLocked(r);
3668 }
3669
3670 if (mService.mPendingThumbnails.size() > 0) {
3671 // There are clients waiting to receive thumbnails so, in case
3672 // this is an activity that someone is waiting for, add it
3673 // to the pending list so we can correctly update the clients.
3674 mService.mCancelledThumbnails.add(r);
3675 }
3676
3677 // Get rid of any pending idle timeouts.
3678 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
3679 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003680 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003681 }
3682
3683 private final void removeActivityFromHistoryLocked(ActivityRecord r) {
3684 if (r.state != ActivityState.DESTROYED) {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -08003685 r.makeFinishing();
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07003686 if (DEBUG_ADD_REMOVE) {
3687 RuntimeException here = new RuntimeException("here");
3688 here.fillInStackTrace();
3689 Slog.i(TAG, "Removing activity " + r + " from stack");
3690 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003691 mHistory.remove(r);
Dianne Hackbornf26fd992011-04-08 18:14:09 -07003692 r.takeFromHistory();
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003693 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
3694 + " (removed from history)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003695 r.state = ActivityState.DESTROYED;
Dianne Hackbornbe707852011-11-11 14:32:10 -08003696 mService.mWindowManager.removeAppToken(r.appToken);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003697 if (VALIDATE_TOKENS) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08003698 validateAppTokensLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003699 }
3700 cleanUpActivityServicesLocked(r);
3701 r.removeUriPermissionsLocked();
3702 }
3703 }
3704
3705 /**
3706 * Perform clean-up of service connections in an activity record.
3707 */
3708 final void cleanUpActivityServicesLocked(ActivityRecord r) {
3709 // Throw away any services that have been bound by this activity.
3710 if (r.connections != null) {
3711 Iterator<ConnectionRecord> it = r.connections.iterator();
3712 while (it.hasNext()) {
3713 ConnectionRecord c = it.next();
3714 mService.removeConnectionLocked(c, null, r);
3715 }
3716 r.connections = null;
3717 }
3718 }
3719
Dianne Hackborn28695e02011-11-02 21:59:51 -07003720 final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj, String reason) {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003721 for (int i=mHistory.size()-1; i>=0; i--) {
3722 ActivityRecord r = mHistory.get(i);
3723 if (owner != null && r.app != owner) {
3724 continue;
3725 }
3726 // We can destroy this one if we have its icicle saved and
3727 // it is not in the process of pausing/stopping/finishing.
3728 if (r.app != null && r.haveState && !r.visible && r.stopped && !r.finishing
3729 && r.state != ActivityState.DESTROYING
3730 && r.state != ActivityState.DESTROYED) {
Dianne Hackborn28695e02011-11-02 21:59:51 -07003731 destroyActivityLocked(r, true, oomAdj, "trim");
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003732 }
3733 }
3734 }
3735
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003736 /**
3737 * Destroy the current CLIENT SIDE instance of an activity. This may be
3738 * called both when actually finishing an activity, or when performing
3739 * a configuration switch where we destroy the current client-side object
3740 * but then create a new client-side object for this same HistoryRecord.
3741 */
3742 final boolean destroyActivityLocked(ActivityRecord r,
Dianne Hackborn28695e02011-11-02 21:59:51 -07003743 boolean removeFromApp, boolean oomAdj, String reason) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003744 if (DEBUG_SWITCH) Slog.v(
3745 TAG, "Removing activity: token=" + r
3746 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
3747 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
3748 System.identityHashCode(r),
Dianne Hackborn28695e02011-11-02 21:59:51 -07003749 r.task.taskId, r.shortComponentName, reason);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003750
3751 boolean removedFromHistory = false;
3752
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003753 cleanUpActivityLocked(r, false, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003754
3755 final boolean hadApp = r.app != null;
3756
3757 if (hadApp) {
3758 if (removeFromApp) {
3759 int idx = r.app.activities.indexOf(r);
3760 if (idx >= 0) {
3761 r.app.activities.remove(idx);
3762 }
3763 if (mService.mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) {
3764 mService.mHeavyWeightProcess = null;
3765 mService.mHandler.sendEmptyMessage(
3766 ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
3767 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003768 if (r.app.activities.size() == 0) {
3769 // No longer have activities, so update location in
3770 // LRU list.
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003771 mService.updateLruProcessLocked(r.app, oomAdj, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003772 }
3773 }
3774
3775 boolean skipDestroy = false;
3776
3777 try {
3778 if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
Dianne Hackbornbe707852011-11-11 14:32:10 -08003779 r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003780 r.configChangeFlags);
3781 } catch (Exception e) {
3782 // We can just ignore exceptions here... if the process
3783 // has crashed, our death notification will clean things
3784 // up.
3785 //Slog.w(TAG, "Exception thrown during finish", e);
3786 if (r.finishing) {
3787 removeActivityFromHistoryLocked(r);
3788 removedFromHistory = true;
3789 skipDestroy = true;
3790 }
3791 }
3792
3793 r.app = null;
3794 r.nowVisible = false;
3795
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003796 // If the activity is finishing, we need to wait on removing it
3797 // from the list to give it a chance to do its cleanup. During
3798 // that time it may make calls back with its token so we need to
3799 // be able to find it on the list and so we don't want to remove
3800 // it from the list yet. Otherwise, we can just immediately put
3801 // it in the destroyed state since we are not removing it from the
3802 // list.
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003803 if (r.finishing && !skipDestroy) {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003804 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYING: " + r
3805 + " (destroy requested)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003806 r.state = ActivityState.DESTROYING;
3807 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
3808 msg.obj = r;
3809 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
3810 } else {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003811 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
3812 + " (destroy skipped)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003813 r.state = ActivityState.DESTROYED;
3814 }
3815 } else {
3816 // remove this record from the history.
3817 if (r.finishing) {
3818 removeActivityFromHistoryLocked(r);
3819 removedFromHistory = true;
3820 } else {
Dianne Hackbornce86ba82011-07-13 19:33:41 -07003821 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
3822 + " (no app)");
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003823 r.state = ActivityState.DESTROYED;
3824 }
3825 }
3826
3827 r.configChangeFlags = 0;
3828
3829 if (!mLRUActivities.remove(r) && hadApp) {
3830 Slog.w(TAG, "Activity " + r + " being finished, but not in LRU list");
3831 }
3832
3833 return removedFromHistory;
3834 }
3835
3836 final void activityDestroyed(IBinder token) {
3837 synchronized (mService) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08003838 ActivityRecord r = ActivityRecord.forToken(token);
3839 if (r != null) {
3840 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
3841 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003842
Dianne Hackbornbe707852011-11-11 14:32:10 -08003843 int index = indexOfActivityLocked(r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003844 if (index >= 0) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003845 if (r.state == ActivityState.DESTROYING) {
3846 final long origId = Binder.clearCallingIdentity();
3847 removeActivityFromHistoryLocked(r);
3848 Binder.restoreCallingIdentity(origId);
3849 }
3850 }
3851 }
3852 }
3853
3854 private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
3855 int i = list.size();
3856 if (localLOGV) Slog.v(
3857 TAG, "Removing app " + app + " from list " + list
3858 + " with " + i + " entries");
3859 while (i > 0) {
3860 i--;
3861 ActivityRecord r = (ActivityRecord)list.get(i);
3862 if (localLOGV) Slog.v(
3863 TAG, "Record #" + i + " " + r + ": app=" + r.app);
3864 if (r.app == app) {
3865 if (localLOGV) Slog.v(TAG, "Removing this entry!");
3866 list.remove(i);
3867 }
3868 }
3869 }
3870
3871 void removeHistoryRecordsForAppLocked(ProcessRecord app) {
3872 removeHistoryRecordsForAppLocked(mLRUActivities, app);
3873 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
Dianne Hackborn4eba96b2011-01-21 13:34:36 -08003874 removeHistoryRecordsForAppLocked(mGoingToSleepActivities, app);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003875 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
3876 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
3877 }
3878
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003879 /**
3880 * Move the current home activity's task (if one exists) to the front
3881 * of the stack.
3882 */
3883 final void moveHomeToFrontLocked() {
3884 TaskRecord homeTask = null;
3885 for (int i=mHistory.size()-1; i>=0; i--) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003886 ActivityRecord hr = mHistory.get(i);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003887 if (hr.isHomeActivity) {
3888 homeTask = hr.task;
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -08003889 break;
Dianne Hackborn621e17d2010-11-22 15:59:56 -08003890 }
3891 }
3892 if (homeTask != null) {
3893 moveTaskToFrontLocked(homeTask, null);
3894 }
3895 }
3896
3897
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003898 final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason) {
3899 if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
3900
3901 final int task = tr.taskId;
3902 int top = mHistory.size()-1;
3903
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003904 if (top < 0 || (mHistory.get(top)).task.taskId == task) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003905 // nothing to do!
3906 return;
3907 }
3908
Dianne Hackbornbe707852011-11-11 14:32:10 -08003909 ArrayList<IBinder> moved = new ArrayList<IBinder>();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003910
3911 // Applying the affinities may have removed entries from the history,
3912 // so get the size again.
3913 top = mHistory.size()-1;
3914 int pos = top;
3915
3916 // Shift all activities with this task up to the top
3917 // of the stack, keeping them in the same internal order.
3918 while (pos >= 0) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003919 ActivityRecord r = mHistory.get(pos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003920 if (localLOGV) Slog.v(
3921 TAG, "At " + pos + " ckp " + r.task + ": " + r);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003922 if (r.task.taskId == task) {
3923 if (localLOGV) Slog.v(TAG, "Removing and adding at " + top);
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07003924 if (DEBUG_ADD_REMOVE) {
3925 RuntimeException here = new RuntimeException("here");
3926 here.fillInStackTrace();
3927 Slog.i(TAG, "Removing and adding activity " + r + " to stack at " + top, here);
3928 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003929 mHistory.remove(pos);
3930 mHistory.add(top, r);
Dianne Hackbornbe707852011-11-11 14:32:10 -08003931 moved.add(0, r.appToken);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003932 top--;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003933 }
3934 pos--;
3935 }
3936
3937 if (DEBUG_TRANSITION) Slog.v(TAG,
3938 "Prepare to front transition: task=" + tr);
3939 if (reason != null &&
3940 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003941 mService.mWindowManager.prepareAppTransition(
3942 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003943 ActivityRecord r = topRunningActivityLocked(null);
3944 if (r != null) {
3945 mNoAnimActivities.add(r);
3946 }
3947 } else {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08003948 mService.mWindowManager.prepareAppTransition(
3949 WindowManagerPolicy.TRANSIT_TASK_TO_FRONT, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003950 }
3951
3952 mService.mWindowManager.moveAppTokensToTop(moved);
3953 if (VALIDATE_TOKENS) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08003954 validateAppTokensLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07003955 }
3956
3957 finishTaskMoveLocked(task);
3958 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
3959 }
3960
3961 private final void finishTaskMoveLocked(int task) {
3962 resumeTopActivityLocked(null);
3963 }
3964
3965 /**
3966 * Worker method for rearranging history stack. Implements the function of moving all
3967 * activities for a specific task (gathering them if disjoint) into a single group at the
3968 * bottom of the stack.
3969 *
3970 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
3971 * to premeptively cancel the move.
3972 *
3973 * @param task The taskId to collect and move to the bottom.
3974 * @return Returns true if the move completed, false if not.
3975 */
3976 final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
3977 Slog.i(TAG, "moveTaskToBack: " + task);
3978
3979 // If we have a watcher, preflight the move before committing to it. First check
3980 // for *other* available tasks, but if none are available, then try again allowing the
3981 // current task to be selected.
3982 if (mMainStack && mService.mController != null) {
3983 ActivityRecord next = topRunningActivityLocked(null, task);
3984 if (next == null) {
3985 next = topRunningActivityLocked(null, 0);
3986 }
3987 if (next != null) {
3988 // ask watcher if this is allowed
3989 boolean moveOK = true;
3990 try {
3991 moveOK = mService.mController.activityResuming(next.packageName);
3992 } catch (RemoteException e) {
3993 mService.mController = null;
3994 }
3995 if (!moveOK) {
3996 return false;
3997 }
3998 }
3999 }
4000
Dianne Hackbornbe707852011-11-11 14:32:10 -08004001 ArrayList<IBinder> moved = new ArrayList<IBinder>();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004002
4003 if (DEBUG_TRANSITION) Slog.v(TAG,
4004 "Prepare to back transition: task=" + task);
4005
4006 final int N = mHistory.size();
4007 int bottom = 0;
4008 int pos = 0;
4009
4010 // Shift all activities with this task down to the bottom
4011 // of the stack, keeping them in the same internal order.
4012 while (pos < N) {
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07004013 ActivityRecord r = mHistory.get(pos);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004014 if (localLOGV) Slog.v(
4015 TAG, "At " + pos + " ckp " + r.task + ": " + r);
4016 if (r.task.taskId == task) {
4017 if (localLOGV) Slog.v(TAG, "Removing and adding at " + (N-1));
Dianne Hackborn98cfebc2011-10-18 13:17:33 -07004018 if (DEBUG_ADD_REMOVE) {
4019 RuntimeException here = new RuntimeException("here");
4020 here.fillInStackTrace();
4021 Slog.i(TAG, "Removing and adding activity " + r + " to stack at "
4022 + bottom, here);
4023 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004024 mHistory.remove(pos);
4025 mHistory.add(bottom, r);
Dianne Hackbornbe707852011-11-11 14:32:10 -08004026 moved.add(r.appToken);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004027 bottom++;
4028 }
4029 pos++;
4030 }
4031
4032 if (reason != null &&
4033 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08004034 mService.mWindowManager.prepareAppTransition(
4035 WindowManagerPolicy.TRANSIT_NONE, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004036 ActivityRecord r = topRunningActivityLocked(null);
4037 if (r != null) {
4038 mNoAnimActivities.add(r);
4039 }
4040 } else {
Dianne Hackborn7da6ac32010-12-09 19:22:04 -08004041 mService.mWindowManager.prepareAppTransition(
4042 WindowManagerPolicy.TRANSIT_TASK_TO_BACK, false);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004043 }
4044 mService.mWindowManager.moveAppTokensToBottom(moved);
4045 if (VALIDATE_TOKENS) {
Dianne Hackbornbe707852011-11-11 14:32:10 -08004046 validateAppTokensLocked();
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004047 }
4048
4049 finishTaskMoveLocked(task);
4050 return true;
4051 }
4052
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07004053 public ActivityManager.TaskThumbnails getTaskThumbnailsLocked(TaskRecord tr) {
4054 TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
4055 ActivityRecord resumed = mResumedActivity;
4056 if (resumed != null && resumed.thumbHolder == tr) {
4057 info.mainThumbnail = resumed.stack.screenshotActivities(resumed);
4058 } else {
4059 info.mainThumbnail = tr.lastThumbnail;
4060 }
4061 return info;
4062 }
4063
4064 public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex) {
4065 TaskAccessInfo info = getTaskAccessInfoLocked(taskId, false);
4066 if (info.root == null) {
4067 Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId);
4068 return null;
4069 }
4070
4071 if (subTaskIndex < 0) {
4072 // Just remove the entire task.
4073 performClearTaskAtIndexLocked(taskId, info.rootIndex);
4074 return info.root;
4075 }
4076
4077 if (subTaskIndex >= info.subtasks.size()) {
4078 Slog.w(TAG, "removeTaskLocked: unknown subTaskIndex " + subTaskIndex);
4079 return null;
4080 }
4081
4082 // Remove all of this task's activies starting at the sub task.
4083 TaskAccessInfo.SubTask subtask = info.subtasks.get(subTaskIndex);
4084 performClearTaskAtIndexLocked(taskId, subtask.index);
4085 return subtask.activity;
4086 }
4087
4088 public TaskAccessInfo getTaskAccessInfoLocked(int taskId, boolean inclThumbs) {
4089 ActivityRecord resumed = mResumedActivity;
4090 final TaskAccessInfo thumbs = new TaskAccessInfo();
4091 // How many different sub-thumbnails?
4092 final int NA = mHistory.size();
4093 int j = 0;
4094 ThumbnailHolder holder = null;
4095 while (j < NA) {
4096 ActivityRecord ar = mHistory.get(j);
4097 if (!ar.finishing && ar.task.taskId == taskId) {
4098 holder = ar.thumbHolder;
4099 break;
4100 }
4101 j++;
4102 }
4103
4104 if (j >= NA) {
4105 return thumbs;
4106 }
4107
4108 thumbs.root = mHistory.get(j);
4109 thumbs.rootIndex = j;
4110
4111 ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>();
4112 thumbs.subtasks = subtasks;
4113 ActivityRecord lastActivity = null;
4114 while (j < NA) {
4115 ActivityRecord ar = mHistory.get(j);
4116 j++;
4117 if (ar.finishing) {
4118 continue;
4119 }
4120 if (ar.task.taskId != taskId) {
4121 break;
4122 }
4123 lastActivity = ar;
4124 if (ar.thumbHolder != holder && holder != null) {
4125 thumbs.numSubThumbbails++;
4126 holder = ar.thumbHolder;
4127 TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask();
4128 sub.thumbnail = holder.lastThumbnail;
4129 sub.activity = ar;
4130 sub.index = j-1;
4131 subtasks.add(sub);
4132 }
4133 }
4134 if (lastActivity != null && subtasks.size() > 0) {
4135 if (resumed == lastActivity) {
4136 TaskAccessInfo.SubTask sub = subtasks.get(subtasks.size()-1);
4137 sub.thumbnail = lastActivity.stack.screenshotActivities(lastActivity);
4138 }
4139 }
4140 if (thumbs.numSubThumbbails > 0) {
4141 thumbs.retriever = new IThumbnailRetriever.Stub() {
4142 public Bitmap getThumbnail(int index) {
4143 if (index < 0 || index >= thumbs.subtasks.size()) {
4144 return null;
4145 }
4146 return thumbs.subtasks.get(index).thumbnail;
4147 }
4148 };
4149 }
4150 return thumbs;
4151 }
4152
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004153 private final void logStartActivity(int tag, ActivityRecord r,
4154 TaskRecord task) {
4155 EventLog.writeEvent(tag,
4156 System.identityHashCode(r), task.taskId,
4157 r.shortComponentName, r.intent.getAction(),
4158 r.intent.getType(), r.intent.getDataString(),
4159 r.intent.getFlags());
4160 }
4161
4162 /**
4163 * Make sure the given activity matches the current configuration. Returns
4164 * false if the activity had to be destroyed. Returns true if the
4165 * configuration is the same, or the activity will remain running as-is
4166 * for whatever reason. Ensures the HistoryRecord is updated with the
4167 * correct configuration and all other bookkeeping is handled.
4168 */
4169 final boolean ensureActivityConfigurationLocked(ActivityRecord r,
4170 int globalChanges) {
4171 if (mConfigWillChange) {
4172 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4173 "Skipping config check (will change): " + r);
4174 return true;
4175 }
4176
4177 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4178 "Ensuring correct configuration: " + r);
4179
4180 // Short circuit: if the two configurations are the exact same
4181 // object (the common case), then there is nothing to do.
4182 Configuration newConfig = mService.mConfiguration;
Dianne Hackborne2515ee2011-04-27 18:52:56 -04004183 if (r.configuration == newConfig && !r.forceNewConfig) {
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004184 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4185 "Configuration unchanged in " + r);
4186 return true;
4187 }
4188
4189 // We don't worry about activities that are finishing.
4190 if (r.finishing) {
4191 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4192 "Configuration doesn't matter in finishing " + r);
4193 r.stopFreezingScreenLocked(false);
4194 return true;
4195 }
4196
4197 // Okay we now are going to make this activity have the new config.
4198 // But then we need to figure out how it needs to deal with that.
4199 Configuration oldConfig = r.configuration;
4200 r.configuration = newConfig;
Dianne Hackborn58f42a52011-10-10 13:46:34 -07004201
4202 // Determine what has changed. May be nothing, if this is a config
4203 // that has come back from the app after going idle. In that case
4204 // we just want to leave the official config object now in the
4205 // activity and do nothing else.
4206 final int changes = oldConfig.diff(newConfig);
4207 if (changes == 0 && !r.forceNewConfig) {
4208 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4209 "Configuration no differences in " + r);
4210 return true;
4211 }
4212
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004213 // If the activity isn't currently running, just leave the new
4214 // configuration and it will pick that up next time it starts.
4215 if (r.app == null || r.app.thread == null) {
4216 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4217 "Configuration doesn't matter not running " + r);
4218 r.stopFreezingScreenLocked(false);
Dianne Hackborne2515ee2011-04-27 18:52:56 -04004219 r.forceNewConfig = false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004220 return true;
4221 }
4222
Dianne Hackborn58f42a52011-10-10 13:46:34 -07004223 // Figure out how to handle the changes between the configurations.
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004224 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
4225 Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
4226 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborne6676352011-06-01 16:51:20 -07004227 + Integer.toHexString(r.info.getRealConfigChanged())
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004228 + ", newConfig=" + newConfig);
4229 }
Dianne Hackborne6676352011-06-01 16:51:20 -07004230 if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) {
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004231 // Aha, the activity isn't handling the change, so DIE DIE DIE.
4232 r.configChangeFlags |= changes;
4233 r.startFreezingScreenLocked(r.app, globalChanges);
Dianne Hackborne2515ee2011-04-27 18:52:56 -04004234 r.forceNewConfig = false;
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004235 if (r.app == null || r.app.thread == null) {
4236 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4237 "Switch is destroying non-running " + r);
Dianne Hackborn28695e02011-11-02 21:59:51 -07004238 destroyActivityLocked(r, true, false, "config");
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004239 } else if (r.state == ActivityState.PAUSING) {
4240 // A little annoying: we are waiting for this activity to
4241 // finish pausing. Let's not do anything now, but just
4242 // flag that it needs to be restarted when done pausing.
4243 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4244 "Switch is skipping already pausing " + r);
4245 r.configDestroy = true;
4246 return true;
4247 } else if (r.state == ActivityState.RESUMED) {
4248 // Try to optimize this case: the configuration is changing
4249 // and we need to restart the top, resumed activity.
4250 // Instead of doing the normal handshaking, just say
4251 // "restart!".
4252 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4253 "Switch is restarting resumed " + r);
4254 relaunchActivityLocked(r, r.configChangeFlags, true);
4255 r.configChangeFlags = 0;
4256 } else {
4257 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4258 "Switch is restarting non-resumed " + r);
4259 relaunchActivityLocked(r, r.configChangeFlags, false);
4260 r.configChangeFlags = 0;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004261 }
Dianne Hackborn3c4c2b72010-10-05 18:07:54 -07004262
4263 // All done... tell the caller we weren't able to keep this
4264 // activity around.
4265 return false;
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004266 }
4267
4268 // Default case: the activity can handle this new configuration, so
4269 // hand it over. Note that we don't need to give it the new
4270 // configuration, since we always send configuration changes to all
4271 // process when they happen so it can just use whatever configuration
4272 // it last got.
4273 if (r.app != null && r.app.thread != null) {
4274 try {
4275 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
Dianne Hackbornbe707852011-11-11 14:32:10 -08004276 r.app.thread.scheduleActivityConfigurationChanged(r.appToken);
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004277 } catch (RemoteException e) {
4278 // If process died, whatever.
4279 }
4280 }
4281 r.stopFreezingScreenLocked(false);
4282
4283 return true;
4284 }
4285
4286 private final boolean relaunchActivityLocked(ActivityRecord r,
4287 int changes, boolean andResume) {
4288 List<ResultInfo> results = null;
4289 List<Intent> newIntents = null;
4290 if (andResume) {
4291 results = r.results;
4292 newIntents = r.newIntents;
4293 }
4294 if (DEBUG_SWITCH) Slog.v(TAG, "Relaunching: " + r
4295 + " with results=" + results + " newIntents=" + newIntents
4296 + " andResume=" + andResume);
4297 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
4298 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
4299 r.task.taskId, r.shortComponentName);
4300
4301 r.startFreezingScreenLocked(r.app, 0);
4302
4303 try {
4304 if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
Dianne Hackborne2515ee2011-04-27 18:52:56 -04004305 r.forceNewConfig = false;
Dianne Hackbornbe707852011-11-11 14:32:10 -08004306 r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents,
Dianne Hackborn813075a62011-11-14 17:45:19 -08004307 changes, !andResume, new Configuration(mService.mConfiguration));
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004308 // Note: don't need to call pauseIfSleepingLocked() here, because
4309 // the caller will only pass in 'andResume' if this activity is
4310 // currently resumed, which implies we aren't sleeping.
4311 } catch (RemoteException e) {
4312 return false;
4313 }
4314
4315 if (andResume) {
4316 r.results = null;
4317 r.newIntents = null;
4318 if (mMainStack) {
4319 mService.reportResumedActivityLocked(r);
4320 }
4321 }
4322
4323 return true;
4324 }
Dianne Hackborn90c52de2011-09-23 12:57:44 -07004325
4326 public void dismissKeyguardOnNextActivityLocked() {
4327 mDismissKeyguardOnNextActivity = true;
4328 }
Dianne Hackborn50dc3bc2010-06-25 10:05:59 -07004329}