Android14 WMS-窗口添加流程(一)-Client端

      窗口布局在onCreate方法中通过setContentView(R.layout.xxx)加载,但窗口的显示并不是在wm_on_create_called中, 而是在wm_on_resume_called后,也就是说应用onResume时此窗口是不可见的,真正可见是当此window窗口的mDrawState变化状态从NO_SURFACE -> DRAW_PENDING -> COMMIT_DRAW_PENDING  -> HAS_DRAWN-> READY_TO_SHOW,然后才会将图层置为可见状态,这个在后面会讲解到。设置为可见的log如下:

05-25 10:56:31.956  1915  1973 V WindowManager: performShow on Window{f4647f5 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: mDrawState=READY_TO_SHOW readyForDisplay=true starting=false during animation: policyVis=true parentHidden=false tok.visibleRequested=true tok.visible=true animating=false tok animating=false Callers=com.android.server.wm.WindowState.performShowLocked:4372 com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked:256 com.android.server.wm.DisplayContent.lambda$new$8:1082 com.android.server.wm.DisplayContent.$r8$lambda$NJwM1ysKPNyOazqyI2QXlp2I4yA:0 
05-25 10:56:31.962  1915  1973 V WindowManager: Showing Window{f4647f5 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: mDrawState=READY_TO_SHOW readyForDisplay=true starting=false during animation: policyVis=true parentHidden=false tok.visibleRequested=true tok.visible=true animating=true tok animating=false Callers=com.android.server.wm.WindowState.performShowLocked:4387 com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked:256 com.android.server.wm.DisplayContent.lambda$new$8:1082 com.android.server.wm.DisplayContent.$r8$lambda$NJwM1ysKPNyOazqyI2QXlp2I4yA:0


1. ActivityThread#handleResumeActivity

Activity启动时一开始都是置为不可见INVISIBLE的,然后才置为可见VISIBLE。
ActivityThread.java - OpenGrok cross reference for /frameworks/base/core/java/android/app/ActivityThread.java

    @Override
    public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            boolean isForward, boolean shouldSendCompatFakeFocus, 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
        // skip below steps for double-resume and r.mFinish = true case.
//这个是activity resume很重要的一步,会调用到activity本身的onResume方法,后面会做详细解释
        if (!performResumeActivity(r, finalStateRequest, reason)) {
            return;
        }
//如果mActivitiesToBeDestroyed集合包含此acitivity,则不往下执行resume操作。
//mActivitiesToBeDestroyed是即将 要销毁的activity集合
        if (mActivitiesToBeDestroyed.containsKey(r.token)) {
            // Although the activity is resumed, it is going to be destroyed. So the following
            // UI operations are unnecessary and also prevents exception because its token may
            // be gone that window manager cannot recognize it. All necessary cleanup actions
            // performed below will be done while handling destruction.
            return;
        }

        final Activity a = r.activity;

        if (localLOGV) {
            Slog.v(TAG, "Resume " + r + " started activity: " + a.mStartedActivity
                    + ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished);
        }
...
//如果这个window没有被add进window manager,并且这个activity没有执行finish操作,或者启动其他activity,则首先要将此window添加进window manager中。
        boolean willBeVisible = !a.mStartedActivity;
        if (!willBeVisible) {
            willBeVisible = ActivityClient.getInstance().willActivityBeVisible(
                    a.getActivityToken());
        }
//这里代表这是首次启动这个activity
//如果window为空,并且不要执行finish,并且申请可见,则进入如下逻辑
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
//先将根布局设置为不可见
            decor.setVisibility(View.INVISIBLE);
//获取当前window manager对象
            ViewManager wm = a.getWindowManager();
//获取当前window属性
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
//将window type类型设置为普通APP类型
            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
                ViewRootImpl impl = decor.getViewRootImpl();
                if (impl != null) {
                    impl.notifyChildRebuilt();
                }
            }
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
//如果此window没有被add进window manager过,则将此根view(decor)add进window manager中
                    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) {//如果这个activity已经被add进window manager过了,并且在resume期间又起了其他activity,那么我们就不会将这个window设置为可见
            if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
//设置立即hide的flag为true
            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.
//这里代表这个activity已经被添加进window manager了,并非首次启动
        if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
            if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward);
//获取ViewRootImpl
            ViewRootImpl impl = r.window.getDecorView().getViewRootImpl();
