Android AMS(三) App啟動過程之onResume
在Android AMS(二) App啟動過程之onCreate中我們講了onCreate的呼叫流程,這篇我們接著分析onResume的流程
ActivityThread.java-->handleLaunchActivity()中呼叫performLaunchActivity()走到activity的onCreate,onStart狀態後,會呼叫handleResumeActivity()方法
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) { ActivityClientRecord r = mActivities.get(token); if (!checkAndUpdateLifecycleSeq(seq, r, "resumeActivity")) { return; } // 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 r = performResumeActivity(token, clearHide, reason); if (r != null) { final Activity a = r.activity; if (localLOGV) Slog.v( TAG, "Resume " + r + " started activity: " + a.mStartedActivity + ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished); final int forwardBit = isForward ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0; // 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. boolean willBeVisible = !a.mStartedActivity; if (!willBeVisible) { try { willBeVisible = ActivityManager.getService().willActivityBeVisible( a.getActivityToken()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } if (r.window == null && !a.mFinished && willBeVisible) { //getWindow就是Activity attach()中new的PhoneWindow() r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (r.mPreserveWindow) { // SPRD: Bug711794, ensure that the decor view is attached to window. // if the remain decor view is not attached to window, we should make sure // that it will been attached in the following workflow. if(DecorView.isAddedToWindow(decor)) 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. ViewRootImpl impl = decor.getViewRootImpl(); if (impl != null) { // add systrace tag for bug 661753 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "notifyChildRebuilt"); impl.notifyChildRebuilt(); // add systrace tag for bug 661753 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } } if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; // add systrace tag for bug 661753 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "addView"); wm.addView(decor, l); // add systrace tag for bug 661753 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); DecorView.setAddedToWindow(a.mDecor); } 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. } else if (!willBeVisible) { if (localLOGV) Slog.v( TAG, "Launch " + r + " mStartedActivity set"); r.hideForNow = true; } // add systrace tag for bug 661753 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "cleanUpPendingRemoveWindows"); // Get rid of anything left hanging around. cleanUpPendingRemoveWindows(r, false /* force */); // add systrace tag for bug 661753 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); // 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.LayoutParams l = 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) { ViewManager wm = a.getWindowManager(); View decor = r.window.getDecorView(); // add systrace tag for bug 661753 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "updateViewLayout"); wm.updateViewLayout(decor, l); // add systrace tag for bug 661753 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } } r.activity.mVisibleFromServer = true; mNumVisibleActivities++; if (r.activity.mVisibleFromClient) { r.activity.makeVisible(); } } if (!r.onlyLocalRequest) { r.nextIdle = mNewActivities; mNewActivities = r; if (localLOGV) Slog.v( TAG, "Scheduling idle handler for " + r); Looper.myQueue().addIdleHandler(new Idler()); } r.onlyLocalRequest = false; if (UsimNotifier.isNotifyEnabled(getApplication())) { UsimNotifier.getInstance().startNotify(r.activity); } // Tell the activity manager we have resumed. if (reallyResume) { try { // add systrace tag for bug 661753 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResumed"); ActivityManager.getService().activityResumed(token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } finally { // add systrace tag for bug 661753 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } } } else { // If an exception was thrown when trying to resume, then // just end this activity. try { // add systrace tag for bug 661753 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "finishActivity"); ActivityManager.getService() .finishActivity(token, Activity.RESULT_CANCELED, null, Activity.DONT_FINISH_TASK_WITH_ACTIVITY); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } finally { // add systrace tag for bug 661753 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } } }
主要作用是呼叫performResumeActivity()到activity的onResume狀態,然後獲取DecorView,建立一個關聯的ViewRootImpl物件,用來配合WindowManagerService服務來管理該Activity元件的視窗狀態,最後addView
1.首先看下performResumeActivity()
public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide, String reason) { ActivityClientRecord r = mActivities.get(token); if (localLOGV) Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished); if (r != null && !r.activity.mFinished) { if (clearHide) { 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); r.pendingResults = null; } // add systrace tag for bug 661753 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "performResume"); r.activity.performResume(); synchronized (mResourcesManager) { // If there is a pending local relaunch that was requested when the activity was // paused, it will put the activity into paused state when it finally happens. // Since the activity resumed before being relaunched, we don't want that to // happen, so we need to clear the request to relaunch paused. for (int i = mRelaunchingActivities.size() - 1; i >= 0; i--) { final ActivityClientRecord relaunching = mRelaunchingActivities.get(i); if (relaunching.token == r.token && relaunching.onlyLocalRequest && relaunching.startsNotResumed) { relaunching.startsNotResumed = false; } } } EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED, UserHandle.myUserId(), r.activity.getComponentName().getClassName(), reason); r.paused = false; r.stopped = false; r.state = null; r.persistentState = null; } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException( "Unable to resume activity " + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } finally { // add systrace tag for bug 661753 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } } return r; }
Activity.java-->performResume()
final void performResume() { performRestart(); mFragments.execPendingActions(); mLastNonConfigurationInstances = null; mCalled = false; // mResumed is set by the instrumentation mInstrumentation.callActivityOnResume(this); if (!mCalled) { throw new SuperNotCalledException( "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) { throw new IllegalStateException( "Activity " + mComponent.toShortString() + " did not call finish() prior to onResume() completing"); } } // Now really resume, and install the current status bar and menu. mCalled = false; mFragments.dispatchResume(); mFragments.execPendingActions(); onPostResume(); if (!mCalled) { throw new SuperNotCalledException( "Activity " + mComponent.toShortString() + " did not call through to super.onPostResume()");
Instrumentation.java-->callActivityOnResume()
public void callActivityOnResume(Activity activity) {
activity.mResumed = true;
// add systrace tag for bug 661753
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activity.onResume");
activity.onResume();
// add systrace tag for bug 661753
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
am.match(activity, activity, activity.getIntent());
}
}
}
}
Activity.java-->onResume()
protected void onResume() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
mActivityTransitionState.onResume(this, isTopOfTask());
mCalled = true;
}
到這裡activity已經到了onResume的狀態,下面我們繼續ViewRootImpl建立的過程
2.ViewRootImpl建立流程
在 Android AMS(二) App啟動過程之onCreate我們知道在activity onCreate後,會呼叫Activity的attach()方法new PhoneWindow
所以r.window = r.activity.getWindow();得到的就是PhoneWindow的例項
getDecorView()是Window.java的一個抽象方法,PhoneWindow繼承了這個Window
@Override
public final View getDecorView() {
if (mDecor == null || mForceDecorInstall) {
installDecor();
}
return mDecor;
}
PhoneWindow.java-->installDecor()
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
......
}
PhoneWindow.java-->generateDecor()
protected DecorView generateDecor(int featureId) {
// System process doesn't have application context and in that case we need to directly use
// the context we have. Otherwise we want the application context, so we don't cling to the
// activity.
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, getContext().getResources());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
return new DecorView(context, featureId, this, getAttributes());
}
創建出DecorView之後,從DecorView中獲取ViewRootImpl
ViewRootImpl impl = decor.getViewRootImpl();
我們看下ViewRootImpl的構造方法
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrace();
mWidth = -1;
mHeight = -1;
mDirty = new Rect();
mTempRect = new Rect();
mVisRect = new Rect();
mWinFrame = new Rect();
mWindow = new W(this);
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
mViewVisibility = View.GONE;
mTransparentRegion = new Region();
mPreviousTransparentRegion = new Region();
mFirst = true; // true for the first time the view is added
mAdded = false;
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
context);
mAccessibilityManager = AccessibilityManager.getInstance(context);
mAccessibilityManager.addAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager, mHandler);
mHighContrastTextManager = new HighContrastTextManager();
mAccessibilityManager.addHighTextContrastStateChangeListener(
mHighContrastTextManager, mHandler);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
mFallbackEventHandler = new PhoneFallbackEventHandler(context);
mChoreographer = Choreographer.getInstance();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
if (!sCompatibilityDone) {
sAlwaysAssignFocus = true;
sCompatibilityDone = true;
}
loadSystemProperties();
}
在這裡獲取了WindowSession,W物件,這個以後我們在WMS學習中再研究
然後addView -->wm.addView(decor, l);
這個wm是ViewManager,ViewManager是個介面,而WindowManager繼承了ViewManager,WindowManagerImpl實現了WindowManager
WindowManagerImpl.java-->addView()
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
WindowManagerGlobal.java-->addView()
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (display == null) {
throw new IllegalArgumentException("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews.size();
for (int i = 0; i < count; i++) {
if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
panelParentView = mViews.get(i);
}
}
}
root = new SprdViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}