preface

This is the second installment of the Android drawing process document that examines how the application is associated with SurfaceFlinger in the Window connection.

Let’s move on to see how the Window starts drawing once it has established the display base.

As a summary of the review record, the same is only a rough, process of exploration.

The goal here is to get a general idea by ignoring some of the esoteric details.

If there is any mistake, please point it out and make progress together

The source code parsing

The following code is based on Android 11 (Android R).

1. Request a view to be drawn

Remember the requestLayout called in the viewrootimpl.setwindow method from the previous article? And that’s the starting point for our analysis.

// ========== android.view.ViewRootImpl ===========

@Override
public void requestLayout(a) {
    if(! mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested =true; scheduleTraversals(); }}// This is initialized in the constructor, not the actual code
// Gets an instance of the current thread, used to manage the message queue that sends asynchronous messages to the current thread
// Each thread has a corresponding Choreographer singleton object
final Choreographer mChoreographer = Choreographer.getInstance();

void scheduleTraversals(a) {
    if(! mTraversalScheduled) { mTraversalScheduled =true;
        // Add the main thread Handler synchronization barrier to the message queue, block all synchronous messages, priority asynchronous messages (draw)
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        // Add the draw task as an asynchronous message to the message queue of the current thread (main thread)
        mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); . }}final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

