SurfaceFlinger源碼分析二

用來描述Android應用程序的UI元數據的SharedClient是如何創(chuàng)建的茅诱?
實際在近期版本的Android 源碼中邑闺,已經移除了SharedClient季俩,只存在于早期版本中栅组,甚至4.4中雀瓢,該類都已經不復存在。

//http://aosp.opersys.com/xref/android-2.3_r1/xref/frameworks/base/include/private/surfaceflinger/SharedBufferStack.h#127
class SharedClient
{
public:
    SharedClient();
    ~SharedClient();
    status_t validate(size_t token) const;

private:
    friend class SharedBufferBase;
    friend class SharedBufferClient;
    friend class SharedBufferServer;

    // FIXME: this should be replaced by a lock-less primitive
    Mutex lock;
    Condition cv;
    SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];
};

SharedClient在早期版本中玉掸,是做什么的呢刃麸?
Android應用和SurfaceFlinger服務是不同的進程,它們通過binder通訊司浪。但是binder有一個問題泊业,無法傳遞大數據(限制在1M-8k,即1016K)断傲,一個Android應用存在多個窗口脱吱,數據量比較大,因此使用Binder的話不合適认罩。于是選擇了使用Android匿名共享內存方案箱蝠。
在每一個Android應用與SurfaceFlinger之間的連接上,加上一塊用來傳遞UI元數據的匿名共享內存垦垂,這塊區(qū)域被包裝成SharedClient宦搬。

http://www.reibang.com/p/987552971637

可以看出,SharedClient是用來解決Android應用與SurfaceFlinger服務之間的數據傳輸問題的劫拗。

所以這個問題也可以換個說法间校,SharedClient被廢棄后,Android系統(tǒng)是如何在Android應用和SurfaceFlinger服務之間傳輸數據的页慷?是如何通訊的呢憔足?

帶著這個問題接著來分析一下SurfaceFlinger源碼胁附。
官方文檔中有張圖。

https://source.android.google.cn/docs/core/graphics

涉及Metadata (元數據)滓彰, WindowManager控妻, SurfaceFlinger,Buffer Data 揭绑, surface.cpp弓候,GLConsumer.cpp ,IGraphicBufferProducer等他匪。

出處:http://www.reibang.com/p/f96ab6646ae3
App到SurfaceFlinger
應用首先通過Surface的接口向SurfaceFlinger申請一塊buffer, 需要留意的是Surface剛創(chuàng)建時是不會有buffer被alloc出來的菇存,只有應用第一次要繪制畫面時dequeueBuffer會讓SurfaceFlinger去alloc buffer, 在應用側會通過importBuffer把這塊內存映射到應用的進程空間來。
之后App通過dequeueBuffer拿到畫布邦蜜, 通過queueBuffer來提交繪制好的數據依鸥。
APP繪畫的畫布是由SurfaceFlinger提供的,而畫布是一塊共享內存畦徘,APP向SurfaceFlinger申請到畫布毕籽,是將共享內存的地址映射到自身進程空間。 App負責在畫布上作畫井辆,畫完的作品提交給SurfaceFlinger, 這個提交操作并不是把內存復制一份給SurfaceFlinger溶握,而是把共享內存的控制權交還給SurfaceFlinger杯缺, SurfaceFlinger把拿來的多個應用的共享內存再送給HWC Service去合成, HWC Service把合成的數據交給DRM去輸出完成app畫面顯示到屏幕上的過程睡榆。為了更有效地利用時間這樣的共享內存不止一份萍肆,可能有兩份或三份,即常說的double buffering, triple buffering.
那么我們就需要設計一個機制可以管理buffer的控制權胀屿,這個就是BufferQueue.

本篇文章的分析塘揣,我先略過Surface相關細節(jié),重點看數據是如何從App到SurfaceFlinger的宿崭。
所以亲铡,要想知道數據是如何傳輸的,關鍵點是理解BufferQueue葡兑。

BufferQueue數據不是通過copy從應用傳遞到SurfaceFlinger奖蔓,而是通過句柄傳遞。先記住這句話讹堤,后面會說道吆鹤。

https://source.android.google.cn/docs/core/graphics/arch-bq-gralloc

BufferQueuesAndroid 圖形組件之間的粘合劑。它們是一對隊列洲守,可以調解緩沖區(qū)從生產方到消耗方的固定周期疑务。一旦生產方移交其緩沖區(qū)沾凄,SurfaceFlinger 便會負責將所有內容合成到顯示部分。

有關 BufferQueue通信過程知允,請參見下圖撒蟀。

https://source.android.google.cn/docs/core/graphics

這個圖結合前面官方文檔的描述,可簡單總結出以下幾點:
1.SurfaceFlinger創(chuàng)建并擁有 BufferQueue數據結構
2.應用需要緩沖區(qū)時廊镜,它會通過調用dequeueBuffer()BufferQueue請求一個可用的緩沖區(qū)
3.應用繪制UI,填充緩沖區(qū),并通過調用 queueBuffer() 將緩沖區(qū)返回到隊列

  1. SurfaceFlinger通過調用acquireBuffer()獲取該緩沖區(qū)并使用該緩沖區(qū)的內容

那么這些是怎么做到的呢牙肝?

出處:http://www.reibang.com/p/730dd558c269
SharedBufferStack中的緩沖區(qū)只是用來描述UI元數據的,這意味著它們不包含真正的UI數據嗤朴。真正的UI數據保存在GraphicBuffer中配椭,后面我們再描述GaphicBuffer。因此雹姊,為了完整地描述一個UI股缸,SharedBufferStack中的每一個已經使用了的緩沖區(qū)都對應有一個GraphicBuffer,用來描述真正的UI數據吱雏。當SurfaceFlinger服務緩制Buffer-1和Buffer-2的時候敦姻,就會找到與它們所對應的GraphicBuffer,這樣就可以將對應的UI繪制出來了歧杏。
當Android應用程序需要更新一個Surface的時候镰惦,它就會找到與它所對應的SharedBufferStack,并且從它的空閑緩沖區(qū)列表的尾部取出一個空閑的Buffer犬绒。我們假設這個取出來的空閑Buffer的編號為index旺入。接下來Android應用程序就請求SurfaceFlinger服務為這個編號為index的Buffer分配一個圖形緩沖區(qū)GraphicBuffer。

早期的源碼中凯力,存在SharedBufferStack茵瘾,現在SharedBufferStack已經沒有了。


那么現在咐鹤,應用繪制UI所需的內存空間是如何分配的拗秘?

出處:http://www.reibang.com/p/3c61375cc15b
在BufferQueue的設計中,一個buffer的狀態(tài)有以下幾種:
FREE :表示該buffer可以給到應用程序祈惶,由應用程序來繪畫
DEQUEUED:表示該buffer的控制權已經給到應用程序側雕旨,這個狀態(tài)下應用程序可以在上面繪畫了
QUEUED: 表示該buffer已經由應用程序繪畫完成,buffer的控制權已經回到SurfaceFlinger手上了
ACQUIRED:表示該buffer已經交由HWC Service去合成了行瑞,這時控制權已給到HWC Service了
Buffer的初始狀態(tài)為FREE, 當生產者通過dequeueBuffer來申請buffer成功時奸腺,buffer狀態(tài)變?yōu)榱薉EQUEUED狀態(tài), 應用畫圖完成后通過queueBuffer把buffer狀態(tài)改到QUEUED狀態(tài)血久, 當SurfaceFlinger通過acquireBuffer操作把buffer拿去給HWC Service合成突照, 這時buffer狀態(tài)變?yōu)锳CQUIRED狀態(tài),合成完成后通過releaseBuffer把buffer狀態(tài)重新改為FREE狀態(tài)氧吐。 狀態(tài)切換如下圖所示:


BufferSlot
每一個應用程序的圖層在SurfaceFlinger里稱為一個Layer讹蘑, 而每個Layer都擁有一個獨立的BufferQueue, 每個BufferQueue都有多個Buffer,Android 系統(tǒng)上目前支持每個Layer最多64個buffer, 這個最大值被定義在frameworks/native/gui/BufferQueueDefs.h末盔, 每個buffer用一個結構體BufferSlot來代表。
每個BufferSlot里主要有如下重要成員:

