当前位置: 首页 > news >正文

浅析Android中View的软件绘制流程

前言

在《浅析Android中View的测量布局流程》中分析到,VSYNC信号到达App进程之后开启了View布局过程,经过对整个View树遍历完成测量和布局,最终确定所有View的大小以及在屏幕中所处的位置。但是View的内容想要在屏幕上可见,还需要经过绘制渲染来生成图形数据并交由硬件来刷新屏幕才可以。

在《浅析Android View绘制过程中的Surface》中分析到,View绘制渲染生成的图形数据需要在进程间传输,最终才能完成合成上屏。基于跨进程的数据传输,生产者(通常是App进程)生产图形数据并交由SurfaceFlinger进程消费,而生产图形数据的实现方式经过多个Android版本迭代之后,最终分为了软件渲染和硬件渲染两种实现。从Android 3.0开始支持硬件加速,Android 4.0开始默认开启硬件加速。下面先从软件渲染机制来分析View的绘制流程,硬件渲染的绘制流程之后再单独分析。

软件渲染

软件渲染是指利用CPU对绘制命令进行处理,直接生成渲染数据并交由SurfaceFlinger进程进行合成上屏。

下面从View绘制流程的入口处分析软件绘制流程对应的源码,看下是如何将各种绘制操作转换为图形数据并用于最终的合成上屏的。

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks, AttachedSurfaceControl {// ...private void performTraversals() {// ...if (!isViewVisible) {// ...} else if (cancelAndRedraw) {// ...} else {// ...// 开始绘制if (!performDraw() && mSyncBufferCallback != null) {mSyncBufferCallback.onBufferReady(null);}}// ...}private boolean performDraw() {final boolean fullRedrawNeeded = mFullRedrawNeeded || mSyncBufferCallback != null;// ...// 软件绘制时,usingAsyncReport为falseboolean usingAsyncReport = isHardwareEnabled() && mSyncBufferCallback != null;// ...try {boolean canUseAsync = draw(fullRedrawNeeded, usingAsyncReport && mSyncBuffer);// ...} finally {// ...}// ...}private boolean draw(boolean fullRedrawNeeded, boolean forceDraw) {Surface surface = mSurface;// surface不可用时直接return,而surface在经过relayoutWindow之后已经被更新并处于可用状态if (!surface.isValid()) {return false;}// ...final Rect dirty = mDirty;if (fullRedrawNeeded) {dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));}// ...if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {if (isHardwareEnabled()) {// ...// 开启硬件绘制时,使用ThreadedRenderer进行绘制mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);} else {// ...// 未开启硬件绘制时,使用软件绘制,surface就是成员变量mSurfaceif (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty, surfaceInsets)) {return false;}}}// 如果当前正在动画,调度下一次VSYNC信号来执行布局流程if (animating) {mFullRedrawNeeded = true;scheduleTraversals();}return useAsyncReport;}private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets) {// Draw with software renderer.final Canvas canvas;// ...try {// ...// 1. 根据dirty从Surface对象中锁定一个canvas对象canvas = mSurface.lockCanvas(dirty);// ...} catch (Surface.OutOfResourcesException e) {handleOutOfResourcesException(e);return false;} catch (IllegalArgumentException e) {mLayoutRequested = true;    // ask wm for a new surface next time.return false;} finally {// ...}try {// ...// 2. 遍历绘制子ViewmView.draw(canvas);// ...} finally {try {// 3. 解锁canvas并将数据提交给SurfaceFlinger进程进行合成上屏surface.unlockCanvasAndPost(canvas);} catch (IllegalArgumentException e) {mLayoutRequested = true;    // ask wm for a new surface next time.return false;}}return true;}
}

上面的代码是软件绘制的主要流程,在关键的代码处增加了注释。对于软件绘制来说,首先从Surface中获取Canvas对象,然后利用Canvas对象在遍历子View时进行绘制命令处理,最终释放Canvas对象并将绘制数据交由SurfaceFlinger进程进行合成上屏。

因此,整个软件绘制过程包括以下步骤:

  1. 通过Surface锁定/创建Canvas
  2. 使用Canvas进行View的绘制;
  3. 使用GraphicBuffer提交图形数据给SurfaceFlinger进程;

Canvas的创建

