「Android」SurfaceFlinger分析


本篇針對surfaceFlinger模塊進行分析,目錄如下:

1、SurfaceFlinger功能

  1.1、BufferQueue原理(native/libs/gui模塊)

  1.2   layer顯示內存分配(native/libs/ui模塊)

  1.3、surfaceFlinger處理(native/.../surfaceFlinger模塊

2、工程代碼解析:

  2.1、surfaceFlinger啟動過程

  2.2、surfaceFlinger事務處理 

3、總結(處理流程、交互模塊)

***********************************************************×*********************************×*******

 

1、SurfaceFlinger功能:

surfaceflinger作用是接受多個來源的圖形顯示數據,將他們合成,然后發送到顯示設備。
比如打開應用,常見的有三層顯示,頂部的statusbar底部或者側面的導航欄以及應用的界面,每個層是單獨更新和渲染,這些界面都是有surfaceflinger合成一個刷新到硬件顯示。
在顯示過程中使用到了 bufferqueue,surfaceflinger作為consumer方,比如windowmanager管理的surface作為生產方產生頁面,交由surfaceflinger進行合成。

1.1、BufferQueue原理(和SF交互)

bufferqueue分為生產者和消費者
比如應用通過windowsmanager分配一個surface,需要分配(dequeueBuffer)顯示空間在上面進行繪圖,在圖形繪制完成后需要推送(queueBuffer)到surfaceflinger進行合成顯示。
surfaceflinger作為消費者,通過acquireBuffer()得到一個要合成的圖形,在合成完畢后再releaseBuffer()將圖形釋放。
(1)在bufferQueuei所在目錄下  ComposerService 為單例模式負責與surfaceflinger 建立binder連接,在native/libs/gui庫
代碼如下:
class ComposerService : public Singleton<ComposerService>
{
    sp<ISurfaceComposer> mComposerService;
    sp<IBinder::DeathRecipient> mDeathObserver;
    Mutex mLock;

    ComposerService();
    void connectLocked();
    void composerServiceDied();
    friend class Singleton<ComposerService>;
public:

    // Get a connection to the Composer Service.  This will block until
    // a connection is established.即getComposerService
    static sp<ISurfaceComposer> getComposerService();
};

(2)ComposerService 為單例模式負責與surfaceflinger建立binder連接;

(3)SurfaceComposerClient則在於surfaceflinger建立連接后(即getComposerService)建立與Client的連接,

  通過client調用createSurface,然后返回SurfaceControl;

(4)SurfaceControl負責這個顯示層的控制。

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.
        mSurfaceData = new Surface(mGraphicBufferProducer, false);
    }
    return mSurfaceData;
}
通過SurfaceControl::getSurface(),得到的真正的顯示層,這樣之后可以通過Lock和unlock將surface空間分配繪圖,再返回給surfaceflinger。

1.2 layer顯示內存分配

(1)surface創建后得到 mGraphicBufferProducer,new GraphicBuffer分配一個GraphicBuffer:

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {.....}

(2) 在graphicbuffer.cpp中分配一個共享內存,在native/libs/ui模塊:

GraphicBuffer::GraphicBuffer(...){...}
status_t GraphicBuffer::initWithSize(...){...}

(3)GraphicBufferAllocator::get() 使用gralloc進行內存分配,分配完成后,得到bufferIdx 將他發給client端也就是surface端

(4)返回虛擬地址給上層

 

1.3、surfaceFlinger處理

 上面創建一個surface后,surfaceflinger對應的是一個layer,當上層layer調用刷新后,onFrameAvailable被調用,通知surfaceflinger有layer更新

void BufferLayer::onFrameAvailable(const BufferItem& item) {
    mFlinger->signalLayerUpdate();
}

 

 

2、工程代碼解析:

2.1、surfaceFlinger啟動過程:

