//frameworks/base/core/java/android/view/Surface.javapublicclassSurfaceimplementsParcelable{publicCanvaslockCanvas(RectinOutDirty)throwsSurface.OutOfResourcesException,IllegalArgumentException{synchronized(mLock){checkNotReleasedLocked();if(mLockedObject!=0){// Ideally, nativeLockCanvas() would throw in this situation and prevent the// double-lock, but that won't happen if mNativeObject was updated. We can't// abandon the old mLockedObject because it might still be in use, so instead// we just refuse to re-lock the Surface.thrownewIllegalArgumentException("Surface was already locked");}mLockedObject=nativeLockCanvas(mNativeObject,mCanvas,inOutDirty);returnmCanvas;}}}
//frameworks/base/core/jni/android_view_Surface.cpp
staticjlongnativeLockCanvas(JNIEnv*env,jclassclazz,jlongnativeObject,jobjectcanvasObj,jobjectdirtyRectObj){sp<Surface>surface(reinterpret_cast<Surface*>(nativeObject));if(!isSurfaceValid(surface)){jniThrowException(env,IllegalArgumentException,NULL);return0;}if(!ACanvas_isSupportedPixelFormat(ANativeWindow_getFormat(surface.get()))){native_window_set_buffers_format(surface.get(),PIXEL_FORMAT_RGBA_8888);}RectdirtyRect(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;}ANativeWindow_Bufferbuffer;status_terr=surface->lock(&buffer,dirtyRectPtr);if(err<0){constchar*constexception=(err==NO_MEMORY)?OutOfResourcesException:IllegalArgumentException;jniThrowException(env,exception,NULL);return0;}graphics::Canvascanvas(env,canvasObj);canvas.setBuffer(&buffer,static_cast<int32_t>(surface->getBuffersDataSpace()));if(dirtyRectPtr){canvas.clipRect({dirtyRect.left,dirtyRect.top,dirtyRect.right,dirtyRect.bottom});}if(dirtyRectObj){env->SetIntField(dirtyRectObj,gRectClassInfo.left,dirtyRect.left);env->SetIntField(dirtyRectObj,gRectClassInfo.top,dirtyRect.top);env->SetIntField(dirtyRectObj,gRectClassInfo.right,dirtyRect.right);env->SetIntField(dirtyRectObj,gRectClassInfo.bottom,dirtyRect.bottom);}// Create another reference to the surface and return it. This reference
// should be passed to nativeUnlockCanvasAndPost in place of mNativeObject,
// because the latter could be replaced while the surface is locked.
sp<Surface>lockedSurface(surface);lockedSurface->incStrong(&sRefBaseOwner);return(jlong)lockedSurface.get();}
//framework/native/libs/gui/Surface.cpp
classSurface:publicANativeObjectBase<ANativeWindow,Surface,RefBase>{status_tSurface::lock(ANativeWindow_Buffer*outBuffer,ARect*inOutDirtyBounds){if(mLockedBuffer!=nullptr){ALOGE("Surface::lock failed, already locked");returnINVALID_OPERATION;}if(!mConnectedToCpu){interr=Surface::connect(NATIVE_WINDOW_API_CPU);if(err){returnerr;}// we're intending to do software rendering from this point
setUsage(GRALLOC_USAGE_SW_READ_OFTEN|GRALLOC_USAGE_SW_WRITE_OFTEN);}ANativeWindowBuffer*out;intfenceFd=-1;status_terr=dequeueBuffer(&out,&fenceFd);ALOGE_IF(err,"dequeueBuffer failed (%s)",strerror(-err));if(err==NO_ERROR){sp<GraphicBuffer>backBuffer(GraphicBuffer::getSelf(out));constRectbounds(backBuffer->width,backBuffer->height);RegionnewDirtyRegion;if(inOutDirtyBounds){newDirtyRegion.set(static_cast<Rectconst&>(*inOutDirtyBounds));newDirtyRegion.andSelf(bounds);}else{newDirtyRegion.set(bounds);}// figure out if we can copy the frontbuffer back
constsp<GraphicBuffer>&frontBuffer(mPostedBuffer);constboolcanCopyBack=(frontBuffer!=nullptr&&backBuffer->width==frontBuffer->width&&backBuffer->height==frontBuffer->height&&backBuffer->format==frontBuffer->format);if(canCopyBack){// copy the area that is invalid and not repainted this round
constRegioncopyback(mDirtyRegion.subtract(newDirtyRegion));if(!copyback.isEmpty()){copyBlt(backBuffer,frontBuffer,copyback,&fenceFd);}}else{// if we can't copy-back anything, modify the user's dirty
// region to make sure they redraw the whole buffer
newDirtyRegion.set(bounds);mDirtyRegion.clear();Mutex::Autolocklock(mMutex);for(size_ti=0;i<NUM_BUFFER_SLOTS;i++){mSlots[i].dirtyRegion.clear();}}{// scope for the lock
Mutex::Autolocklock(mMutex);intbackBufferSlot(getSlotFromBufferLocked(backBuffer.get()));if(backBufferSlot>=0){Region&dirtyRegion(mSlots[backBufferSlot].dirtyRegion);mDirtyRegion.subtract(dirtyRegion);dirtyRegion=newDirtyRegion;}}mDirtyRegion.orSelf(newDirtyRegion);if(inOutDirtyBounds){*inOutDirtyBounds=newDirtyRegion.getBounds();}void*vaddr;status_tres=backBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN|GRALLOC_USAGE_SW_WRITE_OFTEN,newDirtyRegion.bounds(),&vaddr,fenceFd);ALOGW_IF(res,"failed locking buffer (handle = %p)",backBuffer->handle);if(res!=0){err=INVALID_OPERATION;}else{mLockedBuffer=backBuffer;outBuffer->width=backBuffer->width;outBuffer->height=backBuffer->height;outBuffer->stride=backBuffer->stride;outBuffer->format=backBuffer->format;outBuffer->bits=vaddr;}}returnerr;}}