Documentation · Installation guide · Glossary · Troubleshooting
This manual covers daily operation after installation. Follow the installation guide first if Debian and SSH are not configured.
The app separates routine work into three destinations.
| Destination | What belongs there |
|---|---|
| Home | Initial installation, automatic startup, and server controls |
| Access | SSH keys and local debian/root passwords |
| Advanced | USB, hardware codecs, cgroups, Docker, diagnostics, and removal |
Every switch, radio choice, and USB ID field follows one rule: edit it, then tap the global Apply bar above the navigation. The bar appears only when the screen differs from the active configuration. DawnShell saves all pending choices together and, when runtime policy must change, stops and starts a running Debian server at most once. Install, start, stop, tests, key export, and password changes are commands, so their own buttons still act immediately.
- BFU means Before First Unlock; AFU means After First Unlock.
- DawnShell starts Debian systemd and SSH during BFU.
- The same instance remains running after unlock.
- Debian shares the Android kernel and network and is not a fully isolated VM.
See the glossary for DE, CE, PID, rootfs, and other terms, or read Google's Direct Boot guide.
Enable Direct Boot Debian bootstrap controls automatic startup on the next cold boot. After changing it, tap the global Apply button.
Request / verify Magisk root permission checks current root access. Magisk must grant permanent approval because BFU cannot display a prompt.
Refresh BFU probe results reads evidence from the last locked boot; it does not rerun the probe while Android is unlocked.
Keep the BFU CE-readable override disabled on a normal FBE device. It accepts an already unsafe ROM condition; it does not repair encryption.
Install Debian 13 Trixie rootfs creates /data/local/debian without silently
overwriting a valid installation. Configure Debian 13 systemd + SSH prepares
systemd, D-Bus, OpenSSH, the debian account, the current public key, and boot
proof services. Both operations run only after Android is unlocked.
Configuration automatically assigns Android Internet GID 3003 to _apt when
needed and repairs interrupted dpkg work inside the correctly mounted private
configuration namespace before downloading packages.
If only _apt encounters a network permission error on a LineageOS device,
follow the LineageOS apt network-permission guide.
This is distinct from a missing route or broken DNS.
- Start: validate and start Debian systemd.
- Restart: gracefully stop and start a new instance.
- Status: check systemd, D-Bus, SSH, TCP 22, and cgroups.
- Stop: stop Debian services and SSH.
Unlocking Android never stops the running server.
For another computer, export the SSH private-key file:
chmod 600 dawnshell-ed25519
ssh -i ./dawnshell-ed25519 -p 22 debian@PHONE_IPFor a trusted local shell on the phone, run the copied local-shell key import command once, then run the copied SSH connect command. The import command contains the complete private key, so file export is safer.
Generating a new random client key permanently replaces the old identity. Back up the old key, generate the replacement, rerun systemd + SSH configuration, export the new key, and verify it before deleting old copies.
The app can set local debian and root passwords. Passwords are passed directly
to Debian and are not stored in app settings, DE storage, or logs. SSH password
authentication remains disabled.
After connecting as debian:
su rootEnter the root password configured in the app. This root shell can affect the Android device, so run only trusted commands.
To reboot the entire Android device:
reboot --check
reboot nowsystemctl reboot is a namespace-isolation test path, not the Android reboot
command.
This reboot command is the only way to restart Android. Debian and the
containers it runs cannot ask the kernel to reboot directly, because some
kernels do not confine such a request to the container and restart the whole
device instead. That is what can otherwise reboot the phone when a Docker
container starts or is cleaned up.
USB passthrough is disabled by default. Choose a mode and tap the global Apply button. DawnShell combines this with pending cgroup and Docker changes; a running Debian is restarted at most once, while a stopped Debian uses the policy on its next start. USB Ethernet does not require this setting because Debian already shares Android's network namespace.
On old kernels, Debian 13 lsusb -t may query newer rx_lanes and tx_lanes
sysfs attributes that do not exist. DawnShell installs a managed compatibility
wrapper when the USB policy is applied. It suppresses only those expected
ENOENT messages and preserves other USB diagnostics.
- Direct passthrough exposes
/dev/bus/usb, propagates hot-plug, and leaves Android kernel drivers attached. Use this first for ordinary libusb inspection. - Exclusive passthrough also unbinds every interface belonging to a device
whose exact
VID:PIDis listed. Use commas or spaces, such as0403:6001, 10c4:ea60. At least one ID is mandatory. DawnShell scans for new matching devices and tries to restore detached drivers when Debian stops.
The Off setting is specifically a raw USBFS policy: it masks
/dev/bus/usb and denies character-device major 189. It does not stop Android's
kernel from enumerating USB hardware, so shared sysfs may still show the device.
Kernel drivers can also expose derived resources such as /dev/block/sd*, USB
Ethernet, ttyUSB/ttyACM, input, video, or audio nodes. Those resources are
outside the raw USBFS policy and require separate device-class isolation.
Inside Debian, inspect a connected device with:
ls -l /dev/bus/usb/*/* 2>/dev/null
lsusb 2>/dev/null || true
dmesg | tail -n 100USB serial, storage, camera, audio, and input support still require the matching
Android kernel support. SELinux may deny access even to root. Exclusive mode can
disconnect Android input, storage, networking, ADB, or recovery access. Use a
disposable peripheral and independent recovery path; after an abnormal exit you
may need to unplug it or reboot. Never select the phone's internal USB/gadget
controller, and never mount one USB storage filesystem from both systems. A
Docker container must receive the node separately with --device; avoid
--privileged.
For complete commands, automatic integration, audio remuxing, and fallback rules, see the FFmpeg hardware codec guide.
Upstream FFmpeg spellings such as -hwaccel mediacodec and
-c:v h264_mediacodec work as well. Naming MediaCodec explicitly makes
hardware mandatory, so the command fails instead of silently using libx264.
See
Upstream FFmpeg MediaCodec syntax compatibility.
Debian can run H.264/HEVC encoding and decoding on the device's dedicated video codec instead of the CPU. This is not GPU passthrough: Debian only demuxes and muxes containers, while an on-demand bionic NDK worker performs the codec work and returns the result through inherited shared descriptors.
- Turn on Enable hardware codec bridge at Direct Boot.
- Press the global Apply button.
- Press Check hardware codecs.
- Run Configure Debian 13 systemd + SSH again.
- Press Download and run file-based hardware AVC decode self-test.
- Run
sudo dawnshell-codec health --format jsonin Debian.
Configuration installs these commands in Debian.
| Command | Purpose |
|---|---|
dawnshell-ffmpeg |
Accepts ordinary FFmpeg command lines and routes them automatically |
dawnshell-hwdecode |
H.264/HEVC decoding |
dawnshell-hwencode |
Encodes raw I420 to H.264/HEVC |
dawnshell-hwtranscode |
Re-encodes H.264/HEVC to H.264 |
dawnshell-live-encode |
Live AVC encode from a USB webcam, HLS, RTSP, or file input |
dawnshell-codec-self-test |
Verifies the bridge |
gsmi |
Separates 3D GPU state from DawnShell codec activity |
The app's file-backed hardware AVC decode self-test installs wget and
ca-certificates with Debian apt when needed, then downloads the 1920x1080
H.264 Big Buck Bunny sample from test-videos.co.uk inside Debian. Android reads
the staged DE file directly with MediaExtractor and a conservatively selected
hardware MediaCodec. This app-local test uses no interprocess media transport;
the report must show interprocess_media_bytes=0. The first run can take longer
because it installs packages and downloads about 5 MB.
dawnshell-codec-self-test remains the separate advanced private-worker test.
If the file-backed test passes while that command fails, the failure is isolated
to worker launch or inherited memfd/eventfd transport rather than codec
availability.
dawnshell-ffmpeg takes the same arguments as ffmpeg. Commands the bridge can
reproduce exactly run on hardware; everything else is handed to the real FFmpeg
unchanged, so a filter or option is never silently dropped.
dawnshell-ffmpeg -i input.mp4 -c:v libx264 -b:v 3M output.mp4
dawnshell-ffmpeg -i input.mp4 output.yuvDebian configuration enables the managed /usr/local/bin/ffmpeg integration by
default. Inspect, disable, or enable it without editing the symlink manually:
dawnshell-ffmpeg-integration status
sudo dawnshell-ffmpeg-integration disable
sudo dawnshell-ffmpeg-integration enable
hash -rBecause /usr/local/bin precedes /usr/bin, programs that call ffmpeg by name
find the bridge. A program that executes /usr/bin/ffmpeg always bypasses it.
Override the behaviour with an environment variable.
| Value | Behaviour |
|---|---|
auto (default) |
Hardware when possible, otherwise software |
off |
Always use the real FFmpeg |
require |
Fail instead of falling back to software |
DAWNSHELL_FFMPEG_BRIDGE=require dawnshell-ffmpeg -i input.mp4 -c:v libx264 out.mp4Use require when benchmarking so a silent software fallback cannot be mistaken
for a hardware result.
- A single H.264 or HEVC video input.
- A supported AVC/HEVC MediaCodec output spelling, a compatible AVC alias, or a
raw
.yuv/.i420output. - Even dimensions between 16 and 4096.
-b:vwithin 1000..100000000.
These fall back to software: filters such as -vf, x264-specific options such as
-crf and -preset, multiple inputs, audio encoding/filtering, -c:v copy, and
codecs such as VP9 or AV1. ByteBuffer hardware encode can preserve the first
optional audio stream with -c:a copy.
sudo ffmpeg -y -i input.mp4 -c:a copy \
-c:v h264_mediacodec -b:v 4M output.mp4See live HLS and USB-webcam encoding for streaming examples. Monitor an active job from another shell with:
gsmi --loop 1sudo dawnshell-codec health --format json
sudo dawnshell-codec-self-testThe reported backend names the codec that was actually selected. A software codec is never chosen silently; the bridge fails with a clear error instead. A codec failure never stops Debian or SSH.
If codec sessions fail during BFU, Android media services may not be ready yet. Retry after unlocking to compare.
Keep the recommended Automatic: cgroup v2 → v1 fallback unless diagnosing a specific kernel. Automatic mode adopts v2 only after a private delegated subtree and device-BPF probe both succeed; it cleans the probe state before falling back to v1. Force-v2 can prevent Debian from starting, while force-v1 is a legacy diagnostic path. The selection applies on the next Debian start or restart.
The safe starting policy is Safe host network only:
docker info --format '{{.CgroupDriver}}'
docker run --rm --network host hello-worldThe cgroup driver should be cgroupfs. DawnShell keeps Docker inside its
delegated hierarchy instead of asking Android-side systemd compatibility code to
create transient container scopes.
Use host IPC for containers is enabled by default. Some kernels panic during private IPC namespace or mqueue setup. DawnShell blocks that dangerous creation, and the managed wrapper:
- adds
--ipc=hosttodocker runanddocker createwhen IPC was not given; - creates a temporary per-service
ipc: hostoverride fordocker compose; - preserves every explicit
--ipcoripc:value.
Host IPC weakens isolation by sharing IPC objects among Android, Debian, and the container. Do not use it for untrusted containers. Tap the global Apply button after changing the option.
Bridge modes can alter Android-global firewall, NAT, forwarding, and routes and disconnect Wi-Fi, mobile data, USB Ethernet, VPNs, Tailscale, or SSH. Prepare an independent recovery path first. See Docker troubleshooting for common kernel errors.
The Logs screen provides app operations, Debian installation, system configuration, USB, hardware codecs, compatibility, lifecycle, and Direct Boot diagnostics. Readers refresh once per second and support scrolling, selection, and copying. Do not add private keys or passwords when sharing a log.
The SSH server listens on TCP 22 even before Android assigns an address. When Android later brings up Wi-Fi, mobile data, or USB Ethernet, no Debian restart is required.
ssh -i ./dawnshell-ed25519 -p 22 debian@PHONE_IPTreat tailscaled.state as a device credential available before PIN entry. Do
not store reusable authentication keys in the BFU rootfs.
After system configuration, DawnShell places a croc compatibility wrapper in
/usr/local/bin. Explicit send files and receive codes automatically ignore an
idle non-TTY stdin, while printf 'data' | croc send keeps upstream's piped
transfer behavior. See croc troubleshooting
for diagnostics and the /usr/bin/croc bypass.
Back up the exported SSH client key, important Debian configuration and user data, package lists, and service configuration.
To remove Debian completely, stop it, confirm systemd is absent, open the danger
zone, choose permanent rootfs removal, complete both confirmations, type
DELETE, and verify DEBIAN_ROOTFS_REMOVE_SUCCEEDED. Then uninstall DawnShell
from Android settings if desired.
The separate troubleshooting guide provides ordered checks for boot, root, installation, SSH, networking, Docker, USB, and codecs. Include the relevant complete live log, Android version, CPU ABI, BFU/AFU state, and selected options in a report.