An Android browser that compiles Gecko from source and applies LibreWolf's patch set and privacy configuration, sharing both with the desktop build rather than patching a prebuilt Fennec.
Redoubt is a fork. It is not the LibreWolf project and is not endorsed by it.
The privacy configuration is LibreWolf's work and the MPL grants their code, not
their name — read IDENTITY.md before touching anything that names
the project.
This directory is the work plan and the record of what has been done against it.
Looking for the browser itself? Start at the repository README;
beta APKs are on GitHub Releases.
The status paragraphs below are a dated 2026-08-22 snapshot; later status is in
STATUS.md and BETA.md.
Status: M0 and M1 complete, M2 done, M3/M4 well advanced. Gecko builds from
source for aarch64-linux-android with the full patch set and every hardening flag
intact; a three-ABI fat AAR and an installable APK exist and run our GeckoView
(verified from the packaged omni.ja, not inferred).
A fresh release build from current HEAD now validates the core claims.
lw-fresh-2026-08-22 (HEAD 5d8af8f, built 2026-08-22) is built from the
full assets/patches/android.txt (42 patches, verified byte-for-byte) with
R8 on. Measured on it (release, x86_64): 0 GMS and 0 Adjust dex strings
(both removed); for Glean, the generated metrics classes remain (475
GleanMetrics in the dex) but the upload path is gone
(org.mozilla.components.service.glean = 0, GleanHelper = 0) — the metrics
definitions stay, the thing that would send them does not; 14 first-run network
events over 4 Mozilla hostnames (down
from 27 on the partial-patch-set lw-m3-08), and lockPref("librewolf.cfg.version")
from common.cfg:68 present at runtime and locked — so the packaged
configuration is now applied. PRIVACY-BASELINE-2026-08-21.md
keeps the earlier lw-m3-08 baseline this supersedes; the 2026-08-22 build's
numbers and reproducing commands are in ~/lw-fresh-2026-08-22/measurements-2026-08-22.md.
Re-checked against this build: LW-M4-05's --check-no-gms gate now passes —
the zero-GMS result is a real removal (0 com/google/android/gms dex strings,
verified on a build that boots), not the R8-deletion artefact that LW-M4-16's
earlier "zero-GMS" was. LW-M4-16 is now closed: its two residual strings are
gone (GMS = 0), so the allowlist it was hardening is unnecessary — the gate holds
on its own. Still not done: the UI still says "Firefox" (LW-M4-12); and nothing
is signed or distributed.
78 patch files: 24 common, 36 desktop, 18 android.
Not done: the UI still says "Firefox" (LW-M4-12), and nothing is signed or
distributed. (LW-M3-10's common+android composition is now proven on the running
lw-fresh-2026-08-22 build — the packaged cfg loads and the common.cfg:68
canary is locked at runtime.)
| file | what it is |
|---|---|
HANDOVER.md |
start here — current state, open blockers, how work has actually failed here |
IDENTITY.md |
this is a fork, not the LibreWolf project, and what that constrains |
ROADMAP.md |
the shape: strategy, milestones, what we can and cannot promise |
AGENTS.md |
the rules: how to claim a task, ownership, the five landmines |
tasks.yaml |
the board: every task with dependencies, acceptance criteria, verify commands |
PATCH-SCOPE.md |
which patches reach Android — reviewed, one justification per patch |
BUILD.md |
how to reproduce the Android Gecko build |
TRACK.md |
the esr153 decision, with the rebase and security-latency numbers |
UPSTREAM-REPORTS.md |
three defects found in LibreWolf's build, worth reporting back |
STATUS.md |
what is landed versus verified at the last checkpoint |
board.py |
validator and query tool for the board |
python3 docs/android/board.py --check # board integrity — must be green
python3 docs/android/board.py --check-scope # patch lists vs PATCH-SCOPE.md
python3 docs/android/board.py --diff-mozconfig # no hardening flag silently dropped
python3 scripts/lint-patch-scope.py # no patch in a list that cannot build it
./scripts/check-patchfail.sh # every patch still applies
python3 docs/android/board.py --ready --done <finished task ids>All five gates above are green on the current tree. --ready takes the tasks
already finished and prints what that unblocks.
Two of the completed M0 tasks fix the desktop build and are worth landing on
their own, independently of Android: LW-M0-04 pinned the l10n fetch, which was
pulling an unverified refs/heads/main into every release build, and LW-M0-11
fixed check-patchfail, which silently reported success when a patch's target file
was missing.
The board is written to be executed by several people or agents at once, so every
task declares which files it owns. board.py --check refuses a board where two
tasks in the same dependency wave write the same file, or where two patches in the
same wave edit the same file in the extracted source tree. That check is the reason
the dependency graph has edges that look redundant — several of them exist purely
to serialise writes to scripts/librewolf-patches.py and the patch lists.
Every task carries a verify command that a fresh agent can run, and acceptance
criteria written against observable behaviour rather than code inspection. In M4
especially, "verify" means a network capture or a dexdump of the built APK, because
a grep over sources does not prove a telemetry SDK is gone.
Applying webgl-permission.patch's common half to Android compiles
librewolf.webgl.prompt as true, which makes every WebGL context fail silently —
no crash, no console error — because the code that would answer the prompt lives in
the browser/ half Android never receives. A build with this bug installs, browses,
and passes any smoke test that does not specifically check for a live WebGL context.
That is landmine L1 in AGENTS.md, and it is representative: the
failure modes in this port are quiet ones. The board is built around catching them.
See STATUS.md for what is landed versus verified. tasks.yaml is
the source of truth for the board and should be edited in the same commit as the
work it describes.