天天看點

Android Window的添加和顯示過程

文章目錄

    • 1. Android Window
    • 2. Window的添加流程
      • 1. Native Surface的面貌
    • 3. BufferQueue
            • BufferQueue的消費者模型大概的通信流程:
    • 4. Surface 和 Layer
      • 1. Surface繪圖過程
      • 2. 整體繪制過程概述:
    • 5. 總結
本文基于Android N;

1. Android Window

Android中的Window是一個抽象概念,并不是真正的window,而是一個用于對真正的圖形顯示元件(Surface)做管理的 “虛拟視窗概念”。

我們在開發過程中的意識上可以認為Window就是一個螢幕視窗,這也是Android提出Window概念的目的所在,可以更好的面向開發者了解。

實質上的Window其實是一塊 圖形緩沖區 ,這塊圖形緩沖區的承載者就是我們在自定義View的時候所見的Canvas,而對Canvas也有其緩沖區管理者,叫做Surface。

Surface的作用是向SurfaceFlinger擷取App界面建立時候的 GraphicBuffer(IGraphicBufferProducer),并向Buffer中預設填充一個Bitmap資料格式,并設定到Canvas中,這整個流程在接下來都會有講到。

2. Window的添加流程

Window的添加流程從WindowManager的addView開始,這個接口是所有用戶端對視窗的建立的統一接口,并且調用之後,會直接顯示在界面上(系統Window的使用會有權限問題)

Android Window的添加和顯示過程

如上圖所示,addWindow的流程其實就是向WindowManagerService注冊Window的格式/類型/尺寸等大小,然後向SurfaceFlinger申請圖形緩存Layer,Layer中會有建立好的GraphicBuffer,和用于送出圖形的producer對象,消費圖形資料的consumer對象。

  • 圖中重要的幾點:
  1. ViewRootImpl建立的時候,會建立一個Surface,此時這個Surface對象是空的;
  2. Surface的對象填充是在requestLayout之後,底層會傳回Native Surface的位址,并通過1中建立的Surface對象中;

1. Native Surface的面貌

  • 看一下Native的Surface是什麼樣子的?
//frameworks/native/libs/gui/Surface.cpp
Surface::Surface(
        const sp<IGraphicBufferProducer>& bufferProducer,
        bool controlledByApp)
    : mGraphicBufferProducer(bufferProducer),
      mCrop(Rect::EMPTY_RECT),
      mGenerationNumber(0),
      mSharedBufferMode(false),
      mAutoRefresh(false),
      mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
      mSharedBufferHasBeenQueued(false)
{
           

對IGraphicBufferProducer的一個封裝。

  • bufferProducer對象是怎麼來的?
//frameworks/native/libs/gui/SurfaceControl.cpp

SurfaceControl::SurfaceControl(
        const sp<SurfaceComposerClient>& client,
        const sp<IBinder>& handle,
        const sp<IGraphicBufferProducer>& gbp)
    : mClient(client), mHandle(handle),
    mGraphicBufferProducer(gbp) //來自構造函數;
{
}
    ......
sp<Surface> SurfaceControl::getSurface() const
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == 0) {
        // This surface is always consumed by SurfaceFlinger, so the
        // producerControlledByApp value doesn't matter; using false.
        //Native Surface建立
        mSurfaceData = new Surface(mGraphicBufferProducer, false);
    }
    return mSurfaceData;
}
           

SurfaceControl建立的時候會傳遞gbp對象并賦給mGraphicBufferProducer。

  • gbp怎麼來的?
//frameworks/native/libs/gui/SurfaceComposerClient.cpp
sp<SurfaceControl> SurfaceComposerClient::createSurface(
        const String8& name,
        uint32_t w,
        uint32_t h,
        PixelFormat format,
        uint32_t flags)
{
    sp<SurfaceControl> sur;
    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IGraphicBufferProducer> gbp;
        status_t err = mClient->createSurface(name, w, h, format, flags,
                &handle, &gbp);
        ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
        if (err == NO_ERROR) {
            sur = new SurfaceControl(this, handle, gbp);
        }
    }
    return sur;
}
           

