【Android】Framework笔记——View的绘制流程(二)

之前一篇文章讲到在 ViewRootImpl 的 setView 方法中调用 requestLayout 后经过一系列过程完成了整个 View 的测量布局及绘制流程。但是 draw 方法中的 canvas 又是怎么来的呢?

Canvas 的来源

我们都知道,draw 的调用是在 ViewRootImpl 中的 performDraw 方法中调用的,此时还没有传入 Canvas 对象,而它内部调用了 ViewRootImpl 的 draw 方法,让我们看看这个方法的实现:

private boolean draw(boolean fullRedrawNeeded) {
    Surface surface = mSurface;
    if (!surface.isValid()) {
        return false;
    }
    // ...
    if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
        // If accessibility focus moved, always invalidate the root.

        // ...
        mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this, callback);
    } else {
        // If we get here with a disabled & requested hardware renderer, something went
        // wrong (an invalidate posted right before we destroyed the hardware surface
        // for instance) so we should just bail out. Locking the surface with software
        // rendering at this point would lock it forever and prevent hardware renderer
        // from doing its job when it comes back.
        // Before we request a new frame we must however attempt to reinitiliaze the
        // hardware renderer if it's in requested state. This would happen after an
        // eglTerminate() for instance.

        // ...
        if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
                scalingRequired, dirty, surfaceInsets)) {
            return false;
        }
    }
}

可以看出,Android 共有两种绘制方式——硬件绘制和软件绘制。

我们先研究软件绘制的代码,让我们看到 drawSoftware 方法:

private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
        boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
    // Draw with software renderer.
    final Canvas canvas;
    // ...
    try {
        // ...
        canvas = mSurface.lockCanvas(dirty);
        // ...
        canvas.setDensity(mDensity);
    } 
    // ...
    try {
        // ...
        try {
            canvas.translate(-xoff, -yoff);
            // ...
            mView.draw(canvas);
            drawAccessibilityFocusedDrawableIfNeeded(canvas);
        } // ...
    } finally {
        try {
            surface.unlockCanvasAndPost(canvas);
        } // ...
    }
    return true;
}

可以看出来,它的 canvas 是通过 Surface 的 lockCanvas 所得到的,之后我们就可以通过这个 Canvas 上调用其提供的绘制 API 在 Surface 上进行绘制了。

获得 canvas 后,这里对其调用了 translate 方法进行了偏移,之后调用了 View.draw 并传入了我们前面获得的 canvas。看来这就是我们的 Canvas 的来源了。

那么 Surface 与 Canvas 究竟是什么呢?下面我们讨论一下 Canvas、Surface、SurfaceFlinger 到底是什么:

Canvas、Surface、SurfaceFlinger

Canvas、Surface、SurfaceFlinger 与硬件协同作用,共同完成了我们的绘图任务,它们之间通过 Buffer 进行交互,负责不同的职责:

  • Surface 可以理解为一个画布,在程序角度来说就是对应了一个缓冲区,通过它可以与 BufferQueue 进行交互从而拿到缓冲区进行写入数据,具体过程如下:
    • 它首先将 Buffer 从 BufferQueue 中通过 dequeueBuffer取出,通过 Canvas 提供给上层
    • 上层绘制完成后会 enqueueBuffer 放回 BufferQueue
    • SurfaceFlinger 会通过 dequeueBuffer 拿走这个 Buffer,将各个 Surface 的 Buffer 进行合成,再将其交给屏幕显示。
    • SurfaceFlinger 使用完这个 Buffer 之后就会通过 enqueueBuffer 将其放回 BufferQueue 从而实现 Buffer 的循环使用。
  • Canvas 可以理解为画笔,我们可以通过它所提供的 API 在它所对应的画布 Surface 提供的 Buffer 上绘图,如 drawBitmapdrawRect 等等...
  • SurfaceFlinger 是一个系统服务,负责了 Buffer 的合成,它可以将界面中各个 Surface 中的 Buffer 进行合成,合成为一个完整的 Buffer 数据,之后交由屏幕进行显示。

Surface 的创建过程

那么,我们来研究一下,mSurface 究竟是何时被创建并交给我们的 ViewRootImpl 的。在调用了 ViewRootImpl 的 requestLayout 方法中完成了 View 的测量布局绘制的流程后,View 还没有真正的被添加到 WindowManager 中,仅仅是将其添加到了 WindowManagerGlobal 中,之后,其实又调用到了 ViewRootImpl 中的 mWindowSession.addToDisplay,通知远程的 WMS 进行窗口的添加。

这里 mWindowSession 是一个 Binder 对象,它最终会通过 IPC 调用到 WMS 中的 addWindow 方法。

public int addWindow(Session session, IWindow client...) {
    ...
    final WindowState win = new WindowState(this, session, client, token, parentWindow,
                appOp[0], seq, attrs, viewVisibility, session.mUid,
                session.mCanAddInternalSystemWindow);
    // ...
    win.attach();

    mWindowMap.put(client.asBinder(), win);
    // ...
    win.mToken.addWindow(win);
    // ...
}