struct BufferSlot{
    ......
    BufferState mBufferState;//代表當前Buffer的狀態(tài) FREE/DEQUEUED/QUEUED/ACQUIRED
    ....
    sp<GraphicBuffer> mGraphicBuffer;//代表了真正的buffer的存儲空間
    ......
    uint64_t mFrameNumber;//表示這個slot被queued的編號座慰,在應用調dequeueBuffer申請slot時會參考該值
    ......
    sp<Fence> mFence;//在Fence一章再來看它的作用
    .....
}

SurfaceFlinger不僅是Consumer陨舱,創(chuàng)建并擁有 BufferQueue數據結構,而且還提供了Buffer空間——GraphicBufferGraphicBuffer就是緩沖區(qū),真正的buffer的存儲空間)版仔。

了解了上面的這些基本知識后游盲,再來看看調用dequeueBuffer后,如何分配緩存區(qū)蛮粮,以及BufferQueue的基本流程益缎。

1. dequeueBuffer

從應用通過dequeueBuffer來申請buffer這里開始看代碼。應用在第一次dequeueBuffer時會先調用requestBuffer:

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/libs/gui/Surface.cpp
  sp<IGraphicBufferProducer> mGraphicBufferProducer;

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/libs/gui/Surface.cpp

Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp,
                 const sp<IBinder>& surfaceControlHandle)
      : mGraphicBufferProducer(bufferProducer),
//mGraphicBufferProducer 初始化= bufferProducer
    ....
  }

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
....
// 這里嘗試去dequeueBuffer,因為這時SurfaceFlinger對應Layer的slot還沒有分配buffer,這時SurfaceFlinger會回復的flag會有BUFFER_NEEDS_REALLOCATION
  status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, dqInput.width,
                                                            dqInput.height, dqInput.format,
                                                            dqInput.usage, &mBufferAge,
                                                            dqInput.getTimestamps ?
                                                                    &frameTimestamps : nullptr);
....
  if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
       ...
       //這里檢查到dequeueBuffer返回的結果里帶有BUFFER_NEEDS_REALLOCATION標志就會發(fā)出一次requestBuffer
        result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
       ...
    }
 ....
}

調用mGraphicBufferProducer->dequeueBuffer(&buf, &fence, dqInput.width,dqInput.height, dqInput.format, dqInput.usage, &mBufferAge,dqInput.getTimestamps ? &frameTimestamps : nullptr);時發(fā)現分配出來的slot沒有GraphicBuffer然想, 這時會去申請對應的buffer:

//frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
                                            uint32_t width, uint32_t height, PixelFormat format,
                                            uint64_t usage, uint64_t* outBufferAge,
                                            FrameEventHistoryDelta* outTimestamps) {
    if ((buffer == NULL) ||
        buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))//檢查是否已分配了GraphicBuffer
    {
        ......
        returnFlags |= BUFFER_NEEDS_REALLOCATION;//發(fā)現需要分配buffer,置個標記
    }
    ......
    if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
        ......
        //新創(chuàng)建一個新的GraphicBuffer給到對應的slot
        sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
               width, height, format, BQ_LAYER_COUNT, usage,
               {mConsumerName.string(), mConsumerName.size()});
        ......
               mSlots[*outSlot].mGraphicBuffer = graphicBuffer;//把GraphicBuffer給到對應的slot
        ......
    }
    ......
    return returnFlags;//注意在應用第一次請求buffer, dequeueBuffer返回時對應的GraphicBuffer已經創(chuàng)建完成并給到了對應的slot上莺奔,但返回給應用的flags里還是帶有BUFFER_NEEDS_REALLOCATION標記的
}

調用BufferQueueProducer::dequeueBuffer的時候,雖然創(chuàng)建了GraphicBuffer变泄,但是應用側并沒有與擁有可用的緩沖區(qū)令哟,即GraphicBuffer,只是新創(chuàng)建一個新的GraphicBuffer給到對應的slot妨蛹。
然后走到mGraphicBufferProducer->requestBuffer(buf, &gbuf)屏富。

// frameworks/native/libs/gui/IGraphicBufferProducer.cpp
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
{
...

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

然后從bp走到bn端。

// frameworks/native/libs/gui/IGraphicBufferProducer.cpp
status_t BnGraphicBufferProducer::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        case REQUEST_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
            int bufferIdx = data.readInt32();
            sp<GraphicBuffer> buffer;
            int result = requestBuffer(bufferIdx, &buffer);
            reply->writeInt32(buffer != nullptr);
            if (buffer != nullptr) {
                reply->write(*buffer);
            }
            reply->writeInt32(result);
            return NO_ERROR;
        }
        ...
    }
    return BBinder::onTransact(code, data, reply, flags);
}

應用側收到帶有BUFFER_NEEDS_REALLOCATION標記的返回結果后就會調BufferQueueProducer::requestBuffer來獲取對應buffer的信息:

//frameworks/native/libs/gui/include/gui/BufferQueueProducer.h
sp<BufferQueueCore> mCore;

// This references mCore->mSlots. Lock mCore->mMutex while accessing.
BufferQueueDefs::SlotsType& mSlots;

// frameworks/native/libs/gui/BufferQueueProducer.cpp
BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core,
        bool consumerIsSurfaceFlinger) :
    mCore(core),
    mSlots(core->mSlots),
...{}

status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
    ATRACE_CALL();
    BQ_LOGV("requestBuffer: slot %d", slot);
    std::lock_guard<std::mutex> lock(mCore->mMutex);
 ...
    mSlots[slot].mRequestBufferCalled = true;
    *buf = mSlots[slot].mGraphicBuffer;
    return NO_ERROR;
}

這段調用mGraphicBufferProducer->requestBuffer(buf, &gbuf)后發(fā)生的binder通訊創(chuàng)建GraphicBuffer的過程比較難以理解蛙卤,與一般的binder通訊不同役听, 要想理解這一部分通訊是如何創(chuàng)建GraphicBuffer,需要對dma-buf有一定的理解表窘。

關于dmf_buf 機制可以查看這篇:dma-buf 由淺入深(一) —— 最簡單的 dma-buf 驅動程序

概念
dma-buf 的出現就是為了解決各個驅動之間 buffer 共享的問題甜滨,因此它本質上是 buffer 與 file 的結合乐严,即 dma-buf 既是塊物理 buffer,又是個 linux file衣摩。buffer 是內容昂验,file 是媒介,只有通過 file 這個媒介才能實現同一 buffer 在不同驅動之間的流轉艾扮。

一個典型的 dma-buf 應用框圖如下:


https://blog.csdn.net/hexiaolong2009/article/details/102596744

通常既琴,我們將分配 buffer 的模塊稱為 exporter,將使用該 buffer 的模塊稱為 importer 或 user泡嘴。但在本系列文章中甫恩,importer 特指內核空間的使用者,user 特指用戶空間的使用者酌予。

2. GraphicBuffer的創(chuàng)建

為了弄清楚mGraphicBufferProducer->requestBuffer(buf, &gbuf)到底是如何給應用側提供GraphicBuffer磺箕。下面來看一下 GraphicBuffer類奖慌。

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/libs/ui/include/ui/GraphicBuffer.h

class GraphicBufferMapper;

class GraphicBuffer
    : public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>,
      public Flattenable<GraphicBuffer>

GraphicBuffer繼承于ANativeWindowBuffer和Flattenable,前者是在ANativeWindow中的圖元緩沖松靡,后者是Binder 傳輸時候的Parcel封裝IBinder简僧。

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/libs/ui/GraphicBuffer.cpp
GraphicBuffer::GraphicBuffer()
    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
      mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
{
    width  =
    height =
    stride =
    format =
    usage_deprecated = 0;
    usage  = 0;
    layerCount = 0;
    handle = nullptr;
}

status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight,
        PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage,
        std::string requestorName)
{
    GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
    uint32_t outStride = 0;
    status_t err = allocator.allocate(inWidth, inHeight, inFormat, inLayerCount,
            inUsage, &handle, &outStride, mId,
            std::move(requestorName));
   ...
    }
    return err;
}

在初始化中有一個十分核心的類GraphicBufferAllocator,圖元申請器雕欺。這個類真正在一個GraphicBuffer的殼內岛马,通過allocate真正生成一個核心內存塊。接著會調用GraphicBufferMapper. getTransportSize在Mapper中記錄大小屠列。請注意啦逆,allocate方法中有一個十分核心的參數handle。他是來自ANativeWindowBuffer:

//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/libs/nativebase/include/nativebase/nativebase.h#96
 const native_handle_t* handle;

 // system/core/libcutils/include/cutils/native_handle.h中定義了該結構體
//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/system/core/libcutils/include/cutils/native_handle.h#34
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;

