The Window Manager, at a glance
WindowManagerService decides where every visible rectangle goes, what it may overlap, and which areas other windows are allowed to draw in. It is the system's geometry authority, and it never draws a pixel.
Every visible thing on an Android screen is a window: your activity, the status bar, the keyboard, a
dialog, a bubble, the volume overlay. Something has to decide where each of them sits, which one
receives touches, and how much space the ones below are allowed to use. That something is
WindowManagerService.
TL;DR#
- (WMS) owns the window hierarchy: z-order, position, size, focus, and insets.
- It does not composite. It tells what the layers are; SurfaceFlinger and the hardware composer produce the frame.
- It runs in
system_serverand is tightly coupled toActivityTaskManager: a launch creates an activity record and a window. - — the areas consumed by system bars, cutouts and the IME — are computed here and pushed to apps, which is why edge-to-edge is a window-manager story.
- Almost everything about windows can be inspected with
dumpsys windowand , which records the actual hierarchy over time.
Mental model#
Picture a newspaper layout desk.
The editor does not print the paper. They decide that the masthead is three centimetres tall, that the fold sits here, that the advertisement gets the bottom-right corner and that the headline may not run into it. The pressroom does the printing.
WMS is the layout desk. It decides rectangles and rules of overlap. SurfaceFlinger is the pressroom.1
Where the analogy breaks#
A newspaper layout is static for an edition. Android's layout is recomputed on almost every frame boundary: a keyboard slides up, a notification arrives, a video goes fullscreen, and the whole hierarchy is re-evaluated. WMS is not a batch process; it is a state machine that runs continuously and must produce a consistent answer before the next .
The big picture#
Text description of this diagram
A two-layer diagram. The upper layer shows the user's phone as seven layers from apps down to the kernel, each annotated with who can change it: the Play Store for apps, Google for GMS, Mainline for some framework parts, and the OEM for the rest. The lower layer shows the update reality for each: app updates are silent and take minutes, Play services is silent over days, Play System Updates are monthly with one reboot, full OTAs are quarterly to yearly, vendor OTAs often never happen, and kernel updates ride on an OTA. The diagram demonstrates that the parts whose updater is the OEM are the parts where fixes are slowest to arrive.
That diagram is about updates rather than windows, and it is here deliberately. The window manager is
one of the pieces that sits inside the OEM's update cadence: WindowManagerService is in the system
image, so its behaviour changes when the OEM ships a release — not when Google ships a module. That
is why window behaviour varies so much between devices that claim the same API level.
Deep dive#
The two graphs again#
The window hierarchy is not the same as the view hierarchy, and it is not the same as the task stack.
- A task contains activity records. It is a navigation concept.
- An activity has zero or one window while it is visible. It is a lifecycle concept.
- A window is a rectangle with a surface, a z-order and an input region. It is a rendering and input concept.
One activity can add several windows (a dialog, a popup, a SurfaceView overlay). One window can be
created without an activity at all (the status bar, an accessibility overlay, a bubble). The system
keeps these graphs separate and reconciles them on every transaction.
Window types and layers#
Window type determines the layer. The ordering, roughly from back to front:
| Layer | Examples | Notes |
|---|---|---|
| App windows | Activities, dialogs | Normal applications |
| System windows | Status bar, navigation bar, IME | Above apps; consume insets |
| System overlays | Volume dialog, power menu | Above system windows |
| Toasts and accessibility overlays | Toasts, accessibility magnifier | Above overlays |
An app cannot place a window above the status bar or the IME.2 That restriction is not a convention; it is enforced by window type, and the type is checked when the window is added. This is why the "draw over other apps" permission exists: it is the exception that lets an app add a window of a higher type.
Layout, insets and the edge-to-edge era#
Layout is the process of turning a set of window records into rectangles. The interesting part is not the arithmetic; it is the constraints.
A status bar at the top consumes a strip. A navigation bar at the bottom consumes another. A display cutout consumes a shape that is not a rectangle. The IME consumes whatever it needs when it appears. Each of those is expressed as an inset, and each window declares which insets it wants to handle itself and which it wants the system to apply on its behalf.
The practical consequence is that WindowInsets is no longer an optimisation for immersive apps. It
is the layout contract. A view that ignores insets in an edge-to-edge world will be drawn under the
status bar or behind the keyboard.
Focus and input#
WMS decides which window has focus, and the input pipeline uses that answer. When a touch arrives,
InputDispatcher (in system_server, fed by the input HAL) asks WMS which window is under the
pointer, then delivers the event to the owning process.
Input regions are not the same as visible regions. A window can be visible and not touchable, or touchable outside its visible bounds — the latter is how some overlays work and is a common source of security bugs.
Talking to SurfaceFlinger#
The WMS/SurfaceFlinger boundary is one of the oldest and most performance-sensitive in the system. It has changed shape several times:
- Originally, WMS called into SurfaceFlinger over Binder for each layer operation.
- Modern Android batches layer state into a transaction, applied atomically at a frame boundary.
- The transaction is now carried over AIDL, which is the same interface language used for HALs.
Batching matters because a frame must be consistent: if the status bar moved but the app window did not, the frame is torn. A transaction applies all the changes together.
Why it lives in system_server#
WMS needs the same information as ActivityTaskManager: which activity is resumed, which task is on
top, which display the user is looking at. Putting them in the same process turns those questions
into field reads. It also means a WMS deadlock takes the whole framework with it — the same
trade-off that keeps the two services fast.
The cost is real. The window manager is one of the largest and most complex pieces of the framework, and its global lock has been a source of jank for years. Modern Android has been steadily shrinking the critical sections and moving work to per-display and per-window structures.
How it evolved#
| API | Version | What changed |
|---|---|---|
| 1 | 1.0 |
|
| 3 | 1.5 Cupcake |
|
| 9 | 2.3 Gingerbread |
|
| 11 | 3.0 Honeycomb |
|
| 12 | 3.1 Honeycomb |
|
| 16 | 4.1 Jelly Bean |
|
| 20 | 4.4W KitKat (Wear) |
|
| 21 | 5.0 Lollipop |
|
| 24 | 7.0 Nougat |
|
| 26 | 8.0 Oreo |
|
| 28 | 9 Pie |
|
| 29 | 10 |
|
| 30 | 11 |
|
| 31 | 12 |
|
| 33 | 13 Tiramisu |
|
| 36 | 16 Baklava |
|
Four eras are worth naming. The early window manager was a simple stack of full-screen windows.
Holo added the system bar as a first-class window. Material Design and the introduction of
WindowInsets made insets a public contract. Android 10's reorganisation moved activity records into
the window manager's package and split ActivityTaskManager out. Android 15 and 16 made edge-to-edge
the default and started enforcing it.
Under the hood#
- WindowManagerService.javathe service: window records, layout, focus and transactions to SurfaceFlinger
- WindowState.javaone window's state: geometry, type, owner, insets
- DisplayContent.javaper-display window hierarchy and layout root
- WindowInsets.javathe public insets type apps consume
Curiosity corner#
- The status bar is not part of your app's window. It is a separate window owned by SystemUI, which is why it can survive your app crashing.
- A dialog is a window, not a view.
Dialogcreates a window of its own and adds it through the window manager, which is why it can be dismissed by a touch outside its bounds. - Screenshots are a window manager operation. The screenshot path asks WMS for the layer composition, then reads the buffers — it does not ask your app to draw itself.
Try it#
adb shell dumpsys window windows | grep -E "Window #|mBaseLayer"
adb shell dumpsys window displays | head -40
Example output
WINDOW MANAGER WINDOWS (dumpsys window windows)
Window #0 Window{8f2a1c u0 StatusBar}:
mDisplayId=0 mBaseLayer=121000
Window #1 Window{3b4d2e u0 com.example.app/com.example.app.MainActivity}:
mDisplayId=0 mBaseLayer=21000mBaseLayer is the z-order. Higher numbers are closer to the viewer, which is why the status bar's
layer is well above an app's.
Check yourself#
Check yourself
How does system_server's process come into existence at boot?
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.
- docsSurfaceFlinger and WindowManagersource.android.comaccessed 2026-10-27↩
- docsLayers and displayssource.android.comaccessed 2026-10-27↩
- docsAndroid platform architecture (AOSP)source.android.comaccessed 2026-10-27↩
- docsWinscopesource.android.comaccessed 2026-10-27↩
- docsDisplay content edge-to-edgedeveloper.android.comaccessed 2026-10-27↩
- docsBehavior changes: Apps targeting Android 16 or higherdeveloper.android.comaccessed 2026-10-27↩