//获取窗口属性
            WindowManager.LayoutParams l = impl != null
                    ? impl.mWindowAttributes : 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();
            }
...
    }

 这块大概的流程图如上所示,在执行handleResumeActivity的时候,会先去执行activity的onResume方法,然后再将当前的window add进window manager。

这块有个地方拓展下,就是窗口类型,普通apk启动的窗口类型都是TYPE_BASE_APPLICATION

            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

Android系统三大窗口类型

Android系统中共有三大窗口类型,分别是Application类型, 子窗口类型,以及系统窗口类型:

窗口类型Vlaue含义
以下窗口类型为普通APPLICAT窗口类型,范围1-99
FIRST_APPLICATION_WINDOW 1App的初始值
TYPE_BASE_APPLICATION1所有App的基础值
TYPE_APPLICATION2普通应用程序窗口
TYPE_APPLICATION_STARTING3starting窗口
TYPE_DRAWN_APPLICATION4等待绘制完成的窗口
LAST_APPLICATION_WINDOW 99App的最大值
以下窗口类型为子窗口类型,范围1000-1999
FIRST_SUB_WINDOW 1000子窗口的初始值
TYPE_APPLICATION_PANELFIRST_SUB_WINDOW 应用程序窗口顶部的面板。这些窗口出现在它们的附属窗口的顶部。
TYPE_APPLICATION_MEDIAFIRST_SUB_WINDOW +1media子窗口
TYPE_APPLICATION_SUB_PANELFIRST_SUB_WINDOW +2子窗口之上的子窗口

TYPE_APPLICATION_ATTACHED

_DIALOG

FIRST_SUB_WINDOW +3Dialog子窗口

TYPE_APPLICATION_MEDIA

_OVERLAY

FIRST_SUB_WINDOW +4media子窗口之上的子窗口

TYPE_APPLICATION_ABOVE_

SUB_PANEL

FIRST_SUB_WINDOW +5在SUB_PANEL之上的子窗口
LAST_SUB_WINDOW 1999子窗口的最大值
以下为系统窗口类型,范围2000-2999
FIRST_SYSTEM_WINDOW2000系统窗口的初始值
TYPE_STATUS_BARFIRST_SYSTEM_WINDOW系统状态栏窗口
TYPE_SEARCH_BARFIRST_SYSTEM_WINDOW+1搜索条窗口
TYPE_PHONEFIRST_SYSTEM_WINDOW+2通话窗口,位于状态栏之上
TYPE_SYSTEM_ALERTFIRST_SYSTEM_WINDOW+3Alert窗口,如电量不足提示,显示在APP之上窗口
TYPE_KEYGUARDFIRST_SYSTEM_WINDOW+4锁屏窗口
TYPE_TOASTFIRST_SYSTEM_WINDOW+5短暂的提示框窗口
TYPE_SYSTEM_OVERLAYFIRST_SYSTEM_WINDOW+6系统覆盖窗口,不能接受input焦点,否则会与屏保发生冲突
TYPE_PRIORITY_PHONEFIRST_SYSTEM_WINDOW+7电话优先窗口,如屏保状态下显示来电窗口
TYPE_SYSTEM_DIALOGFIRST_SYSTEM_WINDOW+8系统Dialog窗口
TYPE_KEYGUARD_DIALOGFIRST_SYSTEM_WINDOW+9keyguard Dialog窗口
TYPE_SYSTEM_ERRORFIRST_SYSTEM_WINDOW+10系统报错窗口
TYPE_INPUT_METHODFIRST_SYSTEM_WINDOW+11输入法窗口
TYPE_INPUT_METHOD_DIALOGFIRST_SYSTEM_WINDOW+12输入法Dialog窗口
TYPE_WALLPAPERFIRST_SYSTEM_WINDOW+13壁纸窗口
TYPE_STATUS_BAR_PANELFIRST_SYSTEM_WINDOW+14从状态栏滑出的面板在多用户系统中显示在所有用户的窗口上。

TYPE_SECURE_SYSTEM_OVERLAY

FIRST_SYSTEM_WINDOW+15@hide
TYPE_DRAGFIRST_SYSTEM_WINDOW+16@hide拖拽窗口

TYPE_STATUS_BAR_SUB_PANEL