(代碼取自其他博客提供下載的源碼https://blog.csdn.net/ztguang/article/details/64905058,Android7.0以上)

 1、surfaceFlinger代碼倉位置:/frameworks/native/services/surfaceflingers

    surfaceFlinger啟動進程的腳本是surfceFlinger.rc文件,內容如下:

1 service surfaceflinger /system/bin/surfaceflinger
2     class core
3     user system
4     group graphics drmrpc readproc
5     onrestart restart zygote
6     writepid /dev/stune/foreground/tasks

socket pdx/system/vr/display/client
stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
socket pdx/system/vr/display/manager
stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
socket pdx/system/vr/display/vsync
stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0

  注:在.bp腳本中會初始化該腳本,之后執行main_surfaceflinger.cpp文件 (rc文件有3個socket,用於跨進程通信)

2、創建進程后執行main函數,main函數在frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp,main函數主要代碼如下:

int main(int, char**) {
   //忽略了SIGPIPE信號,因為在SurfaceFlinger的Client-Server模型中,或者說IPC機制中,很可能會觸發SIGPIPE信號,而這個信號的默認動作是終止進程
  ////當客戶端/服務端的socket關閉時,防止進程退出 signal(SIGPIPE, SIG_IGN);
// When SF is launched in its own process, limit the number of // binder threads to 4.即SF進程開啟后,線程池限制最大數量為4 ProcessState::self()->setThreadPoolMaxThreadCount(4); // start the thread pool即啟動線程池
  //
大多數程序都是需要IPC的,這里也需要,但是使用Binder機制是很繁瑣的,所以Android為程序進程使用Binder機制封裝了兩個實現類:ProcessState、IPCThreadState
  //其中ProcessState負責打開Binder驅動,進行mmap等准備工作;IPCThreadState負責具體線程跟Binder驅動進行命令交互。
    sp<processstate> ps(ProcessState::self());
    ps->startThreadPool();
 
    // instantiate surfaceflinger即實例化,以及設置進程優先級、事物處理策略
    sp<surfaceflinger> flinger = new SurfaceFlinger();
 
    setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
 
    set_sched_policy(0, SP_FOREGROUND);
 
#ifdef ENABLE_CPUSETS
    // Put most SurfaceFlinger threads in the system-background cpuset
    // Keeps us from unnecessarily using big cores
    // Do this after the binder thread pool init
    set_cpuset_policy(0, SP_SYSTEM);
#endif
 
    // initialize before clients can connect即初始化
    flinger->init();
 
    // publish surface flinger即發布SF,注冊到ServiceManager,sp是strongponiter強指針(sp對象的析構函數調用RefBase的decStrong來減少強弱引用指針計數)
    sp<iservicemanager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
 
    // publish GpuService即注冊GPUservice
    sp<gpuservice> gpuservice = new GpuService();
    sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
 
    struct sched_param param = {0};
    param.sched_priority = 2;
    if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) {
        ALOGE("Couldn't set SCHED_FIFO");
    }
 
    // run surface flinger in this thread即運行當前線程
    flinger->run();
 
    return 0;
}

在執行main函數的時候,執行經過了以下過程: 

(1)創建SurfaceFlinger對象,在其構造函數中,主要是一些成員變量的初始化工作。在SurfaceFlinger.cpp中的構造函數代碼如下:

SurfaceFlinger::SurfaceFlinger()
    :   BnSurfaceComposer(),
        mTransactionFlags(0),
        mTransactionPending(false),
        mAnimTransactionPending(false),
        mLayersRemoved(false),
        mRepaintEverything(0),
        mRenderEngine(NULL),
        mBootTime(systemTime()),
        mBuiltinDisplays(),
        mVisibleRegionsDirty(false),
        mGeometryInvalid(false),
        mAnimCompositionPending(false),
        mDebugRegion(0),
        mDebugDDMS(0),
        mDebugDisableHWC(0),
        mDebugDisableTransformHint(0),
        mDebugInSwapBuffers(0),
        mLastSwapBufferTime(0),
        mDebugInTransaction(0),
        mLastTransactionTime(0),
        mBootFinished(false),
        mForceFullDamage(false),
        mPrimaryDispSync("PrimaryDispSync"),
        mPrimaryHWVsyncEnabled(false),
        mHWVsyncAvailable(false),
        mHasColorMatrix(false),
        mHasPoweredOff(false),
        mFrameBuckets(),
        mTotalTime(0),
        mLastSwapTime(0)
{......}

 

