Google is committed to advancing racial equity for Black communities. See how.

Surface and SurfaceHolder

Surface objects enable apps to render images to be presented on screens. SurfaceHolder interfaces enable apps to edit and control surfaces.

Surface

A surface is an interface for a producer to exchange buffers with a consumer.

The BufferQueue for a display surface is typically configured for triple-buffering. Buffers are allocated on demand, so if the producer generates buffers slowly enough, such as at 30 fps on a 60 fps display, there might only be two allocated buffers in the queue. Allocating buffers on demand helps minimize memory consumption. You can see a summary of the buffers associated with every layer in the dumpsys SurfaceFlinger output.

Most clients render onto surfaces using OpenGL ES or Vulkan. However, some clients render onto surfaces using a canvas.

Canvas rendering

The canvas implementation is provided by the Skia Graphics Library. If you want to draw a rectangle, you call the Canvas API, which sets bytes in a buffer appropriately. To ensure that a buffer isn't updated by two clients at once, or written to while being displayed, lock the buffer to access it. Use the following commands to work with canvas locks:

  • lockCanvas() locks the buffer for rendering on the CPU and returns a Canvas to use for drawing.
  • unlockCanvasAndPost() unlocks the buffer and sends it to the compositor.
  • lockHardwareCanvas() locks the buffer for rendering on the GPU and returns a canvas to use for drawing.

The first time the producer requests a buffer from a BufferQueue, the buffer is allocated and initialized to zero. Initialization is necessary to avoid inadvertently sharing data between processes. However, if you reuse a buffer, the previous contents are still present. If you repeatedly call lockCanvas() and unlockCanvasAndPost() without drawing anything, the producer cycles between previously rendered frames.

The surface lock/unlock code keeps a reference to the previously rendered buffer. If you specify a dirty region when locking the surface, it copies the nondirty pixels from the previous buffer. SurfaceFlinger or HWC typically handle the buffer; but because we only need to read from the buffer, there's no need to wait for exclusive access.

SurfaceHolder

A SurfaceHolder is an interface the system uses to share ownership of surfaces with apps. Some clients that work with surfaces want a SurfaceHolder, because APIs to get and set surface parameters are implemented through a SurfaceHolder. A SurfaceView contains a SurfaceHolder.

Most components that interact with a view involve a SurfaceHolder. Some other APIs, such as MediaCodec, operate on the surface itself.