Surface系统-2-SurfaceControl的创建(java层)

674 阅读8分钟

忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。

                        -- 服装学院的IT男

Surface系统-1-应用与SurfaceFlinger建立链接

Surface系统-2-SurfaceControl的创建(java层)

Surface系统-3-SurfaceControl的创建(native层)

Surface系统-4-BLASTBufferQueue和Surface的创建

Surface系统-5-BLASTBufferQueue工作流程概览

本篇同时已收录于Activity短暂的一生系列

正文

应用在第一个窗口显示的时候会创建出 SurfaceSession 与 SurfaceFlinger 通信。 应用需要显示的一个窗口或者一块区域就是一个 Surface ,一个 SurfaceControl 管理着1个 Surface ,介绍 SurfaceControl 的创建。 为了内容的联系续 java 层的逻辑会与 【窗口显示第二步-relayoutWindow-1】有部分重叠。

1. 流程概览

ViewRootImpl 创建的时候就有 mSurface 和 mSurfaceControl 2个成员变量,但是只是个 java 层的对象实例,目前还没有对应 native 的实现,真正赋值的方式是在 relayoutWindow 流程中。

mSurfaceControl 作为参数传递到 WMS,然后在WMS中作为出参被赋值,这块的代码如下:

# ViewRootImpl

    // 成员变量
    public final Surface mSurface = new Surface();
    private final SurfaceControl mSurfaceControl = new SurfaceControl();

    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
                ......
                // 1. 作为参数传递到 system_sertvice 进程
                relayoutResult = mWindowSession.relayout(......, mSurfaceControl,......);
                ......
                    // 2. 给 mSurface 赋值
                    if (!useBLAST()) {
                        mSurface.copyFrom(mSurfaceControl);
                    } else {
                        // 现在都走这给mSurface赋值
                        updateBlastSurfaceIfNeeded();
                    }
                ......
            }

    1. mSurfaceControl 作为参数(out参数)传递到 system_server ,执行 relayoutWindow 流程,在这个过程中会创建 native 层的 SurfaceControl 也会对应用端传过去的 mSurfaceControl 进行赋值
    1. 经过 system_server 处理后的 mSurfaceControl 有值了,再给 mSurface 赋值

这块的调用链如下:

ViewRootImpl::init 
    Surface::init
    SurfaceControl::init 
    ViewRootImpl::relayoutWindow  -- SurfaceControl作为出参
        Session::relayout
            WindowManagerService::relayoutWindow
                WindowManagerService::createSurfaceControl  -- 创建显示的Surface
                    WindowStateAnimator::createSurfaceLocked
                        WindowSurfaceController::init
                            SurfaceControl.Build::init
                            SurfaceControl::init
                                  nativeCreate  -- native层创建Surface
                    WindowSurfaceController::getSurfaceControl
                        SurfaceControl::copyFrom
                            SurfaceControl::assignNativeObject -- 将Surface的指针和句柄传递给应用端
    Surface::updateBlastSurfaceIfNeeded  -- 赋值给应用端的Surface
        BLASTBufferQueue::init
        BLASTBufferQueue::createSurface
            Surface::transferFrom
                    Surface::setNativeObjectLocked

2. java 层 SurfaceControl 的创建

java 层 SurfaceControl 的创建逻辑主要是在 system_server 端处理,处理的终点就是触发 native 的执行。

看一下 WindowManagerService 的相关逻辑:

# WindowManagerService

    public int relayoutWindow(Session session, IWindow client, ......
            SurfaceControl outSurfaceControl, ......) {
                ......
                // 拿到对应的 WindowState
                final WindowState win = windowForClientLocked(session, client, false);
                ......
                WindowStateAnimator winAnimator = win.mWinAnimator;
                ......
                // 当前主线* 创建 system_server 进程对应的SurfaceControl
                result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
                ......
            }

relayoutWindow 流程是在 addWindow 流程之后, addWindow 流程会在 system_server 进程为要显示的窗口创建对应的 WindowState 。所以这里在执行 relayoutWindow 的时候可以通过windowForClientLocked 方法获取到对应的 WindowState ,而 WindowStateAnimator 是在 WindowState 构造方法中创建的。