在requestLayout的時候,調用createSurface建立的,并通過SurfaceControl包裝的(構造時候傳遞進去的)。

還是沒有說到gbp怎麼來的,繼續跟:

//frameworks/native/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
status_t SurfaceFlinger::createLayer(
        const String8& name,
        const sp<Client>& client,
        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
{
   ...

    sp<Layer> layer;

    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceNormal:
            result = createNormalLayer(client,
                    name, w, h, flags, format,
                    handle, gbp, &layer);
            break;
        case ISurfaceComposerClient::eFXSurfaceDim:
            ...
            break;
        default:
            ...
    }
...
}

status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
        const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
    ...

    *outLayer = new Layer(this, client, name, w, h, flags);
    status_t err = (*outLayer)->setBuffers(w, h, format, flags);
    if (err == NO_ERROR) {
        *handle = (*outLayer)->getHandle();
        *gbp = (*outLayer)->getProducer(); //**gbp來自于這裡
    }
...
}
           

繼續跟

void Layer::onFirstRef() {
    sp<IGraphicBufferProducer> producer;
    sp<IGraphicBufferConsumer> consumer;
    BufferQueue::createBufferQueue(&producer, &consumer); //建立producer和consumer
    mProducer = new MonitoredProducer(producer, mFlinger); //包裝producer
    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName); //包裝consumer
    mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
    mSurfaceFlingerConsumer->setContentsChangedListener(this); //設定consumer的FrameAvailable監聽器,
                                                              //會在producer queueBuffer之後,通知consumer有可用的幀資料需要合成;
    mSurfaceFlingerConsumer->setName(mName);
}

sp<IGraphicBufferProducer> Layer::getProducer() const {
    return mProducer; //gbp實體就是這位大哥,
                      //在Layer建立的時候建立的MonitoredProducer,但是這個隻是一個包裝,實體還不是這個。
}
           

繼續看…

///frameworks/native/libs/gui/BufferQueue.cpp
//!!createBufferQueue是建立BufferQueue需要的元素:BufferQueueCore, Producer和Consumer。
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
        sp<IGraphicBufferConsumer>* outConsumer,
        const sp<IGraphicBufferAlloc>& allocator) {
    LOG_ALWAYS_FATAL_IF(outProducer == NULL,
            "BufferQueue: outProducer must not be NULL");
    LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
            "BufferQueue: outConsumer must not be NULL");

    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
    LOG_ALWAYS_FATAL_IF(core == NULL,
            "BufferQueue: failed to create BufferQueueCore");

    //***BufferQueueProducer 才是真正的Producer
    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
    LOG_ALWAYS_FATAL_IF(producer == NULL,
            "BufferQueue: failed to create BufferQueueProducer");

    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
    LOG_ALWAYS_FATAL_IF(consumer == NULL,
            "BufferQueue: failed to create BufferQueueConsumer");

    *outProducer = producer;
    *outConsumer = consumer;
}
           

3. BufferQueue

參考:

Android BufferQueue生産消費原理概述

Android Window的添加和顯示過程

BufferQueue的消費者模型大概的通信流程:

Android Window的添加和顯示過程

4. Surface 和 Layer

Surface 和 Layer是一一對應的, Surface屬于圖形生産者(Producer),Layer屬于圖形消費者(Consumer)。

App通過Surface送出的圖形資料,通過enqueueBuffer之後,SurfaceFlinger會通過Layer擷取到圖形緩沖資料,最終渲染送出到螢幕做顯示。

1. Surface繪圖過程

ViewRootImpl建立空Surface之後,經過requestLayout操作或建立真正的Surface(見上圖),然後App程序會經過measure,layout和draw最終将畫面繪制出來。

這裡着重看draw方法。