FIRST_SYSTEM_WINDOW+17@hide,status bar之上的子窗口
TYPE_POINTERFIRST_SYSTEM_WINDOW+18@hide
TYPE_NAVIGATION_BARFIRST_SYSTEM_WINDOW+19@hide导航栏窗口
TYPE_VOLUME_OVERLAYFIRST_SYSTEM_WINDOW+20@hide系统音量条
TYPE_BOOT_PROGRESSFIRST_SYSTEM_WINDOW+21@hide启动时的进度条窗口
TYPE_INPUT_CONSUMERFIRST_SYSTEM_WINDOW+22@hide消耗input事件的窗口
TYPE_NAVIGATION_BAR_PANELFIRST_SYSTEM_WINDOW+24@hide
TYPE_DISPLAY_OVERLAYFIRST_SYSTEM_WINDOW+26@hide用于模拟第二个Display显示屏
TYPE_MAGNIFICATION_OVERLAYFIRST_SYSTEM_WINDOW+27@hide
TYPE_PRIVATE_PRESENTATIONFIRST_SYSTEM_WINDOW+30
TYPE_VOICE_INTERACTIONFIRST_SYSTEM_WINDOW+31@hide
TYPE_ACCESSIBILITY_OVERLAYFIRST_SYSTEM_WINDOW+32

TYPE_VOICE_INTERACTION_STARTING

FIRST_SYSTEM_WINDOW+33@hide
TYPE_DOCK_DIVIDERFIRST_SYSTEM_WINDOW+34@hide
TYPE_QS_DIALOGFIRST_SYSTEM_WINDOW+35@hide
TYPE_SCREENSHOTFIRST_SYSTEM_WINDOW+36@hide在锁屏之上,该层保留截图动画,区域选择和UI。
TYPE_PRESENTATIONFIRST_SYSTEM_WINDOW+37@hide用于在外部显示器上显示的窗口(多个屏幕情况下)
TYPE_APPLICATION_OVERLAYFIRST_SYSTEM_WINDOW+38

TYPE_ACCESSIBILITY_MAGNIFICATION

_OVERLAY

FIRST_SYSTEM_WINDOW+39@hide
TYPE_NOTIFICATION_SHADEFIRST_SYSTEM_WINDOW+40@hide
TYPE_STATUS_BAR_ADDITIONALFIRST_SYSTEM_WINDOW+41@hide
LAST_SYSTEM_WINDOW2999系统窗口的最大值

 1.1. ActivityThread#performResumeActivity

    @VisibleForTesting
    public boolean performResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            String reason) {
        if (localLOGV) {
            Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished);
        }
//如果activity将要finish,则直接return掉,不执行resume操作了
        if (r.activity.mFinished) {
            return false;
        }
//如果activity已经on_resume了,则不继续往下执行,return
        if (r.getLifecycleState() == ON_RESUME) {
            if (!finalStateRequest) {
                final RuntimeException e = new IllegalStateException(
                        "Trying to resume activity which is already resumed");
...
            }
            return false;
        }
...
//执行activity的onResume操作
            r.activity.performResume(r.startsNotResumed, reason);

            r.state = null;
            r.persistentState = null;
//设置activity状态为on_resume
            r.setState(ON_RESUME);
//将会打印出event log---wm_on_top_resumed_gained_called相关信息
            reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming");
        } catch (Exception e) {
            if (!mInstrumentation.onException(r.activity, e)) {
                throw new RuntimeException("Unable to resume activity "
                        + r.intent.getComponent().toShortString() + ": " + e.toString(), e);
            }
        }
        return true;
    }

本小节介绍了activity启动过程中其他的知识,下文再继续接着讲怎么添加窗口流程的,下面接着1.1中的addView方法。

2. WindowManager#addView

wm的获取方法如下,可以看到最后是获得到了一个WindowManager对象,

    private WindowManager mWindowManager;
    public WindowManager getWindowManager() {
        return mWindowManager;
    }

那就来到了WindowManager中的addView方法

查看WindowManager中没有addView方法,但是ViewManager中有,那我们再看下谁实现了WindowManager呢

