In the Android Source Graphics System relayoutWindow section, outSurface initializes (calling its copyFrom(…)) Method, whose input is a SurfaceControl object). Now let’s analyze the follow-up process in detail.

CopyFrom (…). Method to copy another Surface to this Surface. This Surface now has a reference to the same data as the original Surface and is not the owner. This is used by the window manager when it returns a window Surface from the client, converting it from a representation managed by the window manager to a representation that the client draws to it.

SurfaceControlPtr pointer to Native SurfaceControl object, then call nativeCreateFromSurfaceControl (…). The JNI method obtains the Native Surface pointer, and finally converts the pointer to jLong and assigns the value to the member variable mNativeObject.

frameworks/base/core/java/android/view/Surface.java

public class Surface implements Parcelable {...public void copyFrom(SurfaceControl other) {
        if (other == null) {
            throw new IllegalArgumentException("other must not be null");
        }

        long surfaceControlPtr = other.mNativeObject;
        if (surfaceControlPtr == 0) {
            throw new NullPointerException(
                    "SurfaceControl native object is null. Are you using a released SurfaceControl?");
        }
        long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);

        synchronized (mLock) {
            if(mNativeObject ! =0) { nativeRelease(mNativeObject); } setNativeObjectLocked(newNativeObject); }}... }Copy the code

After the Surface is constructed, WindowManagerService uses this method, which is required to return the Surface reference to the caller. At this point, we should only have one SurfaceControl.

frameworks/base/core/jni/android_view_Surface.cpp

static jlong nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz, jlong surfaceControlNativeObj) {
    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
    sp<Surface> surface(ctrl->getSurface());
    if(surface ! =NULL) {
        surface->incStrong(&sRefBaseOwner);
    }
    return reinterpret_cast<jlong>(surface.get());
}
Copy the code

The Surface object is finally created in getSurface().

frameworks/native/libs/gui/SurfaceControl.cpp

sp<Surface> SurfaceControl::getSurface(a) const
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == 0) {
        // SurfaceFlinger always consumes the Surface, so the controlledByApp value is irrelevant, use false.
        mSurfaceData = new Surface(mGraphicBufferProducer, false);
    }
    return mSurfaceData;
}
Copy the code

An implementation of ANativeWindow that inputs the graphics buffer to a BufferQueue.

These programs are usually used when you want to render frames by some means (such as OpenGL, a software renderer, or a hardware decoder) and forward the frames they create to SurfaceFlinger for compositing. For example, the video decoder can render frames and call eglSwapBuffers(), which calls the ANativeWindow callback defined by the Surface. The Surface then forwards the buffer to the Producer interface of the BufferQueue via Binder IPC, thus providing the new frame to consumers such as GLConsumer.

Create a Surface (specifically a BufferQueue) based on the given IGraphicBufferProducer.

When disconnected, the Surface is primarily stateless and can be thought of as a glorified igraphicBuff Producer holder. Therefore, it is safe to create other surfaces from the same IGraphicBufferProducer. However, once a Surface is connected, it prevents other surfaces that reference the same IGraphicBufferProducer from being connected, thus preventing them from being used as actual generators for buffers.

The controlledByApp flag indicates that this Surface (producer) is controlled by the application. This flag is used when connecting.

frameworks/native/libs/gui/Surface.cpp


Surface::Surface(
        const sp<IGraphicBufferProducer>& bufferProducer,
        bool controlledByApp)
    : mGraphicBufferProducer(bufferProducer),
      mGenerationNumber(0)
{
    // Initialize the ANativeWindow function pointer.
    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
    ANativeWindow::cancelBuffer     = hook_cancelBuffer;
    ANativeWindow::queueBuffer      = hook_queueBuffer;
    ANativeWindow::query            = hook_query;
    ANativeWindow::perform          = hook_perform;

    ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
    ANativeWindow::cancelBuffer_DEPRECATED  = hook_cancelBuffer_DEPRECATED;
    ANativeWindow::lockBuffer_DEPRECATED    = hook_lockBuffer_DEPRECATED;
    ANativeWindow::queueBuffer_DEPRECATED   = hook_queueBuffer_DEPRECATED;

    const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
    const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;

    mReqWidth = 0;
    mReqHeight = 0;
    mReqFormat = 0;
    mReqUsage = 0;
    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
    mDataSpace = HAL_DATASPACE_UNKNOWN;
    mCrop.clear(a); mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform =0;
    mStickyTransform = 0;
    mDefaultWidth = 0;
    mDefaultHeight = 0;
    mUserWidth = 0;
    mUserHeight = 0;
    mTransformHint = 0;
    mConsumerRunningBehind = false;
    mConnectedToCpu = false;
    mProducerControlledByApp = controlledByApp;
    mSwapIntervalZero = false;
}
Copy the code