在创建ViewRootImpl对象时会创建并持有Surface对象,而Surface对象创建时会创建并持有Canvas对象,因此我们直接看下Canvas对象的构造函数即可。

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks, AttachedSurfaceControl {@UnsupportedAppUsagepublic final Surface mSurface = new Surface();// ...
}public class Surface implements Parcelable {private final Canvas mCanvas = new CompatibleCanvas();// ...
}public class Canvas extends BaseCanvas {/*** Construct an empty raster canvas. Use setBitmap() to specify a bitmap to* draw into.  The initial target density is {@link Bitmap#DENSITY_NONE};* this will typically be replaced when a target bitmap is set for the* canvas.*/public Canvas() {// 软件绘制时,创建一个没有native层的bitmap的Canvasif (!isHardwareAccelerated()) {// 0 means no native bitmapmNativeCanvasWrapper = nInitRaster(0);mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);} else {mFinalizer = null;}}

Canvas构造函数的注释可知,软件绘制时直接创建了一个没有有native层的bitmapCanvas,在使用Canvas时需要调用setBitmap方法设置Bitmap对象用于绘制。从构造函数看没有发现创建Bitmap对象,看一下nInitRaster方法里做了什么。

// frameworks/base/libs/hwui/jni/android_graphics_Canvas.cpp
// Native wrapper constructor used by Canvas(Bitmap)
static jlong initRaster(JNIEnv* env, jobject, jlong bitmapHandle) {SkBitmap bitmap;// bitmapHandle为0if (bitmapHandle != 0) {bitmap::toBitmap(bitmapHandle).getSkBitmap(&bitmap);}return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
}// frameworks/base/libs/hwui/SkiaCanvas.cpp
Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {return new SkiaCanvas(bitmap);
}

可以发现nInitRaster方法调用到了native层,创建了SkBitmap对象并将其用于创建native的Canvas对象之后将句柄值返回给了Java层,用于初始化mNativeCanvasWrapper变量。至此,完成了Canvas在Java层和native层的实例创建,并且完成了native层的SkBitmap对象的创建,用于后续的绘制流程。

Canvas的锁定过程

Canvas对象内部持有了GraphicBuffer,GraphicBuffer指向的内存空间用于存储绘制指令处理后生成的数据。

首先看下Surface#lockCanvas方法,Surface#lockCanvas方法内部通过nativeLockCanvas方法调用到了native层,主要工作是申请一个GraphicBuffer用于后续的绘制流程。

/*** 持有一个被屏幕合成器管理的原始buffer.* surface通常是由graphic buffer的消费者创建或者提供,比如SurfaceTexture、MediaRecorder以及Allocation,然后交由生产者比如OpenGL的EGL14#eglCreateWindowSurface、MediaPlayer的MediaPlayer#setSurface以及CameraDevice的CameraDevice#createCaptureSession进行绘制填充数据。*/
public class Surface implements Parcelable {long mNativeObject;@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)private long mLockedObject;private final Canvas mCanvas = new CompatibleCanvas();/*** 获取一个canvas对象用于将绘制数据推入这个surface对象,在绘制到提供的Canvas对象之后,必须调用unlockCanvasAndPost来将新的绘制内容提交给surface。* @param inOutDirty 希望重新绘制的矩形区域,如果需要将整个surface进行重绘,则该参数传值为null即可。* @return 一个用于将绘制数据推入这个surface对象的canvas对象.*/public Canvas lockCanvas(Rect inOutDirty) throws Surface.OutOfResourcesException, IllegalArgumentException {synchronized (mLock) {checkNotReleasedLocked();// 变量mLockedObject用于确保lockCanvas和unlockCanvasAndPost成对调用,实现同一个Surface对象下只能有一个Canvas对象正在被使用if (mLockedObject != 0) {throw new IllegalArgumentException("Surface was already locked");}// mNativeObject对应native层的surface对象// mLockedObject对应native层的surface对象// mCanvas用于映射surface对象的buffermLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);return mCanvas;}}private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty) throws OutOfResourcesException;// ...
}

从上面的代码可以看到nativeLockCanvas的入参包括了native层的Surface对象mNativeObject以及Java层的Canvas对象mCanvas以及需要刷新的矩形区域inOutDirty,结合源码看下具体的实现是什么样的。

// frameworks/base/core/jni/android_view_Surface.cpp
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {// 获取native层的Surface对象sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));// ...   // 1. 将Java层传递过来的Rect数据拷贝到native层的Rect中Rect dirtyRect(Rect::EMPTY_RECT);Rect* dirtyRectPtr = NULL;if (dirtyRectObj) {dirtyRect.left   = env->GetIntField(dirtyRectObj, gRectClassInfo.left);dirtyRect.top    = env->GetIntField(dirtyRectObj, gRectClassInfo.top);dirtyRect.right  = env->GetIntField(dirtyRectObj, gRectClassInfo.right);dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);dirtyRectPtr = &dirtyRect;}// 2. 通过native层的Surface对象锁定一个缓冲区ANativeWindow_Buffer,缓冲区保存了Rect相关信息ANativeWindow_Buffer buffer;status_t err = surface->lock(&buffer, dirtyRectPtr);// ...// 3. 根据Java层的canvasObj创建一个native层的Canvas对象,并将上面的缓冲区设置到Canvas对象中graphics::Canvas canvas(env, canvasObj);canvas.setBuffer(&buffer, static_cast<int32_t>(surface->getBuffersDataSpace()));// 根据Java层传递的dirtyRectObj对canvas的矩形区域进行设置if (dirtyRectPtr) {canvas.clipRect({dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom});}// 4. 为native层的surface对象创建一个强引用对象lockedSurface, 并返回给Java层,用于在绘制结束之后通过JNI对native层的资源进行释放sp<Surface> lockedSurface(surface);lockedSurface->incStrong(&sRefBaseOwner);return (jlong) lockedSurface.get();
}

可以看到nativeLockCanvas方法中首先通过native层的Surface对象锁定了一个缓冲区ANativeWindowBuffer,然后将ANativeWindowBuffer设置到native层的Canvas对象中,最后将surface返回给了Java层。

通过Surface锁定Buffer

这里主要看下Surface::lock方法做了什么。

// frameworks/native/libs/gui/Surface.cpp
// mSlots存储了分配给每一个slot的buffer,初始化值是空指针,当client从一个没有被使用过的slot中获取buffer时,由IGraphicBufferProducer::requestBuffer返回的结果进行填充。当buffer的状态发生变化时,slot中的buffer将会被替换。
// NUM_BUFFER_SLOTS默认为64
BufferSlot mSlots[NUM_BUFFER_SLOTS];status_t Surface::lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) {// mLockedBuffer记录了最后一次lock成功的buffer,如果上次lock成功的buffer没有被释放则不用重复lockif (mLockedBuffer != nullptr) {return INVALID_OPERATION;}if (!mConnectedToCpu) {int err = Surface::connect(NATIVE_WINDOW_API_CPU);if (err) {return err;}// 从这里开始准备开始软件渲染setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);}ANativeWindowBuffer* out;int fenceFd = -1;// 1. 从BufferQueue中获取buffer以及相关的fencestatus_t err = dequeueBuffer(&out, &fenceFd);if (err == NO_ERROR) {// 将out的类型强转为GraphicBuffersp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));const Rect bounds(backBuffer->width, backBuffer->height);// ...void* vaddr;// 2. 锁定获取的GraphicBuffer,避免被其他地方使用,同时将GraphicBuffer持有的内存地址写入vaddrstatus_t res = backBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, newDirtyRegion.bounds(), &vaddr, fenceFd);if (res != 0) {err = INVALID_OPERATION;} else {// 3. 锁定成功,更新mLockedBuffer变量,并将锁定的Buffer的信息拷贝回outBuffer并返回给上层mLockedBuffer = backBuffer;outBuffer->width  = backBuffer->width;outBuffer->height = backBuffer->height;outBuffer->stride = backBuffer->stride;outBuffer->format = backBuffer->format;// 3.1 将buffer的内存空间地址拷贝到outBuffer中,用于后续的绘制数据填充outBuffer->bits   = vaddr;}}return err;
}// 从BufferQueue中获取一个buffer,并拷贝给入参buffer供上层使用
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {// ...int buf = -1;sp<Fence> fence;nsecs_t startTime = systemTime();FrameEventHistoryDelta frameTimestamps;// 1. 通过mGraphicBufferProducer调用dequeueBuffer方法申请一个buffer,将buffer的槽位赋值给buf变量,将和buffer关联的fence赋值给fence变量(直到fence信号到达之后才能重写buffer的内容)status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, dqInput.width, dqInput.height, dqInput.format, dqInput.usage, &mBufferAge, dqInput.getTimestamps ? &frameTimestamps : nullptr);// ...// 2. 根据槽位buf获取对应的GraphicBuffersp<GraphicBuffer>& gbuf(mSlots[buf].buffer);// ...// 3. 如果fence是有效的,那么将其赋值给入参fenceFd,交由上层使用if (fence->isValid()) {*fenceFd = fence->dup();if (*fenceFd == -1) {ALOGE("dequeueBuffer: error duping fence: %d", errno);}} else {*fenceFd = -1;}// 4. 将获取到的GraphicBuffer赋值给入参buffer,返回给上层使用*buffer = gbuf.get();// ...// 将dequeue的slot记录下来mDequeuedSlots.insert(buf);return OK;
}

Surface::lock方法内部调用了Surface::dequeueBuffer,首先通过mGraphicBufferProducer->dequeueBuffer获取一个GraphicBuffer,然后将获取到的fence以及buffer赋值给入参,交由上层使用。这里的mGraphicBufferProducer是获取GraphicBuffer的关键。在《浅析Android View绘制过程中的Surface》一文中分析了mGraphicBufferProducer是请求SystemServer进程的WindowManagerService更新窗口之后,在App进程创建BLASTBufferQueue对象时创建的,mGraphicBufferProducer持有了BLASTBufferQueue

下面看下mGraphicBufferProducer->dequeueBuffer内部的实现,

// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence, uint32_t width, uint32_t height, PixelFormat format, uint64_t usage, uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps) {// ...status_t returnFlags = NO_ERROR;// ...sp<IConsumerListener> listener;bool callOnFrameDequeued = false;uint64_t bufferId = 0; // Only used if callOnFrameDequeued == true// ...{ // Autolock scopestd::unique_lock<std::mutex> lock(mCore->mMutex);// 如果当前没有空闲buffer并且正在分配,则通过锁来等待分配结束。// mFreeBuffers初始化的值是空的集合,mIsAllocating初始化的值为falseif (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) {mDequeueWaitingForAllocation = true;mCore->waitWhileAllocatingLocked(lock);mDequeueWaitingForAllocation = false;mDequeueWaitingForAllocationCondition.notify_all();}// ...int found = BufferItem::INVALID_BUFFER_SLOT;// 循环尝试获取空闲的bufferwhile (found == BufferItem::INVALID_BUFFER_SLOT) {// 1. 阻塞等待有空闲的buffer status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);if (status != NO_ERROR) {return status;}// ...// 第一次返回的found为0const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);// 如果不允许分配新的buffer,那么waitForFreeSlotThenRelock必须返回包含buffer的slot。// 如果这个buffer要求重新分配,那么释放它并尝试获取其他的buffer。// mAllowAllocation初始化的值为trueif (!mCore->mAllowAllocation) {// ...}}// 2. 根据获取到的slot获取对应的GraphicBuffer,由于第一次获取的BufferSlot对象中mGraphicBuffer是默认值nullptrconst sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);bool needsReallocation = buffer == nullptr || buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage);// ...// 即将返回给上层使用,将其状态更新为Activeif (mCore->mSharedBufferSlot != found) {mCore->mActiveBuffers.insert(found);}// 通过outSlot将获取到的slot通过入参返回给上层*outSlot = found;attachedByConsumer = mSlots[found].mNeedsReallocation;mSlots[found].mNeedsReallocation = false;// 更新对应的状态mSlots[found].mBufferState.dequeue();// 3. 需要分配GraphicBuffer,将BufferSlot的成员变量重置,同时设置returnFlags为BUFFER_NEEDS_REALLOCATIONif (needsReallocation) {mSlots[found].mAcquireCalled = false;mSlots[found].mGraphicBuffer = nullptr;mSlots[found].mRequestBufferCalled = false;mSlots[found].mEglDisplay = EGL_NO_DISPLAY;mSlots[found].mEglFence = EGL_NO_SYNC_KHR;mSlots[found].mFence = Fence::NO_FENCE;mCore->mBufferAge = 0;mCore->mIsAllocating = true;returnFlags |= BUFFER_NEEDS_REALLOCATION;} else {// We add 1 because that will be the frame number when this buffer// is queuedmCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;}eglDisplay = mSlots[found].mEglDisplay;eglFence = mSlots[found].mEglFence;// Don't return a fence in shared buffer mode, except for the first frame.*outFence = (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == found) ? Fence::NO_FENCE : mSlots[found].mFence;mSlots[found].mEglFence = EGL_NO_SYNC_KHR;mSlots[found].mFence = Fence::NO_FENCE;// ...} // Autolock scopeif (returnFlags & BUFFER_NEEDS_REALLOCATION) {BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)std::vector<GraphicBufferAllocator::AdditionalOptions> tempOptions;tempOptions.reserve(allocOptions.size());for (const auto& it : allocOptions) {tempOptions.emplace_back(it.name.c_str(), it.value);}const GraphicBufferAllocator::AllocationRequest allocRequest = {.importBuffer = true,.width = width,.height = height,.format = format,.layerCount = BQ_LAYER_COUNT,.usage = usage,.requestorName = {mConsumerName.c_str(), mConsumerName.size()},.extras = std::move(tempOptions),};sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest);
#else// 4. 创建GraphicBuffer对象sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(width, height, format, BQ_LAYER_COUNT, usage, {mConsumerName.c_str(), mConsumerName.size()});
#endifstatus_t error = graphicBuffer->initCheck();{ // Autolock scopestd::lock_guard<std::mutex> lock(mCore->mMutex);if (error == NO_ERROR && !mCore->mIsAbandoned) {graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);// 将GraphicBuffer对象赋值到BufferSlot中mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)mSlots[*outSlot].mAdditionalOptionsGenerationId = allocOptionsGenId;
#endifcallOnFrameDequeued = true;bufferId = mSlots[*outSlot].mGraphicBuffer->getId();}mCore->mIsAllocating = false;mCore->mIsAllocatingCondition.notify_all();if (error != NO_ERROR) {mCore->mFreeSlots.insert(*outSlot);mCore->clearBufferSlotLocked(*outSlot);BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");return error;}if (mCore->mIsAbandoned) {mCore->mFreeSlots.insert(*outSlot);mCore->clearBufferSlotLocked(*outSlot);BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");return NO_INIT;}VALIDATE_CONSISTENCY();} // Autolock scope}if (listener != nullptr && callOnFrameDequeued) {listener->onFrameDequeued(bufferId);}// ...if (outBufferAge) {*outBufferAge = mCore->mBufferAge;}addAndGetFrameTimestamps(nullptr, outTimestamps);return returnFlags;
}BufferSlot(): mGraphicBuffer(nullptr),mEglDisplay(EGL_NO_DISPLAY),mBufferState(),mRequestBufferCalled(false),mFrameNumber(0),mEglFence(EGL_NO_SYNC_KHR),mFence(Fence::NO_FENCE),mAcquireCalled(false),mNeedsReallocation(false) {}

dequeueBuffer方法中循环调用了waitForFreeSlotThenRelock方法来获取空闲slotwaitForFreeSlotThenRelock方法根据
BufferQueueCore的成员变量依次从mFreeBuffers以及mFreeSlots中获取可用的slot,第一次调用waitForFreeSlotThenRelock方法获取到的slot为0。

status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, std::unique_lock<std::mutex>& lock, int* found) const {auto callerString = (caller == FreeSlotCaller::Dequeue) ? "dequeueBuffer" : "attachBuffer";bool tryAgain = true;while (tryAgain) {// ...int dequeuedCount = 0;int acquiredCount = 0;// 第一次dequeueBuffer时,mActiveBuffers的初始值为空的setfor (int s : mCore->mActiveBuffers) {// }// 不允许dequeue超过mMaxDequeuedBufferCount个buffer,只有queue过buffer才会检查。// mBufferHasBeenQueued初始化的值为falseif (mCore->mBufferHasBeenQueued && dequeuedCount >= mCore->mMaxDequeuedBufferCount) {       return INVALID_OPERATION;}*found = BufferQueueCore::INVALID_BUFFER_SLOT;// If we disconnect and reconnect quickly, we can be in a state where// our slots are empty but we have many buffers in the queue. This can// cause us to run out of memory if we outrun the consumer. Wait here if// it looks like we have too many buffers queued up.const int maxBufferCount = mCore->getMaxBufferCountLocked();bool tooManyBuffers = mCore->mQueue.size() > static_cast<size_t>(maxBufferCount);if (tooManyBuffers) {BQ_LOGV("%s: queue size is %zu, waiting", callerString, mCore->mQueue.size());} else {// mSharedBufferMode为falseif (mCore->mSharedBufferMode && mCore->mSharedBufferSlot !=  BufferQueueCore::INVALID_BUFFER_SLOT) {*found = mCore->mSharedBufferSlot;} else {if (caller == FreeSlotCaller::Dequeue) {// 1. 获取空闲的bufferint slot = getFreeBufferLocked();// 第一次获取由于mFreeBuffers是空的,所以返回了BufferQueueCore::INVALID_BUFFER_SLOTif (slot != BufferQueueCore::INVALID_BUFFER_SLOT) { // 获取到了空间的buffer*found = slot;} else if (mCore->mAllowAllocation) { // 允许为slot分配buffer的情况// 2. 获取空闲的slot// BufferQueueCore实例化的时候mAllowAllocation赋值为true*found = getFreeSlotLocked();}} else {// If we're calling this from attach, prefer free slotsint slot = getFreeSlotLocked();if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {*found = slot;} else {*found = getFreeBufferLocked();}}}}// 如果没有找到buffer,或者queue里有太多的buffer,那么等待一个buffer被acquire或者release,或者最大的buffer数量发生变化。tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || tooManyBuffers;// ...} // while (tryAgain)return NO_ERROR;
}// 获取空闲的buffer
int BufferQueueProducer::getFreeBufferLocked() const {if (mCore->mFreeBuffers.empty()) {return BufferQueueCore::INVALID_BUFFER_SLOT;}// 从mFreeBuffers这个list中获取第一个元素int slot = mCore->mFreeBuffers.front();mCore->mFreeBuffers.pop_front();return slot;
}// 获取空闲的slot,对应的slot还没有分配buffer
int BufferQueueProducer::getFreeSlotLocked() const {// mFreeSlots的初始长度为2if (mCore->mFreeSlots.empty()) {return BufferQueueCore::INVALID_BUFFER_SLOT;}// 第一次取出的slot值为0int slot = *(mCore->mFreeSlots.begin());// 移除0mCore->mFreeSlots.erase(slot);return slot;
}BufferQueueCore::BufferQueueCore(): mMutex(),mIsAbandoned(false),mConsumerControlledByApp(false),mConsumerName(getUniqueName()),mConsumerListener(),mConsumerUsageBits(0),mConsumerIsProtected(false),mConnectedApi(NO_CONNECTED_API),mLinkedToDeath(),mConnectedProducerListener(),mBufferReleasedCbEnabled(false),mBufferAttachedCbEnabled(false),mSlots(),mQueue(),mFreeSlots(),mFreeBuffers(), // 初始化时为空listmUnusedSlots(),mActiveBuffers(),mDequeueCondition(),mDequeueBufferCannotBlock(false),mQueueBufferCanDrop(false),mLegacyBufferDrop(true),mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),mDefaultWidth(1),mDefaultHeight(1),mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),mMaxAcquiredBufferCount(1),mMaxDequeuedBufferCount(1),mBufferHasBeenQueued(false),mFrameCounter(0),mTransformHint(0),mIsAllocating(false),mIsAllocatingCondition(),mAllowAllocation(true),mBufferAge(0),mGenerationNumber(0),mAsyncMode(false),mSharedBufferMode(false),mAutoRefresh(false),mSharedBufferSlot(INVALID_BUFFER_SLOT),mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE, HAL_DATASPACE_UNKNOWN),mLastQueuedSlot(INVALID_BUFFER_SLOT),mUniqueId(getUniqueId()),mAutoPrerotation(false),mTransformHintInUse(0) {// numStartingBuffers为2int numStartingBuffers = getMaxBufferCountLocked();for (int s = 0; s < numStartingBuffers; s++) {mFreeSlots.insert(s);}// mFreeSlots的元素个数为2,取值分别为0、1// BufferQueueDefs::NUM_BUFFER_SLOTS为64for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS; s++) {mUnusedSlots.push_front(s);}// mUnusedSlots的元素个数为62,取值分别为2、3、。。。63
}int BufferQueueCore::getMaxBufferCountLocked() const {// mMaxAcquiredBufferCount为1// mMaxDequeuedBufferCount为1 // mAsyncMode为false// mDequeueBufferCannotBlock为false// maxBufferCount的值为2int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount + ((mAsyncMode || mDequeueBufferCannotBlock) ? 1 : 0);// mMaxBufferCount为64// maxBufferCount最终为2maxBufferCount = std::min(mMaxBufferCount, maxBufferCount);return maxBufferCount;
}

从上面的代码可以看出,mSlots是元素类型为BufferSlot的数组,长度为64。而BufferSlot实例化的时候默认mGraphicBuffer为空指针,接着就会创建GraphicBuffer对象,并更新到BufferSlot对象中。下面看下GraphicBuffer对象的创建过程,毕竟GraphicBuffer是用于传输图形数据的。

// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence, uint32_t width, uint32_t height, PixelFormat format, uint64_t usage, uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps) {// ...uint64_t bufferId = 0; // Only used if callOnFrameDequeued == true// ...{ // Autolock scope// ...int found = BufferItem::INVALID_BUFFER_SLOT;// 循环尝试获取空闲的bufferwhile (found == BufferItem::INVALID_BUFFER_SLOT) {// 1. 阻塞等待可用的空闲buffer status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);if (status != NO_ERROR) {return status;}// ...const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);// ...}// 2. 根据获取到的slot获取对应的GraphicBuffer,第一次获取到的mGraphicBuffer为空指针const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);// needsReallocation为truebool needsReallocation = buffer == nullptr || buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage);// ...// 即将返回给上层使用,将其状态更新为Activeif (mCore->mSharedBufferSlot != found) {mCore->mActiveBuffers.insert(found);}// 3. 通过outSlot将空闲buffer对应的slot返回*outSlot = found;// mNeedsReallocation为falseattachedByConsumer = mSlots[found].mNeedsReallocation;mSlots[found].mNeedsReallocation = false;// 跟新对应的状态mSlots[found].mBufferState.dequeue();// needsReallocation为trueif (needsReallocation) {mSlots[found].mAcquireCalled = false;mSlots[found].mGraphicBuffer = nullptr;mSlots[found].mRequestBufferCalled = false;mSlots[found].mEglDisplay = EGL_NO_DISPLAY;mSlots[found].mEglFence = EGL_NO_SYNC_KHR;mSlots[found].mFence = Fence::NO_FENCE;mCore->mBufferAge = 0;mCore->mIsAllocating = true;returnFlags |= BUFFER_NEEDS_REALLOCATION;} else {// We add 1 because that will be the frame number when this buffer// is queuedmCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;}eglDisplay = mSlots[found].mEglDisplay;eglFence = mSlots[found].mEglFence;// Don't return a fence in shared buffer mode, except for the first frame.*outFence = (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == found) ? Fence::NO_FENCE : mSlots[found].mFence;mSlots[found].mEglFence = EGL_NO_SYNC_KHR;mSlots[found].mFence = Fence::NO_FENCE;// ...} // Autolock scope// returnFlags & BUFFER_NEEDS_REALLOCATION的结果为trueif (returnFlags & BUFFER_NEEDS_REALLOCATION) {// ...
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)std::vector<GraphicBufferAllocator::AdditionalOptions> tempOptions;tempOptions.reserve(allocOptions.size());for (const auto& it : allocOptions) {tempOptions.emplace_back(it.name.c_str(), it.value);}const GraphicBufferAllocator::AllocationRequest allocRequest = {.importBuffer = true,.width = width,.height = height,.format = format,.layerCount = BQ_LAYER_COUNT,.usage = usage,.requestorName = {mConsumerName.c_str(), mConsumerName.size()},.extras = std::move(tempOptions),};sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest);
#elsesp<GraphicBuffer> graphicBuffer = new GraphicBuffer(width, height, format, BQ_LAYER_COUNT, usage, {mConsumerName.c_str(), mConsumerName.size()});
#endifstatus_t error = graphicBuffer->initCheck();{ // Autolock scopestd::lock_guard<std::mutex> lock(mCore->mMutex);// 4. 根据创建的GraphicBuffer更新BufferSlot的mGraphicBufferif (error == NO_ERROR && !mCore->mIsAbandoned) {graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)mSlots[*outSlot].mAdditionalOptionsGenerationId = allocOptionsGenId;
#endifcallOnFrameDequeued = true;bufferId = mSlots[*outSlot].mGraphicBuffer->getId();}mCore->mIsAllocating = false;mCore->mIsAllocatingCondition.notify_all();// ...VALIDATE_CONSISTENCY();} // Autolock scope}if (listener != nullptr && callOnFrameDequeued) {listener->onFrameDequeued(bufferId);}// ...if (outBufferAge) {*outBufferAge = mCore->mBufferAge;}addAndGetFrameTimestamps(nullptr, outTimestamps);return returnFlags;
}

下面看下GraphicBuffer的创建过程,主要实现逻辑在initWithSize方法中,最终通过GraphicBufferAllocator分配器完成内存空间的分配,并将其记录下来。

// frameworks/native/libs/ui/GraphicBuffer.cpp
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage, std::string requestorName) : GraphicBuffer() {mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, std::move(requestorName));
}status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage, std::string requestorName)
{GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();uint32_t outStride = 0;// 分配内存空间status_t err = allocator.allocate(inWidth, inHeight, inFormat, inLayerCount, inUsage, &handle, &outStride, mId, std::move(requestorName));if (err == NO_ERROR) {mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);width = static_cast<int>(inWidth);height = static_cast<int>(inHeight);format = inFormat;layerCount = inLayerCount;usage = inUsage;usage_deprecated = int(usage);stride = static_cast<int>(outStride);}return err;
}// frameworks/native/libs/ui/GraphicBufferAllocator.cpp
status_t GraphicBufferAllocator::allocateHelper(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, buffer_handle_t* handle, uint32_t* stride, std::string requestorName, bool importBuffer) {// ...const uint32_t bpp = bytesPerPixel(format);// ...// Ensure that layerCount is valid.if (layerCount < 1) {layerCount = 1;}// TODO(b/72323293, b/72703005): Remove these invalid bits from callersusage &= ~static_cast<uint64_t>((1 << 10) | (1 << 13));// 1. 分配内存空间的关键实现status_t error = mAllocator->allocate(requestorName, width, height, format, layerCount, usage, stride, handle, importBuffer);if (error != NO_ERROR) {return error;}if (!importBuffer) {return NO_ERROR;}size_t bufSize;// if stride has no meaning or is too large,// approximate size with the input width insteadif ((*stride) != 0 && std::numeric_limits<size_t>::max() / height / (*stride) < static_cast<size_t>(bpp)) {bufSize = static_cast<size_t>(width) * height * bpp;} else {bufSize = static_cast<size_t>((*stride)) * height * bpp;}Mutex::Autolock _l(sLock);KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);alloc_rec_t rec;rec.width = width;rec.height = height;rec.stride = *stride;rec.format = format;rec.layerCount = layerCount;rec.usage = usage;rec.size = bufSize;rec.requestorName = std::move(requestorName);// 2. 记录分配的内存空间以及rec信息list.add(*handle, rec);return NO_ERROR;
}// frameworks/native/libs/ui/include/ui/Gralloc.h
// A wrapper to IAllocator
class GrallocAllocator {
public:/** The returned buffers are already imported and must not be imported* again.  outBufferHandles must point to a space that can contain at* least "bufferCount" buffer_handle_t.* outBufferHandles指向一个内存空间*/virtual status_t allocate(std::string requestorName, uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, uint32_t* outStride, buffer_handle_t* outBufferHandles, bool importBuffers = true) const = 0;
}

从源码可以看出,GraphicBufferAllocator是用于为GraphicBuffer分配内存空间的,最终分配的内存空间存储到了GraphicBufferhandle变量里,用于后续的数据写入。至此,整个GraphicBuffer就已经完成创建并attach到了slot中,后续的canvas就可以使用GraphicBuffer进行数据填充了。

关联buffer到native层的Canvas

Surface分配完GraphicBuffer之后,继续为Surface创建CanvasCanvas用于后续的绘制流程。

// frameworks/base/core/jni/android_view_Surface.cpp
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {// 获取native层的Surface对象sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));// ...   // 1. 将Java层传递过来的Rect数据拷贝到native层的Rect中// ...// 2. 通过native层的Surface对象锁定一个缓冲区ANativeWindow_Buffer,缓冲区保存了Rect相关信息// ...// 3. 根据Java层的canvasObj创建一个native层的Canvas对象,并将上面的缓冲区设置到Canvas对象中graphics::Canvas canvas(env, canvasObj);canvas.setBuffer(&buffer, static_cast<int32_t>(surface->getBuffersDataSpace()));// 根据Java层传递的dirtyRectObj对canvas的矩形区域进行设置if (dirtyRectPtr) {canvas.clipRect({dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom});}// 4. 为native层的surface对象创建一个强引用对象lockedSurface, 并返回给Java层,用于在绘制结束之后通过JNI对native层的资源进行释放sp<Surface> lockedSurface(surface);lockedSurface->incStrong(&sRefBaseOwner);return (jlong) lockedSurface.get();
}// frameworks/base/libs/hwui/apex/include/android/graphics/canvas.h
namespace graphics {class Canvas {public:Canvas(JNIEnv* env, jobject canvasObj) :mCanvas(ACanvas_getNativeHandleFromJava(env, canvasObj)),mOwnedPtr(false) {}// ...private:ACanvas* mCanvas;const bool mOwnedPtr;};
}// frameworks/base/libs/hwui/apex/android_canvas.cpp
ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvasObj) {return TypeCast::toACanvas(GraphicsJNI::getNativeCanvas(env, canvasObj));
}// frameworks/base/libs/hwui/jni/Graphics.cpp
android::Canvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) {// ...// 获取之前Java层Canvas对象创建时对应的native层的对象句柄值jlong canvasHandle = env->GetLongField(canvas, gCanvas_nativeInstanceID);if (!canvasHandle) {return NULL;}// 根据native层的对象句柄值获取对应的Canvas对象return reinterpret_cast<android::Canvas*>(canvasHandle);
}

从源码可以看出,通过Java层的Canvas对象获取native层的句柄,并通过句柄获取到native层的Canvas对象用于构造新的Canvas对象并调用其setBuffer方法,将分配的GraphicBuffer对象关联到Canvas对象持有的SkBitmap上,最终由SkBitmap指向GraphicBuffer的内存空间。

// frameworks/base/libs/hwui/apex/include/android/graphics/canvas.h
namespace graphics {class Canvas {public:bool setBuffer(const ANativeWindow_Buffer* buffer,int32_t /*android_dataspace_t*/ dataspace) {return ACanvas_setBuffer(mCanvas, buffer, dataspace);}// ...}// frameworks/base/libs/hwui/apex/android_canvas.cpp
bool ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,int32_t /*android_dataspace_t*/ dataspace) {SkBitmap bitmap;bool isValidBuffer = (buffer == nullptr) ? false : convert(buffer, dataspace, &bitmap);TypeCast::toCanvas(canvas)->setBitmap(bitmap);return isValidBuffer;
}/** Converts a buffer and dataspace into an SkBitmap only if the resulting bitmap can be treated as a* rendering destination for a Canvas.  If the buffer is null or the format is one that we cannot* render into with a Canvas then false is returned and the outBitmap param is unmodified.*/
static bool convert(const ANativeWindow_Buffer* buffer, int32_t /*android_dataspace_t*/ dataspace, SkBitmap* outBitmap) {if (buffer == nullptr) {return false;}sk_sp<SkColorSpace> cs(uirenderer::DataSpaceToColorSpace((android_dataspace)dataspace));SkImageInfo imageInfo = uirenderer::ANativeWindowToImageInfo(*buffer, cs);size_t rowBytes = buffer->stride * imageInfo.bytesPerPixel();// If SkSurfaces::WrapPixels fails then we should as well as we will not be able to// draw into the canvas.sk_sp<SkSurface> surface = SkSurfaces::WrapPixels(imageInfo, buffer->bits, rowBytes);if (surface.get() != nullptr) {if (outBitmap) {outBitmap->setInfo(imageInfo, rowBytes);outBitmap->setPixels(buffer->bits);}return true;}return false;
}// external/skia/src/core/SkCanvas_Raster.cpp
SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr, nullptr) {}

至此,完成了SurfaceGraphicBuffer分配,并将分配到的GraphicBuffer关联到Canvas持有的SkBitmap上,后续绘制流程将会使用Canvas对象进行绘制处理,最终通过SkBitmap记录绘制操作,最终交由渲染引擎进行处理生成图形数据,交由SurfaceFlinger进程进行合成上屏。

使用Canvas对象进行绘制

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks, AttachedSurfaceControl {// ...private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets) {// Draw with software renderer.final Canvas canvas;// ...try {// ...// 1. 根据dirty从Surface对象中锁定一个canvas对象canvas = mSurface.lockCanvas(dirty);// ...} catch (Surface.OutOfResourcesException e) {handleOutOfResourcesException(e);return false;} catch (IllegalArgumentException e) {mLayoutRequested = true;    // ask wm for a new surface next time.return false;} finally {// ...}try {// ...// 2. 遍历绘制子ViewmView.draw(canvas);// ...} finally {try {// 3. 解锁canvas并将数据提交给SurfaceFlinger进程进行合成上屏surface.unlockCanvasAndPost(canvas);} catch (IllegalArgumentException e) {mLayoutRequested = true;    // ask wm for a new surface next time.return false;}}return true;}// ...
}

锁定canvas之后直接将canvas传给了View#draw方法,源码里的注释已经说明了绘制需要做的事情,一般我们关注onDrawdispatchDraw这两个方法,一个适用于绘制自身的内容,一个是用于分发绘制流程到子View

public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {// ...@CallSuperpublic void draw(Canvas canvas) {final int privateFlags = mPrivateFlags;mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;/** Draw traversal performs several drawing steps which must be executed* in the appropriate order:*      1. Draw the background*      2. If necessary, save the canvas' layers to prepare for fading*      3. Draw view's content*      4. Draw children*      5. If necessary, draw the fading edges and restore layers*      6. Draw decorations (scrollbars for instance)*      7. If necessary, draw the default focus highlight*/// 1. 绘制背景int saveCount;drawBackground(canvas);// skip step 2 & 5 if possible (common case)final int viewFlags = mViewFlags;boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;if (!verticalEdges && !horizontalEdges) {// 3. 绘制自身的内容onDraw(canvas);// 4. 绘制子ViewdispatchDraw(canvas);drawAutofilledHighlight(canvas);// ...// 6. 绘制前景// ...// 7. 绘制默认的highlight// ...return;}// ...}// ...
}

绘制自身的onDraw方法

自定义View的时候需要结合实际需要对onDraw方法进行重写,对于布局类的View则一般不需要重写。下面从TextView#onDraw方法看下一般需要怎么实现。

public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {// ...protected void onDraw(Canvas canvas) {}// ...
}
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {// ...@Overrideprotected void onDraw(Canvas canvas) {// ...// Draw the background for this viewsuper.onDraw(canvas);// ...canvas.save();// ...canvas.clipRect(clipLeft, clipTop, clipRight, clipBottom);// ...canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText);final int layoutDirection = getLayoutDirection();final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);if (isMarqueeFadeEnabled()) {if (!mSingleLine && getLineCount() == 1 && canMarquee() && (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {final int width = mRight - mLeft;final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();final float dx = mLayout.getLineRight(0) - (width - padding);canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);}if (mMarquee != null && mMarquee.isRunning()) {final float dx = -mMarquee.getScroll();canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);}}final int cursorOffsetVertical = voffsetCursor - voffsetText;Path highlight = getUpdatedHighlightPath();if (mEditor != null) {mEditor.onDraw(canvas, layout, highlight, mHighlightPaint, cursorOffsetVertical);} else {layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);}if (mMarquee != null && mMarquee.shouldDrawGhost()) {final float dx = mMarquee.getGhostOffset();canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);}canvas.restore();}}

可以看到,TextView#onDraw方法中通过Canvas#save方法以及Canvas#restore对绘制操作进行批量保存,而实际的绘制操作对应的方法包括:Canvas#clipRectCanvas#translate等,跟进去看下方法内部实现会发现,都是通过JNI调用到native层去处理实际逻辑的。

public class Canvas extends BaseCanvas {/*** Saves the current matrix and clip onto a private stack.* <p>* Subsequent calls to translate,scale,rotate,skew,concat or clipRect,* clipPath will all operate as usual, but when the balancing call to* restore() is made, those calls will be forgotten, and the settings that* existed before the save() will be reinstated.** @return The value to pass to restoreToCount() to balance this save()*/public int save() {return nSave(mNativeCanvasWrapper, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);}@CriticalNativeprivate static native int nSave(long canvasHandle, int saveFlags);/*** This call balances a previous call to save(), and is used to remove all* modifications to the matrix/clip state since the last save call. It is* an error to call restore() more times than save() was called.*/public void restore() {if (!nRestore(mNativeCanvasWrapper) && (!sCompatibilityRestore || !isHardwareAccelerated())) {throw new IllegalStateException("Underflow in restore - more restores than saves");}}@CriticalNativeprivate static native boolean nRestore(long canvasHandle);/*** Intersect the current clip with the specified rectangle, which is* expressed in local coordinates.** @param left   The left side of the rectangle to intersect with the current clip* @param top    The top of the rectangle to intersect with the current clip* @param right  The right side of the rectangle to intersect with the current clip* @param bottom The bottom of the rectangle to intersect with the current clip* @return       true if the resulting clip is non-empty*/public boolean clipRect(float left, float top, float right, float bottom) {return nClipRect(mNativeCanvasWrapper, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);}@CriticalNativeprivate static native boolean nClipRect(long nativeCanvas, float left, float top, float right, float bottom, int regionOp);}

下面跟进去看下内部是如何处理的。都是调用到SkCanvas的方法进行记录。

// frameworks/base/libs/hwui/jni/android_graphics_Canvas.cpp
static jint save(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jint flagsHandle) {SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);return static_cast<jint>(get_canvas(canvasHandle)->save(flags));
}static Canvas* get_canvas(jlong canvasHandle) {return reinterpret_cast<Canvas*>(canvasHandle);
}// frameworks/base/libs/hwui/SkiaCanvas.cpp
int SkiaCanvas::save(SaveFlags::Flags flags) {int count = mCanvas->save();recordPartialSave(flags);return count;
}bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkClipOp op) {SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);this->recordClip(rect, op);mCanvas->clipRect(rect, op);return !mCanvas->isClipEmpty();
}

分发绘制流程

调用dispatchDraw方法绘制子View,具体实现在ViewGroup类中,如果自定义View继承了ViewGroup则根据实际需要进行重写。dispatchDraw方法内部主要是遍历子View并调用其draw方法来对子View进行绘制。

public abstract class ViewGroup extends View implements ViewParent, ViewManager {// ...@Overrideprotected void dispatchDraw(Canvas canvas) {final int childrenCount = mChildrenCount;final View[] children = mChildren;int flags = mGroupFlags;// ...int clipSaveCount = 0;final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;if (clipToPadding) {clipSaveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop, mScrollX + mRight - mLeft - mPaddingRight, mScrollY + mBottom - mTop - mPaddingBottom);}// ...boolean more = false;final long drawingTime = getDrawingTime();canvas.enableZ();final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();int transientIndex = transientCount != 0 ? 0 : -1;// 硬件加速未开启时preorderedList才不会nullfinal ArrayList<View> preorderedList = drawsWithRenderNode(canvas) ? null : buildOrderedChildList();final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled();for (int i = 0; i < childrenCount; i++) {while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {final View transientChild = mTransientViews.get(transientIndex);if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE || transientChild.getAnimation() != null) {more |= drawChild(canvas, transientChild, drawingTime);}transientIndex++;if (transientIndex >= transientCount) {transientIndex = -1;}}final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {// 调用drawChild绘制子Viewmore |= drawChild(canvas, child, drawingTime);}}while (transientIndex >= 0) {// there may be additional transient views after the normal viewsfinal View transientChild = mTransientViews.get(transientIndex);if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE || transientChild.getAnimation() != null) {more |= drawChild(canvas, transientChild, drawingTime);}transientIndex++;if (transientIndex >= transientCount) {break;}}if (preorderedList != null) preorderedList.clear();// Draw any disappearing views that have animationsif (mDisappearingChildren != null) {final ArrayList<View> disappearingChildren = mDisappearingChildren;final int disappearingCount = disappearingChildren.size() - 1;// Go backwards -- we may delete as animations finishfor (int i = disappearingCount; i >= 0; i--) {final View child = disappearingChildren.get(i);more |= drawChild(canvas, child, drawingTime);}}canvas.disableZ();if (clipToPadding) {canvas.restoreToCount(clipSaveCount);}// mGroupFlags might have been updated by drawChild()flags = mGroupFlags;if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {invalidate(true);}// ...}// .../*** Draw one child of this View Group. This method is responsible for getting* the canvas in the right state. This includes clipping, translating so* that the child's scrolled origin is at 0, 0, and applying any animation* transformations.** @param canvas The canvas on which to draw the child* @param child Who to draw* @param drawingTime The time at which draw is occurring* @return True if an invalidate() was issued*/protected boolean drawChild(Canvas canvas, View child, long drawingTime) {return child.draw(canvas, this, drawingTime);}
}

遍历完整个View树之后,对于所有绘制操作完成了处理,此时就可以将处理之后得到的数据提交,用于后续的合成上屏了。

提交图形数据

提交数据是通过Surface#unlockCanvasAndPost方法完成的,下面跟一下源码看下具体做了什么事情。

public class Surface implements Parcelable {// .../*** Posts the new contents of the {@link Canvas} to the surface and* releases the {@link Canvas}.** @param canvas The canvas previously obtained from {@link #lockCanvas}.*/public void unlockCanvasAndPost(Canvas canvas) {synchronized (mLock) {checkNotReleasedLocked();// 软件绘制(未开启硬件加速)时mHwuiContext为nullif (mHwuiContext != null) {mHwuiContext.unlockAndPost(canvas);} else {unlockSwCanvasAndPost(canvas);}}}private void unlockSwCanvasAndPost(Canvas canvas) {if (canvas != mCanvas) {throw new IllegalArgumentException("canvas object must be the same instance that "+ "was previously returned by lockCanvas");}if (mNativeObject != mLockedObject) {Log.w(TAG, "WARNING: Surface's mNativeObject (0x" + Long.toHexString(mNativeObject) + ") != mLockedObject (0x" + Long.toHexString(mLockedObject) +")");}if (mLockedObject == 0) {throw new IllegalStateException("Surface was not locked");}try {nativeUnlockCanvasAndPost(mLockedObject, canvas);} finally {nativeRelease(mLockedObject);mLockedObject = 0;}}private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas);@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)private static native void nativeRelease(long nativeObject);// ...
}

主要逻辑在nativeUnlockCanvasAndPost方法,通过JNI调用到native层,下面看下native层的实现。

// frameworks/base/core/jni/android_view_Surface.cpp
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj) {sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));if (!isSurfaceValid(surface)) {return;}// detach the canvas from the surfacegraphics::Canvas canvas(env, canvasObj);canvas.setBuffer(nullptr, ADATASPACE_UNKNOWN);// unlock surfacestatus_t err = surface->unlockAndPost();if (err < 0) {jniThrowException(env, IllegalArgumentException, NULL);}
}// frameworks/base/libs/hwui/apex/include/android/graphics/canvas.h
namespace graphics {class Canvas {public:bool setBuffer(const ANativeWindow_Buffer* buffer, int32_t /*android_dataspace_t*/ dataspace) {return ACanvas_setBuffer(mCanvas, buffer, dataspace);}// ...
}// frameworks/base/libs/hwui/apex/android_canvas.cpp
bool ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer, int32_t /*android_dataspace_t*/ dataspace) {SkBitmap bitmap;// buffer为nullptrbool isValidBuffer = (buffer == nullptr) ? false : convert(buffer, dataspace, &bitmap);// 设置了一个新的SkBitmap对象TypeCast::toCanvas(canvas)->setBitmap(bitmap);return isValidBuffer;
}// frameworks/native/libs/gui/Surface.cpp
status_t Surface::unlockAndPost()
{if (mLockedBuffer == nullptr) {return INVALID_OPERATION;}int fd = -1;// 解锁bufferstatus_t err = mLockedBuffer->unlockAsync(&fd);// 将buffer放回BufferQueueerr = queueBuffer(mLockedBuffer.get(), fd);// 更新mPostedBuffer(上一个Buffer,存储了准备渲染上屏的数据)mPostedBuffer = mLockedBuffer;mLockedBuffer = nullptr;return err;
}

解锁buffer

// frameworks/native/libs/ui/GraphicBuffer.cpp
status_t GraphicBuffer::unlockAsync(int *fenceFd)
{return getBufferMapper().unlockAsync(handle, fenceFd);
}// frameworks/native/libs/ui/include/ui/GraphicBufferMapper.h
class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
{
public:status_t unlockAsync(buffer_handle_t handle, int* fenceFd) {base::unique_fd temp;status_t result = unlock(handle, fenceFd ? &temp : nullptr);if (fenceFd) {*fenceFd = temp.release();}return result;}// ...
}// frameworks/native/libs/ui/GraphicBufferMapper.cpp
status_t GraphicBufferMapper::unlock(buffer_handle_t handle, base::unique_fd* outFence) {ATRACE_CALL();int fence = mMapper->unlock(handle);if (outFence) {*outFence = unique_fd{fence};} else {sync_wait(fence, -1);close(fence);}return OK;
}

提交数据

// frameworks/native/libs/gui/Surface.cpp
int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {// ...Mutex::Autolock lock(mMutex);int i = getSlotFromBufferLocked(buffer);    // ...IGraphicBufferProducer::QueueBufferOutput output;IGraphicBufferProducer::QueueBufferInput input;getQueueBufferInputLocked(buffer, fenceFd, mTimestamp, &input);applyGrallocMetadataLocked(buffer, input);sp<Fence> fence = input.fence;nsecs_t now = systemTime();// 将buffer放回到BufferQueuestatus_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);mLastQueueDuration = systemTime() - now;if (err != OK)  {ALOGE("queueBuffer: error queuing buffer, %d", err);}onBufferQueuedLocked(i, fence, output);return err;
}

总结

Android中View的软件绘制流程使用的渲染引擎是Skia,软件绘制主要是使用Canvas将绘制操作存储到到Surface持有的GraphicBuffer 中, 主要包括如下步骤:

  1. 首先通过Surface锁定BufferQueue中的一个GraphicBuffer
  2. 接着将SkiaCanvas持有的SkBitmap绑定GraphicBuffer指向的共享内存;
  3. 然后使用SkiaCanvasView树上分发View 绘制;
  4. 最后当绘制结束后释放Surface持有的GraphicBuffer并将其推入SurfaceFlinger进程;
  5. SurfaceFlinger进程获取渲染数据并输出到屏幕,完成屏幕刷新;

http://www.mrgr.cn/news/60635.html

相关文章:

  • 生成式 AI 与向量搜索如何扩大零售运营:巨大潜力尚待挖掘
  • 【Unity实战笔记】第二一 · 基于状态模式的角色控制——以UnityChan为例
  • 鸿蒙网络编程系列32-基于拦截器的性能监控示例
  • 【Vulnhub靶场】DC-2
  • 微信小程序 setData数据量过大的解决与分页加载的实现
  • linux下gpio模拟spi三线时序
  • 【C++】How the C++ Compiler Works
  • Shiro 会话管理和加密
  • 溪源飨提高免疫力治未病:硒+辅酶Q10强力组合
  • numpy——数学运算
  • C++ vector
  • 西门子S7-200 SMART 多泵轮换功能库案例下载
  • 超子物联网HAL库笔记:准备篇
  • TypeScript 接口知识点详解
  • 多态的体现
  • 三维测量与建模笔记 - 2.1 坐标转换基础
  • redis学习路线和内容
  • 亿赛通与Ping32:数据安全领域的两大巨擘对比
  • 二十四、Python基础语法(变量进阶)
  • 计算机网络803-(5)运输层
  • 常见大气校正模型及6S模型安装部署【20241028】
  • 仓颉编程语言一
  • 011:软件卸载工具TotalUninstall安装教程
  • 重写(外壳不变)
  • CSS3新增长度单位
  • Python自动化测试中的Mock与单元测试实战