拿到了 WindowState 和 WindowStateAnimator 就可以创建SurfaceControl了,注意第一个参数,这个 outSurfaceControl 就是在应用端传递过来的,参数前面加上了“out”是 binder 作为出参的方式,也就是说 system_server 进程会对这个参数进行赋值,这样应用端 ViewRootImpl 下的 SurfaceControl 就会持有一个 native 层的 SurfaceControl 指针。

# WindowManagerService

    private int createSurfaceControl(SurfaceControl outSurfaceControl, int result,
            WindowState win, WindowStateAnimator winAnimator) {
        ......
        //  窗口的Surface管理者
        WindowSurfaceController surfaceController;
        try {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
            // 1. 创建 WindowSurfaceController
            surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        if (surfaceController != null) {
            // 2. outSurfaceControl
            surfaceController.getSurfaceControl(outSurfaceControl);
            ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);

        }
        ......
        return result;
    }

这里分为2步:

    1. 创建 SurfaceControl
    1. 赋值给出参 outSurfaceControl

这里看到 WindowSurfaceController 这个类,它内部有一个 SurfaceController , SurfaceController 内部又操作 Surface 。 之前看过他们之间的关系如下:

类图-java层Surface关系.png

2.1 创建 SurfaceController

# WindowStateAnimator

    WindowSurfaceController createSurfaceLocked() {
        final WindowState w = mWin;
        // 如果已经创建过就直接返回
        if (mSurfaceController != null) {
            return mSurfaceController;
        }
        w.setHasSurface(false);
        ProtoLog.i(WM_DEBUG_ANIM, "createSurface %s: mDrawState=DRAW_PENDING", this);
        //   mDrawState = DRAW_PENDING
        resetDrawState();
        ......
        try {
            ......
            // 重点*2. 创建WindowSurfaceController
            mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), format,
                    flags, this, attrs.type);
            mSurfaceController.setColorSpaceAgnostic((attrs.privateFlags
                    & WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);
            // 标志着 WindowState 已经有 surface 了
            w.setHasSurface(true);
            ......
        } catch (OutOfResourcesException e) {
            ......
        } 
        ......
        return mSurfaceController;
    }

WindowSurfaceController 构造后会创建一个 SurfaceControl 也就意味着创建了一个 Surface 所以这里将 执行了 WindowStateAnimator::resetDrawState 把窗口状态设置为 DRAW_PENDING 表示处于等待绘制的状态。

下面看看 WindowSurfaceController 的构造方法,需要留意下第一个参数,这个就是窗口参数的 title 。

# WindowSurfaceController
    // 持有一个SurfaceControl
    SurfaceControl mSurfaceControl;

    WindowSurfaceController(String name, int format, int flags, WindowStateAnimator animator,
            int windowType) {
        ......

        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl");
        // 构建一个Builder
        final SurfaceControl.Builder b = win.makeSurface()
                .setParent(win.getSurfaceControl()) // 挂载在windowState下
                .setName(name) // 名字就是窗口的name
                .setFormat(format)
                .setFlags(flags)
                .setMetadata(METADATA_WINDOW_TYPE, windowType)
                .setMetadata(METADATA_OWNER_UID, mWindowSession.mUid)
                .setMetadata(METADATA_OWNER_PID, mWindowSession.mPid)
                .setCallsite("WindowSurfaceController");

        final boolean useBLAST = mService.mUseBLAST && ((win.getAttrs().privateFlags
                & WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST) != 0);

        // 高版本都为BLAST
        if (useBLAST) {
            // 注意*  设置为非容器图层
            b.setBLASTLayer();
        }
        // 构建SurfaceControl
        mSurfaceControl = b.build();

        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }

构建了一个 SurfaceControl,这里创建 SurfaceControl 的方式和容器是一样的,但是通过 setBLASTLayer方法将当前 Surface 设置成 Buff 类型的 Surface ,这样就可以显示内容了,这点非常重要。

# SurfaceControl.Build

        @NonNull
        public SurfaceControl build() {
            // 构建一个SurfaceControl
            return new SurfaceControl(
                    mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata,
                    mLocalOwnerView, mCallsite);
        }
