Zygote
Graphicsintermediate

Surfaces and SurfaceFlinger

A Surface is a queue of buffers, not a canvas. SurfaceFlinger is the compositor that decides which buffers become pixels. Between them they explain BLAST, overlays, and why SurfaceView beats TextureView for video.

12 minAPI 1–37 · 17interactivequizverified 2026-10-27

Most Android developers meet Surface as an object they get from a SurfaceHolder or a SurfaceView, and assume it is something you draw on. It is not. A Surface is an endpoint of a queue: producers put buffers in, the compositor takes them out. Everything else about it follows from that.

TL;DR#

  • A Surface is a producer's handle to a ; it is not a bitmap and not a canvas.
  • SurfaceFlinger is the compositor. It collects every visible layer on vsync and produces the frame the display scans out.
  • The Hardware Composer lets the display scan out several layers directly as overlays, avoiding GPU composition.
  • SurfaceView gives a view its own separate layer; TextureView renders into the normal view hierarchy.
  • BLAST ties a window's first buffer to the transaction that creates or resizes the window, removing a first-frame flicker that used to be routine.

Mental model#

Think of a slide projector with several carousels.

Each carousel is a Surface: it holds slides (buffers) and feeds them in order. The person loading a carousel is a producer — an app, a video decoder, a camera.

The operator is SurfaceFlinger. On each beat they take the current slide from every carousel, stack them in the right order and project the combination.

The projector's own optics are the Hardware Composer: sometimes it can project several slides at once without the operator having to combine them first.

Where the analogy breaks#

Slides are images. Buffers come with fences, timestamps and a state machine, and a carousel can be empty — a producer that has not queued anything yet — in which case the layer simply is not shown. And unlike a projector, a layer's composition can change every frame: what was an overlay last frame may need GPU composition this frame because a translucent dialog appeared on top of it.

The big picture#

Loading diagram…
Text description of this diagram

An exploded view of the layers on a phone screen: wallpaper, the app window, a translucent dialog, the status bar, the navigation bar and the keyboard. Opaque, non-overlapping layers can be handed to the Hardware Composer as overlays. A translucent or overlapping layer forces SurfaceFlinger to composite with the GPU into a client target.

Each plate in that diagram is a Surface with its own BufferQueue and its own producer. The status bar's buffer comes from SystemUI; the keyboard's from a completely separate app's process. SurfaceFlinger does not care who produced a buffer, only what the layer's transform, alpha and blend mode say to do with it.

Deep dive#

A Surface is a queue endpoint#

Surface (native) and Surface (Java) are the producer-side handle. When you call lockCanvas or when the RenderThread renders, the producer dequeues a buffer, writes into it, and queues it.

The consumer side is either SurfaceFlinger or another app — this is what makes SurfaceTexture possible: it is a consumer you can hand to a producer so that the producer's output becomes a texture you can draw elsewhere.

1

The queue's lifecycle is the four-state machine you have already seen: free, dequeued, queued, acquired. What matters for composition is that the consumer acquires at a specific moment — on vsync — so a buffer queued after that moment waits a full frame.

What SurfaceFlinger actually does#

On each vsync, SurfaceFlinger:

  1. Collects the layers that have a queued buffer and are visible.
  2. Computes each layer's visible region, applying transforms, crops and alpha.
  3. Asks the Hardware Composer which layers it can handle directly.
  4. Composites the remainder with the GPU into a client target.
  5. Presents the resulting set of layers to the display.2

Step 3 is the one that determines cost. A typical phone's HWC supports a handful of overlays. If the visible stack fits, composition is essentially free and the GPU stays idle. If it does not, SurfaceFlinger must render some or all of the stack into a client target, which costs GPU time, memory bandwidth and power.3

Layers, z-order and the window connection#

SurfaceFlinger's layers and WindowManager's windows are different objects kept in sync. WindowManager decides the window's position, size and z-order; SurfaceFlinger receives a Layer with a transform and a z value through a transaction.4

Transactions are the mechanism for changing a layer atomically: position, crop, alpha, buffer and visibility all change together, so a resize never shows an intermediate state. This is also where BLAST comes in.

BLAST: the first-buffer problem#

Historically, creating a window and giving it content were two separate steps. The window could become visible before its first buffer arrived, showing a flash of background — most visibly when launching an app or rotating.

BLAST attaches the buffer to the transaction that creates or updates the layer, through , so the window appears with content already in place.5 In current AOSP the app-side object is BLASTBufferQueue; SurfaceFlinger learns about the buffer at the same time it learns about the geometry.

The practical effect is fewer visible flashes on launch and rotation, and a simpler contract: "here is the window and its first frame, together".

SurfaceView vs TextureView#

Both let you show a producer's output — a video decoder, a camera, a GL renderer — inside a view hierarchy. They differ in where the output lives.

SurfaceViewTextureView
Layera separate SurfaceFlinger layer behind the windowa texture inside the app's window
Compositioncan be an HWC overlayalways GPU-composited into the app's buffer
Transform / alphalimited; the layer is separatefull View transforms, alpha, animation
Costlower, especially for videohigher; the video is drawn as part of the app's frame
First framehistorically later; BLAST improved itimmediate

The trade is straightforward. SurfaceView gives the producer its own layer, which the display can often scan out directly — ideal for full-screen video and games. TextureView puts the producer's output into your window's buffer, which is what you need if you want to animate, scale or fade it like any other view.67

Fences, and why buffers are not just memory#

A buffer carries a fence: a kernel object that signals when the GPU has finished writing to it. The producer queues a buffer with a fence instead of waiting for the GPU to finish; the consumer waits on the fence before reading. The sync framework manages these fences across processes.8

Without fences, every handoff would need a CPU-side wait, and the pipeline would serialise. With them, the GPU can still be writing the last few scanlines while the compositor is already preparing to present.

What a layer is, exactly#

A SurfaceFlinger layer is a record of:

  • A buffer (or nothing, if the producer has not queued one).
  • A transform: position, scale, rotation, crop.
  • A blend mode and alpha.
  • A z-order within its display.
  • A visible region, computed from the crop and the display bounds.

The layer is not the window. WindowManager owns the window — its frame, its insets, its focus state — and it pushes changes to the layer through a transaction. A window can exist with no layer at all, and a layer can outlive the window that created it during a transition.

Transactions make resizes atomic#

A transaction is a batch of layer changes applied together. This matters more than it sounds: a resize changes the layer's buffer size, its crop and its position, and if those changes were applied separately the display could show a frame at the wrong scale, or a buffer cropped to the old size.

Transactions are also the mechanism behind SurfaceView's setFixedSize and setZOrderMediaOverlay — both are properties applied at the next transaction boundary, not immediately.

Why the compositor's cost is invisible to the app#

An app cannot see how many layers are visible or how many overlay planes the display has. It only sees its own frame time. When SurfaceFlinger falls back to client composition, the app's frame is unaffected — its buffer was produced on time — but the overall frame is late because composition took too long.

This is the practical reason the frame's "owner" is the system rather than the app. FrameTimeline attributes a missed deadline to the stage that caused it, which may be a stage the app does not control.

Multiple displays and virtual displays#

SurfaceFlinger composes per display. A phone with an external monitor has two compositions running, and a virtual display — screen recording, casting, or a Presentation on a secondary screen — is a third. Each has its own refresh rate, its own layer stack and its own composition decisions.

For an app, this is mostly invisible, except that a Presentation runs in a separate window on a separate display, with its own insets and its own lifecycle. Screen recording captures the composited output, which is why it captures the status bar and the cursor but not a secure window — secure layers are excluded from virtual displays by the system, not by the app.

How it evolved#

API 1–API 15Single layercomposition without a stable layer modelAPI 1
API 16 →BufferQueue eraproducer/consumer with explicit slotsAPI 16
Interface changes16 releases
APIVersionWhat changed
11.0
  • Pull-down notification shade
  • Home screen with widgets
31.5 Cupcake
  • Home screen widgets and folders
92.3 Gingerbread
  • New UI with dark theme and green accents
113.0 Honeycomb
  • The Holo design language arrives
123.1 Honeycomb
  • Resizable widgets
164.1 Jelly Bean
  • Project Butter: vsync-driven, smooth UI
  • Expandable notifications
204.4W KitKat (Wear)
  • Voice-driven card UI
215.0 Lollipop
  • Material Design
  • Notifications on the lock screen
247.0 Nougat
  • Quick Settings tiles
  • Direct Reply in notifications
268.0 Oreo
  • Notification channels
289 Pie
  • Dark theme groundwork
2910
  • System-wide dark theme
3011
  • Conversation notifications and bubbles
  • Media controls in Quick Settings
3112
  • Material You dynamic colour
3313 Tiramisu
  • Themed app icons
  • Runtime notification permission
3616 Baklava
  • Material 3 Expressive
  • Live Updates notifications

Under the hood#

Curiosity corner#

  • The compositor does not know what your app is. It sees layers, transforms and buffers. That is why a SurfaceView can show a video from a hardware decoder without the app ever touching a pixel.
  • Overlay counts are a hardware property. Two phones with the same SoC can differ in how many layers they can scan out, because the display driver and panel differ.
  • A layer can exist with no buffer. The window is there; it simply produces nothing, and the layer below shows through.

Try it#

List the layers
adb shell dumpsys SurfaceFlinger --list
Example output
+ Layer 0x7f8a2c00 (com.example.app/com.example.app.MainActivity#0)
z= 0  pos=(0,0)  size=(1080,2400)  crop=(0,0,1080,2400)
transform=0  alpha=1.0  composition=HWC
Composition type per layer
adb shell dumpsys SurfaceFlinger
Example output
Display 0 HWC layers:
type    | handle | name
---------+--------+---------------------------
HWC     | 0x1    | com.android.systemui/StatusBar
HWC     | 0x2    | com.example.app/MainActivity
CLIENT  | 0x3    | com.example.app/Dialog

Check yourself#

Check yourself

1 / 12

At 120 Hz, how much time does one frame have before it misses the display's deadline?

0 answered · 0 correct

Sources#

Sources

Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.

  1. docsSurfaceTexturesource.android.comaccessed 2026-10-27↩
  2. docsSurfaceFlinger and WindowManagersource.android.comaccessed 2026-10-27↩
  3. docsHardware Composer (HWC)source.android.comaccessed 2026-10-27↩
  4. docsLayers and displayssource.android.comaccessed 2026-10-27↩
  5. docsUnsignaled buffer latchsource.android.comaccessed 2026-10-27↩
  6. docsSurfaceView and GLSurfaceViewsource.android.comaccessed 2026-10-27↩
  7. docsTextureViewsource.android.comaccessed 2026-10-27↩
  8. docsSync frameworksource.android.comaccessed 2026-10-27↩
  9. docsSurface and SurfaceHoldersource.android.comaccessed 2026-10-27↩
  10. docsBufferQueue and grallocsource.android.comaccessed 2026-10-27↩