(2) 因為這里的SurfaceFlinger對象是一個StrongPointer(強指針,見老羅博客https://blog.csdn.net/luoshengyang/article/details/6786239),所以首先會走到RefBaseonFirstRef方法。

void SurfaceFlinger::onFirstRef()
{
    mEventQueue.init(this);
}

       查看surfaceFlinger.h,發現mEventQueue是MessqgeQueue創建的對象。所以初始化會創建消息隊列需要的Handler、Looper。在相同目錄下的MessageQueue.cpp文件中:

void MessageQueue::init(const sp<surfaceflinger>& flinger)
{
    mFlinger = flinger;
    mLooper = new Looper(true);
    mHandler = new Handler(*this);
}

  此處MessageQueue不是常見的消息隊列,在surfaceFlinger目錄單獨編寫,mEventQueue更像是消息循環機制的管理者,其中包含了一個looper,一個handler。

  looper中的mMessageEnvelopes這個容器才是真正存儲消息的地方:

/* MessageQueue.cpp */

void MessageQueue::waitMessage() {

         int32_tret = mLooper->pollOnce(-1);

}

 

  handler也不是常見的那個handler,而是Messagequeue中自定義的一個事件處理器,是專門為surfaceflinger設計的,handler收到消息,進一步回調surfaceflinger中的onMessageReceived。

void MessageQueue::Handler::handleMessage(constMessage& message) {

         switch(message.what) {

                   caseINVALIDATE:

                            mQueue.mFlinger->onMessageReceived(message.what);

}        } 

(3)之后執行surfaceFlinger::init,方法主要實現的功能

  • 初始化EGL
  • 創建HWComposer
  • 初始化非虛擬顯示屏
  • 啟動EventThreada線程
  • 啟動開機動畫

在SurfaceFlinger.cpp中的代碼如下:

void SurfaceFlinger::init() {
    ALOGI(  "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");  //開始SF線程的准備工作,初始化graphics H/W

    { // Autolock scope
        Mutex::Autolock _l(mStateLock);

        // initialize EGL for the default display即初始化EGL,作為默認顯示(EGL見https://blog.csdn.net/ieearth/article/details/71180457)
        mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
        eglInitialize(mEGLDisplay, NULL, NULL);

        // start the EventThread開啟事件線程
        sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                vsyncPhaseOffsetNs, true, "app");
        mEventThread = new EventThread(vsyncSrc, *this);
        sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                sfVsyncPhaseOffsetNs, true, "sf");
        mSFEventThread = new EventThread(sfVsyncSrc, *this);
        mEventQueue.setEventThread(mSFEventThread);

        // set SFEventThread to SCHED_FIFO to minimize jitter
        struct sched_param param = {0};
        param.sched_priority = 2;
        if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) {
            ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
        }

        // Get a RenderEngine for the given display / config (can't fail)
        mRenderEngine = RenderEngine::create(mEGLDisplay,
                HAL_PIXEL_FORMAT_RGBA_8888);
    }

    // Drop the state lock while we initialize the hardware composer. We drop
    // the lock because on creation, it will call back into SurfaceFlinger to
    // initialize the primary display.即初始化硬件composer對象,和顯示設備交互,硬件顯示設備
    mHwc = new HWComposer(this);
    mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));

    Mutex::Autolock _l(mStateLock);

    // retrieve the EGL context that was selected/created即檢索創建的EGL上下文
    mEGLContext = mRenderEngine->getEGLContext();

    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
            "couldn't create EGLContext");

    // make the GLContext current so that we can create textures when creating
    // Layers (which may happens before we render something)即顯示設備
    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);

    mEventControlThread = new EventControlThread(this);
    mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);//創建EventControl // initialize our drawing state
    mDrawingState = mCurrentState;

    // set initial conditions (e.g. unblank default device)即初始化顯示裝備
    initializeDisplays();

    mRenderEngine->primeCache();

    // start boot animation即啟動開機動畫
    startBootAnim();

    ALOGV("Done initializing");
}

(4)Android系統中有一個ServiceManager,專門用來管理所有的服務,而SurfaceFlinger不是由ServiceManager啟動的,因此需要向ServiceManager注冊SurfaceFlinger,同時還注冊了GpuService。(在main函數里面注冊)

(5)執行SF的run方法,SurfaceFlinger::run,進入消息循環,SurfaceFlinger啟動成功,開始工作。代碼如下:

void SurfaceFlinger::run() {
    do {
        waitForEvent();
    } while (true);
}

