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