public interface WindowManager extends ViewManager {
-------------------------------------------------------------
public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

可找到是WindowManagerImpl中实现此addView方法,因为WindowManagerImpl继承了WindowManager:

/*
 * @see WindowManager
 * @see WindowManagerGlobal
 * @hide
 */
public final class WindowManagerImpl implements WindowManager {
...
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyTokens(params);
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }

此方法又调用了 WindowManagerGlobal中的addView方法,并将view,窗口属性,要显示的屏幕,父window,以及user id传入

WindowManagerGlobal.java - OpenGrok cross reference for /frameworks/base/core/java/android/view/WindowManagerGlobal.java

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
        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);
                    }
                }
            }

            IWindowSession windowlessSession = null;
            // If there is a parent set, but we can't find it, it may be coming
            // from a SurfaceControlViewHost hierarchy.
//如果token不为空并且不是子窗口
            if (wparams.token != null && panelParentView == null) {
                for (int i = 0; i < mWindowlessRoots.size(); i++) {
                    ViewRootImpl maybeParent = mWindowlessRoots.get(i);
                    if (maybeParent.getWindowToken() == wparams.token) {
//获取WindowSession
                        windowlessSession = maybeParent.getWindowSession();
                        break;
                    }
                }
            }

            if (windowlessSession == null) {
//如果windowlessSession为空
                root = new ViewRootImpl(view.getContext(), display);
            } else {
//如果windowlessSession不为空,则在此处传入windowlessSession
                root = new ViewRootImpl(view.getContext(), display,
                        windowlessSession, new WindowlessWindowLayout());
            }
//将窗口布局属性设置进view
            view.setLayoutParams(wparams);
//将此view添加进mViews
            mViews.add(view);
//将此root添加进MRoots
            mRoots.add(root);
//将此窗口布局属性添加进mParams
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
//将view,窗口属性和子窗口,user id 设置进ViewRootImpl
                root.setView(view, wparams, panelParentView, userId);
            } catch (RuntimeException e) {
                final int viewIndex = (index >= 0) ? index : (mViews.size() - 1);
                // BadTokenException or InvalidDisplayException, clean up.
                if (viewIndex >= 0) {
                    removeViewLocked(viewIndex, true);
                }
                throw e;
            }
        }
    }

3. ViewRootImpl#setView

然后就从WindowManagerGlobal走到了ViewRootImpl中