final class TraversalRunnable implements Runnable {
    @Override
    public void run(a) {
        // Perform the UI drawing operationdoTraversal(); }}Copy the code

1.1 Choreographer

Choreographer is a thread singleton created by ThreadLocal, which in this case is the singleton object for the master thread.

// ============= android.view.Choreographer =====================
public final class Choreographer {
    
    // Thread local storage for the choreographer.
    private static final ThreadLocal<Choreographer> sThreadInstance =
            new ThreadLocal<Choreographer>() {
        @Override
        protected Choreographer initialValue(a) {
            Looper looper = Looper.myLooper();
            if (looper == null) {
                throw new IllegalStateException("The current thread must have a looper!");
            }
            Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
            if (looper == Looper.getMainLooper()) {
                mMainInstance = choreographer;
            }
            returnchoreographer; }};public static Choreographer getInstance(a) {
        returnsThreadInstance.get(); }}Copy the code

Choreographer encapsulates a set of asynchronous message task sending and processing logic to manage the timing of callbacks (calls to external Runnable) related tasks such as view drawing, Input events, animations, etc.

The main focus here is to send the Vsync signal request to native and use the Handler synchronization barrier to ensure as much as possible that the drawing task can be performed immediately after the Vsync signal is received.

Synchronization barriers and asynchronous messages about handlers

After calling postSyncBarrier() to add a synchronization barrier, the current thread message queue is blocked, traversed, and the asynchronous task is pulled out for priority execution.

Synchronous barrier related methods use the @hide annotation, and external use can only be called through reflection.

// ================== android.view.Choreographer =====================

public final class Choreographer {
    // Used to send and receive Sync signal notifications
    private final FrameDisplayEventReceiver mDisplayEventReceiver;
    // The main thread Handler that handles asynchronous messages
    private final FrameHandler mHandler;
    private boolean mFrameScheduled;
    
    
    private Choreographer(Looper looper, int vsyncSource) {
        mLooper = looper;
        // The Handler for the current thread (main thread) to redraw the message
        mHandler = new FrameHandler(looper);
        // Non-actual code
        mDisplayEventReceiver = new FrameDisplayEventReceiver(looper, vsyncSource);
    }
    
    private final class FrameHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_DO_FRAME:
                    // Perform drawing runnable
                    doFrame(System.nanoTime(), 0);
                    break;
                case MSG_DO_SCHEDULE_VSYNC:
                    // Call the native method of nativeScheduleVsync internally and send a notification to request the next Vsync signal
                    doScheduleVsync();
                    break;
                case MSG_DO_SCHEDULE_CALLBACK:
                    // The actual internal operation is to request the Vsync signal
                    doScheduleCallback(msg.arg1);
                    break; }}}// The receiver that receives the Vsync signal returned from the native layer
    private final class FrameDisplayEventReceiver extends DisplayEventReceiver
            implements Runnable {
        private int mFrame;
        private long mTimestampNanos;
        
        
        @Override
        public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
            // Receive Vsync signal sent by Native layer (e.g. 16ms once)
            longnow = System.nanoTime(); .// Save the timestamp of the current Vsync signal
            mTimestampNanos = timestampNanos;
            mFrame = frame;
            // Send the execution asynchronous message, executing the internal run() method
            Message msg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);    
        }
        
        @Override
        public void run(a) {
            mHavePendingVsync = false;
            // Call the external draw RunnabledoFrame(mTimestampNanos, mFrame); }}// The entry to the external call is here, sending a draw request
    public void postCallback(int callbackType, Runnable action, Object token) {
        postCallbackDelayed(callbackType, action, token, 0);
    }
    
    public void postCallbackDelayed(int callbackType,
            Runnable action, Object token, long delayMillis) {... postCallbackDelayedInternal(callbackType, action, token, delayMillis); }/ / call to postCallbackDelayedInternal postCallback eventually
    private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            Action is added to the queue and waits for the specified time (screen refresh time, such as 16ms) to execute the drawing task
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

            if (dueTime <= now) {
                // Send MSG_DO_SCHEDULE_VSYNC or MSG_DO_FRAME asynchronous messages depending on whether USE_VSYNC is used
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                // Set the message to asynchronous
                msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, dueTime); }}}ScheduleVsyncLocked is used to request Vsync signals
    private void scheduleFrameLocked(long now) {
        if(! mFrameScheduled) { mFrameScheduled =true;
            if (USE_VSYNC) {
                ...
                if (isRunningOnLooperThreadLocked()) {
                    // Call the native method of nativeScheduleVsync internally and send a notification to request Vsync synchronization signal
                    scheduleVsyncLocked();
                } else {
                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                    msg.setAsynchronous(true);
                    // Force the message to the top of the message queue, immediatelymHandler.sendMessageAtFrontOfQueue(msg); }}else {
                final longnextFrameTime = Math.max( mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now); . Message msg = mHandler.obtainMessage(MSG_DO_FRAME); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, nextFrameTime); }}}void doScheduleCallback(int callbackType) {
        synchronized (mLock) {
            if(! mFrameScheduled) {final long now = SystemClock.uptimeMillis();
                if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
                    // Call the Vsync requestscheduleFrameLocked(now); }}}}void doFrame(long frameTimeNanos, int frame) {
        
        // Other callbacks are handled as well,
        // For example, CALLBACK_INPUT handles Input events, i.e. the onTouch event distribution of the View
        // CALLBACK_ANIMATION handles animation-related transactions.// Call the Runnable execution inside the CallBack of the specified typedoCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); . }private void scheduleVsyncLocked(a) {
        // Call native method to request Vsync sync signalmDisplayEventReceiver.scheduleVsync(); }}// ============ android.view.DisplayEventReceiver ================
public abstract class DisplayEventReceiver {
    // Request to send Vsync signal notification
	@FastNative
    private static native void nativeScheduleVsync(long receiverPtr);
   
    public void scheduleVsync(a) {... nativeScheduleVsync(mReceiverPtr); }// Called from native code.
    // The source code actually calls this method in the native layer, distributing the Vsync signal
    private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) { onVsync(timestampNanos, physicalDisplayId, frame); }}Copy the code

PS: in its internal also USES a Handler. SendMessageAtFrontOfQueue method, can immediately add a message to the top of the message queue, gain priority in executive power.

See also: Uninteresting facts about messaging mechanisms

Due to limited personal capabilities and the focus of this article is on the overall process, nativeScheduleVsync will not be further advanced for the time being.

For more information about Choreographer and Vsync sync signaling mechanisms see:

Android Systrace Basics (7) – Vsync interpretation

Details on Android based rendering mechanism Choreographer

Request for redraw timing with Vsync

Android messaging mechanism Looper and VSync propagation

Application layer Vsync signal registration and reception

Android Screen refresh mechanisms – VSync, Choreographer Understand!

1.2 summary

Choreographer actually plays a very important role in the drawing process, acting as a communication hub.

Most of the view-related mechanical instructions are controlled by Choreographer to perform distribution tasks.

2. The Surface creation

Since requestLayout internally sends a task message to the main thread Handler and executes a Runable when the Vsync sync signal returns.

Let’s move on and see what the doTraversal method that is executed inside Runable does.

// ========== android.view.ViewRootImpl ===========

void doTraversal(a) {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        // The synchronization barrier is removed, and the View drawing task has started, allowing synchronization messages to continuemHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); .// Perform the view tree traversal operationperformTraversals(); . }}private void performTraversals(a) {
    // This is actually the top-level DecorView
    finalView host = mView; .// Key code to check the Surface image buffer queue to establish a connectionrelayoutResult = relayoutWindow(...) ; ./ / window width
    if(mWidth ! = frame.width() || mHeight ! = frame.height()) { mWidth = frame.width(); mHeight = frame.height(); }...// Measure the width and height of the outermost layer
    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
    // Perform the view.measure () method internallyperformMeasure(childWidthMeasureSpec, childHeightMeasureSpec); .View.layout() = view.layout ()performLayout(lp, mWidth, mHeight); .// Start drawing the View, internally executing the view.draw () methodperformDraw(); . }Copy the code

View rendering requests are eventually traversals in the performTraversals method, executing measure, Layout, draw, and so on.

Before these operations are called, a relayoutWindow method is called, which is used to continue the analysis.

2.1 Java layer SurfaceControl creation

// ============== android.view.ViewRootImpl ================
final IWindowSession mWindowSession;

// The Surface handle class is constructed as an empty object by default, just a pointer with no actual reference
private final SurfaceControl mSurfaceControl = new SurfaceControl();
private SurfaceControl mBlastSurfaceControl = new SurfaceControl();
// The default constructor is an empty object, just a pointer, with no actual reference
public final Surface mSurface = new Surface();


private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,...).{...// A cross-process Binder proxy call creates a native SurfaceControl internally and assigns it to the jave layer internal variable object reference address
    int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
                (int) (mView.getMeasuredWidth() * appScale + 0.5 f),
                (int) (mView.getMeasuredHeight() * appScale + 0.5 f),... , mSurfaceControl, mSurfaceSize, mBlastSurfaceControl); .if (mSurfaceControl.isValid()) {  
        // At this point mSurfaceControl already has an actual reference.// Copy native Surface object references from the SurfaceControlmSurface.copyFrom(mSurfaceControl); . }}// ============ android.view.SurfaceControl =================

public final class SurfaceControl implements Parcelable {
    // The native layer's SurfaceControl object reference address
    public long mNativeObject;
    // The default implementation is null
    public SurfaceControl(a) {}public boolean isValid(a) {
        returnmNativeObject ! =0; }}// android.view.Surface
public class Surface implements Parcelable {
   	// Empty object by default
    public Surface(a) {}}Copy the code

RelayoutWindow internally calls the session. relayout method within the System_service process and passes in the mSurfaceControl object through the Binder mechanism across processes.

The next step is to determine that the mNativeObject variable inside the object is not zero, and then have the mSurface copy the assignment from the object.

However, the mSurfaceControl default constructor is empty, so it is probably assigned inside the Relayout method.

// ============== com.android.server.wm.Session =======================
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
	@Override
    public int relayout(IWindow window, ... SurfaceControl outSurfaceControl, ... , Point outSurfaceSize SurfaceControl outBLASTSurfaceControl) {...int res = mService.relayoutWindow(this, window, ... , outSurfaceControl, outSurfaceSize, outBLASTSurfaceControl); .returnres; }}//================== com.android.server.wm.WindowManagerService ===================

public int relayoutWindow(Session session, IWindow client, ... , SurfaceControl outSurfaceControl, ... , Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) {...// Get the WindowState object created when addWindow
    final WindowState win = windowForClientLocked(session, client, false); . WindowStateAnimator winAnimator = win.mWinAnimator; .int result = 0; .// Determine whether the Associated SurfaceControl needs to be re-established
    final boolean shouldRelayout = viewVisibility == View.VISIBLE &&
        (win.mActivityRecord == null|| win.mAttrs.type == TYPE_APPLICATION_STARTING || win.mActivityRecord.isClientVisible()); .// The window starts for the first time
    if(shouldRelayout){    
        // Create native SurfaceControl
        result = createSurfaceControl(outSurfaceControl, outBLASTSurfaceControl,
                                result, win, winAnimator);
    }else{... }...return result    
}

final WindowState windowForClientLocked(Session session, IBinder client, boolean throwOnError) {
    // The View of the current App process is associated with the system_service process, and the WindowState created when addWindow,
    // It holds the Client connected to SurfaceFLingerWindowState win = mWindowMap.get(client); .return win;    
}

Copy the code

The Session as a middle class, will be handed over to WindowManagerService. RelayoutWindow processing.

And in relayoutWindow, an outSurfaceControl parameter is passed, which is an output object, as the variable name indicates.

The createSurfaceControl method is called internally and passed in the parameter.

//================== com.android.server.wm.WindowManagerService ===================

private int createSurfaceControl(SurfaceControl outSurfaceControl,
            SurfaceControl outBLASTSurfaceControl, int result,
            WindowState win, WindowStateAnimator winAnimator) {... WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid); .// Call the copyFrom method internally, that is, copy to outSurfaceControl
    surfaceController.getSurfaceControl(outSurfaceControl);
    surfaceController.getBLASTSurfaceControl(outBLASTSurfaceControl);    
}
Copy the code

In order to avoid lost in the source code, we’ll ignore WindowStateAnimator. CreateSurfaceLocked () to create, from getSurfaceControl method as a starting point.

// ============ com.android.server.wm.WindowSurfaceController ====================
class WindowSurfaceController {
    SurfaceControl mSurfaceControl;
    
    WindowSurfaceController(String name, int w, inth, ... , WindowStateAnimator animator,...) {finalWindowState win = animator.mWin; .// Ignore the Builder argument for the moment,Window requests Surface
        final SurfaceControl.Builder b = win.makeSurface()
                .setParent(win.getSurfaceControl())
                .setName(name)
                .setBufferSize(w, h)
                .setFormat(format)
                .setFlags(flags)
                .setMetadata(METADATA_WINDOW_TYPE, windowType)
                .setMetadata(METADATA_OWNER_UID, ownerUid)
                .setCallsite("WindowSurfaceController"); . mSurfaceControl = b.build(); . }void getSurfaceControl(SurfaceControl outSurfaceControl) {
        outSurfaceControl.copyFrom(mSurfaceControl, "WindowSurfaceController.getSurfaceControl");
    }
    
    void getBLASTSurfaceControl(SurfaceControl outSurfaceControl) {
        if(mBLASTSurfaceControl ! =null) {
            outSurfaceControl.copyFrom(mBLASTSurfaceControl, "WindowSurfaceController.getBLASTSurfaceControl"); }}}Copy the code

GetSurfaceControl essentially copies a SurfaceControl from within the WindowSurfaceController and assigns a value to the outSurfaceControl passed in.

And within the WindowSurfaceController constructor, through SurfaceControl. Builder. The build method request and created the original SurfaceControl.

// ============ android.view.SurfaceControl ====================
public final class SurfaceControl implements Parcelable {
    
    public static class Builder {
        private SurfaceSession mSession;
        
        public SurfaceControl build(a) {
            return new SurfaceControl(mSession, mName, mWidth, mHeight,...);
        }
    }
    // Native SurfaceControl object reference address
    public long mNativeObject;
    
    / / empty implementation
    public SurfaceControl(a) {}private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
            SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,
            String callsite).{...// Key codemNativeObject = nativeCreate(session, name, w, h, format, flags, parent ! =null ? parent.mNativeObject : 0, metaParcel); . }// The native method actually creates the Native layer Surface
    private static native long nativeCreate(SurfaceSession session, ... ).;
    
    private static native long nativeCopyFromSurfaceControl(long nativeObject);
    
    private static native long nativeGetHandle(long nativeObject);
    
    
    public void copyFrom(@NonNull SurfaceControl other, String callsite) {...// The mNativeObject object reference is actually copied
        assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject), callsite);
    }
    
    private void assignNativeObject(long nativeObject, String callsite) {
        ...
        mNativeObject = nativeObject;
        mNativeHandle = mNativeObject != 0 ? nativeGetHandle(nativeObject) : 0; }}Copy the code

