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.