http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/view/ViewRootImpl.java#1214

    final IWindowSession mWindowSession;

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        setView(view, attrs, panelParentView, UserHandle.myUserId());
    }

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {
        synchronized (this) {
//这个mView和上一个方法中的可不一样,当窗口detach后,这个mView会被置为空
            if (mView == null) {
                mView = view;
...

                mWindowAttributes.copyFrom(attrs)
...
                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
//首先需要layout
                requestLayout();
...
//这个是很重要的一步
                    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId,
                            mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets, mTempControls, attachedFrame, compatScale);
...
                mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars;
                mInsetsController.onStateChanged(mTempInsets);
                mInsetsController.onControlsChanged(mTempControls.get());
                final InsetsState state = mInsetsController.getState();
                final Rect displayCutoutSafe = mTempRect;
                state.getDisplayCutoutSafe(displayCutoutSafe);
                final WindowConfiguration winConfig = getCompatWindowConfiguration();
                mWindowLayout.computeFrames(mWindowAttributes, state,
                        displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
                        UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
                        mInsetsController.getRequestedVisibleTypes(), 1f /* compactScale */, mTmpFrames);
                setFrame(mTmpFrames.frame, true /* withinRelayout */);
...
    }

接着往下走,就会讲到WindowSession.addToDisplayAsUser方法

4. WindowSession.addToDisplayAsUser

这里是涉及到AIDL通信,因为mWindowSession是final IWindowSession mWindowSession;

用到的AIDL文件如下:

frameworks/base/core/java/android/view/IWindowSession.aidl

http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/view/IWindowSession.aidl

 在Client端,WindowlessWindowManager实现了IWindowSession

public class WindowlessWindowManager implements IWindowSession {
    /**
     * IWindowSession implementation. Currently this class doesn't need to support for multi-user.
     */
    @Override
    public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, int userId, @InsetsType int requestedVisibleTypes,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
            float[] outSizeCompatScale) {
        return addToDisplay(window, attrs, viewVisibility, displayId, requestedVisibleTypes,
                outInputChannel, outInsetsState, outActiveControls, outAttachedFrame,
                outSizeCompatScale);
    }

    @Override
    public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, @InsetsType int requestedVisibleTypes,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
            float[] outSizeCompatScale) {
// setParent方法作用如下
// Set a parent surface for our new SurfaceControl.
// 给我们的new SurfaceControl设置父surface
// Child surfaces are constrained to the onscreen region of their parent.
//子surfaces被限制在它们的父surface之上
// Furthermore they stack relatively in Z order, and inherit the transformation of the parent.
//此外这些stack按照Z值排序,并继承父级的transformation 

//window leash 图层创建
        final SurfaceControl leash = new SurfaceControl.Builder(mSurfaceSession)
                .setName(attrs.getTitle().toString() + "Leash")
                .setCallsite("WindowlessWindowManager.addToDisplay")
                .setParent(getParentSurface(window, attrs))
                .build();
//window图层创建
        final SurfaceControl sc = new SurfaceControl.Builder(mSurfaceSession)
                .setFormat(attrs.format)
                .setBLASTLayer()
                .setName(attrs.getTitle().toString())
                .setCallsite("WindowlessWindowManager.addToDisplay")
                .setHidden(false)
                .setParent(leash)
                .build();
//在当前文件的最上面有State的定义,主要就是将入参赋值给State的全局变量
        final State state = new State(sc, attrs, displayId, window, leash, /* frame= */ new Rect());
        synchronized (this) {
            State parentState = mStateForWindow.get(attrs.token);
            if (parentState != null) {
                state.mAttachedFrame = parentState.mFrame;
            }

            // Give the first window the mFocusGrantToken since that's the token the host can use
            // to give focus to the embedded.
            if (mStateForWindow.isEmpty()) {
                state.mFocusGrantToken = mFocusGrantToken;
            } else {
                state.mFocusGrantToken = new Binder();
            }

            mStateForWindow.put(window.asBinder(), state);
        }

        if (state.mAttachedFrame == null) {
            outAttachedFrame.set(0, 0, -1, -1);
        } else {
            outAttachedFrame.set(state.mAttachedFrame);
        }
        outSizeCompatScale[0] = 1f;

        if (((attrs.inputFeatures &
                WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) {
            try {
                if (mRealWm instanceof IWindowSession.Stub) {
                    mRealWm.grantInputChannel(displayId,
                            new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"),
                            window, mHostInputToken, attrs.flags, attrs.privateFlags,
                            attrs.inputFeatures, attrs.type,
                            attrs.token, state.mFocusGrantToken, attrs.getTitle().toString(), outInputChannel);
                } else {
                    mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags, attrs.privateFlags, attrs.inputFeatures, attrs.type, attrs.token,
                  state.mFocusGrantToken, attrs.getTitle().toString(), outInputChannel);
                }
                state.mInputChannelToken =
                        outInputChannel != null ? outInputChannel.getToken() : null;
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to grant input to surface: ", e);
            }
        }

        final int res = WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE |
                        WindowManagerGlobal.ADD_FLAG_USE_BLAST;

        // Include whether the window is in touch mode.
        return isInTouchModeInternal(displayId) ? res | WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE
                : res;
    }

这里我们来看一下mRealWm的赋值过程

public class WindowlessWindowManager implements IWindowSession {
    ...
//全局变量声明
    private final IWindowSession mRealWm;
    public WindowlessWindowManager(Configuration c, SurfaceControl rootSurface,
            IBinder hostInputToken) {
        mRootSurface = rootSurface;
        mConfiguration = new Configuration(c);
//赋值
        mRealWm = WindowManagerGlobal.getWindowSession();
        mHostInputToken = hostInputToken;
    }

然后就走到了WindowManagerGlobal这里去获取WindowSession

WindowManagerGlobal.java - OpenGrok cross reference for /frameworks/base/core/java/android/view/WindowManagerGlobal.java

    @UnsupportedAppUsage
    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
// Emulate the legacy behavior.  The global instance of InputMethodManager
// was instantiated here.
// TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
                    InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
//第一步
                    IWindowManager windowManager = getWindowManagerService();
//第二步
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            });
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }

 在第一步中,通过getWindowManagerService方法获取了server端binder对象,即获取了WMS服务, 看代码是单例模式,可以看出来这个sWindowSession是一个单例,也就是一个应用的所有ViewRootImpl的WindowSession都是同一个,也就是一个应用只有一个WindowSession,用于与WMS进行通信。

    @UnsupportedAppUsage
    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