# SurfaceControl
    // 指针
    public long mNativeObject;
    // 句柄
    private long mNativeHandle;

    private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
        SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,
        String callsite)
                    throws OutOfResourcesException, IllegalArgumentException {
        ......
        // *1. native创建,返回对象指针
        mNativeObject = nativeCreate(session, name, w, h, format, flags,
                    parent != null ? parent.mNativeObject : 0, metaParcel);
        if (mNativeObject == 0) {
            throw new OutOfResourcesException(
                    "Couldn't allocate SurfaceControl native object");
        }
        // 2.根据指针获取SurfaceControl的句柄
        mNativeHandle = nativeGetHandle(mNativeObject);
        mCloseGuard.openWithCallSite("release", callsite);
    }

这里出现了句柄和指针的概念: 指针:指向对象的内存地址 句柄:JNI经常使用句柄来引用本地代码中的对象或资源,以便在Java和本地代码之间传递引用而不暴露底层实现细节。

这里用到的 session 就是 SurfaceSession。

上面这代码是 SurfaceControl 的构造方法,虽然目前还是没看到 Surface 的身影,但是其实在 native 层创建 SurfaceControl 的时候也会创建好一个 Surface 。 native 的处理逻辑后面会单独详细解释,目前就先以黑盒的概念继续往后看。

2.2 应用端 SurfaceController 的赋值

继续看是怎么把创建好的 SurfaceController 传递给应用端的。 回到主流程知道在 WindowManagerService::createSurfaceControl 方法里会先执行 WindowStateAnimator::createSurfaceLocked 创建 SurfaceControl 然后再执行 SurfaceController::getSurfaceControl 方法将新创建的 SurfaceControl 赋值给应用端。

# WindowSurfaceController

    void getSurfaceControl(SurfaceControl outSurfaceControl) {
        outSurfaceControl.copyFrom(mSurfaceControl, "WindowSurfaceController.getSurfaceControl");
    }

这里的参数 outSurfaceControl 是应用端传递过来的, mSurfaceControl 就是前面 WindowStateAnimator::createSurfaceLocked 创建的 SurfaceControl 。

# SurfaceControl

    public void copyFrom(@NonNull SurfaceControl other, String callsite) {
        mName = other.mName;
        mWidth = other.mWidth;
        mHeight = other.mHeight;
        mLocalOwnerView = other.mLocalOwnerView;
        // 注意将刚刚创建的 SurfaceControl 句柄作为参数
        assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject), callsite);
    }

    private void assignNativeObject(long nativeObject, String callsite) {
        ......
        // 赋值给 SurfaceControl
        mNativeObject = nativeObject;
        mNativeHandle = mNativeObject != 0 ? nativeGetHandle(nativeObject) : 0;
    }
    1. java 层的 SurfaceControl 通过 mNativeObject 持有 native 层的 SurfaceControl
    1. java 层 SurfaceControl 的赋值只需要把自己的 mNativeObject 赋值给另一个 SurfaceControl 对象即可,这样它们2个就可以持有同一个 native 层的 SurfaceControl

nativeCopyFromSurfaceControl 也是一个 native 方法,将 native 层的 SurfaceControl 进行拷贝然后获取到一个新的指针,将这个指针再传递给应用端的 SurfaceControl 。 这样一来,应用端的 SurfaceControl 就也持有了 native 层的 SurfaceControl 指针和句柄。 后续应用端对 Surface 的操作就可以体现在 native 层的Surface中了。

3. 应用端的 Surface 的赋值

经过前面的分析,现在 ViewRootImpl 下的 mSurfaceControl 已经持有了 native 层 SurfaceControl 的指针,现在看看是如何对 mSurface 赋值的。

# ViewRootImpl

public final Surface mSurface = new Surface();
private final SurfaceControl mSurfaceControl = new SurfaceControl();

    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
                ......
                // 作为参数传递到 system_sertvice进程
                relayoutResult = mWindowSession.relayout(......, mSurfaceControl,......);
                ......
                    // 经过system_server处理后的mSurfaceControl有值了,再赋值给mSurface
                    if (!useBLAST()) {
                        mSurface.copyFrom(mSurfaceControl);
                    } else {
                        // 目前版本都走这,内部也是
                        updateBlastSurfaceIfNeeded(); 
                    }
                ......
            }

