Skip to content

Chromium Customization for Kiosk

Warmwind runs a customized Chromium in kiosk mode on Sway, rendering each AI agent's UI. This article covers Chromium's multi-process architecture, the Ozone abstraction for Wayland, kiosk flags, CEF embedding, building from source, and how Brave/ungoogled-chromium patch upstream.

Multi-Process Architecture

graph LR
    Browser["Browser"] --> GPU["GPU"]
    Browser --> R1["Renderer 1"]
    Browser --> R2["Renderer 2"]
    Browser --> Util["Utility"]
Process Sandbox Role
Browser None (privileged) Tab management, navigation, IPC routing
Renderer seccomp-bpf + namespaces HTML/CSS/JS per site instance
GPU Namespace sandbox All GL/Vulkan calls, compositing
Utility Varies Codecs, network service

For kiosk: typically one renderer process (single origin) and one GPU process.

Ozone Platform Abstraction

Ozone decouples Chromium from the display server. At build time you select backends; at runtime --ozone-platform= picks one:

Platform Backend
wayland wl_surface, linux-dmabuf, xdg-shell
x11 X11 (legacy)
headless Off-screen rendering
drm Direct KMS (ChromeOS)

Wayland backend uses linux-dmabuf-unstable-v1 for zero-copy buffer sharing with the compositor and xdg-shell for window management.

Kiosk Command-Line Flags

chromium \
    --kiosk \                          # fullscreen, no UI chrome
    --ozone-platform=wayland \         # Wayland backend
    --noerrdialogs \                   # suppress error popups
    --disable-extensions \             # no extension loading
    --disable-translate \              # no translate bar
    --disable-infobars \               # no info bars
    --disable-session-crashed-bubble \ # no crash recovery UI
    --disable-component-update \       # no background updates
    --autoplay-policy=no-user-gesture-required \
    --no-first-run \                   # skip first-run wizard
    --start-maximized \                # fallback if --kiosk fails
    --disable-features=TranslateUI \
    "https://agent.warmwind.internal"

Additional flags for hardened environments:

    --disable-gpu-sandbox \            # if GPU sandbox conflicts with container
    --enable-features=UseOzonePlatform \
    --disable-dev-shm-usage \          # use /tmp instead of /dev/shm (containers)
    --user-data-dir=/tmp/chromium      # ephemeral profile

CEF (Chromium Embedded Framework)

CEF wraps Chromium's content layer into a C/C++ library for custom browsers:

// Minimal CEF kiosk browser
class KioskClient : public CefClient, public CefLifeSpanHandler {
    CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override {
        return this;
    }
    void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
        // Browser window created -- go fullscreen
    }
    bool DoClose(CefRefPtr<CefBrowser> browser) override {
        return false;  // prevent closing
    }
    IMPLEMENT_REFCOUNTING(KioskClient);
};

CEF advantages: stable API across Chromium versions, fine-grained control over navigation, JavaScript bindings, no address bar code to strip.

Building Chromium from Source

# ~30GB source, ~4 hours build on 16-core
fetch --nohooks chromium
cd src && gclient sync

# GN build configuration
cat > out/Release/args.gn << 'EOF'
is_official_build = true
is_debug = false
target_os = "linux"
ozone_platform_wayland = true
ozone_platform_x11 = false
ozone_auto_platforms = false
use_system_minigbm = true
enable_nacl = false
is_component_build = false
EOF

gn gen out/Release
autoninja -C out/Release chrome    # ~16,000 build targets

Key GN variables for Warmwind: ozone_platform_wayland, use_system_minigbm, enable_vulkan, proprietary_codecs.

Brave's Patching Approach

Brave builds on top of upstream Chromium using chromium_src overrides:

brave/chromium_src/chrome/browser/ui/views/frame/browser_view.cc

If this file exists, the build system compiles it instead of the upstream file. Conditional compilation:

#if BUILDFLAG(BRAVE_CHROMIUM_BUILD)
    // Brave-specific behavior
#else
    // Upstream Chromium behavior
#endif

Brave also patches via brave/patches/*.patch (applied during gclient sync). This approach minimizes merge conflicts on Chromium rebases.

ungoogled-chromium's Approach

Different philosophy: no forked source, only:

  1. Config flags (user_flags.gn): disable Google services at build time.
  2. Patch series: patches/core/*.patch applied in order.
  3. Pruning list: files deleted before build (telemetry, updater).

Warmwind can adopt this model: maintain a small patch set on top of upstream Chromium releases, rebuild per release cycle.

systemd Unit for Kiosk Chromium on Sway

[Unit]
Description=Kiosk Chromium on Sway
After=sway.service
Requires=sway.service

[Service]
Type=simple
User=kiosk
Environment=WAYLAND_DISPLAY=wayland-1
Environment=XDG_RUNTIME_DIR=/run/user/1000
ExecStart=/usr/bin/chromium \
    --kiosk \
    --ozone-platform=wayland \
    --noerrdialogs \
    --disable-extensions \
    --user-data-dir=/tmp/chromium-kiosk \
    https://agent.warmwind.internal
Restart=always
RestartSec=3

# Hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
SystemCallFilter=@system-service

[Install]
WantedBy=graphical.target
What's new (2025–2026)
  • Rust in Chromium: production Rust components now ship -- crabbyavif (AVIF image decoder) and a QR code generator, with more on the way.
  • WebDriver BiDi shipping across Selenium, Cypress, and Puppeteer as the successor to the Chrome DevTools Protocol (CDP).
  • Chrome 132 removed old headless mode; --headless=new is now the only headless option (full browser rendering, not the old minimal path).

Glossary

Ozone
Chromium's platform abstraction layer. Selects display backend (Wayland, X11, DRM) at build or runtime.
CEF (Chromium Embedded Framework)
Library wrapping Chromium's content layer for embedding in custom applications.
GN
Chromium's meta-build system generating Ninja files. Replaced GYP.
Ninja
Fast build system consuming GN-generated files. autoninja auto-selects parallelism.
chromium_src override
Brave's mechanism: drop a file in brave/chromium_src/ to replace the upstream equivalent.
linux-dmabuf
Wayland protocol for zero-copy buffer sharing via dma-buf file descriptors.
kiosk mode
Chromium mode hiding all UI chrome (address bar, tabs, menus) and going fullscreen.