1. 程式人生 > >adb shell dumpsys SurfaceFlinge 分析

adb shell dumpsys SurfaceFlinge 分析

對於很多Android的顯示問題,我們需要使用adb shell dumpsys SurfaceFlinger命令來獲取SurfaceFlinger的dump資訊,這對於我們分析問題有很大的幫助,因此我們這裡來詳細講解下SurfaceFlinger的dump.

SurfaceFlinger的dump資訊主要通過dumpAllLocked 函式來獲取,因此我們這裡就以android 5.0在主螢幕上的一份dump來詳細說明下dump的作用.

1 特殊巨集的開啟

一般dump的第一行都是這樣的:

Build configuration: [sf] [libui] [libgui]

這說明其實沒有開啟任何特殊的巨集,實際上,如果一下特殊巨集開啟,第一行log會打印出來:

FRAMEBUFFER_FORCE_FORMAT,HAS_CONTEXT_PRIORITY,NEVER_DEFAULT_TO_ASYNC_MODE,TARGET_DISABLE_TRIPLE_BUFFERING,DONT_USE_FENCE_SYNC

一般情況下,這些巨集一個都不會開啟.

2 Sync機制

第二行一般是這樣的:

Sync configuration: [using: EGL_ANDROID_native_fence_sync EGL_KHR_wait_sync]

這行其實列印了目前使用的sync機制,這個值源於這段邏輯:

         if (useNativeFenceSync()) {
              mString.append
(" EGL_ANDROID_native_fence_sync"); } if (useFenceSync()) { mString.append(" EGL_KHR_fence_sync"); } if (useWaitSync()) { mString.append(" EGL_KHR_wait_sync"); }

注意,一二是互斥的,三可以與一二共存.

3 DispSync引數

第三行是列印的是Vsync相關的引數:

DispSync configuration: app phase 0 
ns, sf phase 0 ns, present offset 0 ns (refresh 16666667 ns)

這些引數我們還是比較熟悉的,有意思的是列印這些引數時候使用的語法:

    result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
            "present offset %d ns (refresh %" PRId64 " ns)",
        vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS,
        mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));

PRId64的用法很獨特,這是一種跨平臺的列印64位整數的做法:

printf("%" PRId64 "\n", value);
// 相當於64位的:
printf("%" "ld" "\n", value);
// 或32位的:
printf("%" "lld" "\n", value);

4 layer的dump

接下來就是很長的一段layer的dump,一般以這樣一句話開始:

Visible layers (count = 9)

count的值來源於layersSortedByZ中layer的數量.
接下來就進入各個layer的dump,我們參考程式碼並以launcher所在的layer為例來解釋下各行的意義:

+ Layer 0xb3f92000 (com.sec.android.app.launcher/com.android.launcher2.Launcher) id=87

0xb3f92000指向當前layer物件的值,括號中是當前layer的名稱,id是建立layer時產生的序列號.

4.1 區域資訊

  Region transparentRegion (this=0xb3f92164, count=1)
    [  0,   0,   0,   0]
  Region visibleRegion (this=0xb3f92008, count=1)
    [  0,   0, 1440, 2560]

接下來的兩段是兩個Region的dump,每個region可能包含多個區域,所以這裡count也可能不等於1.
前兩行的值來源於activeTransparentRegion,表示的是這個layer裡面透明區域的大小.
後兩行值來源於visibleRegion,表示可見區域的大小.

4.2 基本資訊

layerStack=   0, z=    21010, pos=(0,0), size=(1440,2560), crop=(0, 0,1440,2560), isOpaque=0, 
invalidate=0, alpha=0xff, flags=0x00000000, tr=[1.00, 0.00][0.00, 1.00]
client=0xb11160c0