BLAST 算新特性了,现在的版本都支持,所以走 ViewRootImpl::updateBlastSurfaceIfNeeded 方法,不过也可以确定 Surface::copyFrom 方法也能从一个 SurfaceControl 对象里获取到 Surface 对象。

下面看看 ViewRootImpl::updateBlastSurfaceIfNeeded 方法的实现。

# ViewRootImpl

    private BLASTBufferQueue mBlastBufferQueue;
    
    void updateBlastSurfaceIfNeeded() {
        // 1. 确认 SurfaceControl 是否有对应的 native 指针
        
        if (!mSurfaceControl.isValid()) {
            return;
        }
        ......
        // 2. 创建 BLASTBufferQueue
        mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
                mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
        mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
        // 3. 通过 BLASTBufferQueue 创建一个 Surface
        Surface blastSurface = mBlastBufferQueue.createSurface();
        // Only call transferFrom if the surface has changed to prevent inc the generation ID and
        // causing EGL resources to be recreated.
        // 4. 给当前mSurface赋值
        mSurface.transferFrom(blastSurface);
    }

逻辑还是比较清晰的,分为4步。 之前分析过在 system_server 执行 relayoutWindow 流程创建 SurfaceControl 的时候 native 层也会创建一个 Surface 。这里又看到通过 BLASTBufferQueue::createSurface 创建了一个 Surface ,这里可能会怀疑为什么又要创建一个 Surface ,这里可以先确定一个结论: 这里“创建”的 Surface 其实和之前创建 SurfaceControl 时创建的 Surface 是一个 native 层的 Surface 。

具体执行后续分析 native 代码会单独详细分析,这里其实也有2个点可以引起猜测:

    1. SurfaceControl::isValid 的实现就是判断是不是有 native 的值,只有满足条件才会根据这个 SurfaceControl 创建 BLASTBufferQueue 。这说明肯定和 relayoutWindow 流程创建 SurfaceControl 有联系
    1. BLASTBufferQueue::createSurface 虽然叫“create” 但是对应的 JNI 方法为 nativeGetSurface (获取)。

先看看 java 层是如何通过 Surface::transferFrom 给另一个 Surface 赋值的。

# Surface
    // native 层指针
    long mNativeObject; // package scope only for SurfaceControl access
    public void transferFrom(Surface other) {
        if (other == null) {
            throw new IllegalArgumentException("other must not be null");
        }
        if (other != this) {
            final long newPtr;
            synchronized (other.mLock) {
                // 设置 surface 指针
                newPtr = other.mNativeObject;
                other.setNativeObjectLocked(0);
            }

            synchronized (mLock) {
                if (mNativeObject != 0) {
                    // 释放之前的
                    nativeRelease(mNativeObject);
                }
                // 设置新的
                setNativeObjectLocked(newPtr);
            }
        }
    }
    private void setNativeObjectLocked(long ptr) {
        if (mNativeObject != ptr) {
            if (mNativeObject == 0 && ptr != 0) {
                mCloseGuard.open("Surface.release");
            } else if (mNativeObject != 0 && ptr == 0) {
                mCloseGuard.close();
            }
            // 设置 native 指针
            mNativeObject = ptr;
            mGenerationId += 1;
            if (mHwuiContext != null) {
                mHwuiContext.updateSurface();
            }
        }
    }

可以看到 Java 层的 Surface 中定义了一个变量 mNativeObject ,这个变量和 SurfaceControl 是一样都代表着 native 层的指针。

总之,经过这段调用,应用端的 Surface 也持有了对应的 native 层的 Surface 指针。

3. 结束语

上层的 SurfaceControl、 Surface、BLASTBufferQueue 的创建和赋值逻辑介绍完毕,

在 system_server 触发创建 native 层的 SurfaceControl 和 Surface 将 native 的句柄保存在 java 中。SurfaceControl 这个 Surface 的控制者控制的其实是 native 层的Surface 指针。

对应分析过程中遇到的 native 问题有下面3个,后面会单独分析:

    1. SurfaceControl 对应的 native 创建逻辑
    1. BLASTBufferQueue 的 native 创建逻辑,和 SurfaceControl 有什么联系
    1. BLASTBufferQueue::nativeGetSurface 获取的 Surface 流程