Android P窗口机制之Window加载流程

相关源码:
\frameworks\base\core\java\android\app\Activity.java
\frameworks\base\core\java\android\app\ActivityThread.java
\frameworks\base\core\java\android\app\servertransaction\ClientTransaction.java
\frameworks\base\core\java\android\app\servertransaction\ResumeActivityItem.java
\frameworks\base\core\java\android\app\servertransaction\TransactionExecutor.java
\frameworks\base\core\java\android\view\WindowManagerImpl.java
\frameworks\base\core\java\android\view\WindowManagerGlobal.java
\frameworks\base\core\java\android\view\ViewRootImpl.java
\frameworks\base\services\core\java\com\android\server\wm\Session.java

activity的启动可以参考:
《Android P窗口机制之Activity启动流程》

从attach()方法说起

Activity

创建Window:从Activity的启动流程得知,最终会调用Activity中的attach来初始化window。

final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window, ActivityConfigCallback activityConfigCallback) {
    attachBaseContext(context);

    mFragments.attachHost(null /*parent*/);

	//关键点
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }
    if (info.uiOptions != 0) {
        mWindow.setUiOptions(info.uiOptions);
    }
    mUiThread = Thread.currentThread();

    mMainThread = aThread;
    mInstrumentation = instr;
    mToken = token;
    mIdent = ident;
    mApplication = application;
    mIntent = intent;
    mReferrer = referrer;
    mComponent = intent.getComponent();
    mActivityInfo = info;
    mTitle = title;
    mParent = parent;
    mEmbeddedID = id;
    mLastNonConfigurationInstances = lastNonConfigurationInstances;
    if (voiceInteractor != null) {
        if (lastNonConfigurationInstances != null) {
            mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
        } else {
            mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                    Looper.myLooper());
        }
    }

    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    if (mParent != null) {
        mWindow.setContainer(mParent.getWindow());
    }
    mWindowManager = mWindow.getWindowManager();
    mCurrentConfig = config;

    mWindow.setColorMode(info.colorMode);

    setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
    enableAutofillCompatibilityIfNeeded();
}

关键点:mWindow = new PhoneWindow(this),创建了一个PhoneWindow对象。并设置一些回调。

ActivityThread

Activity创建后会执行:handleResumeActivity()方法,该方法中Window加载了DecorView

@Override
public void handleResumeActivity(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
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    if (r == null) {
        // We didn't actually resume the activity, so skipping any follow-up actions.
        return;
    }

    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) {
        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) {
            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) {
                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.
    } else if (!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.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();
                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(new Idler());
}

关键点1:wm.addView(decor, l),加载DecorView到window中去。DecorView中包含了StatusBar和NavigationBar的View,包含应用程序MainActivity的ContentView
关键点2:wm.updateViewLayout(decor, l),更新window

Window更新机制

WindowManagerImpl

源码:frameworks\base\core\java\android\view\WindowManagerImpl.java
最终执行WindowManagerImpl中的updateViewLayout():

@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.updateViewLayout(view, params);
}
WindowManagerGlobal

源码:\frameworks\base\core\java\android\view\WindowManagerGlobal.java

public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }

    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;

    view.setLayoutParams(wparams);

    synchronized (mLock) {
        int index = findViewLocked(view, true);
        ViewRootImpl root = mRoots.get(index);
        mParams.remove(index);
        mParams.add(index, wparams);
        root.setLayoutParams(wparams, false);
    }
}

设置新的params,调用ViewRootImpl.setLayoutParams()方法来设置。

ViewRootImpl

源码:\frameworks\base\core\java\android\view\ViewRootImpl.java

void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
    synchronized (this) {
        final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
        final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
        final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
        final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
        final int oldSoftInputMode = mWindowAttributes.softInputMode;
        final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;

        if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
                & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
                && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
            Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!");
        }

        // Keep track of the actual window flags supplied by the client.
        mClientWindowLayoutFlags = attrs.flags;

        // Preserve compatible window flag if exists.
        final int compatibleWindowFlag = mWindowAttributes.privateFlags
                & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;

        // Transfer over system UI visibility values as they carry current state.
        attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
        attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;

        mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
        if ((mWindowAttributesChangesFlag
                & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
            // Recompute system ui visibility.
            mAttachInfo.mRecomputeGlobalAttributes = true;
        }
        if ((mWindowAttributesChangesFlag
                & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
            // Request to update light center.
            mAttachInfo.mNeedsUpdateLightCenter = true;
        }
        if (mWindowAttributes.packageName == null) {
            mWindowAttributes.packageName = mBasePackageName;
        }
        mWindowAttributes.privateFlags |= compatibleWindowFlag;

        if (mWindowAttributes.preservePreviousSurfaceInsets) {
            // Restore old surface insets.
            mWindowAttributes.surfaceInsets.set(
                    oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
            mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
        } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft
                || mWindowAttributes.surfaceInsets.top != oldInsetTop
                || mWindowAttributes.surfaceInsets.right != oldInsetRight
                || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) {
            mNeedsRendererSetup = true;
        }

        applyKeepScreenOnFlag(mWindowAttributes);

        if (newView) {
            mSoftInputMode = attrs.softInputMode;
            requestLayout();
        }

        // Don't lose the mode we last auto-computed.
        if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
                == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
            mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
                    & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
                    | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
        }

        mWindowAttributesChanged = true;
        scheduleTraversals();
    }
}

根据params计算了一系列的高度和宽度,包括上,下,左,右的间距等等。

关键点:scheduleTraversals(),最后会调用performTraversals

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        if (!mUnbufferedInputDispatch) {
            scheduleConsumeBatchedInput();
        }
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

执行了mTraversalRunnable,

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

        if (mProfile) {
            Debug.startMethodTracing("ViewAncestor");
        }

        performTraversals();

        if (mProfile) {
            Debug.stopMethodTracing();
            mProfile = false;
        }
    }
}

关键点:performTraversals()
performTraversals方法对View进行测量、布局和绘制。

private void performTraversals() {
	//省略一部分代码
	//...
	relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
	//省略一部分代码
	//...
}

**关键点:relayoutWindow()**
```java
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
        boolean insetsPending) throws RemoteException {

	//省略一部分代码
	//...
	
    int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
            (int) (mView.getMeasuredWidth() * appScale + 0.5f),
            (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
            insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
            mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
            mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
            mPendingMergedConfiguration, mSurface);
            
	//省略一部分代码
	//...

    return relayoutResult;
}

通过mWindowSession进行进程间通信,最终调用到WindowManagerService中去。完成Window更新。

Session

源码:\frameworks\base\services\core\java\com\android\server\wm\Session.java

@Override
public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
        Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
        Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
        DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
        Surface outSurface) {
    if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
            + Binder.getCallingPid());
    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
    int res = mService.relayoutWindow(this, window, seq, attrs,
            requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
            outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
            outStableInsets, outsets, outBackdropFrame, cutout,
            mergedConfiguration, outSurface);
    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
            + Binder.getCallingPid());
    return res;
}

通过mService调用了relayoutWindow,mService就是WinodwManagerService.

WinodwManagerService

源码:\frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java

public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewVisibility, int flags,
            long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
            Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
            DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
            Surface outSurface) {
            
//省略一部分代码
//...
//关键点1,根据session和client获取WindowState对象
WindowState win = windowForClientLocked(session, client, false);

//省略一部分代码
//...

//关键点2,更新window
result = win.relayoutVisibleWindow(result, attrChanges, oldVisibility);

//省略一部分代码
//...
}
WindowState
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunxiaolin2016

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值