1. 程式人生 > >「Android」SurfaceFlinger分析

「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以上原始碼)很多地方還不理解,所以有不正確的地方還請指正。