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).
- Finding free Slots
- Get the number of available slots (newBufferCount)
- Create GraphicBuffer
- 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
- New a GraphicBuffer object
- 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
- Get the GraphicBufferAllocator object
- 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