View绘制原理(05)-ANativeWindow

作者: 代码多哥 | 来源:发表于2023-07-16 18:24 被阅读0次

    再上一篇文章中,介绍了Surface的创建的流程,我们说到在App层生成的Surface实质上即一个BBQSurface,它继承自Surface,Surfaced的继承比较隐晦,它实际上是继承自ANativeWindow的。

    frameworks/native/include/gui/Surface.h

    class Surface
        : public ANativeObjectBase<ANativeWindow, Surface, RefBase>
    {
    

    frameworks/native/libs/ui/include/ui/ANativeObjectBase.h

    template <typename NATIVE_TYPE, typename TYPE, typename REF,
            typename NATIVE_BASE = android_native_base_t>
    class ANativeObjectBase : public NATIVE_TYPE, public REF
    

    这里是通过模板的方式,间接继承自NATIVE_TYPE,此处是ANativeWindow,因此明确了Surface继承自ANativeWindow的关系。

    因为ANativeWindow在绘制的过程中是比较重要的一个类,因此这里专门写一篇文章来介绍一下。

    1 定义

    1.1 定义

    我们来看一下ANativeWindow的定义:

    frameworks/native/libs/nativewindow/include/system/window.h
    frameworks/native/libs/nativewindow/include/vndk/window.h
    frameworks/native/libs/nativewindow/include/apex/window.h
    frameworks/native/libs/nativewindow/include/android/native_window.h

    struct ANativeWindow
    {
    #ifdef __cplusplus
        ANativeWindow()
            : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
        {
            common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
            common.version = sizeof(ANativeWindow);
            memset(common.reserved, 0, sizeof(common.reserved));
        }
       ...
    }
    
    

    它也定义了一些成员函数, 比如下面的:

     int     (*query)(const struct ANativeWindow* window,
                    int what, int* value);
    
     int     (*perform)(struct ANativeWindow* window,
                    int operation, ... );
    
     int     (*dequeueBuffer)(struct ANativeWindow* window,
                    struct ANativeWindowBuffer** buffer, int* fenceFd);
    
     int     (*queueBuffer)(struct ANativeWindow* window,
                    struct ANativeWindowBuffer* buffer, int fenceFd);
    

    这些header文件里还定义了一系列的全局函数:

    int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
    
    int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);
    
    int ANativeWindow_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd);
    
    int ANativeWindow_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
    
    

    这些函数的定义分散在上述个header文件,但是实现是在一个cpp文件中

    frameworks/native/libs/nativewindow/ANativeWindow.cpp

    int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
            ARect* inOutDirtyBounds) {
        return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds);
    }
    
    int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) {
        return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST);
    }
    
    int ANativeWindow_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd) {
        return window->dequeueBuffer(window, buffer, fenceFd);
    }
    
    int ANativeWindow_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
        return window->queueBuffer(window, buffer, fenceFd);
    }
    ...
    

    所以这些全局方法都转发到了window上去执行的,window类型是ANativeWindow的指针,而实际上就一个Surface.

    java层的Surface 可以与ANativeWindow相互转换

    1.2 Surface转换成ANativeWindow

    frameworks/base/native/android/native_window_jni.cpp

    ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface) {
        sp<ANativeWindow> win = android_view_Surface_getNativeWindow(env, surface);
        if (win != NULL) {
            ANativeWindow_acquire(win.get());
        }
        return win.get();
    }
    

    frameworks/base/core/jni/android_view_Surface.cpp

    sp<ANativeWindow> android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) {
        return android_view_Surface_getSurface(env, surfaceObj);
    }
    
    sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) {
        sp<Surface> sur;
        jobject lock = env->GetObjectField(surfaceObj,
                gSurfaceClassInfo.mLock);
        if (env->MonitorEnter(lock) == JNI_OK) {
            sur = reinterpret_cast<Surface *>(
                    env->GetLongField(surfaceObj, gSurfaceClassInfo.mNativeObject));
            env->MonitorExit(lock);
        }
        env->DeleteLocalRef(lock);
        return sur;
    }
    

    它是直接读取Surface对象的mNativeObject字段,这个是一个指向JNI层的的Surface的指针。然后直接转换成ANativeWindow。

    1.3 ANativeWindow转Java层的Surface对象

    jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window) {
        if (window == NULL) {
            return NULL;
        }
        sp<Surface> surface = static_cast<Surface*>(window);
        return android_view_Surface_createFromSurface(env, surface);
    }
    
    jobject android_view_Surface_createFromSurface(JNIEnv* env, const sp<Surface>& surface) {
        jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz,
                gSurfaceClassInfo.ctor, (jlong)surface.get());
        if (surfaceObj == NULL) {
            if (env->ExceptionCheck()) {
                ALOGE("Could not create instance of Surface from IGraphicBufferProducer.");
                LOGE_EX(env);
                env->ExceptionClear();
            }
            return NULL;
        }
        surface->incStrong(&sRefBaseOwner);
        return surfaceObj;
    }
    

    直接以surface的指针为参数,反射构造方法构造一个java层的Surface对象。

    2 Surface与ANativeWindow

    如上所说,他们的直接关系是Surface继承自ANativeWindow。但是我们想知道是Surface扩展了什么
    frameworks/native/libs/gui/Surface.cpp

    Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp,
                     const sp<IBinder>& surfaceControlHandle)
          : mGraphicBufferProducer(bufferProducer),
            ...
        // Initialize the ANativeWindow function pointers.
        ANativeWindow::setSwapInterval  = hook_setSwapInterval;
        ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
        ANativeWindow::cancelBuffer     = hook_cancelBuffer;
        ANativeWindow::queueBuffer      = hook_queueBuffer;
        ANativeWindow::query            = hook_query;
        ANativeWindow::perform          = hook_perform;
    
        ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
        ANativeWindow::cancelBuffer_DEPRECATED  = hook_cancelBuffer_DEPRECATED;
        ANativeWindow::lockBuffer_DEPRECATED    = hook_lockBuffer_DEPRECATED;
        ANativeWindow::queueBuffer_DEPRECATED   = hook_queueBuffer_DEPRECATED;
       ...
    }
    

    我们看到构造方法里对ANativeWindow类的方法进行了hook,比如常见的 ANativeWindow::dequeueBuffer = hook_dequeueBuffer;ANativeWindow::perform = hook_perform;,因此调用ANativeWindow的这些方法的时候,会去执行Surface中定义的hook_xxx方法。
    我们这里来分析几个主要的方法

    2.1 hook_dequeueBuffer

    int Surface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd) {
        Surface* c = getSelf(window);
        {
            std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex);
            if (c->mDequeueInterceptor != nullptr) {
                auto interceptor = c->mDequeueInterceptor;
                auto data = c->mDequeueInterceptorData;
                return interceptor(window, Surface::dequeueBufferInternal, data, buffer, fenceFd);
            }
        }
        return c->dequeueBuffer(buffer, fenceFd);
    }
    

    frameworks/native/libs/ui/include/ui/ANativeObjectBase.h

        static inline TYPE const* getSelf(NATIVE_TYPE const* self) {
            return static_cast<TYPE const *>(self);
        }
    

    首先强制将window转换成Surface,因为这个window本身就是一个Surface,因此可以强转。然后经过一些拦截处理,如果没有被拦截的话才调用Surface->dequeueBuffer(buffer, fenceFd)。拦截者保存在suface上的mDequeueInterceptor字段。这个拦截者会在后面的文章里继续介绍。在调用拦截者的时候又传入了Surface::dequeueBufferInternal这个函数执行,因此执行完拦截后,可以调用这个函数来实现dequeueBuffer的目的

    int Surface::dequeueBufferInternal(ANativeWindow* window, ANativeWindowBuffer** buffer,
                                       int* fenceFd) {
        Surface* c = getSelf(window);
        return c->dequeueBuffer(buffer, fenceFd);
    }
    

    最后调用的还是suface的dequeueBuffer方法。

    2.2 dequeueBuffer

    dequeueBuffer是一个重要的方法,Surface是的角色是生产者,它持有一个IGraphicBufferProducer类型的producer,当需要生产新的内容的时候,需要调用dequeueBuffer获得一个可用的图形缓存GraphcBuffer用于绘制。传入的buffer指针将指向这个可用的GraphcBuffer。下面介绍一下这个方法。

    int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
         ...
        IGraphicBufferProducer::DequeueBufferInput dqInput;
        {
            Mutex::Autolock lock(mMutex);
            if (mReportRemovedBuffers) {
                mRemovedBuffers.clear();
            }
    
            getDequeueBufferInputLocked(&dqInput);
    
            /*注释1:
             一般模式下,GraphicBuffer会受到Fence的保护,从而只能被串行访问.
             mSharedBufferMode 下这个GraphicBuffer将会被Application和SurfaceFlingger同时访问,可能会导致画面撕裂。正常情况下不会开启这个模式
           */
            if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot !=
                    BufferItem::INVALID_BUFFER_SLOT) {
                sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
                if (gbuf != nullptr) {
                    *buffer = gbuf.get();
                    *fenceFd = -1;
                    return OK;
                }
            }
        } // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer
    
        int buf = -1;
        sp<Fence> fence;
        nsecs_t startTime = systemTime();
    
        FrameEventHistoryDelta frameTimestamps;
        /*注释2:
        通过调用mGraphicBufferProducer的dequeueBuffer的方法获取一个graphicbuffer,将其索引index保存到buf指针,每个graphicbuffer都有对应的fence,它的fence保存到fence。
        返回的result中会包含一些控制信息位。
       */
        status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, dqInput.width,
                                                                dqInput.height, dqInput.format,
                                                                dqInput.usage, &mBufferAge,
                                                                dqInput.getTimestamps ?
                                                                        &frameTimestamps : nullptr);
        mLastDequeueDuration = systemTime() - startTime;
        /**
       dequeue失败,直接返回
       */
        if (result < 0) {
            ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer"
                    "(%d, %d, %d, %#" PRIx64 ") failed: %d",
                    dqInput.width, dqInput.height, dqInput.format, dqInput.usage, result);
            return result;
        }
       
        if (buf < 0 || buf >= NUM_BUFFER_SLOTS) {
            ALOGE("dequeueBuffer: IGraphicBufferProducer returned invalid slot number %d", buf);
            android_errorWriteLog(0x534e4554, "36991414"); // SafetyNet logging
            return FAILED_TRANSACTION;
        }
    
        Mutex::Autolock lock(mMutex);
    
        // Write this while holding the mutex
        mLastDequeueStartTime = startTime;
        /*
        这个mSlots是Surface中定义的一个结构体BufferSlot数组,与BufferQueueCore中定义的BufferSlot不是一个概念,但是都有相同的长度64,二者 
        之间可以通过index来映射。如果第一次执行,此处取到的mSlots[buf].buffer应该是为空的。同时result中也包含有BUFFER_NEEDS_REALLOCATION位
       */
    
       sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
    
        // this should never happen
        ALOGE_IF(fence == nullptr, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
    
        if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) {
            static FenceMonitor hwcReleaseThread("HWC release");
            hwcReleaseThread.queueFence(fence);
        }
    
        if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
            freeAllBuffers();
        }
    
        if (dqInput.getTimestamps) {
             mFrameEventHistory->applyDelta(frameTimestamps);
        }
    
       /*
        此处需要进一步调用 mGraphicBufferProducer->requestBuffer去获取buf索引中的GraphicBuffer,并保存到&gbuf,也即保存到了mSlot[buf].buffer.
        */
        if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
            if (mReportRemovedBuffers && (gbuf != nullptr)) {
                mRemovedBuffers.push_back(gbuf);
            }
            result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
            if (result != NO_ERROR) {
                ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
                mGraphicBufferProducer->cancelBuffer(buf, fence);
                return result;
            }
        }
    
        if (fence->isValid()) {
            /**
             复制fenceFd给fenceFd,供调用方使用。
            */
            *fenceFd = fence->dup();
            if (*fenceFd == -1) {
                ALOGE("dequeueBuffer: error duping fence: %d", errno);
                // dup() should never fail; something is badly wrong. Soldier on
                // and hope for the best; the worst that should happen is some
                // visible corruption that lasts until the next frame.
            }
        } else {
            *fenceFd = -1;
        }
        /**
         buffer将指向一个graphicBuffer,供调用方使用。
        *
        *buffer = gbuf.get();
    
        if (mSharedBufferMode && mAutoRefresh) {
            mSharedBufferSlot = buf;
            mSharedBufferHasBeenQueued = false;
        } else if (mSharedBufferSlot == buf) {
            mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
            mSharedBufferHasBeenQueued = false;
        }
    
        mDequeuedSlots.insert(buf);
    
        return OK;
    }
    

    上面的代码中加入了相关的注释。它主要是通过mGraphicBufferProducer->dequeueBuffer去获取到一个可用的GraphicBuffer索引buf,以及该GraphicBuffer绑定的fence,然后通过mGraphicBufferProducer->requestBuffer去获取buf索引处的GraphicBuffer,保存到Surface的mSlot对应索引位置,并保存到调用方指定的buffer位置。从而调用就可以通过buffer引用到这个GraphicBuffer,将绘制的内容写入其中。

    2.3. queueBuffer

    hook_queueBuffer就介绍了,和hook_dequeueBuffer的原理差不多,我们就直接介绍queueBuffer方法。当Surface中的绘制结束后,需要将GraphicBuffer还回来,并通知消费者有新的数据可以展示。

    int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
         ...
        int i = getSlotFromBufferLocked(buffer);
    
        IGraphicBufferProducer::QueueBufferOutput output;
        IGraphicBufferProducer::QueueBufferInput input;
        getQueueBufferInputLocked(buffer, fenceFd, mTimestamp, &input);
        sp<Fence> fence = input.fence;
    
        nsecs_t now = systemTime();
        status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
        mLastQueueDuration = systemTime() - now;
        if (err != OK)  {
            ALOGE("queueBuffer: error queuing buffer, %d", err);
        }
    
        onBufferQueuedLocked(i, fence, output);
        return err;
    }
    
    

    它传入的参数buffer的类型是android_native_buffer_t* buffer, 它的定义在frameworks/native/libs/nativebase/include/nativebase/nativebase.h,是一个ANativeWindowBuffer,主要持有一个native_handle_t的属性handle用于保存文件句柄。

    typedef struct native_handle
    {
        int version;        /* sizeof(native_handle_t) */
        int numFds;         /* number of file-descriptors at &data[0] */
        int numInts;        /* number of ints at &data[numFds] */
    #if defined(__clang__)
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wzero-length-array"
    #endif
        int data[0];        /* numFds + numInts ints */
    #if defined(__clang__)
    #pragma clang diagnostic pop
    #endif
    } native_handle_t;
    
    

    通过这个buffer参数, 调用getSlotFromBufferLocked获取这个buffer的在mSlots中的索引

    int Surface::getSlotFromBufferLocked(
            android_native_buffer_t* buffer) const {
        if (buffer == nullptr) {
            ALOGE("%s: input buffer is null!", __FUNCTION__);
            return BAD_VALUE;
        }
    
        for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
            if (mSlots[i].buffer != nullptr &&
                    mSlots[i].buffer->handle == buffer->handle) {
                return i;
            }
        }
        ALOGE("%s: unknown buffer: %p", __FUNCTION__, buffer->handle);
        return BAD_VALUE;
    }
    

    通过比较mSlots中的graphicbuffer的handle是否与传入的handle一致,匹配出索引位置i,然后后通过调用mGraphicBufferProducer->queueBuffer(i, input, &output);来实现的。

    需要额外说明一点的是,mSlots是一个BufferSlot的数组,每个元素都是一个BufferSlot对象,每个BufferSlot持有的是一个GraphicBuffer对象,这里queueBuffer方法传入的是一个android_native_buffer_t*类型的参数,或者说是一个ANativeWindowBuffer。他们二者之间是什么关系呢?答案是GraphicBuffer继承自ANativeWindowBuffer。

    最后,通过mQueueBufferCondition通知等待的线程

    void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence,
            const IGraphicBufferProducer::QueueBufferOutput& output) {
        mDequeuedSlots.erase(slot);
       ...
        mQueueBufferCondition.broadcast();
      ...
    }
    

    3. 总结

    本文介绍了一个非常重要的类ANativeWindow,它是Surface类的父类,虽然在C层,很多场景都是使用的ANativeWindow,但实质上是一个Surface对象,对ANativeWindow的调用最后都会进入到Surface定义的方法。 接着分析了Surface作为生产者的两个重要方法,dequeueBuffer和queueBuffer,它们最后都进入到GraphicBufferProducer对应的方法。Surface还有很多其他的方法,这里就不一一介绍了。

    相关文章

      网友评论

        本文标题:View绘制原理(05)-ANativeWindow

        本文链接:https://www.haomeiwen.com/subject/rdfjudtx.html