A brief analysis of the initialization process of SurfaceFlinger

Table of Contents

SurfaceFlinger main function

The general process of SurfaceFlinger’s init:

Initialize EGL to retrieve EFL context

CreateHWComposer

Code part:

Initialize non-virtual display

Code part:

EventThread::waitForEvent


Rough process: ISurfaceComposer is used to define the Binder IPC interface for accessing SurfaceFlinger (the application’s DisplayEventReceiver sends a request to create an event connection to SurfaceFlinger through this interface, which is createEventConnection), and then SF will create a Connection object, and then use the Connection The object obtains the BitTube object (essentially a Socket), Looper listens to BitTube’s fd, and calls back MQ’s eventReceiver method after receiving the event.

Post a picture from the Internet:

SurfaceFlinger main function

int main(int, char**) {
    ProcessState::self()->setThreadPoolMaxThreadCount(4);
    
    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);
    
    //Initialization (call init function)
    flinger->init();
    
    //Add SurfaceFliger to Service Manager
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
    
    //Call run method
    flinger->run();
    
    return 0;
}

Summary process:

  • Instantiate surfaceflinger
  • Initialization (call init function)
  • Add SurfaceFliger to Service Manager
  • Call the run method of SurfaceFliger

SurfaceFlinger’s init general process:

void SurfaceFlinger::init() {
    Mutex::Autolock _l(mStateLock);

    //Initialize EGL as the default display
    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(mEGLDisplay, NULL, NULL);

    //Initialize the hardware HWcomposer object
    mHwc = new HWComposer(this, *static_cast<HWComposer::EventHandler *>(this));

    //Get the RenderEngine engine
    mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID());

    //Retrieve the created EGL context
    mEGLContext = mRenderEngine->getEGLContext();

    //Initialize the non-virtual display screen
    for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i + + ) {
        DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
        //Create a connected display device
        if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
            bool isSecure = true;
            createBuiltinDisplayLocked(type);
            wp<IBinder> token = mBuiltinDisplays[i];

            sp<IGraphicBufferProducer> producer;
            sp<IGraphicBufferConsumer> consumer;
            //Create producers and consumers of BufferQueue
            BufferQueue::createBufferQueue( & amp;producer, & amp;consumer,
                    new GraphicBufferAlloc());

            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i, consumer);
            int32_t hwcId = allocateHwcDisplayId(type);
            //Create display device
            sp<DisplayDevice> hw = new DisplayDevice(this,
                    type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
                    fbs, producer,
                    mRenderEngine->getEGLConfig());
            if (i > DisplayDevice::DISPLAY_PRIMARY) {
                hw->setPowerMode(HWC_POWER_MODE_NORMAL);
            }
            mDisplays.add(token, hw);
        }
    }

    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);

    //When the vsync offset of the application and sf are consistent, only one EventThread thread is created
    if (vsyncPhaseOffsetNs != sfVsyncPhaseOffsetNs) {
        sp<VSyncSource> vsyncSrc = new DispSyncSource( & amp;mPrimaryDispSync,
                vsyncPhaseOffsetNs, true, "app");
        mEventThread = new EventThread(vsyncSrc);
        sp<VSyncSource> sfVsyncSrc = new DispSyncSource( & amp;mPrimaryDispSync,
                sfVsyncPhaseOffsetNs, true, "sf");
        mSFEventThread = new EventThread(sfVsyncSrc);
        mEventQueue.setEventThread(mSFEventThread);
    } else {
        //Create DispSyncSource object
        sp<VSyncSource> vsyncSrc = new DispSyncSource( & amp;mPrimaryDispSync,
                vsyncPhaseOffsetNs, true, "sf-app");
        //Create thread EventThread
        mEventThread = new EventThread(vsyncSrc);
        //Save the created EventThread to MQ
        mEventQueue.setEventThread(mEventThread);
    }

    //Create the EventControlThread thread and run it
    mEventControlThread = new EventControlThread(this);
    mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);

    //When HWComposer does not exist, set up software vsync simulation
    if (mHwc->initCheck() != NO_ERROR) {
        mPrimaryDispSync.setPeriod(16666667);
    }
}

Initialize EGL to retrieve EFL context

Subsequent search data analysis in this part

Create HWComposer

Initialization to create the HWComposer module (Hardware display device used to register Vsync signal emitted by the driver): The HWComposer module will determine whether the hardware supports vsync, that is, whether the composer device can be opened; if not When supported, a thread will be created to simulate the arrival of the Vsync signal regularly (VsyncThread)

HWComposer internally loads the HWComposer module of the HAL layer

The HWComposer constructor accepts the SurfaceFlinger parameter, and internally loads the HAL layer module of the frameBuffer and loads the HWComposer module. After the HWCompser module is successfully loaded, it will register the callback function of Vsync [Subsequent hardware underlying Vsync When the signal comes up, it is also received by this module]

Code part:
HWComposer::HWComposer(
        const sp<SurfaceFlinger> & amp; flinger,
        EventHandler & handler)
    : mFlinger(flinger),
      mFbDev(0), mHwc(0), mNumDisplays(1),
      mCBContext(new cb_context),
      mEventHandler(handler),
      mDebugForceFakeVSync(false)
{
    ...
    bool needVSyncThread = true;
    int fberr = loadFbHalModule(); //Load the HAL layer module of the framebuffer
    loadHwcModule(); //Load HWComposer module

    //Mark the assigned display ID
    for (size_t i=0; i<NUM_BUILTIN_DISPLAYS; i + + ) {
        mAllocatedDisplayIDs.markBit(i);
    }

    if (mHwc) {
        if (mHwc->registerProcs) {
            mCBContext->hwc = this;
            mCBContext->procs.invalidate = & amp;hook_invalidate;
            //Callback method of VSYNC signal
            mCBContext->procs.vsync = & amp;hook_vsync;
            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
                mCBContext->procs.hotplug = & amp;hook_hotplug;
            else
                mCBContext->procs.hotplug = NULL;
            memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
            //Register callback function
            mHwc->registerProcs(mHwc, & amp;mCBContext->procs);
        }

        //Entering here means that the hardware composer device has been successfully opened, and the vsync thread is no longer needed.
        needVSyncThread = false;
        eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
        ...
    }
    ...

    if (needVSyncThread) {
        //If hardware VSYNC is not supported, a thread will be created to simulate the scheduled VSYNC signal.
        mVSyncThread = new VSyncThread(*this);
    }
}

Initialize non-virtual display screen

(Create producers and consumers of display devices DisplayDevice and GraphicBufferQuene) Start two EventThread threads of app and sf (when the offsets of vsync of application and sf are different)

Main work: Establish connection device display device

Explanation of necessary conditions: The display device needs to consume the data put into the buffer by the GPU for display, so it is necessary to create a buffer and a display device. The buffer is divided into producers and consumers, so a FraphicBufferQuene needs to be created before creating a display device. producers and consumers.

Display devices are divided into three categories: main device, extended device, and virtual device. The first two are built-in display devices, so only two display devices can be created. In addition, when creating a display device, a FrameBufferSurface will also be created, so so far, two display devices, two FrameBufferSurfaces, and two GraphicBufferQuenes of the producer (IGraphicBufferProducer) and the consumer (IGraphicBufferConsumer) have been created. >

Code part:
## Create EventThread and save it to MQ

**Process processing:**

Create DispSyncSource, use DispSyncSource to create EventThread, and then add the created EventThread to MessageQuene (mEventQuene.setEventhread)

\


remind:

If Vsync has no offset, only one DisplayVsyncSource (named app-sf) and one EventThread are initialized; otherwise, two EventThreads and two DisplayEventSources (named one app for processing and one Sf for synthesis) are initialized.

The EventThread constructor requires a DisplayVsyncSource parameter, and there will be a collection internally to store its internal class Connection (singalConnections attribute, which represents the Connection connection that needs to accept Vsync connections)

EventThread's onFirstRef will call its run method and enter the **EventThread's threadloop method**: In this method, the **waitForEvent** (waiting for event) method is called, and the parameter is the DisplayEventReceiver parameter (the client is used to accept Vsync Signal class, **EventThread has one by default**)

#### EventThread::threadLoop

Determine the length of singalConnections by finding the number of connection collections waiting for events (the length of mDisplayEventConnection). If there is no Connection that needs to accept the Vsync signal, condition.await will block and sleep When there is no Connection that needs to accept the event When connecting, traverse the singalConnections collection and distribute it to all Connections

This Condition will be awakened when the Vsync signal is received, and then it will traverse the singalConnections and call the postEvent method of its element Conneciton.

EventThread::waitForEvent
After creating the EventThread, put it into MQ and implement it by calling the MessageQuene.setEventThread method. It internally calls createEventConnection of eventThread to establish a connection, obtains the BitTube object through the return value of createEventConnection, obtains BitTube's fd and uses Looper's addFd to monitor the data. Once the data arrives, the cb_eventReceiver method of MedssageQuene is called to process on behalf of the event receiver.

When the Vsync signal comes, look at the logic processing here.

#### MessageQueue::setEventThread

Original link: SurfaceFlinger brief analysis of the initialization process (Part 2) – Nuggets (juejin.cn)?

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 138831 people are learning the system