//获取server端binder对象,即获取WMS服务
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
...
            return sWindowManagerService;
        }
    }

在第二步中,则调用到了Server端服务WMS中的方法,这里也是单例模式的写法,sWindowManagerService 在Client端也只有一个对象。

WindowManagerService.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    @Override
    public IWindowSession openSession(IWindowSessionCallback callback) {
        return new Session(this, callback);
    }

然后在WMS中new了一个Session,Session实例化相关如下 

Session.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/Session.java

class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
    final WindowManagerService mService;
    final IWindowSessionCallback mCallback;
    final int mUid;
    final int mPid;
  ...
    public Session(WindowManagerService service, IWindowSessionCallback callback) {
        mService = service;
        mCallback = callback;
        mUid = Binder.getCallingUid();
        mPid = Binder.getCallingPid();
...

来看看WMS,其实也是继承了 IWindowSession.Stub

/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {

从上我们总结出:

一个应用只有一个WindowSession, 用于与WMS进行通信。

5. Session#grantInputChannel

接着讲上文中的 grantInputChannel方法

Session.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/Session.java

    @Override
    public void grantInputChannel(int displayId, SurfaceControl surface,
            IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type, int inputFeatures, IBinder windowToken, IBinder focusGrantToken, String inputHandleName,
            InputChannel outInputChannel) {
...
//这里会调用Server端的grantInputChannel方法
            mService.grantInputChannel(this, mUid, mPid, displayId, surface, window, hostInputToken, flags, mCanAddInternalSystemWindow ? privateFlags : 0,
                    type, inputFeatures, windowToken, focusGrantToken, inputHandleName,
                    outInputChannel);
...
    }

下面是一个关于以上流程的setting主页面启动流程

05-25 12:58:21.791  1909  2175 I wm_task_created: 441
05-25 12:58:21.795  1909  2175 I wm_task_moved: [441,441,0,1,2]
05-25 12:58:21.795  1909  2175 I wm_task_to_front: [0,441,0]
05-25 12:58:21.795  1909  2175 I wm_create_task: [0,441,441,0]
05-25 12:58:21.795  1909  2175 I wm_create_activity: [0,232997572,441,com.android.settings/.homepage.SettingsHomepageActivity,android.settings.SETTINGS,NULL,NULL,335544320]
05-25 12:58:21.795  1909  2175 I wm_task_moved: [441,441,0,1,2]
05-25 12:58:22.265  1909  3494 I wm_restart_activity: [0,232997572,441,com.android.settings/.homepage.SettingsHomepageActivity]
05-25 12:58:22.267  1909  3494 I wm_set_resumed_activity: [0,com.android.settings/.homepage.SettingsHomepageActivity,minimalResumeActivityLocked - onActivityStateChanged]
05-25 12:58:22.363  2518  2518 I wm_on_create_called: [232997572,com.android.settings.homepage.SettingsHomepageActivity,performCreate,66]
05-25 12:58:22.457  2518  2518 I wm_on_start_called: [232997572,com.android.settings.homepage.SettingsHomepageActivity,handleStartActivity,92]
05-25 12:58:22.460  2518  2518 V ActivityThread: Performing resume of ActivityRecord{a4a98fc token=android.os.BinderProxy@c7155ef {com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}} finished=false
05-25 12:58:22.460  2518  2518 I wm_on_resume_called: [232997572,com.android.settings.homepage.SettingsHomepageActivity,RESUME_ACTIVITY,0]
05-25 12:58:22.525  2518  2518 V ActivityThread: Resume ActivityRecord{a4a98fc token=android.os.BinderProxy@c7155ef {com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}} started activity: false, hideForNow: false, finished: false
05-25 12:58:22.545  1909  2175 V WindowManager: Attaching Window{a90e6ab u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity} token=ActivityRecord{de342c4 u0 com.android.settings/.homepage.SettingsHomepageActivity t441}
05-25 12:58:22.552  2518  2518 V ActivityThread: Resuming ActivityRecord{a4a98fc token=android.os.BinderProxy@c7155ef {com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}} with isForward=true
05-25 12:58:22.552  2518  2518 V ActivityThread: Scheduling idle handler for ActivityRecord{a4a98fc token=android.os.BinderProxy@c7155ef {com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}}
05-25 12:58:22.553  2518  2518 I wm_on_top_resumed_gained_called: [232997572,com.android.settings.homepage.SettingsHomepageActivity,topStateChangedWhenResumed]
05-25 12:58:22.769  1909  1971 I wm_activity_launch_time: [0,232997572,com.android.settings/.homepage.SettingsHomepageActivity,970]

6. WindowManagerService#grantInputChannel

这里就到了Server端,以上都是Client端。

由于本篇文章已经过长,故Server端的另起一篇文章分析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/658702.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年社会发展、人文艺术与文化国际会议(ICSDHAC 2024)

2024年社会发展、人文艺术与文化国际会议&#xff08;ICSDHAC 2024&#xff09; 会议简介 2024年国际社会发展、人文、艺术和文化会议&#xff08;ICSDHAC 2024&#xff09;将在广州举行。会议旨在为从事社会发展、人文、艺术和文化研究的专家学者提供一个平台&#xff0c;分…

xjar加密springboot的jar包,并编译为执行程序

场景&#xff1a;当前项目需要进行jar包部署在windows环境和linux环境&#xff0c;并要求使用xjar加密。 1. xjar加密 源码程序自行搜索&#xff0c;这里只介绍加密及运行&#xff0c;运行加密程序&#xff0c;指定jar包&#xff0c;输入密码 2. 加密后的目录 3. go程序编译 …

Vanna使用ollama分析本地MySQL数据库

上一章节中已经实现了vanna的本地运行&#xff0c;但是大模型和数据库都还是远程的&#xff0c;因为也就没办法去训练&#xff0c;这节一起来实现vanna分析本地mysql数据库&#xff0c;因为要使用本地大模型&#xff0c;所以开始之前需要给本地安装好大模型&#xff0c;我这里用…

【数据结构】二叉搜索树——高阶数据结构的敲门砖

目录 树概述 二叉搜索树概述 概念 特性 元素操作 插入 删除 模拟实现 框架 查找 插入 删除 树概述 树——在计算机中是一种很常见的数据结构。 树是一种很强大的数据结构&#xff0c;数据库&#xff0c;linux操作系统管理和windows操作系统管理所有文件的结构就是…

PS教程08

光效 新建一个图层 按住Altdelete将颜色填充完毕。 转换智能对象 作用&#xff1a;我们可以对这个图层无限期修改 接下来找到滤镜-渲染-镜头光晕 选择需要的亮度和镜头类型&#xff0c;点击确定 如果发现位置不太理想&#xff0c;可以直接双击右下角的镜头光晕&#xff0c;…

swagger-ui页面接口的入参出参与代码实体类不一致有差异、swagger请求实体与预期定义不符、swagger参数与实体中参数不一致原因分析

文章目录 一、问题背景二、问题原因及解决方法 一、问题背景 项目集成swagger之后&#xff0c;发现有个接口的请求跟接口对应不上&#xff0c;把其他接口的请求参数放到当前这个请求上了。 如下图&#xff1a;test1接口的请求参数是其他请求的&#xff0c;并不是test1接口的 …

RFID芯片掼蛋牌:高科技与传统玩法结合,游戏体验焕然一新。

火爆“出圈”的掼蛋&#xff0c;是一种玩法相当鲜明的智力游戏。近年来得到了不少的推广和发展&#xff0c;各地举办了各种掼蛋比赛和活动&#xff0c;吸引了大量的参赛者和观众。此外&#xff0c;一些企业和机构也开始将掼蛋作为一种企业文化或者社交活动的方式&#xff0c;通…

无需开孔,安全美观:低功耗微波雷达模块开启宠物喂食器新未来

在快节奏的现代生活中&#xff0c;宠物已成为许多家庭的重要成员。然而&#xff0c;忙碌的主人常常为如何确保宠物按时进食而困扰。近年来&#xff0c;智能家居技术飞速发展&#xff0c;宠物喂食器也逐渐智能化&#xff0c;极大地方便了宠物主人。今天&#xff0c;我们要介绍的…

项目成功的关键要素:进度管理

在项目管理中&#xff0c;进度管理是决定项目成败的关键因素之一。它关乎项目能否在预定的时间范围内高效、准确地完成既定目标。 一、进度管理的重要性 1、时间控制&#xff1a;项目的成功往往与时间的把握息息相关。进度管理能够确保项目在既定的时间框架内有序进行&#x…

MySQL select for update 加锁

背景 当多人操作同一个客户下账号的时候&#xff0c;希望顺序执行&#xff0c;某个时刻只有一个人在操作&#xff1b;当然可以通过引入redis这种中间件实现&#xff0c;但考虑到并发不会很多&#xff0c;所以不想再引入别的中间件。 表结构 create table jiankunking_accoun…

肆拾玖坊FFC模式,社群裂变,股权众筹设计

肆拾玖坊商业模式&#xff0c;白酒新零售体系&#xff0c;众筹合伙模式 坐标&#xff1a;厦门&#xff0c;我是易创客肖琳 深耕社交新零售行业10年&#xff0c;主要提供新零售系统工具及顶层商业模式设计、全案策划运营陪跑等。 联想高管辞职跑去卖酒&#xff0c;6年狂赚30亿&…

手机“本地”也能玩转AI大模型 - 万物皆可AI

友友们&#xff0c;大家好&#xff01;我最近发现一个很有意思的AI项目——MiniCPM-V&#xff0c;可以说它将AI技术的应用推向了一个全新的高度&#xff0c;让我们能够将GPT-4V级的多模态大模型直接部署在我们的手机上&#xff0c;而且完全不需要联网&#xff0c;真正的手机本地…

Unity版本使用情况统计(更新至2024年4月)

UWA发布&#xff5c;本期UWA发布的内容是第十四期Unity版本使用统计&#xff0c;统计周期为2023年11月至2024年4月&#xff0c;数据来源于UWA网站&#xff08;www.uwa4d.com&#xff09;性能诊断提测的项目。希望给Unity开发者提供相关的行业趋势作为参考。 2023年11月 - 2024年…

C++候捷stl-视频笔记1

认识headers、版本、重要资源 STL的核心思想是泛型编程 新式头文件内的组件封装在命名空间std中&#xff1a; using namespace std; using std::cout;或std::vector vec; 旧式头文件内的组件不封装在命名空间std中 注:不建直接使用using namespace xxx&#xff0c;如果使用的…

apexcharts数据可视化之极坐标区域图

apexcharts数据可视化之极坐标区域图 有完整配套的Python后端代码。 本教程主要会介绍如下图形绘制方式&#xff1a; 基础极坐标区域图单色极坐标区域图 基础极坐标区域图 import ApexChart from react-apexcharts;export function BasicPolar() {// 数据序列const series…

深入解析多维数组与主对角线元素之和

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;多维数组的奥秘 二、多维数组的基本概念 1. 定义与创建 2. 维度与形…

Linux服务器安装docker,基于Linux(openEuler、CentOS8)

本实验环境为openEuler系统(以server方式安装)&#xff08;CentOS8基本一致&#xff0c;可参考本文) 目录 知识点实验 知识点 Docker 是一个开源的应用容器引擎。它允许开发者将应用及其所有依赖项打包到一个可移植的容器中&#xff0c;并发布到任何支持Docker的流行Linux或Wi…

歌曲转换成mp3格式超简单!快来试试看

在数字音乐时代&#xff0c;我们经常从各种来源下载或收藏到各种音频文件&#xff0c;但有时这些文件可能并不是我们设备所支持的常见格式&#xff0c;尤其是当我们更倾向于使用MP3格式的时候。因此&#xff0c;对于那些希望统一音乐库格式的人来说&#xff0c;将歌曲转换成mp3…

redis面试知识点

Redis知识点 Redis的RDB和AOF机制各是什么&#xff1f;它们有什么区别&#xff1f; 答&#xff1a;Redis提供了RDB和AOF两种数据持久化机制&#xff0c;适用于不同的场景。 RDB是通过在特定的时刻对内存中的完整的数据复制快照进行持久化的。 RDB工作原理&#xff1a; 当执行…

深入理解深度学习中的激活层:Sigmoid和Softmax作为非终结层的应用

深入理解深度学习中的激活层&#xff1a;Sigmoid和Softmax作为非终结层的应用Sigmoid 和 Softmax 激活函数简介Sigmoid函数Softmax函数 Sigmoid 和 Softmax 作为非终结层多任务学习特征变换增加网络的非线性实际案例 注意事项结论 深入理解深度学习中的激活层&#xff1a;Sigmo…