native_handle_t實際上是的GraphicBuffer的句柄脸哀。
這里的句柄蹦浦,就是官方文檔中緩沖區(qū)始終通過句柄進行傳遞。


https://source.android.google.cn/docs/core/graphics/arch-bq-gralloc

3. GraphicBufferAllocator

下面來看看GraphicBufferAllocator 初始化

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/libs/ui/GraphicBufferAllocator.cpp
ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferAllocator )
Mutex GraphicBufferAllocator::sLock;
KeyedVector<buffer_handle_t,
    GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;

GraphicBufferAllocator::GraphicBufferAllocator() : mMapper(GraphicBufferMapper::getInstance()) {
//  按照版本由高到低的順序加載 gralloc allocator, 成功則退出
mAllocator = std::make_unique<const Gralloc4Allocator>(
            reinterpret_cast<const Gralloc4Mapper&>(mMapper.getGrallocMapper())); 
// 創(chuàng)建 Gralloc4Allocator 
   ...
}

ANDROID_SINGLETON_STATIC_INSTANCE這個宏實際上就是一個單例,在構造函數中做了2件事情:
1.初始化GraphicBufferMapper
2.創(chuàng)建Gralloc4Allocator

3.1 GraphicBufferMapper

下面我們來看GraphicBufferMapper 初始化做了什么撞蜂。

//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/libs/ui/GraphicBufferMapper.cpp
GraphicBufferMapper::GraphicBufferMapper() {
    mMapper = std::make_unique<const Gralloc4Mapper>();
   ...
}

Gralloc4Mapper 的初始化

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/libs/ui/Gralloc4.cpp#90
Gralloc4Mapper::Gralloc4Mapper() {
    mMapper = IMapper::getService();
   ...
}

本質上是溝通了Hal層的hwServiceManager之后盲镶,獲取IMapper的服務。
最后我們關注IMapper.hal蝌诡,看看這個hal層開放了什么方法給上層,看幾個重點函數溉贿。

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/hardware/interfaces/graphics/mapper/4.0/IMapper.hal#23

interface IMapper {
    // BufferDescriptorInfo用于描述圖形buffer的屬性(寬、高浦旱、格式...)
    struct BufferDescriptorInfo {
        string name; // buffer的名字宇色,用于debugging/tracing
        uint32_t width; // width說明了分配的buffer中有多少個像素列,但它并不表示相鄰行的同一列元素的偏移量,區(qū)別stride颁湖。
        uint32_t height; // height說明了分配的buffer中有多少像素行
        uint32_t layerCount; // 分配的緩沖區(qū)中的圖像層數
        PixelFormat format; // 像素格式 (參見/frameworks/native/libs/ui/include/ui/PixelFormat.h中的定義)
        bitfield<BufferUsage> usage;buffer使用方式的標志位(參見/frameworks/native/libs/ui/include/ui/GraphicBuffer.h的定義)宣蠕。
        uint64_t reservedSize; // 與緩沖區(qū)關聯(lián)的保留區(qū)域的大小(字節(jié))甥捺。
    };
    /**
     * 創(chuàng)建一個 buffer descriptor抢蚀,這個descriptor可以用于IAllocator分配buffer
     * 主要完成兩個工作:
     * 1. 檢查參數的合法性(設備是否支持);
     * 2. 把BufferDescriptorInfo這個結構體變量進行重新的包裝镰禾,本質就是轉化為byte stream皿曲,這樣可以傳遞給IAllocator
     */
    createDescriptor(BufferDescriptorInfo description)  
            generates (Error error,
                       BufferDescriptor descriptor);
                       
    /**
     * 把raw buffer handle轉為imported buffer handle,這樣就可以在調用進程中使用了
     * 當其他進程分配的GraphicBuffer傳遞到當前進程后吴侦,需要通過該方法映射到當前進程屋休,為后續(xù)的lock做好準備
     */
    importBuffer(handle rawHandle) generates (Error error, pointer buffer);
    
    /**
     * importBuffer()返回的buffer handle不再使用后必須調用freeBuffer()釋放
     */
    freeBuffer(pointer buffer) generates (Error error);

    /**
     * 已指定的CPU usage 鎖定緩沖區(qū)的指定區(qū)域accessRegion。lock之后就可以對buffer進行讀寫了
     */
    lock(pointer buffer,
         uint64_t cpuUsage,
         Rect accessRegion,
         handle acquireFence)
            generates (Error error,
                       pointer data);
    /**
     * 解鎖緩沖區(qū)以指示對緩沖區(qū)的所有CPU訪問都已完成
     */
    unlock(pointer buffer) generates (Error error, handle releaseFence);
    
    /**
     * 根據給定的MetadataType獲取對應的buffer metadata 
     */
    get(pointer buffer, MetadataType metadataType)
            generates (Error error,
                       vec<uint8_t> metadata);
 
    /**
     * 設置給定的MetadataType對應的buffer metadata 
     */
    set(pointer buffer, MetadataType metadataType, vec<uint8_t> metadata)
            generates (Error error);
};

1.importBuffer 生成可用的Buffer
2.freeBuffer 釋放Buffer
3.lock 上鎖buffer
4.unlock 解鎖鎖buffer

IMapper::getService()我們可以理解為完成了 buffer handle 所指向的圖形緩存到運行進程的映射备韧。訪問 buffer 數據一般遵循這樣的流程:

importBuffer -> lock -> 讀寫GraphicBuffer-> unlock -> freeBuffer劫樟。

3.2 Gralloc4Allocator

Gralloc4Allocator構造函數中會去創(chuàng)建一個 Gralloc4Allocator 對象,并且傳遞一個 Gralloc4Mapper 對象作為參數:

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/libs/ui/Gralloc4.cpp
Gralloc4Allocator::Gralloc4Allocator(const Gralloc4Mapper& mapper) : mMapper(mapper) {
    mAllocator = IAllocator::getService();
    if (mAllocator == nullptr) {
        ALOGW("allocator 4.x is not supported");
        return;
    }
}

Gralloc4Allocator 的構造函數中去獲取 gralloc-allocator hal service,這是一個 binderized hal service毅哗。
這里我們先暫時理解為:透過 GraphicBufferAllocator & Gralloc4Allocator 我們就可以使用 gralloc-alloctor hal 的功能了听怕。

GraphicBuffer類圖如下所示:


https://www.cnblogs.com/roger-yu/p/16041193.html
  1. GraphicBuffer:對應gralloc分配的圖形Buffer(也可能是普通內存,具體要看gralloc實現)虑绵,它繼承ANativeWindowBuffer結構體尿瞭,核心成員是指向圖形緩存的句柄(native_handle_t * handle),并且圖形Buffer本身是多進程共享的翅睛,跨進程傳輸的是GraphicBuffer的關鍵屬性声搁,這樣在使用進程可以重建GraphicBuffer,同時指向同一塊圖形Buffer捕发。
  2. GraphicBufferAllocator:向下對接gralloc allocator HAL服務疏旨,是進程內單例,負責分配進程間共享的圖形Buffer扎酷。
  3. GraphicBufferMapper:向下對接gralloc mapper HAL服務檐涝,是進程內單例,負責把GraphicBufferAllocator分配的GraphicBuffer映射到當前進程空間法挨。

GraphicBufferAllocator分配內存的具體實現在HAL層谁榜,GraphicBufferMapper映射GraphicBuffer到當前進程空間的具體實現也一樣,暫不做深入凡纳。

現在來看GraphicBuffer是怎么做到跨進程共享的窃植。

3.3 關于GraphicBuffer的跨進程共享

在圖形系統(tǒng)中,生產者和最終的消費者往往不在同一個進程中荐糜,所以 GraphicBuffer 需要跨進程傳遞巷怜,以實現數據共享。我們先用一張流程圖來概況:


https://www.cnblogs.com/roger-yu/p/16041193.html
  1. 首先暴氏,生產進程通過GraphicBuffer::flatten把ANativeWindowBuffer關鍵屬性保存在兩個數組中:buffer和fds,其實就是 Binder 數據傳輸前的序列化處理延塑;

  2. 其次,跨進程傳輸buffer和fds答渔,這里一般就是 Binder IPC 跨進程通信页畦;

  3. 然后,消費進程通過GraphicBuffer::unflatten在自己的進程中重建ANativeWindowBuffer研儒,關鍵是重建ANativeWindowBuffer.handle這個結構體成員,相當于把生產進程的GraphicBuffer映射到了消費進程独令;

  4. 最后端朵,遵循 importBuffer->lock->讀寫GraphicBuffer->unlock->freeBuffer 的基本流程操作GraphicBuffer淹朋。

