Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions .github/workflows/android-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: Android build

# Compiles Neonwolf for Android (full-source GeckoView + Fenix, arm64) on a
# hosted runner and uploads the APKs as artifacts. This exists because local
# builds OOM the dev box: rustc peaked at ~17GB RSS and the kernel oom-killer
# hung the machine (2026-07-10). Hosted runners have 16GB RAM — the swapfile
# step below absorbs the rustc peak — and the job fits the 6h limit.
#
# Trigger: manual dispatch, or push to an android/** branch.

on:
workflow_dispatch:
push:
branches: ['android/**']

concurrency:
group: android-build-${{ github.ref }}
cancel-in-progress: true

jobs:
build-arm64:
name: GeckoView + Fenix arm64 APK
runs-on: ubuntu-latest
timeout-minutes: 360
steps:
- name: Checkout (with settings submodule)
uses: actions/checkout@v4
with:
submodules: recursive
persist-credentials: false

- name: Free disk space (drop preinstalled toolchains we don't use)
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/usr/local/.ghcup /opt/hostedtoolcache/CodeQL
sudo docker image prune --all --force >/dev/null 2>&1 || true
df -h /

- name: Add 16GB swap (single rustc crate peaks ~17GB)
run: |
# The runner image ships an active 4GB /mnt/swapfile — replace it.
sudo swapoff -a || true
sudo rm -f /mnt/swapfile
sudo fallocate -l 16G /mnt/swapfile
sudo chmod 600 /mnt/swapfile
sudo mkswap /mnt/swapfile
sudo swapon /mnt/swapfile
free -h

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
make python3 python3-pip curl gnupg unzip zip patch xz-utils tar rsync

- name: Ensure rustup (runner images no longer ship Rust)
run: |
if ! command -v rustup >/dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
fi
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"

- name: Read pinned Firefox version
id: ver
run: |
echo "version=$(cat version)" >> "$GITHUB_OUTPUT"
echo "release=$(cat release)" >> "$GITHUB_OUTPUT"

- name: Cache Firefox source tarball
uses: actions/cache@v4
with:
path: firefox-${{ steps.ver.outputs.version }}.source.tar.xz
key: ff-src-${{ steps.ver.outputs.version }}

- name: Fetch Firefox source (curl + gpg verify)
run: make fetch

- name: Extract + apply all patches + Neonwolf overlay (make dir)
run: make dir

- name: Bootstrap Android toolchain (mach bootstrap)
run: |
cd neonwolf-${{ steps.ver.outputs.version }}-${{ steps.ver.outputs.release }}
./mach --no-interactive bootstrap --application-choice=mobile_android
rustup target add aarch64-linux-android

- name: Build (make build-android)
run: make build-android

- name: Collect APKs
run: |
make package-android
ls -lh dist-android/

- name: Upload APKs
uses: actions/upload-artifact@v4
with:
name: neonwolf-android-arm64-${{ steps.ver.outputs.version }}-${{ steps.ver.outputs.release }}
path: dist-android/*.apk
if-no-files-found: error

- name: Upload build log
if: always()
uses: actions/upload-artifact@v4
with:
name: android-build-log
path: android-build.log
if-no-files-found: ignore
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
/neonwolf-*
/docker-dist
*.log
*.nohup.out
android-apk-list.txt
/dist-android
patchfail.out
scripts/__pycache__/
__pycache__/
Expand Down
34 changes: 34 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,40 @@ package :
run :
(cd $(lw_source_dir) && ./mach run)

# --- Android (local full-source GeckoView + Fenix; never artifact mode) ---
# Produces arm64 APK under $(lw_source_dir)/obj-android. Does not push/commit.
# Requires: Android SDK/NDK under ~/.mozbuild, rustup target aarch64-linux-android.
bootstrap-android : $(lw_source_dir)
(cd $(lw_source_dir) && ./mach --no-interactive bootstrap --application-choice=mobile_android) || true
rustup target add aarch64-linux-android x86_64-linux-android || true
mkdir -p $$HOME/.mozbuild/android-device/avd

build-android : $(lw_source_dir)
cp -v assets/mozconfig.android $(lw_source_dir)/mozconfig
@grep -q 'with-android-sdk' $(lw_source_dir)/mozconfig || \
printf '\nac_add_options --with-android-sdk=%s\nac_add_options --with-android-ndk=%s\n' \
"$$HOME/.mozbuild/android-sdk-linux" \
"$$(ls -d $$HOME/.mozbuild/android-ndk-* 2>/dev/null | sort -V | tail -1)" >> $(lw_source_dir)/mozconfig
# Android Gradle computeVersionCode() parseInts each dotted part and dies on
# "$(version)-$(release)" — bake the pure Firefox version for Android builds.
# (A desktop rebuild in this tree shows plain $(version) until the next `make dir`.)
echo $(version) > $(lw_source_dir)/browser/config/version.txt
echo $(version) > $(lw_source_dir)/browser/config/version_display.txt
# Inject Neonwolf GeckoView prefs if not already present in the tree
@if ! grep -q 'Neonwolf Android privacy defaults' $(lw_source_dir)/mobile/android/app/geckoview-prefs.js 2>/dev/null; then \
cat assets/android/neonwolf-geckoview-prefs.js >> $(lw_source_dir)/mobile/android/app/geckoview-prefs.js; \
fi
NEONWOLF_TREE=$(abspath $(lw_source_dir)) \
ANDROID_AVD_PATH=$$HOME/.mozbuild/android-device/avd \
ANDROID_HOME=$$HOME/.mozbuild/android-sdk-linux \
bash scripts/build-android.sh

package-android :
@find $(lw_source_dir)/obj-android -name '*.apk' 2>/dev/null | tee android-apk-list.txt
@mkdir -p dist-android
@find $(lw_source_dir)/obj-android/gradle/build/mobile/android/fenix -name '*.apk' -not -name '*androidTest*' -exec cp -v {} dist-android/ \; 2>/dev/null || true
@find $(lw_source_dir)/obj-android -name '*arm64*.apk' -not -path '*/fenix/*' -exec cp -v {} dist-android/ \; 2>/dev/null || true
@ls -lh dist-android 2>/dev/null || echo "No APKs yet — build still running or failed; see android-build.log"

check-patchfail:
sh -c "./scripts/check-patchfail.sh" > patchfail.out
Expand Down
98 changes: 98 additions & 0 deletions assets/android/neonwolf-geckoview-prefs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// === Neonwolf Android privacy defaults ===
// Appended/injected into mobile/android/app/geckoview-prefs.js at patch time.
// Mirrors the Gecko-shared surface of assets/neonwolf.overrides.cfg + critical
// LibreWolf baseline items that Fenix would otherwise leave open.
// Prefer pref() here (static defaults). Fenix must not clobber these on start.

// --- Branding / support ---
pref("app.support.baseURL", "https://github.com/neon798/neonwolf/");
pref("app.releaseNotesURL", "https://github.com/neon798/neonwolf/releases/");

// --- Native uBO / content-classifier (must init on GV) ---
pref("privacy.trackingprotection.content.protection.enabled", true);
pref("privacy.trackingprotection.content.protection.list_names", "easylist,easyprivacy,peterlowe,ubo-filters,ubo-badware,ubo-privacy,ubo-quickfixes,adguard-mobile,adguard-base,adguard-tracking,neonwolf-extra");
pref("privacy.trackingprotection.defer_annotation_enabled", true);
pref("privacy.trackingprotection.content.network_cancel.enabled", false);
pref("privacy.trackingprotection.ubo.cosmetic.enabled", true);
pref("privacy.trackingprotection.ubo.scriptlet.enabled", false);
pref("privacy.trackingprotection.enabled", true);
pref("privacy.trackingprotection.pbmode.enabled", true);
pref("privacy.trackingprotection.socialtracking.enabled", true);
pref("privacy.trackingprotection.fingerprinting.enabled", true);
pref("privacy.trackingprotection.cryptomining.enabled", true);

// Live list refresh (same contract as desktop)
pref("neonwolf.shields.lists.autoRefresh", true);
pref("neonwolf.shields.lists.refreshIntervalHours", 24);
pref("neonwolf.shields.lists.refreshNow", false);
pref("neonwolf.shields.lists.lastRefresh", 0);
pref("neonwolf.shields.lists.subscriptions", "");

// --- FPP-forward farbling (RFP off) ---
pref("privacy.resistFingerprinting", false);
pref("privacy.fingerprintingProtection", true);
pref("privacy.fingerprintingProtection.remoteOverrides.enabled", false);
pref("privacy.fingerprintingProtection.overrides", "+WebGLRandomization,+WebGLRenderInfo,+NavigatorHWConcurrency,+AudioContext,+AudioSampleRate,+FontVisibilityBaseSystem,+ReduceTimerPrecision");
pref("privacy.spoof_english", 2);
pref("layout.css.prefers-color-scheme.content-override", 2);

// --- DNS-over-HTTPS Mullvad TRR-only ---
pref("network.trr.mode", 3);
pref("network.trr.uri", "https://base.dns.mullvad.net/dns-query");
pref("network.trr.default_provider_uri", "https://base.dns.mullvad.net/dns-query");
pref("network.trr.wait-for-portal", true);
pref("network.trr.skip-address-validation", true);

// --- Credential / autofill: remove, don't manage ---
pref("signon.rememberSignons", false);
pref("signon.autofillForms", false);
pref("extensions.formautofill.addresses.enabled", false);
pref("extensions.formautofill.creditCards.enabled", false);
pref("extensions.formautofill.addresses.supported", "off");
pref("extensions.formautofill.creditCards.supported", "off");

// --- Permissions default block ---
pref("permissions.default.geo", 2);
pref("permissions.default.camera", 2);
pref("permissions.default.microphone", 2);
pref("permissions.default.desktop-notification", 2);

// --- Extra hardening ---
pref("browser.send_pings", false);
pref("network.http.referer.defaultPolicy", 0);
pref("dom.security.https_only_mode", true);
pref("dom.security.mixed_content.block_active_content", true);
pref("webgl.disabled", false);
pref("device.sensors.enabled", false);
pref("dom.battery.enabled", false);
pref("dom.gamepad.enabled", false);
pref("dom.netinfo.enabled", false);
pref("media.peerconnection.ice.no_host", true);
pref("privacy.globalprivacycontrol.enabled", true);
pref("privacy.globalprivacycontrol.functionality.enabled", true);
pref("network.cookie.cookieBehavior", 5);

// --- Safe Browsing: no Google phone-home (malware via uBO lists) ---
pref("browser.safebrowsing.malware.enabled", false);
pref("browser.safebrowsing.phishing.enabled", false);
pref("browser.safebrowsing.downloads.enabled", false);
pref("browser.safebrowsing.provider.google4.enabled", false);
pref("browser.safebrowsing.provider.google5.enabled", false);
pref("browser.safebrowsing.provider.google5.updateURL", "");
pref("browser.safebrowsing.provider.google5.gethashURL", "");

// --- Telemetry / experiments off (belt + suspenders with Lite) ---
pref("toolkit.telemetry.enabled", false);
pref("toolkit.telemetry.unified", false);
pref("datareporting.healthreport.uploadEnabled", false);
pref("datareporting.policy.dataSubmissionEnabled", false);
pref("app.shield.optoutstudies.enabled", false);
pref("browser.discovery.enabled", false);
pref("nimbus.remote-settings.enabled", false);

// --- Clear on shutdown defaults (Fenix also has its own clear-on-exit) ---
pref("privacy.clearOnShutdown_v2.cookiesAndStorage", true);

// RemoteSettings dump allowlist (LibreWolf/Neonwolf rs-blocker)
pref("librewolf.services.settings.allowedCollectionsFromDump", "main/devtools-devices,main/devtools-compatibility-browsers,main/search-config-icons,main/search-config-v2,main/search-config-overrides-v2,main/content-classifier-lists");
pref("librewolf.services.settings.allowedCollections", "security-state/intermediates,security-state/onecrl,security-state/cert-revocations,security-state/message-signatures,main/anti-tracking-url-decoration,main/query-stripping,main/url-parser-default-unknown-schemes-interventions,main/partitioning-exempt-urls,main/url-classifier-skip-urls,main/fingerprinting-protection-overrides,main/translations-models,main/translations-wasm");
56 changes: 56 additions & 0 deletions assets/mozconfig.android
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Neonwolf Android / GeckoView — full source build (NOT artifact mode).
# Artifact mode would pull stock Mozilla Gecko and drop native uBO / content-classifier.
# Keep desktop mozconfig untouched; this file is copied to the tree as mozconfig
# only for Android builds (see Makefile android targets).

# Separate objdir so we never clobber the desktop Linux build.
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-android

ac_add_options --enable-project=mobile/android

# arm64 first for physical devices; also build x86_64 for emulator later via
# a second mozconfig if needed. Default host-arch is fine for emulator smoke;
# pin aarch64 for phone APKs.
ac_add_options --target=aarch64

# NOTE: --enable-geckoview-lite was dropped: Fenix consumes the full GeckoView
# artifact (its Glean integration expects it; lite is for third-party
# embedders). Telemetry is disabled via geckoview-prefs + the Fenix
# liberation work instead.

# End product: Fenix shell. For earliest engine smoke use:
# ac_add_options --enable-android-subproject=geckoview_example
ac_add_options --enable-android-subproject=fenix
# Allow attach/debug on release-optimized GV (local night builds)
ac_add_options --enable-android-debuggable

ac_add_options --disable-crashreporter
ac_add_options --disable-debug
ac_add_options --disable-tests
ac_add_options --disable-updater
ac_add_options --disable-cargo-incremental
ac_add_options --enable-hardening
ac_add_options --enable-optimize
ac_add_options --enable-release
ac_add_options --enable-rust-simd
ac_add_options --enable-bootstrap

ac_add_options --with-app-name=neonwolf

# Branding: desktop branding path may not apply 1:1 on mobile; Fenix branding
# is patched under mobile/android. Keep name identity here for Gecko strings.
# ac_add_options --with-branding=mobile/android/branding/neonwolf

export MOZ_TELEMETRY_REPORTING=
export MOZ_REQUIRE_SIGNING=
export MOZILLA_OFFICIAL=1

mk_add_options MOZ_CRASHREPORTER=0
mk_add_options MOZ_DATA_REPORTING=0
mk_add_options MOZ_SERVICES_HEALTHREPORT=0
mk_add_options MOZ_TELEMETRY_REPORTING=0

# Toolchain roots (mach bootstrap installs these under ~/.mozbuild).
# Override if your SDK/NDK live elsewhere.
# ac_add_options --with-android-sdk=$HOME/.mozbuild/android-sdk-linux
# ac_add_options --with-android-ndk=$HOME/.mozbuild/android-ndk-r29
1 change: 1 addition & 0 deletions assets/patches.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ patches/vendor-name.patch
patches/webgl-permission.patch
patches/windows-theming-bug.patch
patches/xdg-dir.patch
patches/android/fenix-neonwolf-appid.patch
Loading
Loading