可以看到,这里先构建了一个 WindowState 对象,之后调用了 WindowState 的 attach 方法,之后以调用的 client 的 Binder 作为 key 将其放入了 mWindowMap,最后调用了其 token 下的 addWindow 方法。

与 SurfaceFlinger 建立连接

这个 WindowState 的 attach 方法其实就是 Window 与 SurfaceFlinger 相关联的起点,而 WindowState 的 attach 方法又调用到了 Session.windowAddedLocked 方法。

void windowAddedLocked(String packageName) {
    // ...
    if (mSurfaceSession == null) { 
        // ...
        mSurfaceSession = new SurfaceSession();
        // ...
    }
}

windowAddedLocked 方法中构建了一个 SurfaceSession 对象,而 SurfaceSession 的构造函数中实际上是调用了 nativeCreate 方法在 Native 层构建了一个 SurfaceComposerClient 对象,并返回了其在 Native 层对象的地址。

这个 SurfaceComposerClient 对象其实就是应用与 SurfaceFlinger 进行沟通的桥梁,它在整个应用程序中只有一个实例。在对它初次使用的时候会调用到 onFirstRef 方法:

void SurfaceComposerClient::onFirstRef() {
    // ...
    sp<ISurfaceComposerClient> conn;
    conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
            sf->createConnection();
    // ...
}

上面代码中的 sf 就是 SurfaceFlinger,通过 IPC 调用了它的 createScopedConnection 方法从而创建了一个 ISurfaceComposerClient 对象。

在 createScopedConnection 的实现中,它其实是构建了一个 Client 对象,这个对象实现了 ISurfaceComposerClient 内的虚函数,是一个可用于 IPC 的对象。SurfaceComposerClient 可以通过它与 SurfaceFlinger 进行通信。

Client 大致结构如下:

class Client : public BnSurfaceComposerClient
{
public:
    // ...
    void attachLayer(const sp<IBinder>& handle, const sp<Layer>& layer);
    void detachLayer(const Layer* layer);
    // ...
private:
    virtual status_t createSurface(...sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp);

    virtual status_t destroySurface(const sp<IBinder>& handle); 

    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
    // ...

    sp<SurfaceFlinger> mFlinger;

    DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayers;
    // ...
};

可以看出来,它是一个 Native 层的 Binder 对象,通过 Client 我们就可以与 SurfaceFlinger 进行通信了。

创建 Surface

每个 ViewRootImpl 中含有一个 mSurface 对象,也就是说一个 ViewRootImpl 对应了一个 Surface。ViewRootImpl 被创建时其实就创建了 mSurface,但 Surface 的构造函数其实是空的,说明此时这个 Surface 还不能被使用:

public final Surface mSurface = new Surface();

我们回到 View 的测量、布局、绘制前所调用到的 performTraversals 方法:

private void performTraversals() {
    finalView host = mView; //mView是一个Window的根View,对于Activity来说就是DecorView
    // ...
    relayoutWindow(params, viewVisibility, insetsPending);
    // ...
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    // ...         
    performLayout(lp, mWidth, mHeight);
    // ...
    performDraw();
    // ...
}

可以看出来,在三大流程之前调用了 relayoutWindow 方法,这个过程中其实就实现了 Surface 的具体创建流程

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;
}

它调用到了 Session.relayout 方法,其中就将 mSurface 参数传递了过去。

而这个 WindowSession 我们都知道是个 Binder 对象,它最终调用了 WMS 的 relayoutWindow 方法:

 public int relayoutWindow(Session session, IWindow client, int seq,
         WindowManager.LayoutParams attrs, int requestedWidth,
         int requestedHeight, int viewVisibility, int flags,
         Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
         Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
    // ...
    result = createSurfaceControl(outSurface, result, win, winAnimator);  

    // ...
    return (inTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0)
             | (toBeDisplayed ? WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME : 0)
             | (surfaceChanged ? WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED : 0)
             | (animating ? WindowManagerGlobal.RELAYOUT_RES_ANIMATING : 0);
 }

可以看到这里调用到了 createSurfaceControl 方法:

private int createSurfaceControl(Surface outSurface, int result, WindowState win, WindowStateAnimator winAnimator) {
    // ...
    surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
    // ...
    surfaceController.getSurface(outSurface);
    // ...
}

它首先调用 createSurfaceLocked 方法构建了一个 SurfaceControl,之后调用了 SurfaceControl.getSurface 方法获取到了 Surface 对象。

SurfaceControl 的创建

在 winAnimator 的 createSurfaceLocked 方法中实际上是调用了 SurfaceControl 的构造函数,而 SurfaceControl 构造函数中实际上是调用了 Native 层的 nativeCreate 方法,并持有了其 Native 层对象的地址。

static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
        jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
        jint windowType, jint ownerUid) {
    ScopedUtfChars name(env, nameStr);
    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
    SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
    sp<SurfaceControl> surface = client->createSurface(
            String8(name.c_str()), w, h, format, flags, parent, windowType, ownerUid);
    if (surface == NULL) {
        jniThrowException(env, OutOfResourcesException, NULL);
        return 0;
    }

    surface->incStrong((void *)nativeCreate);
    return reinterpret_cast<jlong>(surface.get());
}