下面跟著代碼一步步說明這個流程残揉。

GraphicBuffer的數據太大了,沒有辦法進行Binder通信燕鸽,那么他為什么可以辦到binder返回呢招狸?我們調用IGraphicBufferProducerrequestBuffer,走到BnGraphicBufferProducer::onTransact敬拓,最后會走到BufferQueueProducer::requestBuffer邻薯。

// frameworks/native/libs/gui/IGraphicBufferProducer.cpp
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
{
...

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

// frameworks/native/libs/gui/IGraphicBufferProducer.cpp
status_t BnGraphicBufferProducer::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        case REQUEST_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
            int bufferIdx = data.readInt32();
            sp<GraphicBuffer> buffer;
            int result = requestBuffer(bufferIdx, &buffer);
            reply->writeInt32(buffer != nullptr);
            if (buffer != nullptr) {
                reply->write(*buffer);
            }
            reply->writeInt32(result);
            return NO_ERROR;
        }
        ...
    }
    return BBinder::onTransact(code, data, reply, flags);
}

// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
 ...
    mSlots[slot].mRequestBufferCalled = true;
    *buf = mSlots[slot].mGraphicBuffer;
    return NO_ERROR;
}

requestBuffer,到BufferQueueProducer::requestBuffer,這就是一個flatten-> unflatten ->importBuffer->lock->讀寫GraphicBuffer的過程乘凸。

這個binder流程應該是SF端寫fd厕诡,AP端讀出fd',binder驅動幫助轉換了這個fd营勤。
具體怎么做的呢灵嫌,先來看看Parcel的reply.read和reply.write。

//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/libs/binder/Parcel.cpp
status_t Parcel::read(FlattenableHelperInterface& val) const
{
...
        err = val.unflatten(buf, len, fds, fd_count);
...
}


status_t Parcel::write(const FlattenableHelperInterface& val)
{
...
    err = val.flatten(buf, len, fds, fd_count);
...
}

requestBuffer---->BnGraphicBufferProducer::onTransact----> reply->write(*buffer)---->Parcel::write---->val.flatten(buf, len, fds, fd_count)---->GraphicBuffer::flatten葛作。

val 是調用 BufferQueueProducer::requestBuffer生成的GraphicBuffer寿羞。

// frameworks/native/libs/ui/GraphicBuffer.cpp
status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
    ...
    int32_t* buf = static_cast<int32_t*>(buffer);
    buf[0] = 'GB01';
    buf[1] = width;
    buf[2] = height;
    ...
    if (handle) {
       ...
        memcpy(fds, handle->data, static_cast<size_t>(mTransportNumFds) * sizeof(int));
        memcpy(buf + 13, handle->data + handle->numFds,
               static_cast<size_t>(mTransportNumInts) * sizeof(int));
    }
    ...
}

memcpy是內存拷貝函數,這里把handle->data中的中復制到fds中赂蠢。
void *memcpy(void *dest, const void *src, size_t n);
從源src所指的內存地址的起始位置開始拷貝n個字節(jié)到目標dest所指的內存地址的起始位置中绪穆。memcpy可以復制任意內容,例如字符數組虱岂、整型玖院、結構體、類等量瓜。

這里的handle就是ANativeWindowBuffer::handle司恳。調用initWithHandle的時候會初始化。

// frameworks/native/libs/ui/GraphicBuffer.cpp
GraphicBuffer::GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method,
                             uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
                             uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride)
      : GraphicBuffer() {
    mInitCheck = initWithHandle(inHandle, method, inWidth, inHeight, inFormat, inLayerCount,
                                inUsage, inStride);
}

ANativeWindowBuffer::handle = inHandle;

native_handle_t是上層抽象的可以在進程間傳遞的數據結構绍傲,對private_handle_t的抽象包裝扔傅。

https://blog.csdn.net/yangwen123/article/details/16863377

numFds=1表示有一個文件句柄:fd
numInts= 8表示后面跟了8個INT型的數據:magic,flags,size,offset,base,lockState,writeOwner,pid;

服務進程將創(chuàng)建的GraphicBuffer對象的成員變量handle寫回到請求創(chuàng)建圖形緩沖區(qū)的客戶進程,這時客戶進程通過以下方式就可以讀取服務進程返回的關于創(chuàng)建圖形buffer的信息數據烫饼。

服務端返回replay后,應用側通過reply.read(**buf)讀native_handle_t數據猎塞。

// frameworks/native/libs/gui/IGraphicBufferProducer.cpp
    virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {
...
if (nonNull) {
//新建GraphicBuffer
            *buf = new GraphicBuffer();
            result = reply.read(**buf);
            if(result != NO_ERROR) {
                (*buf).clear();
                return result;
            }
        }
...
}

reply.read(**buf)---->Parcel::read---->val.unflatten(buf, len, fds, fd_count)---->GraphicBuffer::unflatten

//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/libs/ui/GraphicBuffer.cpp#101
status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& fds,
                                  size_t& count) {
...
        native_handle* h =
                native_handle_create(static_cast<int>(numFds), static_cast<int>(numInts));
 ...
        memcpy(h->data, fds, numFds * sizeof(int));
        memcpy(h->data + numFds, buf + flattenWordCount, numInts * sizeof(int));
        handle = h;
...


    if (handle != nullptr) {
        buffer_handle_t importedHandle;
        status_t err = mBufferMapper.importBuffer(handle, uint32_t(width), uint32_t(height),
                uint32_t(layerCount), format, usage, uint32_t(stride), &importedHandle);
...

        native_handle_close(handle);
        native_handle_delete(const_cast<native_handle_t*>(handle));
        handle = importedHandle;
        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
    }
...
}

關注2個重點函數:native_handle_createimportBuffer

調用native_handle_create在應用側進程構造一個native_handle對象杠纵。

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/system/core/libcutils/native_handle.cpp#38
native_handle_t* native_handle_create(int numFds, int numInts) {
    if (numFds < 0 || numInts < 0 || numFds > NATIVE_HANDLE_MAX_FDS ||
        numInts > NATIVE_HANDLE_MAX_INTS) {
        errno = EINVAL;
        return NULL;
    }

    size_t mallocSize = sizeof(native_handle_t) + (sizeof(int) * (numFds + numInts));
    native_handle_t* h = static_cast<native_handle_t*>(malloc(mallocSize));
    if (h) {
        h->version = sizeof(native_handle_t);
        h->numFds = numFds;
        h->numInts = numInts;
    }
    return h;
}

importBuffer的調用在HAL層荠耽,這里看看其接口。

// IMapper.hal
   /**
     * 把raw buffer handle轉為imported buffer handle比藻,這樣就可以在調用進程中使用了
     * 當其他進程分配的GraphicBuffer傳遞到當前進程后铝量,需要通過該方法映射到當前進程,為后續(xù)的lock做好準備
     */
    importBuffer(handle rawHandle) generates (Error error, pointer buffer);

Android早期版本調用的是mBufferMapper.registerBuffer银亲,作用是將創(chuàng)建的圖形緩沖區(qū)映射到客戶進程的地址空間來慢叨,這樣客戶端進程就可以直接在圖形buffer映射的地址空間繪圖。
客戶端進程讀取到服務進程創(chuàng)建的圖形buffer的描述信息native_handle后务蝠,通過GraphicBufferMapper對象mBufferMapper的registerBuffer函數將創(chuàng)建的圖形buffer映射到客戶端進程地址空間拍谐。

前面調用GraphicBuffer::flatten,會走到memcpy(fds, handle->data, static_cast<size_t>(mTransportNumFds) * sizeof(int));,把handle->data復制到fds中,這里調用 GraphicBuffer::unflatten之后轩拨,走到memcpy(h->data, fds, numFds * sizeof(int));,把fds復制到handle->data中践瓷。
這樣就把整個handle拷貝過來了,接著調用importBuffer亡蓉,把handle轉化從hidl_handle轉化為可用的private_handle_t晕翠。
這樣就將Private_native_t中的數據:magic,flags,size,offset,base,lockState,writeOwner,pid復制到了客戶端進程。服務端(SurfaceFlinger)分配了一段內存作為Surface的作圖緩沖區(qū)寸宵,客戶端怎樣在這個作圖緩沖區(qū)上繪圖呢崖面?兩個進程間如何共享內存,這就需要GraphicBufferMapper將分配的圖形緩沖區(qū)映射到客戶端進程地址空間梯影。對于共享緩沖區(qū)巫员,他們操作同一物理地址的內存塊。

https://blog.csdn.net/yangwen123/article/details/16863377

其實這里還有一個很重要的點ION沒有深入甲棍。

http://www.reibang.com/p/3bfc0053d254

出處:http://www.reibang.com/p/3bfc0053d254
一般來說:圖元的繪制分為如下幾個步驟:
1.dequeueBuffer 獲取一個圖元的插槽位置简识,或者生產一個圖元。其實在IGrraphicBufferProducer通過flattern進行一次句柄GraphicBuffer拷貝感猛,依次為依據找到底層的共享內存七扰。
2.lock 綁定圖元共享內存地址,最后通過句柄在GrallocImportedBufferPool中找到在SF進程申請好的內存地址
3.queueBuffer 把圖元放入mActiveBuffer中陪白,并且從新計算dequeue和acquire的數量颈走,同時把GrapicBuffer放到mQueue進行消費,最后調用frameAvilable回調通知消費者咱士。
4.unlock 解鎖圖元 揭開共享內存的映射立由。
到這里面涉及到了幾個fd的轉化,先不用太關注序厉,知道是通過ion申請一段共享內存锐膜,通過fd的方式告訴App進程可以映射到同一段物理內存。

更高一點的版本ION也被換掉了弛房。
在 Android 12 中道盏,GKI 2.0 將 ION 分配器替換為 DMA-BUF。


https://source.android.google.cn/devices/architecture/kernel/dma-buf-heaps?hl=en

4.queueBuffer

客戶端/應用通過調用dequeueBuffer獲取到一個可用的buffer后文捶,就可以往這個buffer中填充數據了荷逞。填充好數據后,就要把這個buffer再返還給BufferQueue粹排,調用的方法是queueBuffer颅围。

status_t BufferQueueProducer::queueBuffer(int slot,
        const QueueBufferInput &input, QueueBufferOutput *output) {
    ATRACE_CALL();
    ATRACE_BUFFER_INDEX(slot);

    int64_t requestedPresentTimestamp;
    bool isAutoTimestamp;
    android_dataspace dataSpace;
    Rect crop(Rect::EMPTY_RECT);
    int scalingMode;
    uint32_t transform;
    uint32_t stickyTransform;
    sp<Fence> acquireFence;
    bool getFrameTimestamps = false;
    // 保存Surface傳遞過來的input里面封裝的buffer信息
    input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,
            &crop, &scalingMode, &transform, &acquireFence, &stickyTransform,
            &getFrameTimestamps);
    const Region& surfaceDamage = input.getSurfaceDamage();
    const HdrMetadata& hdrMetadata = input.getHdrMetadata();

    if (acquireFence == nullptr) {
        BQ_LOGE("queueBuffer: fence is NULL");
        return BAD_VALUE;
    }

    auto acquireFenceTime = std::make_shared<FenceTime>(acquireFence);

    switch (scalingMode) {
        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
        case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
            break;
        default:
            BQ_LOGE("queueBuffer: unknown scaling mode %d", scalingMode);
            return BAD_VALUE;
    }
    // 回調接口,用于通知consumer
    sp<IConsumerListener> frameAvailableListener;
    sp<IConsumerListener> frameReplacedListener;
    int callbackTicket = 0;
    uint64_t currentFrameNumber = 0;
    BufferItem item;
    { // Autolock scope
        std::lock_guard<std::mutex> lock(mCore->mMutex);
        // BufferQueue是否被棄用
        if (mCore->mIsAbandoned) {
            BQ_LOGE("queueBuffer: BufferQueue has been abandoned");
            return NO_INIT;
        }
        // BufferQueue是否沒有連的producer
        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
            BQ_LOGE("queueBuffer: BufferQueue has no connected producer");
            return NO_INIT;
        }
        // BufferSlot對應的slot序號是否合法恨搓,狀態(tài)是否為DEQUEUE
        if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
            BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)",
                    slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
            return BAD_VALUE;
        } else if (!mSlots[slot].mBufferState.isDequeued()) {
            BQ_LOGE("queueBuffer: slot %d is not owned by the producer "
                    "(state = %s)", slot, mSlots[slot].mBufferState.string());
            return BAD_VALUE;
        } else if (!mSlots[slot].mRequestBufferCalled) { // 是否調用了requestBuffer 函數
            BQ_LOGE("queueBuffer: slot %d was queued without requesting "
                    "a buffer", slot);
            return BAD_VALUE;
        }

        // If shared buffer mode has just been enabled, cache the slot of the
        // first buffer that is queued and mark it as the shared buffer.
        if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot ==
                BufferQueueCore::INVALID_BUFFER_SLOT) {
            mCore->mSharedBufferSlot = slot;
            mSlots[slot].mBufferState.mShared = true;
        }

        BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d"
                " validHdrMetadataTypes=0x%x crop=[%d,%d,%d,%d] transform=%#x scale=%s",
                slot, mCore->mFrameCounter + 1, requestedPresentTimestamp, dataSpace,
                hdrMetadata.validTypes, crop.left, crop.top, crop.right, crop.bottom,
                transform,
                BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode)));
        // 當前queue的具體GraphicBuffer
        const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
        // 根據當前的GraphicBufferd的寬高創(chuàng)建矩形區(qū)域
        Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
        // 創(chuàng)建裁剪區(qū)域
        Rect croppedRect(Rect::EMPTY_RECT);
        // 裁剪區(qū)域 賦值為crop和bufferRect相交部分
        crop.intersect(bufferRect, &croppedRect);
        if (croppedRect != crop) {
            BQ_LOGE("queueBuffer: crop rect is not contained within the "
                    "buffer in slot %d", slot);
            return BAD_VALUE;
        }

        // Override UNKNOWN dataspace with consumer default
        if (dataSpace == HAL_DATASPACE_UNKNOWN) {
            dataSpace = mCore->mDefaultBufferDataSpace;
        }

        mSlots[slot].mFence = acquireFence;
        // 改變入隊的BufferSlot的狀態(tài)為QUEUED
        mSlots[slot].mBufferState.queue();

        // Increment the frame counter and store a local version of it
        // for use outside the lock on mCore->mMutex.
        ++mCore->mFrameCounter;
        currentFrameNumber = mCore->mFrameCounter;
        mSlots[slot].mFrameNumber = currentFrameNumber;
        
        // 把BufferSlot中的信息封裝為BufferItem,后續(xù)會把這個BufferItem加入到隊列中
        item.mAcquireCalled = mSlots[slot].mAcquireCalled;
        item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
        item.mCrop = crop;
        item.mTransform = transform &
                ~static_cast<uint32_t>(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
        item.mTransformToDisplayInverse =
                (transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
        item.mScalingMode = static_cast<uint32_t>(scalingMode);
        item.mTimestamp = requestedPresentTimestamp;
        item.mIsAutoTimestamp = isAutoTimestamp;
        item.mDataSpace = dataSpace;
        item.mHdrMetadata = hdrMetadata;
        item.mFrameNumber = currentFrameNumber;
        item.mSlot = slot;
        item.mFence = acquireFence;
        item.mFenceTime = acquireFenceTime;
        item.mIsDroppable = mCore->mAsyncMode ||
                (mConsumerIsSurfaceFlinger && mCore->mQueueBufferCanDrop) ||
                (mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) ||
                (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);
        item.mSurfaceDamage = surfaceDamage;
        item.mQueuedBuffer = true;
        item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh;
        item.mApi = mCore->mConnectedApi;

        mStickyTransform = stickyTransform;

        // Cache the shared buffer data so that the BufferItem can be recreated.
        if (mCore->mSharedBufferMode) {
            mCore->mSharedBufferCache.crop = crop;
            mCore->mSharedBufferCache.transform = transform;
            mCore->mSharedBufferCache.scalingMode = static_cast<uint32_t>(
                    scalingMode);
            mCore->mSharedBufferCache.dataspace = dataSpace;
        }

        output->bufferReplaced = false;
        if (mCore->mQueue.empty()) {
            // 如果mQueue隊列為空,則直接push進入這個mQueue斧抱,不用考慮阻塞
            // When the queue is empty, we can ignore mDequeueBufferCannotBlock
            // and simply queue this buffer
            mCore->mQueue.push_back(item);
            //取出BufferQueueCore的回調接口常拓,下面調用這個接口的onFrameAvailable函數來通知Consumer
            frameAvailableListener = mCore->mConsumerListener;
        } else {
            // When the queue is not empty, we need to look at the last buffer
            // in the queue to see if we need to replace it
            const BufferItem& last = mCore->mQueue.itemAt(
                    mCore->mQueue.size() - 1);
            if (last.mIsDroppable) {
                // 判斷最后一個BufferItem是否可以丟棄   
                if (!last.mIsStale) {
                    mSlots[last.mSlot].mBufferState.freeQueued();

                    // After leaving shared buffer mode, the shared buffer will
                    // still be around. Mark it as no longer shared if this
                    // operation causes it to be free.
                    if (!mCore->mSharedBufferMode &&
                            mSlots[last.mSlot].mBufferState.isFree()) {
                        mSlots[last.mSlot].mBufferState.mShared = false;
                    }
                    // Don't put the shared buffer on the free list.
                    if (!mSlots[last.mSlot].mBufferState.isShared()) {
                        mCore->mActiveBuffers.erase(last.mSlot);
                        mCore->mFreeBuffers.push_back(last.mSlot);
                        output->bufferReplaced = true;
                    }
                }

                // Make sure to merge the damage rect from the frame we're about
                // to drop into the new frame's damage rect.
                if (last.mSurfaceDamage.bounds() == Rect::INVALID_RECT ||
                    item.mSurfaceDamage.bounds() == Rect::INVALID_RECT) {
                    item.mSurfaceDamage = Region::INVALID_REGION;
                } else {
                    item.mSurfaceDamage |= last.mSurfaceDamage;
                }
                // 用當前BufferItem,替換了隊列最后一個BufferItem
                // Overwrite the droppable buffer with the incoming one
                mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item;
                //取出回調接口辉浦,因為是替換弄抬,所以后續(xù)調用接口的函數 onFrameReplaced
                frameReplacedListener = mCore->mConsumerListener;
            } else {
                // 直接push進入這個mQueue
                mCore->mQueue.push_back(item);
                frameAvailableListener = mCore->mConsumerListener;
            }
        }
        // 表示 buffer已經queued,此時入隊完成
        mCore->mBufferHasBeenQueued = true;
        // mDequeueCondition是C++條件變量用作等待/喚醒宪郊,這里調用notify_all會喚醒調用了wait的線程
        mCore->mDequeueCondition.notify_all();
        mCore->mLastQueuedSlot = slot;
        //output 參數掂恕,會在Surface中繼續(xù)使用
        output->width = mCore->mDefaultWidth;
        output->height = mCore->mDefaultHeight;
        output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint;
        output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size());
        output->nextFrameNumber = mCore->mFrameCounter + 1;

        ATRACE_INT(mCore->mConsumerName.string(),
                static_cast<int32_t>(mCore->mQueue.size()));
#ifndef NO_BINDER
        mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
#endif
        // Take a ticket for the callback functions
        callbackTicket = mNextCallbackTicket++;

        VALIDATE_CONSISTENCY();
    } // Autolock scope

    // It is okay not to clear the GraphicBuffer when the consumer is SurfaceFlinger because
    // it is guaranteed that the BufferQueue is inside SurfaceFlinger's process and
    // there will be no Binder call
    if (!mConsumerIsSurfaceFlinger) {
        item.mGraphicBuffer.clear();
    }

    // Update and get FrameEventHistory.
    nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC);
    NewFrameEventsEntry newFrameEventsEntry = {
        currentFrameNumber,
        postedTime,
        requestedPresentTimestamp,
        std::move(acquireFenceTime)
    };
    addAndGetFrameTimestamps(&newFrameEventsEntry,
            getFrameTimestamps ? &output->frameTimestamps : nullptr);

    // Call back without the main BufferQueue lock held, but with the callback
    // lock held so we can ensure that callbacks occur in order

    int connectedApi;
    sp<Fence> lastQueuedFence;

    { // scope for the lock
        std::unique_lock<std::mutex> lock(mCallbackMutex);
        while (callbackTicket != mCurrentCallbackTicket) {
            mCallbackCondition.wait(lock);
        }
        //通知consumer,此處調用接口的不同弛槐,是有上面懊亡,是否替換最后一個BufferItem 決定的
        if (frameAvailableListener != nullptr) {
            frameAvailableListener->onFrameAvailable(item);
        } else if (frameReplacedListener != nullptr) {
            frameReplacedListener->onFrameReplaced(item);
        }

        connectedApi = mCore->mConnectedApi;
        lastQueuedFence = std::move(mLastQueueBufferFence);

        mLastQueueBufferFence = std::move(acquireFence);
        mLastQueuedCrop = item.mCrop;
        mLastQueuedTransform = item.mTransform;

        ++mCurrentCallbackTicket;
        mCallbackCondition.notify_all();
    }

    // Wait without lock held
    if (connectedApi == NATIVE_WINDOW_API_EGL) {
        // Waiting here allows for two full buffers to be queued but not a
        // third. In the event that frames take varying time, this makes a
        // small trade-off in favor of latency rather than throughput.
        lastQueuedFence->waitForever("Throttling EGL Production");
    }

    return NO_ERROR;
}

queueBuffer 的流程主要做了這兩件事情:
1.將對應 BufferSlot 狀態(tài)設置成 QUEUED
2.創(chuàng)建 BufferItem 對象,并將 GraphicBuffer 的數據復制給 BufferItem乎串,并入隊到 BufferQueueCore 的 mQueue 隊列中店枣,這樣可以方便圖像消費者直接按先進先出的順序從 mQueue 隊列取出 GraphicBuffer 使用

生產者寫完數據,把buffer還給buffer queue后叹誉,會通知消費者來使用鸯两。

5.acquireBuffer 和 releaseBuffer

BufferQueueConsumer作為消費者的一個代表元素通過 acquireBuffer 來獲取圖像緩沖區(qū),通過 releaseBuffer 來釋放該緩沖區(qū)长豁。

5.1 acquireBuffer
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
        nsecs_t expectedPresent, uint64_t maxFrameNumber) {
    ATRACE_CALL();

    int numDroppedBuffers = 0;
    sp<IProducerListener> listener;
    {
        std::unique_lock<std::mutex> lock(mCore->mMutex);

        // Check that the consumer doesn't currently have the maximum number of
        // buffers acquired. We allow the max buffer count to be exceeded by one
        // buffer so that the consumer can successfully set up the newly acquired
        // buffer before releasing the old one.
        
        // 檢查acquire的buffer的數量是否超出了限制
        int numAcquiredBuffers = 0;
        for (int s : mCore->mActiveBuffers) {
            if (mSlots[s].mBufferState.isAcquired()) {
                ++numAcquiredBuffers;
            }
        }
        const bool acquireNonDroppableBuffer = mCore->mAllowExtraAcquire &&
                numAcquiredBuffers == mCore->mMaxAcquiredBufferCount + 1;
        if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1 &&
            !acquireNonDroppableBuffer) {
            BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
                    numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
            return INVALID_OPERATION;
        }

        bool sharedBufferAvailable = mCore->mSharedBufferMode &&
                mCore->mAutoRefresh && mCore->mSharedBufferSlot !=
                BufferQueueCore::INVALID_BUFFER_SLOT;

        // In asynchronous mode the list is guaranteed to be one buffer deep,
        // while in synchronous mode we use the oldest buffer.
        // 檢查BufferQueueCore中的mQueue隊列是否為空
        if (mCore->mQueue.empty() && !sharedBufferAvailable) {
            return NO_BUFFER_AVAILABLE;
        }
        // 獲取BufferQueueCore中的mQueue隊列的迭代器
        BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
        
        // If expectedPresent is specified, we may not want to return a buffer yet.
        // If it's specified and there's more than one buffer queued, we may want
        // to drop a buffer.
        // Skip this if we're in shared buffer mode and the queue is empty,
        // since in that case we'll just return the shared buffer.
        if (expectedPresent != 0 && !mCore->mQueue.empty()) {
            
            // expectedPresent表示期望這個buffer什么時候顯示到屏幕上钧唐。
            // 如果buffer的期望顯示時間小于expectedPresent,我們會acquire and return這個buffer
            // 如果我們不想顯示它直到expectedPresent之后匠襟,可以返回PRESENT_LATER
            
            // The 'expectedPresent' argument indicates when the buffer is expected
            // to be presented on-screen. If the buffer's desired present time is
            // earlier (less) than expectedPresent -- meaning it will be displayed
            // on time or possibly late if we show it as soon as possible -- we
            // acquire and return it. If we don't want to display it until after the
            // expectedPresent time, we return PRESENT_LATER without acquiring it.
            //
            
            // 安全起見钝侠,如果expectedPresent超過了buffer的期望顯示時間1秒,我們會推遲acquire
            // To be safe, we don't defer acquisition if expectedPresent is more
            // than one second in the future beyond the desired present time
            // (i.e., we'd be holding the buffer for a long time).
            //
            // NOTE: Code assumes monotonic time values from the system clock
            // are positive.
            
            // 檢查是否需要丟棄一些幀,主要是判斷timestamps & expectedPresent
            // Start by checking to see if we can drop frames. We skip this check if
            // the timestamps are being auto-generated by Surface. If the app isn't
            // generating timestamps explicitly, it probably doesn't want frames to
            // be discarded based on them.
            while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
                const BufferItem& bufferItem(mCore->mQueue[1]);

                // If dropping entry[0] would leave us with a buffer that the
                // consumer is not yet ready for, don't drop it.
                if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
                    break;
                }

                // If entry[1] is timely, drop entry[0] (and repeat). We apply an
                // additional criterion here: we only drop the earlier buffer if our
                // desiredPresent falls within +/- 1 second of the expected present.
                // Otherwise, bogus desiredPresent times (e.g., 0 or a small
                // relative timestamp), which normally mean "ignore the timestamp
                // and acquire immediately", would cause us to drop frames.
                //
                // We may want to add an additional criterion: don't drop the
                // earlier buffer if entry[1]'s fence hasn't signaled yet.
                nsecs_t desiredPresent = bufferItem.mTimestamp;
                
                // desiredPresent比expectedPresent小了1 second多宅此,或desiredPresent大于expectedPresent
                if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
                        desiredPresent > expectedPresent) {
                    // This buffer is set to display in the near future, or
                    // desiredPresent is garbage. Either way we don't want to drop
                    // the previous buffer just to get this on the screen sooner.
                    BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%"
                            PRId64 " (%" PRId64 ") now=%" PRId64,
                            desiredPresent, expectedPresent,
                            desiredPresent - expectedPresent,
                            systemTime(CLOCK_MONOTONIC));
                    break;
                }

                BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64
                        " size=%zu",
                        desiredPresent, expectedPresent, mCore->mQueue.size());
                // 處理要drop的buffer
                if (!front->mIsStale) {
                    // Front buffer is still in mSlots, so mark the slot as free 
                    // 對應的BufferSlot設置為FREE狀態(tài)
                    mSlots[front->mSlot].mBufferState.freeQueued();

                    // After leaving shared buffer mode, the shared buffer will
                    // still be around. Mark it as no longer shared if this
                    // operation causes it to be free.
                    if (!mCore->mSharedBufferMode &&
                            mSlots[front->mSlot].mBufferState.isFree()) {
                        mSlots[front->mSlot].mBufferState.mShared = false;
                    }
                    
                    // mActiveBuffers :綁定了GraphicBuffer且狀態(tài)為非FREE的BufferSlot集合;
                    // mFreeBuffers :綁定了GraphicBuffer且狀態(tài)為FREE的BufferSlot集合机错;
                    
                    // Don't put the shared buffer on the free list
                    if (!mSlots[front->mSlot].mBufferState.isShared()) {
                        mCore->mActiveBuffers.erase(front->mSlot); // 從mActiveBuffers刪除
                        mCore->mFreeBuffers.push_back(front->mSlot);// 添加進mFreeBuffers
                    }

                    if (mCore->mBufferReleasedCbEnabled) {
                        listener = mCore->mConnectedProducerListener; // 設置生產者的監(jiān)聽器
                    }
                    ++numDroppedBuffers; // 計數加1,記錄drop了幾個buffer
                }

                mCore->mQueue.erase(front);// 從mQueue中刪除
                front = mCore->mQueue.begin();// 重置front父腕,進入下一次while循環(huán)
            }

            // See if the front buffer is ready to be acquired
            nsecs_t desiredPresent = front->mTimestamp;
            bool bufferIsDue = desiredPresent <= expectedPresent ||
                    desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
            bool consumerIsReady = maxFrameNumber > 0 ?
                    front->mFrameNumber <= maxFrameNumber : true;
            if (!bufferIsDue || !consumerIsReady) {
                BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
                        " (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64
                        " consumer=%" PRIu64,
                        desiredPresent, expectedPresent,
                        desiredPresent - expectedPresent,
                        systemTime(CLOCK_MONOTONIC),
                        front->mFrameNumber, maxFrameNumber);
                ATRACE_NAME("PRESENT_LATER");
                return PRESENT_LATER;
            }

            BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " "
                    "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent,
                    desiredPresent - expectedPresent,
                    systemTime(CLOCK_MONOTONIC));
        }
        // 走到這里就說明:該丟棄的已經都丟棄了弱匪,余下的就可以拿去顯示了。
        int slot = BufferQueueCore::INVALID_BUFFER_SLOT;

        if (sharedBufferAvailable && mCore->mQueue.empty()) {
            // make sure the buffer has finished allocating before acquiring it
            // 共享Buffer模式下處理
            mCore->waitWhileAllocatingLocked(lock);

            slot = mCore->mSharedBufferSlot;

            // Recreate the BufferItem for the shared buffer from the data that
            // was cached when it was last queued.
            outBuffer->mGraphicBuffer = mSlots[slot].mGraphicBuffer;
            outBuffer->mFence = Fence::NO_FENCE;
            outBuffer->mFenceTime = FenceTime::NO_FENCE;
            outBuffer->mCrop = mCore->mSharedBufferCache.crop;
            outBuffer->mTransform = mCore->mSharedBufferCache.transform &
                    ~static_cast<uint32_t>(
                    NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
            outBuffer->mScalingMode = mCore->mSharedBufferCache.scalingMode;
            outBuffer->mDataSpace = mCore->mSharedBufferCache.dataspace;
            outBuffer->mFrameNumber = mCore->mFrameCounter;
            outBuffer->mSlot = slot;
            outBuffer->mAcquireCalled = mSlots[slot].mAcquireCalled;
            outBuffer->mTransformToDisplayInverse =
                    (mCore->mSharedBufferCache.transform &
                    NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
            outBuffer->mSurfaceDamage = Region::INVALID_REGION;
            outBuffer->mQueuedBuffer = false;
            outBuffer->mIsStale = false;
            outBuffer->mAutoRefresh = mCore->mSharedBufferMode &&
                    mCore->mAutoRefresh;
        } else if (acquireNonDroppableBuffer && front->mIsDroppable) {
            BQ_LOGV("acquireBuffer: front buffer is not droppable");
            return NO_BUFFER_AVAILABLE;
        } else {
            // 從front獲取對應的slot index
            slot = front->mSlot;
            *outBuffer = *front;
        }

        ATRACE_BUFFER_INDEX(slot);

        BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
                slot, outBuffer->mFrameNumber, outBuffer->mGraphicBuffer->handle);

        if (!outBuffer->mIsStale) {
            mSlots[slot].mAcquireCalled = true;
            // Don't decrease the queue count if the BufferItem wasn't
            // previously in the queue. This happens in shared buffer mode when
            // the queue is empty and the BufferItem is created above.
            if (mCore->mQueue.empty()) {
                mSlots[slot].mBufferState.acquireNotInQueue();
            } else {
                // 將BufferState狀態(tài)改為acquire
                mSlots[slot].mBufferState.acquire();
            }
            mSlots[slot].mFence = Fence::NO_FENCE;
        }

        // If the buffer has previously been acquired by the consumer, set
        // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
        // on the consumer side
        if (outBuffer->mAcquireCalled) {
            outBuffer->mGraphicBuffer = nullptr;
        }
        //將該Buffer從mQueue中移除
        mCore->mQueue.erase(front);

        // We might have freed a slot while dropping old buffers, or the producer
        // may be blocked waiting for the number of buffers in the queue to
        // decrease.
        mCore->mDequeueCondition.notify_all();

        ATRACE_INT(mCore->mConsumerName.string(),
                static_cast<int32_t>(mCore->mQueue.size()));
#ifndef NO_BINDER
        mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
#endif
        VALIDATE_CONSISTENCY();
    }
    // 回調璧亮,通知生產者
    if (listener != nullptr) {
        for (int i = 0; i < numDroppedBuffers; ++i) {
            listener->onBufferReleased();
        }
    }

    return NO_ERROR;
}

主要就是這幾件事情:
1.判斷 BufferQueueCore 中的 mQueue 是否為空萧诫,mQueue 就是前面 BufferQueueProducer 調用 queueBuffer 函數時,將緩沖區(qū)入隊的容器枝嘶;
2.取出對應的 BufferSlot(會有一些判斷規(guī)則帘饶,舍棄一些buffer);
3.將 BufferState 改為 acquire 狀態(tài)群扶;
4.將該 Buffer 從 mQueue 中移除及刻;

5.2 releaseBuffer
status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
        const sp<Fence>& releaseFence, EGLDisplay eglDisplay,
        EGLSyncKHR eglFence) {
    ATRACE_CALL();
    ATRACE_BUFFER_INDEX(slot);

    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
            releaseFence == nullptr) {
        BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot,
                releaseFence.get());
        return BAD_VALUE;
    }

    sp<IProducerListener> listener;
    { // Autolock scope
        std::lock_guard<std::mutex> lock(mCore->mMutex);

        // If the frame number has changed because the buffer has been reallocated,
        // we can ignore this releaseBuffer for the old buffer.
        // Ignore this for the shared buffer where the frame number can easily
        // get out of sync due to the buffer being queued and acquired at the
        // same time.
        if (frameNumber != mSlots[slot].mFrameNumber &&
                !mSlots[slot].mBufferState.isShared()) {
            return STALE_BUFFER_SLOT;
        }

        if (!mSlots[slot].mBufferState.isAcquired()) {
            BQ_LOGE("releaseBuffer: attempted to release buffer slot %d "
                    "but its state was %s", slot,
                    mSlots[slot].mBufferState.string());
            return BAD_VALUE;
        }

        mSlots[slot].mEglDisplay = eglDisplay;
        mSlots[slot].mEglFence = eglFence;
        mSlots[slot].mFence = releaseFence;
        mSlots[slot].mBufferState.release();//置為FREE狀態(tài)

        // After leaving shared buffer mode, the shared buffer will
        // still be around. Mark it as no longer shared if this
        // operation causes it to be free.
        if (!mCore->mSharedBufferMode && mSlots[slot].mBufferState.isFree()) {
            mSlots[slot].mBufferState.mShared = false;
        }
        // Don't put the shared buffer on the free list.
        if (!mSlots[slot].mBufferState.isShared()) {
            mCore->mActiveBuffers.erase(slot);// 從mActiveBuffers中刪除
            mCore->mFreeBuffers.push_back(slot);//加入到mFreeBuffers中
        }

        if (mCore->mBufferReleasedCbEnabled) {
            listener = mCore->mConnectedProducerListener; // 設置listener
        }
        BQ_LOGV("releaseBuffer: releasing slot %d", slot);
        // 喚醒等待的線程
        mCore->mDequeueCondition.notify_all();
        VALIDATE_CONSISTENCY();
    } // Autolock scope

    // Call back without lock held
    if (listener != nullptr) {
        listener->onBufferReleased(); //通知producer
    }

    return NO_ERROR;
}

至此镀裤,BufferQueue的大致流程已經看完〗煞梗回到一開始的問題暑劝,APPSurfaceFlinger如何傳輸數據?
關于這個問題颗搂,我覺得這里總結的蠻好的担猛。

出處:http://www.reibang.com/p/f96ab6646ae3
APP繪畫的畫布是由SurfaceFlinger提供的,而畫布是一塊共享內存丢氢,APP向SurfaceFlinger申請到畫布傅联,是將共享內存的地址映射到自身進程空間。 App負責在畫布上作畫疚察,畫完的作品提交給SurfaceFlinger蒸走, 這個提交操作并不是把內存復制一份給SurfaceFlinger,而是把共享內存的控制權交還給SurfaceFlinger稍浆。

最后载碌,給出一張BufferQueue的流程圖,復盤一下:

https://www.cnblogs.com/roger-yu/p/16029867.html

更多關于BufferQueue源碼方面細節(jié)衅枫,可以參考這篇
Android 12(S) 圖像顯示系統(tǒng) - 開篇

參考鏈接:
Android圖形系統(tǒng)(八)-app與SurfaceFlinger共享UI元數據過程
SurfaceFlinger 原理分析
SurfaceFlinger中的SharedClient
《深入理解android內核設計思想》
Android畫面顯示流程分析(2)
Android畫面顯示流程分析(3)
顯示框架之app與SurfaceFlinger通信
android Gui系統(tǒng)之SurfaceFlinger(2)---BufferQueue
Android 重學系列 GraphicBuffer的誕生
Android 重學系列 圖元的消費
Android graphics(二) bufferqueue
[Android禪修之路] 解讀 GraphicBuffer 開篇
[Android禪修之路] 解讀 GraphicBuffer 之 Ion 驅動層
Android P 圖形顯示系統(tǒng)(十) BufferQueue(一)
AndroidQ 圖形系統(tǒng)(7)GraphicBuffer內存分配與Gralloc
android graphic(8)—surface申請GraphicBuffer過程
surfaceflinger分析
Android P 圖形顯示系統(tǒng)(十一) BufferQueue(二)
Android graphics(二) bufferqueue
Android 12(S) 圖像顯示系統(tǒng) - 解讀Gralloc架構及GraphicBuffer創(chuàng)建/傳遞/釋放(十四)
Android GraphicBuffer分配過程

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末嫁艇,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子弦撩,更是在濱河造成了極大的恐慌步咪,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,222評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件益楼,死亡現場離奇詭異猾漫,居然都是意外死亡,警方通過查閱死者的電腦和手機感凤,發(fā)現死者居然都...
    沈念sama閱讀 90,455評論 3 385
  • 文/潘曉璐 我一進店門悯周,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人陪竿,你說我怎么就攤上這事禽翼。” “怎么了族跛?”我有些...
    開封第一講書人閱讀 157,720評論 0 348
  • 文/不壞的土叔 我叫張陵闰挡,是天一觀的道長。 經常有香客問我礁哄,道長长酗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,568評論 1 284
  • 正文 為了忘掉前任桐绒,我火速辦了婚禮夺脾,結果婚禮上之拨,老公的妹妹穿的比我還像新娘。我一直安慰自己咧叭,他們只是感情好敦锌,可當我...
    茶點故事閱讀 65,696評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著佳簸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪颖变。 梳的紋絲不亂的頭發(fā)上生均,一...
    開封第一講書人閱讀 49,879評論 1 290
  • 那天,我揣著相機與錄音腥刹,去河邊找鬼马胧。 笑死,一個胖子當著我的面吹牛衔峰,可吹牛的內容都是我干的佩脊。 我是一名探鬼主播,決...
    沈念sama閱讀 39,028評論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼垫卤,長吁一口氣:“原來是場噩夢啊……” “哼威彰!你這毒婦竟也來了?” 一聲冷哼從身側響起穴肘,我...
    開封第一講書人閱讀 37,773評論 0 268
  • 序言:老撾萬榮一對情侶失蹤歇盼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后评抚,有當地人在樹林里發(fā)現了一具尸體豹缀,經...
    沈念sama閱讀 44,220評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,550評論 2 327
  • 正文 我和宋清朗相戀三年慨代,在試婚紗的時候發(fā)現自己被綠了邢笙。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,697評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡侍匙,死狀恐怖氮惯,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情丈积,我是刑警寧澤筐骇,帶...
    沈念sama閱讀 34,360評論 4 332
  • 正文 年R本政府宣布,位于F島的核電站江滨,受9級特大地震影響铛纬,放射性物質發(fā)生泄漏。R本人自食惡果不足惜唬滑,卻給世界環(huán)境...
    茶點故事閱讀 40,002評論 3 315
  • 文/蒙蒙 一告唆、第九天 我趴在偏房一處隱蔽的房頂上張望棺弊。 院中可真熱鬧,春花似錦擒悬、人聲如沸模她。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侈净。三九已至,卻和暖如春僧凤,著一層夾襖步出監(jiān)牢的瞬間畜侦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評論 1 266
  • 我被黑心中介騙來泰國打工躯保, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留旋膳,地道東北人。 一個月前我還...
    沈念sama閱讀 46,433評論 2 360
  • 正文 我出身青樓途事,卻偏偏與公主長得像验懊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子尸变,可洞房花燭夜當晚...
    茶點故事閱讀 43,587評論 2 350

推薦閱讀更多精彩內容