上面這段dump源自這段程式碼:

  result.appendFormat(            "      "
            "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
            "isOpaque=%1d, invalidate=%1d, "
            "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
            "      client=%p\n",
            s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
            s.active.crop.left, s.active.crop.top,
            s.active.crop.right, s.active.crop.bottom,
            isOpaque(s), contentDirty,
            s.alpha, s.flags,
            s.transform[0][0], s.transform[0][1],
            s.transform[1][0], s.transform[1][1],
            client.get());
  • layerStack表示這個layer是儲存在哪個layerstack中(不同的display是有不同的layerstack的,這點可以通過一個連線HDMI時的layerstack很容易確認).

  • z表示Z軸座標,z值越大,layer越靠上.

  • pos的值是layer左上角的位置,這個值比較特殊的是ImageWallpaper這個layer的pos值,因為ImageWallpaper的大小大於螢幕大小,所以ImageWallpaper的pos值在螢幕的外面(note4是pos=(-560,0)).

  • size自然是layer的大小

  • crop代表裁剪區域,這點依然是對於桌布很明顯,因為桌布layer大小大於螢幕,必須涉及到需要裁剪一部分顯示在螢幕上,因此它的裁剪區域是crop=( 560, 0,2000,2560).
  • isOpaque代表是否是不透明的,只有完全不透明的layer這個值才是1,比如桌布,像狀態列和launcher他們都是0,代表不是完全不透明的
  • invalidate表示這個layer的資料是失效的,這個值絕大多數情況下都是0.因為我們看到的一般都是繪製好的有效的資料.一種情況下這值特別頻繁的多見為1,就是剛剛鎖屏(解鎖)時.因為突然鎖屏,會導致繪製的內容和要顯示的內容完全不同,導致layer的各種資料要重新計算,所以將layer置為失效.
  • alpha表示了這張layer的透明度,這個值跟isOpaque是有區別的.isOpaque表示了這個layer可以是透明的,也就是沒有顯示資料的地方,可以透明;而alpha表示透明度,也即是有資料的地方也可以因為透明度而收到影響產生透明的效果.
  • flag值含義豐富,它是眾多flag或出來的結果,影響它值的包括:
enum {
      eLayerHidden        = 0x01,     // SURFACE_HIDDEN in SurfaceControl.java
      eLayerOpaque        = 0x02,     // SURFACE_OPAQUE
      eLayerTransparent   = 0x200,     // SURFACE_TRANSPARENT
};

enum {
    ePositionChanged            = 0x00000001,
    eLayerChanged               = 0x00000002,
    eSizeChanged                = 0x00000004,
    eAlphaChanged               = 0x00000008,
    eMatrixChanged              = 0x00000010,
    eTransparentRegionChanged   = 0x00000020,
    eVisibilityChanged          = 0x00000040,
    eLayerStackChanged          = 0x00000080,
    eCropChanged                = 0x00000100,
/* SRIB : Smg Surface Animator : State that will indicate animation change */
        e3DAnimationChanged         = 0x00001000,
/* SRIB : Smg Surface Animator : Change End*/
        eOpacityChanged             = 0x00000200,
// { SRUK-SFBLUR
        eTranslucentRegionChanged   = 0x00000400,
// SRUK-SFBLUR }
        eTransparencyChanged        = 0x80000000,
};
enum { // (keep in sync with Surface.java)
    eHidden             = 0x00000004,
    eDestroyBackbuffer  = 0x00000020,
    eSecure             = 0x00000080,
    eNonPremultiplied   = 0x00000100,
    eOpaque             = 0x00000400,
    eProtectedByApp     = 0x00000800,
    eProtectedByDRM     = 0x00001000,
    eCursorWindow       = 0x00002000,
    /* SISO Changes for Internal_Only - Start */
    eFXInternalDisplay = 0x80000000,
    /* SISO Changes for Internal_Only - End */
    eFXSurfaceNormal    = 0x00000000,
    eFXSurfaceDim       = 0x00020000,
    eFXSurfaceMask      = 0x000F0000,
    // begin of app fw : fixed orientation window
    eFixedOrientation   = 0x40000000,
    // end of app fw
    // begin of MDM remote control
    eNoRemoteControl      = 0x08000000,
    // end of MDM remote control
};

所有的這些值都可能影響layer的狀態,涉及不同模組不同功能,這裡不再展開.

  • 接下來的一組tr資料代表螢幕的旋轉和縮放程度.大多數的layer實際上是不需要旋轉和縮放的,因為他們定義的大小就是跟螢幕一致的,所以他們的這組資料是[1.00, 0.00][0.00, 1.00],實際上如果你使用這組資料來做矩陣變換的話,矩陣是不會發生變化的.
    需要旋轉的比較典型的場景是照相機.橫著拿相機時它的layer的變換矩陣是[-1.00, 0.00][-0.00, -1.00],也就是旋轉180°.
    這個值的來源是上層呼叫setMatrix函式設定的.

  • client含義比較簡單,值的來源是建立layer時,對應的SurfaceSession中mNativeClient.這東西也是跟SurfaceSession一一對應的,也就是跟SurfaceFlinger連線時一一對應的.從這個值我們可以判斷,client值相同的layer,必然來自同一個程序(因為他們是由同一個連線創建出來的).

4.3 buffer資訊

      format= 1, activeBuffer=[1440x2560:1664,  1], queued-frames=0, mRefreshPending=0
            mTexName=38 mCurrentTexture=2
            mCurrentCrop=[0,0,0,0] mCurrentTransform=0
            mAbandoned=0
            -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0,
            default-size=[1440x2560], default-format=1, transform-hint=00, FIFO(0)={}
             [00:0xb110e100] state=FREE    , 0xb3eb1ec0 [1440x2560:1664,  1]
             [01:0xb3ec7000] state=FREE    , 0xb620d060 [1440x2560:1664,  1]
            >[02:0xb110e200] state=ACQUIRED, 0xb1111100 [1440x2560:1664,  1]

4.3.1 資料格式

首先是資料的format,值的來源是layer建立時賦予的,當然我們如果追溯的話,可以追溯到WindowManagerService建立SurfaceControl的過程,值也是建立時指定的.值的定義如下:

 enum {
    //
    // these constants need to match those
    // in graphics/PixelFormat.java & pixelflinger/format.h
    //
    PIXEL_FORMAT_UNKNOWN    =   0,
    PIXEL_FORMAT_NONE       =   0,
    // logical pixel formats used by the SurfaceFlinger -----------------------
    PIXEL_FORMAT_CUSTOM         = -4,
    // Custom pixel-format described by a PixelFormatInfo structure
    PIXEL_FORMAT_TRANSLUCENT    = -3,
    // System chooses a format that supports translucency (many alpha bits)
    PIXEL_FORMAT_TRANSPARENT    = -2,
    // System chooses a format that supports transparency
    // (at least 1 alpha bit)
    PIXEL_FORMAT_OPAQUE         = -1,
    // System chooses an opaque format (no alpha bits required)
    // real pixel formats supported for rendering -----------------------------
    PIXEL_FORMAT_RGBA_8888   = HAL_PIXEL_FORMAT_RGBA_8888,   // 4x8-bit RGBA
    PIXEL_FORMAT_RGBX_8888   = HAL_PIXEL_FORMAT_RGBX_8888,   // 4x8-bit RGB0
    PIXEL_FORMAT_RGB_888     = HAL_PIXEL_FORMAT_RGB_888,     // 3x8-bit RGB
    PIXEL_FORMAT_RGB_565     = HAL_PIXEL_FORMAT_RGB_565,     // 16-bit RGB
    PIXEL_FORMAT_BGRA_8888   = HAL_PIXEL_FORMAT_BGRA_8888,   // 4x8-bit BGRA
    PIXEL_FORMAT_RGBA_5551   = 6,                            // 16-bit ARGB
    PIXEL_FORMAT_RGBA_4444   = 7,                            // 16-bit ARGB
    PIXEL_FORMAT_sRGB_A_8888 = HAL_PIXEL_FORMAT_sRGB_A_8888, // 4x8-bit sRGB + A
    PIXEL_FORMAT_sRGB_X_8888 = HAL_PIXEL_FORMAT_sRGB_X_8888, // 4x8-bit sRGB, no A
};

其實只有下面的值是真實可用的,其餘值在SurfaceFlinger建立時會被轉換:

    switch (format) {
    case PIXEL_FORMAT_TRANSPARENT:
    case PIXEL_FORMAT_TRANSLUCENT:
        format = PIXEL_FORMAT_RGBA_8888;
        break;
    case PIXEL_FORMAT_OPAQUE:
        format = PIXEL_FORMAT_RGBX_8888;
        break;
    }

其實當前常見的format也就是這幾種.

HAL_PIXEL_FORMAT_RGBA_8888          = 1,
HAL_PIXEL_FORMAT_RGBX_8888          = 2,
HAL_PIXEL_FORMAT_RGB_888            = 3,
HAL_PIXEL_FORMAT_RGB_565            = 4,
HAL_PIXEL_FORMAT_BGRA_8888          = 5,

0代表未知格式.
常見的layer中,dimlayer一般是0,大多數layer是1,桌布是2,照相機的預覽資料是4,視訊播放也是4.

4.3.2 activeBuffer

  • activeBuffer的前兩項表示了當前正在顯示的buffer的寬和高.
  • 第三項表示Stride.這個值很有意思,我們發現他有時候是等於寬的,有時候是大於寬的,我們先來看下這個值的解釋.
    The number of pixels that a line in the buffer takes in memory. This may be >= width.
    我們知道記憶體申請使用是需要成塊對齊的,也就是說不是說使我們申請多大的記憶體,就會給我們多大的記憶體,因為涉及到對齊,所以很可能這個記憶體實際上是大於我們的需要的.(暫時沒有仔細研究,有待確認)像有些marvell型號,記憶體是按照64位對齊的,那麼我們申請一個100寬的buffer,系統就會給我們留出128的buffer大小供我們使用.
  • 第四項並沒有什麼特殊,表示format,跟前面的format應該是一致的.

4.3.3 queued-frames 新的幀的數量

queued-frames的含義是是否有新的幀,如果當前沒有新的幀,這個值是0.
一般在畫面持續變化時(照相預覽,視訊播放,視窗滑動,遊戲),這個值會是1.表示有新的一幀.
偶爾也可以見到這個值是2(這個值應該最大就是2,因為只有三個緩衝區).

4.3.4 mRefreshPending重新整理卡住了嗎?

mRefreshPending幾乎所有的常見情況下都是0,因為這個引數代表了一個layer執行了Invalidate卻沒有完成Refresh,除非發生錯誤這顯然不可能.

4.4 SurfaceFlingerConsumer的dump

接下來開始對消費者進行dump,SurfaceFlingerConsumer是GLConsumer子類,所以這裡實際上是呼叫了GLConsumer的dumpLocked函式.
先來看下程式碼:

    result.appendFormat(
       "%smTexName=%d mCurrentTexture=%d\n"
       "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
       prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
       mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
       mCurrentTransform);

它會對應打印出來這一段資訊:

            mTexName=38 mCurrentTexture=2
            mCurrentCrop=[0,0,0,0] mCurrentTransform=0

4.4.1 材質名稱

mTexName的值來源是在消費者被建立時,我們知道最常見的建立消費者的時候是Layer::onFirstRef時會呼叫:

mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);

建立一個消費者,有兩個引數,其中mTextureName是我們目前關注的,如果追溯來源你會發現mTextureName的值來源於glGenTextures,這個函式的實現依賴平臺,參考ligagl,它是這樣的:

   // generate unique (shared) texture names
   c->surfaceManager->getToken(n, textures);

還是繼續回來看SurfaceFlingerConsumer的建立:

 SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
            uint32_t tex)
        : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false),
          mTransformToDisplayInverse(false)

GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
        uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
    ConsumerBase(bq, isControlledByApp),
    mCurrentTransform(0),
    mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
    mCurrentFence(Fence::NO_FENCE),
    mCurrentTimestamp(0),
    mCurrentFrameNumber(0),
    mDefaultWidth(1),
    mDefaultHeight(1),
    mFilteringEnabled(true),
    mTexName(tex),
    mUseFenceSync(useFenceSync),
    mTexTarget(texTarget),
    mEglDisplay(EGL_NO_DISPLAY),
    mEglContext(EGL_NO_CONTEXT),
    mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
    mAttached(true)

我們現在可以看出來mTexName的值來源於前面建立的材質名稱.
mCurrentTexture的初始值是INVALID_BUFFER_SLOT,也就是-1,後面會在updateAndReleaseLocked時被更改,值的來源是使用的BufferItem的mBuf值,也就是mSlot,這應該是使用的buffer陣列的slot值,這個變數的合理取值只有0,1,2三個值(mSlot is the slot index of this buffer ,default INVALID_BUFFER_SLOT).

4.4.2 mCurrentCrop裁剪區域

mCurrentCrop的值來源同樣是updateAndReleaseLocked呼叫時被賦值,值的來源是BufferItem的mCrop值.這個值基本一直都是0,只有在視訊播放和照相機時會被設定(值的來源有待更深入的研究, mCrop is the current crop rectangle for this buffer slot).

4.4.3 mCurrentTransform 旋轉相關

mCurrentTransform的值和前面我們說過的tr值很類似. (mTransform is the current transform flags for this buffer slot. refer to NATIVE_WINDOW_TRANSFORM_* in <window.h>).
它也跟旋轉有關,我們來看下window.h中的定義:

/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */
enum {
    /* flip source image horizontally */
    NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
    /* flip source image vertically */
    NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
    /*rotate source image 90 degrees clock-wise, is applied after TRANSFORM_FLIP_{H|V} */
    NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
    /* rotate source image 180 degrees */
    NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
    /* rotate source image 270 degrees clock-wise */
    NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
    /* transforms source by the inverse transform of the screen it is displayed onto. This
     * transform is applied last */
    NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08
};

enum {
    /* flip source image horizontally (around the vertical axis) */
    HAL_TRANSFORM_FLIP_H    = 0x01,
    /* flip source image vertically (around the horizontal axis)*/
    HAL_TRANSFORM_FLIP_V    = 0x02,
    /* rotate source image 90 degrees clockwise */
    HAL_TRANSFORM_ROT_90    = 0x04,
    /* rotate source image 180 degrees */
    HAL_TRANSFORM_ROT_180   = 0x03,
    /* rotate source image 270 degrees clockwise */
    HAL_TRANSFORM_ROT_270   = 0x07,
    /* don't use. see system/window.h */
    HAL_TRANSFORM_RESERVED  = 0x08,
};

4.5 ConsumerBase(消費者)的dump

子類GLConsumer dump完畢,呼叫了它的父類的dump函式,基本就是呼叫了IGraphicBufferConsumer的dump函式.
生產者消費者這套體系我們之前以前講過,這裡我們就不再詳細展開,如果不清楚看下Layer::onFirstRef這個函式就明白了,消費者這個值來自於BufferQueue::createBufferQueue的建立,其中建立了新的BufferQueueConsumer做為消費者.

void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
        sp<IGraphicBufferConsumer>* outConsumer,
        const sp<IGraphicBufferAlloc>& allocator) {
    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
    *outProducer = producer;
    *outConsumer = consumer;

當然BufferQueueConsumer的dump函式啥也沒寫,就呼叫了BufferQueueCore的dump函式.

打印出來的資訊一般是這樣的:

            -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0,
            default-size=[1440x2560], default-format=1, transform-hint=00, FIFO(0)={}
             [00:0xb110e100] state=FREE    , 0xb3eb1ec0 [1440x2560:1664,  1]
             [01:0xb3ec7000] state=FREE    , 0xb620d060 [1440x2560:1664,  1]
            >[02:0xb110e200] state=ACQUIRED, 0xb1111100 [1440x2560:1664,  1]

下面我們按照程式碼順序詳細解釋一下:

4.5.1 佇列中的buffer

我們之前在解釋queued-frames的含義時已經說過,在畫面持續變化時(照相預覽,視訊播放,視窗滑動,遊戲),queued-frames值會是1.表示有新的一幀.
對應的,有新的frames自然需要有在佇列中等待的buffer,對應這段程式碼會把這個佇列打印出來:

    Fifo::const_iterator current(mQueue.begin());
    while (current != mQueue.end()) {
        fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], "
                "xform=0x%02x, time=%#" PRIx64 ", scale=%s\n",
                current->mSlot, current->mGraphicBuffer.get(),
                current->mCrop.left, current->mCrop.top, current->mCrop.right,
                current->mCrop.bottom, current->mTransform, current->mTimestamp,
                BufferItem::scalingModeName(current->mScalingMode));
        ++current;
    }

對應打印出來的dump資訊是這樣的:

02:0xb631e480 crop=[0,0,0,0], xform=0x07, time=0xc4d5da9b1e0, scale=FREEZE
  • 02是mSlot的值,crop是裁剪區域,xform是旋轉,這三個我們上面已經講過,這裡不再展開.

  • time是這個buffer被queue的時間(mTimestamp is the current timestamp for this buffer slot. This gets to set by queueBuffer each time this slot is queued. This value is guaranteed to be monotonically increasing for each newly acquired buffer.).

  • scale是縮放模式,一般取值如下:

    enum {
      /* the window content is not updated (frozen) until a buffer of
       * the window size is received (enqueued)
       */
      NATIVE_WINDOW_SCALING_MODE_FREEZE           = 0,
      /* the buffer is scaled in both dimensions to match the window size */
      NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW  = 1,
      /* the buffer is scaled uniformly such that the smaller dimension
       * of the buffer matches the window size (cropping in the process)
       */
      NATIVE_WINDOW_SCALING_MODE_SCALE_CROP       = 2,
      /* the window is clipped to the size of the buffer's crop rectangle; pixels
       * outside the crop rectangle are treated as if they are completely
       * transparent.
       */
      NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP    = 3,
    };

4.5.2 BufferQueue的基本預設資訊

接下來的一段程式碼會列印BufferQueue的一些基本資訊:

    result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
            "mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
            "default-format=%d, transform-hint=%02x, FIFO(%zu)={%s}\n",
            prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock,
            mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint,
            mQueue.size(), fifo.string());

一般會列印如下:

-BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1920x1080],
 default-format=4, transform-hint=04

4.5.2.1 允許同時acquire的buffer的數量

mMaxAcquiredBufferCount是允許同時acquire的buffer的數量,解釋如下:

    // mMaxAcquiredBufferCount is the number of buffers that the consumer may
    // acquire at one time. It defaults to 1, and can be changed by the consumer
    // via setMaxAcquiredBufferCount, but this may only be done while no
    // producer is connected to the BufferQueue. This value is used to derive
    // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer.

基本這個值只能是1,不再深究.

4.5.2.2 dequeueBuffer是否允許被block

    // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to
    // block. This flag is set during