可以看到,这里最后调用到了之前建立连接时创建的 Client 的 createSurface 方法:

sp<SurfaceControl> SurfaceComposerClient::createSurface(
        const String8& name,
        uint32_t w,
        uint32_t h,
        PixelFormat format,
        uint32_t flags,
        SurfaceControl* parent,
        uint32_t windowType,
        uint32_t ownerUid)
{
    sp<SurfaceControl> sur;
    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IBinder> parentHandle;
        sp<IGraphicBufferProducer> gbp;

        if (parent != nullptr) {
            parentHandle = parent->getHandle();
        }
        status_t err = mClient->createSurface(name, w, h, format, flags, parentHandle,
                windowType, ownerUid, &handle, &gbp);
        ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
        if (err == NO_ERROR) {
            sur = new SurfaceControl(this, handle, gbp);
        }
    }
    return sur;
}

这里通过了 Client 最后调用到了 SurfaceFlinger 的 createLayer 方法。

其实我们客户端的 Surface 在 SurfaceFlinger 中看来叫做 Layer,因此这里的方法叫做 createLayer

status_t SurfaceFlinger::createLayer(
        const String8& name,
        const sp<Client>& client
        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        uint32_t windowType, uint32_t ownerUid, sp<IBinder>* handle,
        sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent)
)
{
    status_t result = NO_ERROR;
    sp<Layer> layer;
    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceNormal:
            result = createNormalLayer(client,
                    uniqueName, w, h, flags, format,
                    handle, gbp, &layer);
            break;
            // ...
    }
    // ...
    result = addClientLayer(client, *handle, *gbp, layer, *parent);
    // ...
    return result;
}

Layer 有很多类型,其中一般的 Layer 最后会调用到 createNormalLayer 方法:

status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
        const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
    // ...
    *outLayer = new Layer(this, client, name, w, h, flags);
    status_t err = (*outLayer)->setBuffers(w, h, format, flags);
    if (err == NO_ERROR) {
        *handle = (*outLayer)->getHandle();
        *gbp = (*outLayer)->getProducer();
    }

    ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
    return err;
}

这里主要的操作是创建了一个 Layer 对象,并将 outLayer 所指向的对象改为了真正的 Layer 对象。并且将 Layer 的 Handle 及 IGraphicBufferProducer 通过指针传递回给了 SurfaceControl。这里的 IGraphicBufferProducer 会在创建 Surface 时用到。

Surface 的 native 对象的创建

那么我们再来看看,Surface 对象是如何被修改为可用的,我们看到 SurfaceControl.getSurface 方法:

void getSurface(Surface outSurface) {
    outSurface.copyFrom(mSurfaceControl);
}

它调用到了 outSurface 对象的 copyFrom 方法,看来这里是一个内存拷贝的操作:

public void copyFrom(SurfaceControl other) {
    // ...
    long surfaceControlPtr = other.mNativeObject;
    // ...
    long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr);
    synchronized (mLock) {
        if (mNativeObject != 0) {
            nativeRelease(mNativeObject);
        }
        setNativeObjectLocked(newNativeObject);
    }
}

首先,它通过 SurfaceControl 获取到了其 native 对象的地址,然后调用到了 nativeGetFromSurfaceControl 这一 Native 方法,之后通过 setNativeObjectLocked 方法将前面方法所得到的新 native 对象的地址设置到了当前 Surface。

我们先看看 nativeGetFromSurfaceControl 方法:

static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz, jlong surfaceControlNativeObj) {
    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
    sp<Surface> surface(ctrl->getSurface()); 
    if (surface != NULL) {
        surface->incStrong(&sRefBaseOwner);
    }
    return reinterpret_cast<jlong>(surface.get());
}

这里直接通过 Native 下 SurfaceControl 的 getSurface 方法传入构造函数构造了一个 Native 下的 Surface 对象:

sp<Surface> SurfaceControl::getSurface() const
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == 0) {
        return generateSurfaceLocked();
    }
    return mSurfaceData;
}

最后调用到的其实是 generateSurfaceLocked 方法:

sp<Surface> SurfaceControl::generateSurfaceLocked() const
{
    mSurfaceData = new Surface(mGraphicBufferProducer, false); 
    return mSurfaceData;
}

它其实是通过 mGraphicBufferProducer 构建了一个新的 Surface 对象,之后将其返回。这个 mGraphicBufferProducer 是之前创建 SurfaceControl 时所创建的 BufferLayer 的一个成员变量,看名字应该能猜出来 Surface 可以通过它创建 Buffer。

这段可能比较乱,可以用下面的图来表达 Surface、SurfaceControl、SurfaceFlinger 及 GraphicBufferProducer 的关系:

image-20190724213754758

参考资料

Android图形显示系统(一)

Android的UI显示原理之Surface的创建

点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注

%d 博主赞过: