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