Android-View绘制原理(05)-ANativeWindow

再上一篇文章中,介绍了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还有很多其他的方法,这里就不一一介绍了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容