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