下圖是Surface申請 GraphicBuffer, 繪制填充Buffer, 送出Buffer的流程。Buffer的設定其實是設定到了SKBitmap(Skia)中,然後再把SKBitmap設定到Canvas中,是以真正的Buffer攜帶者其實是Canvas,Surface負責申請Buffer,控制Buffer在繪制過程中的lock和unlock同步操作:

Android Window的添加和顯示過程

圖形繪制的生産者消費者模型:

Android Window的添加和顯示過程

[在這裡Producer是

Surface

, Consumer是

Layer

]

2. 整體繪制過程概述:

  • 1_ Surface -> lock,連接配接BufferQueue, 注冊用于接收consumer消費完并會受到Buffer Queue的可用Frame的監聽器(DummyProducerListener);
  • 2_ dequeueBuffer, 向QueueBuffer申請可用的GraphicBuffer;
  • 3_ 将申請的GraphicBuffer包裝成SkBitmap,并設定到Canvas中,最後傳回lockedSurface給Java層;
  • 4_ View繪制Canvas,填充圖形資料到Canvas中;
  • 5_ Surface-> unlockAndPost, 送出填充完成的Buffer到BufferQueue;
  • 6_ BufferQueue會通知Consumer(Layer)目前有需要合成的Buffer存在,Layer收到監聽之後,會通知SurfaceFlinger,最後通過Layer更新Texture,渲染完成後送出到螢幕顯示;

綜合兩張圖可以大緻的看下從addView開始到Surface建立、申請Buffer、填充Buffer、繪制到體送出Buffer的整體流程:

Android Window的添加和顯示過程

5. 總結

從軟體層面上看,Android的Graphic架構主要有幾個子產品:

Activity、Window、Surface、Layer、Canvas、BufferQueue。

其中:

  1. Activity:标記一個活動,是活動的管理者(并不參與繪制),是Window的承載者;
  2. Window:标記一個視窗(真實其實是WindowState),是一個抽象概念,用來對承載和管理Surface;
  3. Surface:标記一個繪制流程,面向開發者弱化了GraphicBuffer的概念,用來申請/送出Buffer,管理Canvas,管理一個繪制回合(繪制流程的同步);
  4. Layer:Graphic服務端的Buffer承載者,對應一個Surface,它受SurfaceFlinger的管理。SurfaceFlinger是Surface的消費者,消費機關是Layer;
  5. Canvas: 真正用于圖形資料填充(繪制)的對象,Surface申請的Buffer會儲存在Canvas中的SKBitmap中,繪制完成後,Surface會将Canvas對應的已經填充了有效資料的緩沖區enqueue到BufferQueue,然後通消費者有需要渲染的Buffer入隊,然後交由消費者消費;

在App側,隻需要使用2D/3D圖形繪制引擎來繪制出自己的圖形資料,然後送出到這一塊申請好的Buffer中,

并送出到BufferQueue,消費者SurfaceFlinger會從BufferQueue取出資料經由opengl渲染之後遞交到螢幕顯示。

  • App一般使用的事2D圖形引擎Skia,3D由OpenGL做渲染。也可以通過開啟硬體加速交由opengl來渲染,在Android N上有hwui作為硬體加速的可選項。
  • 關于Android APP中 Skia和openGL的了解,可以參考:

    Android Graphic : apk and Skia/OpenGL|ES

  1. BufferQueue: Android Graphic的核心之一,管理生産者和消費者之間對Buffer使用的同步,還有GPU/CPU的跨硬體同步(Fence),在Graphic系統上起着關鍵的作用。具體參考上面的第三大點。

以上所有的流程個人總結為:

初始化會話連結 -> 添加Window,設定Window資訊(顯示螢幕、顯示大小,格式等等) -> 建立Surface ->

初始化Layer -> 建立BufferQueue -> 申請Buffer -> 填充Buffer -> 送出Buffer -> 消費Buffer(渲染)->顯示渲染内容

繼續閱讀