finalbooleanstartPausingLocked(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming, boolean pauseImmediately) { if (mPausingActivity != null) { Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity + " state=" + mPausingActivity.getState()); if (!shouldSleepActivities()) { // Avoid recursion among check for sleep and complete pause during sleeping. // Because activity will be paused immediately after resume, just let pause // be completed by the order of activity paused from clients. completePauseLocked(false, resuming); } } ActivityRecordprev= mResumedActivity;
if (prev == null) { if (resuming == null) { Slog.wtf(TAG, "Trying to pause when nothing is resumed"); mStackSupervisor.resumeFocusedStackTopActivityLocked(); } returnfalse; }
if (prev == resuming) { Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed"); returnfalse; }
mService.getLifecycleManager().scheduleTransaction(prev.app.thread, prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, prev.configChangeFlags, pauseImmediately)); } catch (Exception e) { // Ignore exception, if process died other code will cleanup. Slog.w(TAG, "Exception thrown during pause", e); mPausingActivity = null; mLastPausedActivity = null; mLastNoHistoryActivity = null; } } else { mPausingActivity = null; mLastPausedActivity = null; mLastNoHistoryActivity = null; }
// If we are not going to sleep, we want to ensure the device is // awake until the next activity is started. if (!uiSleeping && !mService.isSleepingOrShuttingDownLocked()) { mStackSupervisor.acquireLaunchWakelock(); }
if (mPausingActivity != null) { // Have the window manager pause its key dispatching until the new // activity has started. If we're pausing the activity just because // the screen is being turned off and the UI is sleeping, don't interrupt // key dispatch; the same activity will pick it up again on wakeup. if (!uiSleeping) { prev.pauseKeyDispatchingLocked(); } elseif (DEBUG_PAUSE) { Slog.v(TAG_PAUSE, "Key dispatch not paused for screen off"); }
if (pauseImmediately) { // If the caller said they don't want to wait for the pause, then complete // the pause now. completePauseLocked(false, resuming); returnfalse;
} else { // This activity failed to schedule the // pause, so just treat it as being paused now. if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next."); if (resuming == null) { mStackSupervisor.resumeFocusedStackTopActivityLocked(); } returnfalse; } }
private Bundle performPauseActivity(ActivityClientRecord r, boolean finished, String reason, PendingTransactionActions pendingActions) { if (r.paused) { if (r.activity.mFinished) { // If we are finishing, we won't call onResume() in certain cases. // So here we likewise don't want to call onPause() if the activity // isn't resumed. returnnull; } RuntimeExceptione=newRuntimeException( "Performing pause of activity that is not resumed: " + r.intent.getComponent().toShortString()); Slog.e(TAG, e.getMessage(), e); } if (finished) { r.activity.mFinished = true; }
// Pre-Honeycomb apps always save their state before pausing // 调用 Activity 的 OnSaveInstanceState 方法 finalbooleanshouldSaveState= !r.activity.mFinished && r.isPreHoneycomb(); if (shouldSaveState) { callActivityOnSaveInstanceState(r); } // 调用 onPause performPauseActivityIfNeeded(r, reason);
// Notify any outstanding on paused listeners ArrayList<OnActivityPausedListener> listeners; synchronized (mOnPauseListeners) { listeners = mOnPauseListeners.remove(r.activity); } intsize= (listeners != null ? listeners.size() : 0); for (inti=0; i < size; i++) { listeners.get(i).onPaused(r.activity); }
finalBundleoldState= pendingActions != null ? pendingActions.getOldState() : null; if (oldState != null) { // We need to keep around the original state, in case we need to be created again. // But we only do this for pre-Honeycomb apps, which always save their state when // pausing, so we can not have them save their state when restarting from a paused // state. For HC and later, we want to (and can) let the state be saved as the // normal part of stopping the activity. if (r.isPreHoneycomb()) { r.state = oldState; } }
return shouldSaveState ? r.state : null; }
privatevoidperformPauseActivityIfNeeded(ActivityClientRecord r, String reason) { if (r.paused) { // You are already paused silly... return; }
try { r.activity.mCalled = false; // 调用 Activity.onPause mInstrumentation.callActivityOnPause(r.activity); if (!r.activity.mCalled) { thrownewSuperNotCalledException("Activity " + safeToComponentShortString(r.intent) + " did not call through to super.onPause()"); } } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { thrownewRuntimeException("Unable to pause activity " + safeToComponentShortString(r.intent) + ": " + e.toString(), e); } } r.setState(ON_PAUSE); }
@Override publicvoidhandleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); mSomeActivitiesChanged = true;
// TODO Push resumeArgs into the activity for consideration // 请关注这里 finalActivityClientRecordr= performResumeActivity(token, finalStateRequest, reason); if (r == null) { // We didn't actually resume the activity, so skipping any follow-up actions. return; }
finalActivitya= r.activity;
if (localLOGV) { Slog.v(TAG, "Resume " + r + " started activity: " + a.mStartedActivity + ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished); }
// If the window hasn't yet been added to the window manager, // and this guy didn't finish itself or start another activity, // then go ahead and add the window. booleanwillBeVisible= !a.mStartedActivity; if (!willBeVisible) { try { willBeVisible = ActivityManager.getService().willActivityBeVisible( a.getActivityToken()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); Viewdecor= r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManagerwm= a.getWindowManager(); WindowManager.LayoutParamsl= r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (r.mPreserveWindow) { a.mWindowAdded = true; r.mPreserveWindow = false; // Normally the ViewRoot sets up callbacks with the Activity // in addView->ViewRootImpl#setView. If we are instead reusing // the decor view we have to notify the view root that the // callbacks may have changed. ViewRootImplimpl= decor.getViewRootImpl(); if (impl != null) { impl.notifyChildRebuilt(); } } if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; wm.addView(decor, l); } else { // The activity will get a callback for this {@link LayoutParams} change // earlier. However, at that time the decor will not be set (this is set // in this method), so no action will be taken. This call ensures the // callback occurs with the decor set. a.onWindowAttributesChanged(l); } }
// If the window has already been added, but during resume // we started another activity, then don't yet make the // window visible. } elseif (!willBeVisible) { if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set"); r.hideForNow = true; }
// Get rid of anything left hanging around. cleanUpPendingRemoveWindows(r, false/* force */);
// The window is now visible if it has been added, we are not // simply finishing, and we are not starting another activity. if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) { if (r.newConfig != null) { performConfigurationChangedForActivity(r, r.newConfig); if (DEBUG_CONFIGURATION) { Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig " + r.activity.mCurrentConfig); } r.newConfig = null; } if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward); WindowManager.LayoutParamsl= r.window.getAttributes(); if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != forwardBit) { l.softInputMode = (l.softInputMode & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)) | forwardBit; if (r.activity.mVisibleFromClient) { ViewManagerwm= a.getWindowManager(); Viewdecor= r.window.getDecorView(); wm.updateViewLayout(decor, l); } }
r.activity.mVisibleFromServer = true; mNumVisibleActivities++; if (r.activity.mVisibleFromClient) { r.activity.makeVisible(); } }
r.nextIdle = mNewActivities; mNewActivities = r; if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r); Looper.myQueue().addIdleHandler(newIdler()); }
@VisibleForTesting public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, String reason) { finalActivityClientRecordr= mActivities.get(token); if (localLOGV) { Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished); } if (r == null || r.activity.mFinished) { returnnull; } if (r.getLifecycleState() == ON_RESUME) { if (!finalStateRequest) { finalRuntimeExceptione=newIllegalStateException( "Trying to resume activity which is already resumed"); Slog.e(TAG, e.getMessage(), e); Slog.e(TAG, r.getStateString()); // TODO(lifecycler): A double resume request is possible when an activity // receives two consequent transactions with relaunch requests and "resumed" // final state requests and the second relaunch is omitted. We still try to // handle two resume requests for the final state. For cases other than this // one, we don't expect it to happen. } returnnull; } if (finalStateRequest) { r.hideForNow = false; r.activity.mStartedActivity = false; } try { r.activity.onStateNotSaved(); r.activity.mFragments.noteStateNotSaved(); checkAndBlockForNetworkAccess(); if (r.pendingIntents != null) { deliverNewIntents(r, r.pendingIntents); r.pendingIntents = null; } if (r.pendingResults != null) { deliverResults(r, r.pendingResults, reason); r.pendingResults = null; } // 调用 Activity 的 performResume 方法 r.activity.performResume(r.startsNotResumed, reason);
if (mAutoFillResetNeeded) { // When Activity is destroyed in paused state, and relaunch activity, there will be // extra onResume and onPause event, ignore the first onResume and onPause. // see ActivityThread.handleRelaunchActivity() mAutoFillIgnoreFirstResumePause = followedByPause; if (mAutoFillIgnoreFirstResumePause && DEBUG_LIFECYCLE) { Slog.v(TAG, "autofill will ignore first pause when relaunching " + this); } }
mCalled = false; // mResumed is set by the instrumentation mInstrumentation.callActivityOnResume(this); writeEventLog(LOG_AM_ON_RESUME_CALLED, reason); if (!mCalled) { thrownewSuperNotCalledException( "Activity " + mComponent.toShortString() + " did not call through to super.onResume()"); }
// invisible activities must be finished before onResume() completes if (!mVisibleFromClient && !mFinished) { Log.w(TAG, "An activity without a UI must call finish() before onResume() completes"); if (getApplicationInfo().targetSdkVersion > android.os.Build.VERSION_CODES.LOLLIPOP_MR1) { thrownewIllegalStateException( "Activity " + mComponent.toShortString() + " did not call finish() prior to onResume() completing"); } }
// Now really resume, and install the current status bar and menu. mCalled = false;
onPostResume(); if (!mCalled) { thrownewSuperNotCalledException( "Activity " + mComponent.toShortString() + " did not call through to super.onPostResume()"); } }
if (r == null) { // Ignore requests for non-existent client records for now. return; }
// Cycle to the state right before the final requested state. // 这里的 lifecycleItem.getTargetState() 正是 ResumeActivityItem.ON_RESUME cycleToPath(r, lifecycleItem.getTargetState(), true/* excludeLastState */);
// Execute the final transition with proper parameters. lifecycleItem.execute(mTransactionHandler, token, mPendingActions); lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions); }
@VisibleForTesting public IntArray getLifecyclePath(int start, int finish, boolean excludeLastState) { if (start == UNDEFINED || finish == UNDEFINED) { thrownewIllegalArgumentException("Can't resolve lifecycle path for undefined state"); } if (start == ON_RESTART || finish == ON_RESTART) { thrownewIllegalArgumentException( "Can't start or finish in intermittent RESTART state"); } if (finish == PRE_ON_CREATE && start != finish) { thrownewIllegalArgumentException("Can only start in pre-onCreate state"); }
mLifecycleSequence.clear(); if (finish >= start) { // just go there for (inti= start + 1; i <= finish; i++) { mLifecycleSequence.add(i); } } else { // finish < start, can't just cycle down if (start == ON_PAUSE && finish == ON_RESUME) { // Special case when we can just directly go to resumed state. mLifecycleSequence.add(ON_RESUME); } elseif (start <= ON_STOP && finish >= ON_START) { // Restart and go to required state.
// Go to stopped state first. for (inti= start + 1; i <= ON_STOP; i++) { mLifecycleSequence.add(i); } // Restart mLifecycleSequence.add(ON_RESTART); // Go to required state for (inti= ON_START; i <= finish; i++) { mLifecycleSequence.add(i); } } else { // Relaunch and go to required state
// Go to destroyed state first. for (inti= start + 1; i <= ON_DESTROY; i++) { mLifecycleSequence.add(i); } // Go to required state for (inti= ON_CREATE; i <= finish; i++) { mLifecycleSequence.add(i); } } }
// Remove last transition in case we want to perform it with some specific params. if (excludeLastState && mLifecycleSequence.size() != 0) { mLifecycleSequence.remove(mLifecycleSequence.size() - 1); }
@Override publicvoidhandleStartActivity(ActivityClientRecord r, PendingTransactionActions pendingActions) { finalActivityactivity= r.activity; if (r.activity == null) { // TODO(lifecycler): What do we do in this case? return; } if (!r.stopped) { thrownewIllegalStateException("Can't start activity that is not stopped."); } if (r.activity.mFinished) { // TODO(lifecycler): How can this happen? return; }
if (!mCalled) { thrownewSuperNotCalledException( "Activity " + mComponent.toShortString() + " did not call through to super.onStart()"); } mFragments.dispatchStart(); mFragments.reportLoaderStart();
// This property is set for all non-user builds except final release booleanisDlwarningEnabled= SystemProperties.getInt("ro.bionic.ld.warning", 0) == 1;
// This property is set for all non-user builds except final release booleanisApiWarningEnabled= SystemProperties.getInt("ro.art.hiddenapi.warning", 0) == 1;
if (isAppDebuggable || isApiWarningEnabled) { if (!mMainThread.mHiddenApiWarningShown && VMRuntime.getRuntime().hasUsedHiddenApi()) { // Only show the warning once per process. mMainThread.mHiddenApiWarningShown = true;
StringappName= getApplicationInfo().loadLabel(getPackageManager()) .toString(); Stringwarning="Detected problems with API compatibility\n" + "(visit g.co/dev/appcompat for more info)"; if (isAppDebuggable) { newAlertDialog.Builder(this) .setTitle(appName) .setMessage(warning) .setPositiveButton(android.R.string.ok, null) .setCancelable(false) .show(); } else { Toast.makeText(this, appName + "\n" + warning, Toast.LENGTH_LONG).show(); } } }
ActivityRecordr= ActivityRecord.forTokenLocked(token); if (r != null) { if (DEBUG_IDLE) Slog.d(TAG_IDLE, "activityIdleInternalLocked: Callers=" + Debug.getCallers(4)); mHandler.removeMessages(IDLE_TIMEOUT_MSG, r); r.finishLaunchTickingLocked(); if (fromTimeout) { reportActivityLaunchedLocked(fromTimeout, r, -1, -1); }
// This is a hack to semi-deal with a race condition // in the client where it can be constructed with a // newer configuration from when we asked it to launch. // We'll update with whatever configuration it now says // it used to launch. if (config != null) { r.setLastReportedGlobalConfiguration(config); }
// We are now idle. If someone is waiting for a thumbnail from // us, we can now deliver. r.idle = true;
if (allResumedActivitiesIdle()) { if (r != null) { mService.scheduleAppGcsLocked(); }
if (mLaunchingActivity.isHeld()) { mHandler.removeMessages(LAUNCH_TIMEOUT_MSG); if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) { thrownewIllegalStateException("Calling must be system uid"); } mLaunchingActivity.release(); } ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); }
// Atomically retrieve all of the other things to do. final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(r, true/* remove */, processPausingActivities); NS = stops != null ? stops.size() : 0; if ((NF = mFinishingActivities.size()) > 0) { finishes = newArrayList<>(mFinishingActivities); mFinishingActivities.clear(); }
if (mStartingUsers.size() > 0) { startingUsers = newArrayList<>(mStartingUsers); mStartingUsers.clear(); }
// Stop any activities that are scheduled to do so but have been // waiting for the next one to start. for (inti=0; i < NS; i++) { r = stops.get(i); finalActivityStackstack= r.getStack(); if (stack != null) { if (r.finishing) { stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false, "activityIdleInternalLocked"); } else { stack.stopActivityLocked(r); } } }
// Finish any activities that are scheduled to do so but have been // waiting for the next one to start. for (inti=0; i < NF; i++) { r = finishes.get(i); finalActivityStackstack= r.getStack(); if (stack != null) { activityRemoved |= stack.destroyActivityLocked(r, true, "finish-idle"); } }
if (!booting) { // Complete user switch if (startingUsers != null) { for (inti=0; i < startingUsers.size(); i++) { mService.mUserController.finishUserSwitch(startingUsers.get(i)); } } }
if (activityRemoved) { resumeFocusedStackTopActivityLocked(); }
return r; }
上面这段代码有点长,其实我们只要关注以下这段代码就好了
// Stop any activities that are scheduled to do so but have been
// waiting for the next one to start.
for (int i = 0; i < NS; i++) {
r = stops.get(i);
final ActivityStack stack = r.getStack();
if (stack != null) {
if (r.finishing) {
stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false,
"activityIdleInternalLocked");
} else {
stack.stopActivityLocked(r);
}
}
}
privatevoidperformStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown, boolean saveState, boolean finalStateRequest, String reason) { if (localLOGV) Slog.v(TAG, "Performing stop of " + r); if (r != null) { if (!keepShown && r.stopped) { if (r.activity.mFinished) { // If we are finishing, we won't call onResume() in certain // cases. So here we likewise don't want to call onStop() // if the activity isn't resumed. return; } if (!finalStateRequest) { finalRuntimeExceptione=newRuntimeException( "Performing stop of activity that is already stopped: " + r.intent.getComponent().toShortString()); Slog.e(TAG, e.getMessage(), e); Slog.e(TAG, r.getStateString()); } }
// One must first be paused before stopped... performPauseActivityIfNeeded(r, reason);
if (info != null) { try { // First create a thumbnail for the activity... // For now, don't create the thumbnail here; we are // doing that by doing a screen snapshot. info.setDescription(r.activity.onCreateDescription()); } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { thrownewRuntimeException( "Unable to save state of activity " + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } }
if (!keepShown) { callActivityOnStop(r, saveState, reason); } } }