显示设备探寻(3)

回顾

我们回顾一下前面两节的内容:

  1. init进程创建了SurfaceFlinger服务进程,然后将SurfaceFlinger服务添加到ServiceManager中管理
  2. SurfaceFliger的继承关系
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder{}
class BnSurfaceComposer: public BnInterface<ISurfaceComposer> {}

class BpSurfaceComposer : public BpInterface<ISurfaceComposer>{}
class SurfaceFlinger : public BnSurfaceComposer,
                       private IBinder::DeathRecipient,
                       private HWComposer::EventHandler{}

主要反映SurfaceFlinger是一个Binder服务,同时继承了死亡回调

  1. 我们通过以下代码探寻
sp<SurfaceComposerClient> client = new SurfaceComposerClient();//[1]
sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),160, 240, PIXEL_FORMAT_RGB_565, 0);//[2]
sp<Surface> surface = surfaceControl->getSurface();//[3]
SurfaceComposerClient::openGlobalTransaction();
surfaceControl->setLayer(100000);
SurfaceComposerClient::closeGlobalTransaction();
ANativeWindow_Buffer outBuffer;
surface->lock(&outBuffer, NULL);//[4]
  • 通过[1]我们了解到

    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
        return ComposerService& instance = ComposerService::getInstance();
            getService(name, &mComposerService)
    sp<ISurfaceComposerClient> conn = sm->createConnection();
        remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply);
        sp<Client> client(new Client(this));
    
    1. 可以看出通过ComposerService获取SurfaceFlinger服务
    2. 通过SurfaceFlinger创建了Client对象
      class Client : public BnSurfaceComposerClient{}
      
  • 通过[2]我们知道

    status_t err = mClient->createSurface(name, w, h, format, flags,&handle, &gbp);
        *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
        flinger->createLayer(name, client, w, h, format, flags,handle, gbp);
    return sur = new SurfaceControl(this, handle, gbp);
        createNormalLayer(client,name, w, h, flags, format,handle, gbp, &layer);
            new Layer()
                BufferQueue::createBufferQueue(&producer, &consumer);
                    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
                        BufferSlot[64]//成员变量
                    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
                    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
    
    1. 使用Client创造Layer
    2. 创建SurfaceControl返回
    3. 创建layer,bufferqueue,生产者消费者,BufferQueueCore
  • 通过[3]知道

    return new Surface()
    
  • 通过[4]我们知道

    surface->lock(&outBuffer, NULL);
        status_t err = dequeueBuffer(&out, &fenceFd);
            mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,reqWidth, reqHeight, reqFormat, reqUsage);
                //开始对端
                mCore->mAllocator->createGraphicBuffer(width, height, format, usage, &error)
                        new GraphicBuffer(width, height, format, usage)
                            initSize()
                                allocator.alloc()
            result = mGraphicBufferProducer->requestBuffer(buf, &gbuf)
    

    现在我们知道lock分配内存

介绍

这一节我们需要知道当把内存分配出来之后需要做什么事情。

我们本节继续回到dequeueBuffer我们已经通过mGraphicBufferProducer->dequeueBuffer分配出来内存我们就需要知道分配内存之后怎么办,所以看下文

mGraphicBufferProducer->requestBuffer()

frameworks\native\libs\gui\Surface.cpp

virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {
    Parcel data, reply;
    data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
    data.writeInt32(bufferIdx);
    status_t result =remote()->transact(REQUEST_BUFFER, data, &reply);
    if (result != NO_ERROR) {
        return result;
    }
    bool nonNull = reply.readInt32();
    if (nonNull) {
        *buf = new GraphicBuffer();
        result = reply.read(**buf);
        if(result != NO_ERROR) {
            (*buf).clear();
            return result;
        }
    }
    result = reply.readInt32();
    return result;
}
  • 通过Binder系统发起REQUEST_BUFFER
  • 如果返回结果不为null,则创建GraphicBuffer对象
    调用栈
    surface->lock(&outBuffer, NULL);
        status_t err = dequeueBuffer(&out, &fenceFd);
            mGraphicBufferProducer->requestBuffer(buf, &gbuf)
                remote()->transact(REQUEST_BUFFER...);
                *buf = new GraphicBuffer();
                result = reply.read(**buf);

我们由关系知道:

IGraphicBufferProducer

class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>{}

class BnGraphicBufferProducer : public BnInterface<IGraphicBufferProducer>{}

class BufferQueueProducer : public BnGraphicBufferProducer,
                            private IBinder::DeathRecipient {}

case REQUEST_BUFFER: {
    CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
    int bufferIdx   = data.readInt32();
    sp<GraphicBuffer> buffer;
    int result = requestBuffer(bufferIdx, &buffer);
    reply->writeInt32(buffer != 0);
    if (buffer != 0) {
        reply->write(*buffer);
    }
    reply->writeInt32(result);
    return NO_ERROR;

所以我们知道调用如下对端:

BufferQueueProducer

status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
    Mutex::Autolock lock(mCore->mMutex);
    if (mCore->mIsAbandoned) {
        return NO_INIT;
    }
    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
        return BAD_VALUE;
    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
        return BAD_VALUE;
    }

    mSlots[slot].mRequestBufferCalled = true;
    *buf = mSlots[slot].mGraphicBuffer;
    return NO_ERROR;
}

我们通过上面两段代码

片段1
mSlots[slot].mRequestBufferCalled = true;
*buf = mSlots[slot].mGraphicBuffer;
片段2
sp<GraphicBuffer> buffer;
int result = requestBuffer(bufferIdx, &buffer);
reply->writeInt32(buffer != 0);
if (buffer != 0) {
    reply->write(*buffer);
}

我们通过代码看出来,对端把Buffer写到客户端去,然后客户端通过

 *buf = new GraphicBuffer();
result = reply.read(**buf);

读取buffer,所以服务端写buffer,客户端读buffer

我们继续看一看写了哪些内容:


status_t Parcel::write(const FlattenableHelperInterface& val)
{
    status_t err;

    // size if needed
    const size_t len = val.getFlattenedSize();
    const size_t fd_count = val.getFdCount();//文件句柄的个数

    if ((len > INT32_MAX) || (fd_count > INT32_MAX)) {
        return BAD_VALUE;
    }

    err = this->writeInt32(len);
    if (err) return err;

    err = this->writeInt32(fd_count);
    if (err) return err;

    // payload
    void* const buf = this->writeInplace(pad_size(len));
    if (buf == NULL)
        return BAD_VALUE;

    int* fds = NULL;
    if (fd_count) {
        fds = new int[fd_count];
    }

    //调用GraphicBuffer::flatten()将GraphicBuffer中重要信息写入buffer
    err = val.flatten(buf, len, fds, fd_count);
    for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) {
        err = this->writeDupFileDescriptor( fds[i] );
    }

    if (fd_count) {
        delete [] fds;
    }

    return err;
}

我们看出来核心是通过err = val.flatten(buf, len, fds, fd_count);将核心数据通过binder驱动写到客户端

我们再来看看读

virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {
    result = reply.read(**buf);
}

status_t Parcel::read(FlattenableHelperInterface& val) const
{
    // size
    const size_t len = this->readInt32();
    const size_t fd_count = this->readInt32();

    if (len > INT32_MAX) {
        return BAD_VALUE;
    }

    // payload
    void const* const buf = this->readInplace(pad_size(len));
    if (buf == NULL)
        return BAD_VALUE;

    int* fds = NULL;
    if (fd_count) {
        fds = new int[fd_count];
    }

    status_t err = NO_ERROR;
    for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) {
        fds[i] = dup(this->readFileDescriptor());
        if (fds[i] < 0) {
            err = BAD_VALUE;
            ALOGE("dup() failed in Parcel::read, i is %zu, fds[i] is %d, fd_count is %zu, error: %s",
                i, fds[i], fd_count, strerror(errno));
        }
    }

    if (err == NO_ERROR) {
        err = val.unflatten(buf, len, fds, fd_count);
    }

    if (fd_count) {
        delete [] fds;
    }

    return err;
}

这里读的核心在val.unflatten(buf, len, fds, fd_count)

读到的核心是:

  • 使用fd'构造handle
  • 得到虚拟地址,是通过mmap(fd')获取虚拟地址,mmap的值放入handle->base中

小结

可能大家看到这里就有点懵逼了,我们大概说一下做了什么,我们通过surface->lock()函数分配了一块匿名共享内存用fd表示,然后应用程序通过远程调用得到fd',应用程序这边通过fd'构造出handle,然后通过mmap(handle)得到地址。

所以到目前为止调用栈情况是:

    surface->lock(&outBuffer, NULL);
        status_t err = dequeueBuffer(&out, &fenceFd);
            mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,reqWidth, reqHeight, reqFormat, reqUsage);
                //开始对端
                mCore->mAllocator->createGraphicBuffer(width, height, format, usage, &error)
                        new GraphicBuffer(width, height, format, usage)
                            initSize()
                                allocator.alloc()
            result = mGraphicBufferProducer->requestBuffer(buf , &gbuf)
                remote()->transact(REQUEST_BUFFER...);
                *buf = new GraphicBuffer();
                result = reply.read(**buf);
    sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));//[1]
    backBuffer->lockAsync(...,&vaddr, fenceFd);//[2]

在1中的out就是我们在mGraphicBufferProducer->dequeueBuffer(&buf,...);中得到的buffer我们将得到的buffer赋值给backBuffer,然后使用GraphicBuffer::lockAsync(...,&vaddr)下面我们就看看具体这个函数做什么事情

GraphicBuffer::lockAsync()

status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect,
        void** vaddr, int fenceFd)
{
    if (rect.left < 0 || rect.right  > width ||
        rect.top  < 0 || rect.bottom > height) {
        return BAD_VALUE;
    }
    status_t res = getBufferMapper().lockAsync(handle, inUsage, rect, vaddr,fenceFd);
    return res;
}

我们调用到:

status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
        uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd)
{
    ATRACE_CALL();
    status_t err;

    if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) {
        err = mAllocMod->lockAsync(mAllocMod, handle, static_cast<int>(usage),
                bounds.left, bounds.top, bounds.width(), bounds.height(),
                vaddr, fenceFd);
    } else {
        if (fenceFd >= 0) {
            sync_wait(fenceFd, -1);
            close(fenceFd);
        }
        err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage),
                bounds.left, bounds.top, bounds.width(), bounds.height(),
                vaddr);
    }
    return err;
}

这个时候就需要看GRALLOC_MODULE这个版本,如果超过0.3就调用mAllocMod->lockAsync()否则就调用mAllocMod->lock()

我们调用的是lock()
由于我们加载的HAL层:

GraphicBufferMapper::GraphicBufferMapper()
    : mAllocMod(0)
{
    hw_module_t const* module;
    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
    if (err == 0) {
        mAllocMod = reinterpret_cast<gralloc_module_t const *>(module);
    }
}

所以我们看不到代码,因为每个厂商都不一样,但是我们查阅资料知道是将是hande->base写入vaddr中,也就是虚拟地址。

所以GraphicBufferMapper::lockAsync()的事情就是直接返回handl->base写入了vaddr中

所以到目前为止我们就知道了:

  • APP跟SurfaceFlinger之间的重要数据结构
  • APP创建SurfaceFlinger Client的过程
  • APP申请创建Surface的过程
  • APP申请lock(buffer)的过程_框架
  • APP申请lock(buffer)的过程_分配buffer
  • APP申请lock(buffer)的过程_获得buffer信息

下一节我们将设计构图将这些串起来

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

推荐阅读更多精彩内容