Can see SurfaceControl. CopyFrom method, the actual method is through the native nativeCopyFromSurfaceControl mNativeObject to copy, This variable is also created by the native method nativeCreate in the private constructor called by the Builder.build() method.

2.2 Native Layer SurfaceControl creation

The following native methods are viewed through Android Search Code, which requires climbing the wall.

Code based on Android11-RC3, limited space, only retain the key core code.

Let’s start with the Native vector ate method

// ========== frameworks/base/core/jni/android_view_SurfaceControl.cpp ===============

static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj, jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject, jobject metadataParcel) {... sp<SurfaceComposerClient> client;if(sessionObj ! =NULL) {
        //SurfaceSession is not empty, that is, the SurfaceComposerClient created when the connection is established
        client = android_view_SurfaceSession_getClient(env, sessionObj);
    } else {
        client = SurfaceComposerClient::getDefault(a); } SurfaceControl *parent =reinterpret_cast<SurfaceControl*>(parentObject);
    sp<SurfaceControl> surface;
    LayerMetadata metadata;
    Parcel* parcel = parcelForJavaObject(env, metadataParcel);
    if(parcel && ! parcel->objectsCount()) {
        status_t err = metadata.readFromParcel(parcel); . }// Create a native SurfaceControl using the SurfaceComposerClient
    status_t err = client->createSurfaceChecked(
            String8(name.c_str()), w, h, format, &surface, flags, parent, std::move(metadata)); . surface->incStrong((void *)nativeCreate);
    return reinterpret_cast<jlong>(surface.get());
}

// =========== frameworks/base/core/jni/android_view_SurfaceSession.cpp =================

sp<SurfaceComposerClient> android_view_SurfaceSession_getClient( JNIEnv* env, jobject surfaceSessionObj) {
    return reinterpret_cast<SurfaceComposerClient*>(
            env->GetLongField(surfaceSessionObj, gSurfaceSessionClassInfo.mNativeClient));
}

Copy the code

Internally, it returns a native SurfaceControl object reference address.

And here we see the familiar SurfaceComposerClient again!

Then through SurfaceComposerClient. CreateSurfaceChecked SurfaceControl objects create the native layer.

// ================= frameworks/native/libs/gui/SurfaceComposerClient.cpp ===================

sp<ISurfaceComposerClient>  mClient;

status_t SurfaceComposerClient::createSurfaceChecked(... , sp
       
        * outSurface, ... , SurfaceControl* parent, LayerMetadata metadata, ...)
        {
    sp<SurfaceControl> sur;
    status_terr = mStatus; .if(mStatus == NO_ERROR) { sp<IBinder> handle; sp<IGraphicBufferProducer> gbp; .// The cross-process Binder proxy calls Client's createSurface method,
        / / internal and eventually call to SurfaceFlinger. The createLayer, create Layer
        // Two proxy class object references are passed in
        err = mClient->createSurface(... &handle,&gbp,...) ;if(outTransformHint) { *outTransformHint = transformHint; }...if (err == NO_ERROR) {
            // Create a new SurfaceControl object and assign the reference to the SurfaceControl passed in externally
            *outSurface = new SurfaceControl(this, handle, gbp, transformHint); }}return err;
}
Copy the code

Remember the mClient object inside SurfaceComposerClient?

Bind with SurfaceFlinger to create Client’s Binder proxy class.

Client. CreateSurface will call to SurfaceFlinger. CreateLayer method to create Layer.

Layer is the basic operation unit of SurfaceFlinger.

// =========== frameworks/native/services/surfaceflinger/Client.cpp ==================

sp<SurfaceFlinger> mFlinger;

status_t Client::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
                               uint32_t flags, const sp<IBinder>& parentHandle,
                               LayerMetadata metadata, sp<IBinder>* handle,
                               sp<IGraphicBufferProducer>* gbp, uint32_t* outTransformHint) {
    // We rely on createLayer to check permissions.
    return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp,
                                 parentHandle, nullptr, outTransformHint);
}

// ================== frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp ==================

status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
                                     uint32_t h, PixelFormat format, uint32_t flags,
                                     LayerMetadata metadata, sp<IBinder>* handle,
                                     sp<IGraphicBufferProducer>* gbp,
                                     const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer,
                                     uint32_t* outTransformHint) {
    status_t result = NO_ERROR;
    sp<Layer> layer;
    // Create different layers according to flags
    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
            // Common BufferQueueLayer
            result = createBufferQueueLayer(client, std::move(uniqueName), w, h, flags,
                                            std::move(metadata), format, handle, gbp, &layer);
            break;
        // There are several layers. }...// Save the newly created Layer
    mInterceptor->saveSurfaceCreation(layer);
    return result;
}

Copy the code

I’m just going to focus on the BufferQueueLayer for now.

For more information about SurfaceFlinger’s Layer creation process, see:

SurfaceFlinger Layer and Bufferqueue creation process

Create Layer for graphics system

// ================ frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp ==================

status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, std::string name,
                                                uint32_t w, uint32_t h, uint32_t flags,
                                                LayerMetadata metadata, PixelFormat& format,
                                                sp<IBinder>* handle,
                                                sp<IGraphicBufferProducer>* gbp,
                                                sp<Layer>* outLayer) { sp<BufferQueueLayer> layer; .// Create a BufferQueueLayer in factory mode
    layer = getFactory().createBufferQueueLayer(args); .// Set some properties inside the Layer
    status_t err = layer->setDefaultBufferProperties(w, h, format);
    if (err == NO_ERROR) {
        // Note that these two object references are passed to the external SurfaceControl constructor
        *handle = layer->getHandle(a); *gbp = layer->getProducer(a); *outLayer = layer; }return err;
}
Copy the code

After SurfaceFlinger creates the Layer, it elicits the IGraphicBufferProducer and IBinder proxy class passed into the SurfaceControl constructor.

// =========== frameworks/native/libs/gui/SurfaceControl.cpp ===============
SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
                               const sp<IGraphicBufferProducer>& gbp,
                               uint32_t transform)
      : mClient(client),
        mHandle(handle),
        mGraphicBufferProducer(gbp),
        mTransformHint(transform) {}
Copy the code

That is, the Layer created in SurfaceFlinger is associated with the SurfaceControl via its internal Producer proxy and Handle proxy.

So what do getProducer and getHandle get?

// ========= frameworks/native/services/surfaceflinger/Layer.cpp =================

sp<IBinder> Layer::getHandle(a) {...return new Handle(mFlinger, this);
}

class Handle : public BBinder, public LayerCleaner {
    public:
    Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
        : LayerCleaner(flinger, layer), owner(layer) {}
    wp<Layer> owner;
};

// ============== frameworks/native/services/surfaceflinger/BufferQueueLayer.cpp =================

sp<IGraphicBufferProducer> BufferQueueLayer::getProducer(a) const {
    return mProducer;
}
Copy the code

GetHandle is a newly created Handle that belongs to the BBinder implementation class and contains references to the SurfaceFlinger and Layer as the Surface operation Layer Handle class.

What about the internal object references returned by getProducer? Let’s move on to the constructor

BufferQueueLayer inherits from BufferLayer, and BufferLayer inherits from Layer. Layer again inherits from RefBase.

// ============= frameworks/native/services/surfaceflinger/BufferQueueLayer.h ==============
class BufferQueueLayer : public BufferLayer {
    private{ sp<IGraphicBufferProducer> mProducer; }... }// ============== frameworks/native/services/surfaceflinger/BufferLayer.h ============
class BufferLayer : public Layer {
    ...
}

// ============== frameworks/native/services/surfaceflinger/Layer.h ================
class Layer : public virtual RefBase, compositionengine::LayerFE {
    ...
}

// ============== frameworks/native/services/surfaceflinger/BufferQueueLayer.cpp ================

void BufferQueueLayer::onFirstRef(a) {
    BufferLayer::onFirstRef(a);// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
    // Create a producer and consumer model,
    sp<IGraphicBufferProducer> producer; // Producer buffer
    sp<IGraphicBufferConsumer> consumer; // Consumer buffer
    // Create a BufferQueueCore to manage the BufferQueue queue and create assignment producers and consumers at the core
    mFlinger->getFactory().createBufferQueue(&producer, &consumer, true);
    mProducer = mFlinger->getFactory().createMonitoredProducer(producer, mFlinger, this);
    mConsumer = mFlinger->getFactory().createBufferLayerConsumer(consumer, mFlinger->getRenderEngine(),
                                                             	 mTextureName, this); .// BufferQueueCore::mMaxDequeuedBufferCount is default to 1
    if(! mFlinger->isLayerTripleBufferingDisabled()) {
        // If level 3 buffer is not enabled, set it to level 2 buffer
        mProducer->setMaxDequeuedBufferCount(2); }}Copy the code

Since it is a subclass of RefBase, the onFirstRef method is triggered the first time a strong reference is obtained, which internally creates a BufferQueue-based producer and consumer model.

The getProducer method is used to obtain the BufferQueueProducer, which is used to obtain the image buffer object from the BufferQueueCore and send it to the client to write the display content.

// ============ frameworks/native/libs/gui/BufferQueue.cpp ===============

// getFactory().createBufferQueue
/ / will call to BufferQueue. CreateBufferQueue method
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
                                    sp<IGraphicBufferConsumer>* outConsumer,
                                    bool consumerIsSurfaceFlinger) {
    LOG_ALWAYS_FATAL_IF(outProducer == nullptr."BufferQueue: outProducer must not be NULL");
    LOG_ALWAYS_FATAL_IF(outConsumer == nullptr."BufferQueue: outConsumer must not be NULL");
	// The central class of the graphics buffer queue
    sp<BufferQueueCore> core(new BufferQueueCore()); .// Use the core class to create a producer that gets the buffer from the queue and writes the drawn content
    // Return as Binder proxy class
    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger)); .// Create a consumer with the core class to fetch buffer data from the queue and submit it to Surfaceflinger for processing
    // Return as Binder proxy class
    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core)); . *outProducer = producer; *outConsumer = consumer; }Copy the code

Due to limited personal capabilities, this paper focuses more on the main process, Surfaceflinger’s producer-consumer model, which will not be analyzed in depth here for the time being.

See also: Android Graphics Architecture 4 — Graphics Buffer application and consumption processes and core classes

Each process that requires display functionality sets up a separate producer-consumer model, BufferQueue, with the SurfaceFlinger.

PS: Producer is in the SurfaceFlinger process and needs to communicate with Binder mechanism.

  • Summary:

At this point, the Native Layer SurfaceControl is created, using the Binder agent class of BufferQueueProducer to associate the Layer created by SurfaceFlinger.

Finally, the Native layer SurfaceControl object is referenced and assigned to the Java layer SurfaceControl object.

The other:

The SurfaceControl in relayoutWindow mentioned earlier is copied from the WindowSurfaceController native method by calling the Surfacecontrol. copyFrom method.

// ============= frameworks/base/core/jni/android_view_SurfaceControl.cpp ================
static jlong nativeCopyFromSurfaceControl(JNIEnv* env, jclass clazz, jlong surfaceControlNativeObj) {
 sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
 if (surface == nullptr) {
     return 0;
 }

 sp<SurfaceControl> newSurface = new SurfaceControl(surface);
 newSurface->incStrong((void *)nativeCreate);
 return reinterpret_cast<jlong>(newSurface.get());
}

static jlong nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
 SurfaceControl *surfaceControl = reinterpret_cast<SurfaceControl*>(nativeObject);
 return reinterpret_cast<jlong>(surfaceControl->getHandle().get());
}
Copy the code

2.3 Java Layer Surface creation

The next step is to copy the available Surface to the new SurfaceControl by surfacing. CopyFrom.

// ============= android.view.Surface ================

public class Surface implements Parcelable {
    long mNativeObject; // package scope only for SurfaceControl access
    
    private static native long nativeGetFromSurfaceControl(long surfaceObject,
            long surfaceControlNativeObject);
    private static native void nativeRelease(long nativeObject);
    
    
    public void copyFrom(SurfaceControl other) {...longsurfaceControlPtr = other.mNativeObject; .// Create a Surface from within the SurfaceControl
        long newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr);
        synchronized (mLock) {
            if (newNativeObject == mNativeObject) {
                return;
            }
            if(mNativeObject ! =0) { nativeRelease(mNativeObject); } setNativeObjectLocked(newNativeObject); }}private void setNativeObjectLocked(long ptr) {
        if(mNativeObject ! = ptr) { ... mNativeObject = ptr; mGenerationId +=1;
            if(mHwuiContext ! =null) { mHwuiContext.updateSurface(); }}}}Copy the code

2.4 Creation of native layer Surface

In surface. copyFrom method, the native object reference address is also assigned through native method.

By calling the native layer SurfaceControl. GenerateSurfaceLocked method to create a native layer Surface.

Then, the object reference pointer of the Native layer Surface is assigned to the mNativeObject of the Java layer Surface.

// ============== frameworks/base/core/jni/android_view_Surface.cpp ====================

static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz, jlong nativeObject, jlong surfaceControlNativeObj) {
    Surface* self(reinterpret_cast<Surface *>(nativeObject));
    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));

    // If the underlying IGBP's are the same, we don't need to do anything.
    if(self ! =nullptr &&
            IInterface::asBinder(self->getIGraphicBufferProducer()) ==
            IInterface::asBinder(ctrl->getIGraphicBufferProducer())) {
        // The actual Producer agent objects are the same and no action is taken
        return nativeObject;
    }
	// Create a native layer Surface from the SurfaceControl
    sp<Surface> surface(ctrl->getSurface());
    if(surface ! =NULL) {
        surface->incStrong(&sRefBaseOwner);
    }
	// Return the native layer surface object reference address
    return reinterpret_cast<jlong>(surface.get());
}

// =========== frameworks/native/libs/gui/SurfaceControl.cpp ==================

mutable sp<Surface>         mSurfaceData;

sp<Surface> SurfaceControl::getSurface(a) const
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == nullptr) {
        return generateSurfaceLocked(a); }return mSurfaceData;
}

sp<Surface> SurfaceControl::generateSurfaceLocked(a) const
{
    // mGraphicBufferProducer is the producer of the graph buffer region in the Layer
    // Create a native layer Surface
    mSurfaceData = new Surface(mGraphicBufferProducer, false);
    return mSurfaceData;
}


Copy the code

2.5 summary

At this point, the Suface held in the ViewRootImpl becomes available and refers to the correct Native layer Surface object, which in turn is associated with the BufferQueue created by SurfaceFlinger.

conclusion

Finally, a brief overview of the Surface creation process

  1. First by the ViewRootImpl. RequestLayout Vsync synchronization signal by Choreographer to native applications.

  2. After the App process Choreographer receives the Vsync signal, it creates and holds the corresponding Native layer SurfaceControl object reference address within the SurfaceControl.

  3. SurfaceComposerClient held by SurfaceSession at the native layer is invoked by Binder across processes to create a separate bufferQueue-based producer-consumer model within the SurfaceFlinger process.

    When the Native layer SurfaceControl is created, Binder proxies of Producer Producer of BufferQueue are assigned to their internal variables.

  4. A Native layer Surface object is created from a Java layer Surface. CopyFrom a Native layer SurfaceControl, which holds object references from Producer of the Native layer SurfaceControl.

    Native layer SurfaceControl internally caches native layer Surface references to internal variables that are only created on the first fetch.

    Assign the native layer Surface object reference address to the Jave layer Surface object so that the latter points to the correct object reference address.

    The Surface and the SurfaceControl of the Java layer are empty shells, and the actual things that do are the Surface and the SurfaceControl of the Native layer.

The next article continues to analyze the View drawing process.

The resources

Android Java layer UI rendering to achieve the creation of four Surface and View rendering

Android drawing mechanism and Surface family source code full analysis

Explore the origin of Android View drawing process, Canvas

Android Surface create

Create Layer, Surface, and SurfaceControl