Now what does the Surface allocate buffer do? This is done by calling the Surface class allocateBuffers().

The mGraphicBufferProducer is initialized in the Surface constructor. It actually points to a BpGraphicBufferProducer object. Surface::allocateBuffers() calls BpGraphicBufferProducer allocateBuffers(…) Methods.

frameworks/native/libs/gui/Surface.cpp

void Surface::allocateBuffers(a) {
    uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth;
    uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight;
    mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, reqWidth,
            reqHeight, mReqFormat, mReqUsage);
}
Copy the code

Call BpGraphicBufferProducer allocateBuffers(…) Method, which will eventually call the bN-side corresponding implementation (BufferQueueProducer).

  1. Finding free Slots
  2. Get the number of available slots (newBufferCount)
  3. Create GraphicBuffer
  4. Associate GraphicBuffer to the corresponding slot

frameworks/native/libs/gui/BufferQueueProducer.cpp

void BufferQueueProducer::allocateBuffers(bool async, uint32_t width,
        uint32_t height, PixelFormat format, uint32_t usage) {
    ATRACE_CALL(a);while (true) {
        Vector<int> freeSlots;
        size_t newBufferCount = 0;
        uint32_t allocWidth = 0;
        uint32_t allocHeight = 0;
        PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN;
        uint32_t allocUsage = 0;
        { // Autolock scope
            Mutex::Autolock lock(mCore->mMutex);
            mCore->waitWhileAllocatingLocked(a);if(! mCore->mAllowAllocation) {BQ_LOGE("allocateBuffers: allocation is not allowed for this "
                        "BufferQueue");
                return;
            }

            int currentBufferCount = 0;
            for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
                if(mSlots[slot].mGraphicBuffer ! =NULL) {
                    ++currentBufferCount;
                } else {
                    if(mSlots[slot].mBufferState ! = BufferSlot::FREE) {BQ_LOGE("allocateBuffers: slot %d without buffer is not FREE",
                                slot);
                        continue;
                    }

                    freeSlots.push_back(slot); }}int maxBufferCount = mCore->getMaxBufferCountLocked(async);
            BQ_LOGV("allocateBuffers: allocating from %d buffers up to %d buffers",
                    currentBufferCount, maxBufferCount);
            if (maxBufferCount <= currentBufferCount)
                return;
            newBufferCount =
                    static_cast<size_t>(maxBufferCount - currentBufferCount);
            if (freeSlots.size() < newBufferCount) {
                BQ_LOGE("allocateBuffers: ran out of free slots");
                return;
            }
            allocWidth = width > 0 ? width : mCore->mDefaultWidth;
            allocHeight = height > 0? height : mCore->mDefaultHeight; allocFormat = format ! =0 ? format : mCore->mDefaultBufferFormat;
            allocUsage = usage | mCore->mConsumerUsageBits;

            mCore->mIsAllocating = true;
        } // Autolock scope

        Vector<sp<GraphicBuffer>> buffers;
        for (size_t i = 0; i <  newBufferCount; ++i) {
            status_t result = NO_ERROR;
            sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer( allocWidth, allocHeight, allocFormat, allocUsage, &result));
            if(result ! = NO_ERROR) {BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
                        " %u, usage %u)", width, height, format, usage);
                Mutex::Autolock lock(mCore->mMutex);
                mCore->mIsAllocating = false;
                mCore->mIsAllocatingCondition.broadcast(a);return;
            }
            buffers.push_back(graphicBuffer);
        }

        { // Autolock scope
            Mutex::Autolock lock(mCore->mMutex);
            uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth;
            uint32_t checkHeight = height > 0? height : mCore->mDefaultHeight; PixelFormat checkFormat = format ! =0 ?
                    format : mCore->mDefaultBufferFormat;
            uint32_t checkUsage = usage | mCore->mConsumerUsageBits;
            if(checkWidth ! = allocWidth || checkHeight ! = allocHeight || checkFormat ! = allocFormat || checkUsage ! = allocUsage) {// Something changes when we release the lock. Try again.
                BQ_LOGV("allocateBuffers: size/format/usage changed while allocating. Retrying.");
                mCore->mIsAllocating = false;
                mCore->mIsAllocatingCondition.broadcast(a);continue;
            }

            for (size_t i = 0; i < newBufferCount; ++i) {
                int slot = freeSlots[i];
                if(mSlots[slot].mBufferState ! = BufferSlot::FREE) {// The consumer uses attachBuffer to allocate free slots. Discard our allocated buffer.
                    BQ_LOGV("allocateBuffers: slot %d was acquired while allocating. "
                            "Dropping allocated buffer.", slot);
                    continue;
                }
                mCore->freeBufferLocked(slot); // Clean the slot first
                mSlots[slot].mGraphicBuffer = buffers[i];
                mSlots[slot].mFence = Fence::NO_FENCE;

                // freeBufferLocked adds this slot to the list of free slots.
                // Since we attached the buffer later, we moved the slot to the free buffer list.
                mCore->mFreeSlots.erase(slot);
                mCore->mFreeBuffers.push_front(slot);

                BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot);
            }

            mCore->mIsAllocating = false;
            mCore->mIsAllocatingCondition.broadcast(a); mCore->validateConsistencyLocked(a); }// Autolock scope}}Copy the code
  1. New a GraphicBuffer object
  2. Call the GraphicBuffer class initCheck() to check its return value

frameworks/native/libs/gui/GraphicBufferAlloc.cpp

sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
        uint32_t height, PixelFormat format, uint32_t usage, status_t* error) {
    sp<GraphicBuffer> graphicBuffer(
            new GraphicBuffer(width, height, format, usage));
    status_t err = graphicBuffer->initCheck(a); *error = err;if(err ! =0 || graphicBuffer->handle == 0) {
        if (err == NO_MEMORY) {
            GraphicBuffer::dumpAllocationsToSystemLog(a); }ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
             "failed (%s), handle=%p",
                width, height, strerror(-err), graphicBuffer->handle);
        return 0;
    }
    return graphicBuffer;
}
Copy the code

The GraphicBuffer constructor initializes the member variable mBufferMapper, and gets the GraphicBufferMapper singleton for initialization. InitSize (…) is then called. Begin the actual assignment of work.

frameworks/native/libs/ui/GraphicBuffer.cpp

GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
        PixelFormat inFormat, uint32_t inUsage)
    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
      mInitCheck(NO_ERROR), mId(getUniqueId())
{
    width  =
    height =
    stride =
    format =
    usage  = 0;
    handle = NULL;
    mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage);
}
Copy the code

HAL module Gralloc is loaded in the GraphicBufferMapper class constructor.

frameworks/native/libs/ui/GraphicBufferMapper.cpp

ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )

GraphicBufferMapper::GraphicBufferMapper()
    : mAllocMod(0)
{
    hw_module_t const* module;
    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
    ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
    if (err == 0) {
        mAllocMod = reinterpret_cast<gralloc_module_t const* > (module); }}Copy the code
  1. Get the GraphicBufferAllocator object
  2. Call GraphicBufferAllocator class alloc(…) Method to allocate memory

frameworks/native/libs/ui/GraphicBuffer.cpp

status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
        PixelFormat inFormat, uint32_t inUsage)
{
    GraphicBufferAllocator& allocator = GraphicBufferAllocator::get(a);uint32_t outStride = 0;
    status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage,
            &handle, &outStride);
    if (err == NO_ERROR) {
        width = static_cast<int>(inWidth);
        height = static_cast<int>(inHeight);
        format = inFormat;
        usage = static_cast<int>(inUsage);
        stride = static_cast<int>(outStride);
    }
    return err;
}
Copy the code

The initCheck() method simply returns the value of the member variable mInitCheck.

frameworks/native/libs/ui/GraphicBuffer.cpp

status_t GraphicBuffer::initCheck(a) const {
    return static_cast<status_t>(mInitCheck);
}
Copy the code