(分析參考博客https://blog.csdn.net/u012439416/article/details/79733178)

waitForEvent方法如下:

mEventQueue.waitMessage();

MessageQueue的waitMessage方法也是一個do – while循環,里面邏輯如下:

>阻塞消息

IPCThreadState::self()->flushCommands();
int32_t ret = mLooper->pollOnce(-1);

flushCommands方法主要是對binder驅動進行交互, 清理binder

pollOnce是消息機制,主要調用了epoll_wait函數,會阻塞,阻塞完了會分發消息隊列中的消息。這里的消息只有自己在Handler中發的消息,還有在setEventThread中自己添加的消息。
>處理不同消息

 

2.2、工作流程

  在執行SF的run方法時,SurfaceFlinger::run,進入MessageQueue.cpp中的waitForEvent方法:

 

當Surface繪制完成后會發出一個Invalidate的消息給Surfaceflinger的等待線程,當waitForEvent接收到消息后就會交給onMessageReceivered去處理,處理過程中會依次調用handleMessageTransaction、handleMessageInvalidate、handleMessageRefresh接口。
 (1)調用handleMessageTransaction時,會調用:

    > 有事務處理請求時,調用handleTransaction進行處理(getTransactionFlags)  

      > 調用handleTransactionLocked

      > commitTransactionao提交事務

    該函數主要處理之前對屏幕和應用程序窗口的改動。窗口狀態的改變只能在一個Transaction中進行。因為窗口狀態的改變可能造成本窗口和其他窗口的可見區域變化,所以就必須重新來計算窗口的可見區域。在這個處理子過程中Android會根據標志位來對所有layer進行遍歷,一旦發現哪個窗口的狀態發生了變化就設置標志位以在將來重新計算這個窗口的可見區域。

 (2)調用handleMessageInvalidate時,會調用handlePageFlip

    > handlePageFlip繪制(Layer從FrontBuffer中取得新數據,並生成一張OpenGL中的紋理。現在Layer准備好了數據,下一步開始進行繪制)

    該函數主要調用handlePageFlip()函數,該函數主要是從各Layer對應的BufferQueue中拿圖形緩沖區數據,並根據內容更新臟區域。

   (3)handleMessageRefresh——進行合並和渲染輸出:

   (4)合並渲染完成后,該線程繼續等待下一個invalidate消息。

 

 

 

4、總結(處理流程、交互模塊)

4.1、處理流程

  首先SF的啟動過程:> 啟動進程腳本.rc

            > main_sf.cpp的main()函數

             >> 啟動線程池,設置線程最大數量

             >> 實例化(創建對象)SF.cpp

               >>> SF:SF構造函數,初始化一些成員變量

               >>> (強指針<p>)SF::onFirstRef執行到MessageQueue.cpp,執行init()創建Handler、Looper

             >> 設置進程優先級 

             >> 執行sf.init()初始化方法 

               >>> 初始化 graphics H/W ...,

               >>> 創建對象顯示設備HWComposer.cpp

               >>> 創建event線程

               >>> 初始化顯示設備

             >> 注冊ServiceManager、GPUService

             >> 運行SF.run()方法  (詳細處理合成圖像)

 

 

  SF的工作流程分析(實現圖像混合):

           > 在run方法中waitForEvent等待事件(MessagQueu.cpp),收到重繪消息后,將退出等待,交給onMessageReceivered去處理

           > handleMessageTransaction處理事務

              >> 有事務處理請求時,調用handleTransaction進行處理(getTransactionFlags)

             >> 調用handleTransactionLocked

             >> commitTransactionao提交事務

           > handleMessageInvalidateia調用handlePageFlip繪制

           > handleMessageRefresh合並和渲染

           > 完成后,線程繼續等待下一個invalidate消息

 

          (以下是深入理解Android的講解,源碼為2.2

           > 處理事務

                >> 有事務處理請求時,調用handleTransaction進行處理(getTransactionFlags)

             >> 調用handleTransactionLocked

             >> commitTransactionao提交事務

             > handlePageFlip繪制(Layer從FrontBuffer中取得新數據,並生成一張OpenGL中的紋理。現在Layer准備好了數據,下一步開始進行繪制)

             > handleRepaint對每一層進行重繪(顯示層的onDraw函數,使用OpenGL)

             > 繪制完圖后,unlockClient釋放之前占着FrontBuffer的索引,調用各個顯示層的finishPageFlip函數

             > postFrameBuffer調用DisplayHardware.cpp的flip函數,flipg調用eglSwapBuffers函數,以完成FrameBuffer的apgeFlip操作,之后混合后的圖像就會傳遞到屏幕中顯示

 

 

  交互模塊:

    應用通過windowsmanager分配一個surface,需要分配顯示空間在上面進行繪圖,在圖形繪制完成后需要推送到surfaceflinger進行合成顯示。
   surfaceflinger作為消費者,得到一個要合成的圖形,在合成完畢后再將圖形釋放。

    大概流程:

    ->bufferqueue.cpp(../native/libs/gui庫

    -> composerService(單例模式)與SF建立bind連接

    -> SurfaceComposerClinet.cpp調用createaSurfce創建surface,返回surfaceControl

    -> 創建surface后在graphicBuffer.cpp(../native/libs/ui庫)分配共享內存

    -> 創建surface后,SF也對應一個layer,當上層layer調用刷新后,onFrameAvailable被調用,通知SF有layer更新 

 

  !!!初次接觸,翻閱《深入理解Android》(2.2源碼)以及其他的博客(Android6.0以上源碼)很多地方還不理解,所以有不正確的地方還請指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM