Last updated: 2026-10-01 (APK rebranded to New Moon — package org.palemoon.community, label "New Moon", newmoon-52.6.0 APK — installs and launches on an Android 34 emulator; XRE_mainRun reaches steady state with the Fennec XUL chrome parsed and XBL-cached; content page loads are not yet confirmed to execute — see below).
- Historical source recovered.
vendor/uxp-android/was extracted from UXP @63295d0087eb58a6eb34cad324c4c53d1b220491— confirmed to contain the full pm4a surface:mobile/android(incl.geckoview/, brandingofficial/unofficial),widget/android,mozglue/android,gradle/,build/mobile,build/annotationProcessors,hal/android,dom/system/android,dom/gamepad/android,dom/media/platforms/android,dom/plugins/base/android,dom/xbl/builtin/android,image/decoders/icon/android,media/libyuv/util/android,media/webrtc/trunk/build/android. - Android triples canonicalize.
build/autoconf/config.subnow mapsaarch64-linux-android,arm-linux-androideabi, etc. (patch 0002). - NSPR cross-builds. With
patches/0001-nspr-modern-android-ndk.patchapplied and Android NDK r27,nsprpubconfigures and compiles foraarch64-linux-android(API 21). Output:libnspr4.so,libplc4.so,libplds4.so— ELF 64-bit ARM aarch64 shared objects. Reproduce:scripts/build-nspr-android.sh. - Full-tree
./mach configurecompletes for--enable-application=mobile/android --target=aarch64-linux-androidwith--enable-noncomm-build --enable-default-toolkit=cairo-android, NDK r27.2 (unified LLVM toolchain, API 21), Android SDK 34 (build-tools 34.0.0: aapt/aapt2/d8/aidl/zipalign/apksigner), JDK 17. Reproduce:cp mozconfig/mozconfig.android-aarch64 upstream/uxp/mozconfig,export ANDROID_HOME=<sdk> ANDROID_NDK=<sdk>/ndk/27.2.12479018, thencd upstream/uxp && ./mach configure. 917 moz.build files read, 6206 descriptors, RecursiveMake + FasterMake backends generated. ./mach buildcompletes end-to-end. All C++ (incl.libxul.so, ~19 MB),libmozglue.so(shared, withBionicGlue.cpp), and all Java jars (gecko-browser, gecko-util, geckoview, sync/etc. restored from mozilla/gecko-dev esr52, stumbler, bouncer, constants, thirdparty) compile for aarch64-android. Fennec JNI wrappers were regenerated viamake -C obj-android-aarch64/mobile/android/base FennecJNIWrappers.cppthenmake update-fennec-wrappers../mach packageproduces a signed, installable APK:upstream/obj-android-aarch64/dist/newmoon-52.6.0.linux-android-aarch64.apk(~33 MB, 1536 entries). Verified by inspection:lib/arm64-v8a/:libmozglue.so,libplugin-container.so(Fennec layout: only the custom-linker loader libs live under lib/).assets/arm64-v8a/:libxul.so+ all NSS/NSPR/sqlite/etc. — extracted and loaded at runtime by mozglue's custom linker.classes.dex(~7.5 MB, produced by d8),assets/omni.ja(~6.4 MB, includeschrome/chrome/content/browser.xul+ 38 XUL/XBL files — the full Fennec XUL frontend), 1183res/drawables.apksigner verify --verbose --print-certs: Verifies with v1+v2+v3 schemes (CN=Android Debug cert from~/.android/debug.keystore).- aapt badging: package
org.palemoon.community, versionName52.6.0, minSdk 15, targetSdk 23; application-label "New Moon".
- Restores
build/autoconf/android.m4(modernized):MOZ_ANDROID_NDK,MOZ_ANDROID_CPU_ARCH,MOZ_ANDROID_SDKrewritten for unified LLVM NDK- modern SDK layout (d8/aapt2,
emulator/dir); legacy support-AAR checks are gated off (those deps will come from androidx/Gradle later).
- modern SDK layout (d8/aapt2,
- Restores ~20 Android hunks in
old-configure.in(toolchain flags, MOZ_LINKER, hash-style sysv, ANDROID_PACKAGE_NAME, gamepad, mozglue, TK_CFLAGS forandroidwidget toolkit,MOZ_ANDROID_SDK(34)formobile/android). - Restores moz.build Android frontend machinery:
ANDROID_RES_DIRS,ANDROID_EXTRA_RES_DIRS,ANDROID_ASSETS_DIRS,ANDROID_EXTRA_PACKAGES,ANDROID_GENERATED_RESFILES,ANDROID_APK_NAME,ANDROID_APK_PACKAGE,ANDROID_INSTRUMENTATION_MANIFESTSincontext.py/data.py/emitter.py/recursivemake.py. constants.py:Androidadded toOSenum (required for--enable-default-toolkit=cairo-android).java.configure:javahoptional (removed in JDK 10+);javac_versiondecoded as text.icu.m4: accepts clang as the ICU assembler (unified NDK has no GNU as and no yasm target flags on aarch64).config/external/moz.build:modules/xz-embeddedbuilds whenMOZ_LINKER(mozglue/linker needs it for szip APK decompression).dom/base/moz.build,toolkit/modules/moz.build: Android provides its ownSiteSpecificUserAgent.js/LightweightThemeConsumer.jsm— gated like 2019'sMOZ_FENNECguards.mobile/android: GCM default off (no Play Services yet);MOZ_NATIVE_DEVICESunset; deadimply_options removed; deadmozilla.dtdlocale entries removed.- New file
build/autoconf/android.m4andgradlewshim live undervendor/uxp-android/(applied by overlay).
mozglue/build/moz.build: buildslibmozglue.soas a shared library on Android (was WINNT/Darwin only) and addsBionicGlue.cpp.upload-files.mk:MOZ_PKG_FORMAT = APKfor the android widget toolkit;upload-files-APK.mkrestored to vendor — drivesmozbuild.action.package_fennec_apk.old-configure.in:OMNIJAR_NAME = assets/omni.jawhenMOZ_BUILD_APP=mobile/android(required by the APK packager).config/makefiles/java-build.mk+mobile/android/base/Makefile.in(vendor): dexing switched from dx to d8 (build-tools 34 has no dx; d8 needs an existing output dir and jar/class-file inputs).config/android-common.mk(vendor):RELEASE_SIGN_ANDROID_APKnow does zipalign thenapksigner signwith the standard debug keystore (v1+v2+v3); the old jarsigner path produced APKs that failapksigner verifyon API 15–20.mobile/androidproguard cfgs (vendor):-dontwarn com.google.android.gms.**(play-services-ads 8.4.0 references WebSettings AppCache APIs removed in API 28).python/mozbuild/mozpack/files.py,recursivemake.py,emitter.py,generate_browsersearch.py: py3 str/bytes fixes for the packaging path.config/config.mk:-static-libstdc++forOS_TARGET=Android— the custom linker loads packaged .so files itself, so nothing may needlibc++_shared.so(same approach as the 2019 port).mobile/android/installer/package-manifest.in(vendor):libhunspell.soadded toassets/— it is aNEEDEDdep of libxul and its absence aborted the libxul load.mozglue/linker/XZStream.cpp:ParseUncompressedSize()now sums all index records instead of reading only the first. Modernxz -Twrites multi-block streams (4 blocks for libxul); only the first block's size was used, producing a 25 MB cache file for an 80 MB libxul → SIGBUS on segment mapping. Fixed file now decompresses fully (verified in logcat:XZStream decoded 80352792).mozglue/linker/Elfxx.h: aarch64R_AARCH64_ABS64/GLOB_DAT/JUMP_SLOT/ RELATIVEconstants for the custom linker.- Remaining C++ interface fixes across
dom/plugins/ipc,ipc/chromium,hal,widget,gfx,netwerk,security,toolkit,xpcom,memory/jemalloc,mozglue/linkerto reconcile the 2019 Android code with current UXP. - API-34 javac collisions renamed in vendor:
RemotePresentationService.getDeviceId()→getPresentationDeviceId()(clashes withContextWrapper.getDeviceId():int), andBouncerService.getDataDir()→getAppDataDir()(clashes withContext.getDataDir():File).
- Android SDK 34 + NDK
27.2.12479018, JDK 17. - ProGuard is no longer in the SDK. A 6.2.0
proguard.jarmust be at$ANDROID_HOME/tools/proguard/lib/proguard.jar(obtained here from the Ubuntulibproguard-javadeb). ~/.android/debug.keystore(aliasandroiddebugkey, passandroid) is created automatically by the signing rule if absent.- Vendored AARs under
$ANDROID_HOME/extras/{android,google}/m2repository/(incl. play-services-*-8.4.0) — seescripts/for install steps.
AVD nocturne-emu (google_apis x86_64, abi list includes arm64-v8a via
ndk_translation). No /dev/kvm → TCG software CPU, cold boot ~8 min.
adb install -r dist/newmoon-52.6.0.linux-android-aarch64.apk: succeeds (adb installitself is flaky on this emulator;adb pushto/data/local/tmp/+pm install -ris reliable).am start -n org.palemoon.community/.App: the app launches. Java frontend verified working end-to-end: LauncherActivity → BrowserApp, profile migration, preferences, network listener, search engine manager, and the home screen UI renders (GLES/EGL).- mozglue's custom linker on aarch64 works: decompresses every xz'd
library (incl. 80 MB libxul), resolves all relocations
(
ABS64/GLOB_DAT/JUMP_SLOT/RELATIVE), loads NSS/NSPR/sqlite/hunspell/etc., and begins running libxul's C++ static initializers. MOZ_LINKER_ONDEMAND=0(eager page mapping) is required on this emulator — without it the run dies earlier withSEGV_ACCERRon the main thread; the fault-handler-based lazy-page path is untested on real arm64 hardware.- The app reaches steady state.
XRE_mainRuncompletes end to end: omni.ja component/xpt registration, directory-provider startup, chrome manifest registration, profile prefs,profile-after-change, chrome window creation viansWindowWatcher::OpenWindow(browser.xulloads —nsWebShellWindow::JustCreateWebShell→ docshell →CreateAboutBlankContentViewer→ XPConnect globals wrapped →loadURIrv=0), hidden window,final-ui-startup,appstartup-run, and the Gecko event loop then idles inepoll_wait. Verified on cold (pm clear) and warm launches; the warm launch renders Top Sites with real bookmark data (profile DB works). Screenshot-verified, not just logcat. - The earlier
SIGSEGV@0in libxul static-init was actually two packaging/config bugs, both now fixed (see below); the stagefright frame turned out to be a red herring (first.init_arrayentry to trip the pref service, not the culprit). - Remaining emulator issue (environmental):
system_serverand the app both ANR under ndk_translation load during startup ("Timed out while trying to bind" / broadcast timeouts onMY_PACKAGE_REPLACED). The ANR dialogs block input dispatch, so interactive verification (typing a URL, clicking links) is not possible on this emulator. system_server keeps making progress (not deadlocked); a real arm64 device is unlikely to exhibit this. - XUL pipeline verified on-device. The profile's startupCache
contains
xulcache/…/chrome/content/browser.xul(the chrome XUL was parsed and its prototype cached) plusxblcache/entries for toolkit bindings — XUL parsing, the prototype cache, and the XBL binding engine all execute correctly. - Real web page loads verified end-to-end (2026-10-01). After
fixing the libxul logging blackout (see root causes), the earlier
"navigations never start" conclusion proved to be an observability
artifact, not a functional failure. Verified via
am start -a VIEW:http://neverssl.com— full navigation lifecycle:START → TITLE → LOCATION_CHANGE → SECURITY_CHANGE → PAGE_SHOW → STOP → FAVICON → THUMBNAIL, including a followed HTTP redirect chain (neverssl.com → fineolduniquesong.neverssl.com/online).https://example.com— same full cycle includingSECURITY_CHANGE(NSS/PSM path works; TLS handshake + cert verification complete, ~48 s wall-clock under ndk_translation). The first-ever HTTPS attempt appeared to stall atSTARTfor several minutes — first-use NSS/certdb initialization under translation is extremely slow; a subsequent run completed normally.
- All observed chrome JS errors resolved. After
browser.xulloads, the GeckoConsole bridge showed a cascade of JS errors — every one root-caused and fixed (see root causes): unpreprocessedbrowser.js, missingServices.androidBridge/Services.telemetrygetters,UITelemetrymodule absent, parental-controlsNOT_AVAILABLE, missing tracking-protection prefs, stalestorage-mozStorage.jscontract+manifest entries, unpackagedblocklist.manifest, and unguarded imports of modules (ExtensionContent,PresentationDeviceInfoManager,SimpleServiceDiscovery) that UXP no longer ships. Remaining console noise is cosmetic:GMPInstallManager.jsmlazy import (MOZ_GMPunset),ua-update.jsonprofile-path lookup, a dead snippets.mozilla.net endpoint, and Cu.import failure lines logged (but caught) by the guarded stubs. - Emulation caveat: everything above runs under ndk_translation
(arm64→x86_64).
lldb-server/gdbserver cannot run inside it, so native debugging is limited to logcat instrumentation.
- Omnijar never initialized on Android —
XRE_InitCommandLineintoolkit/xre/nsAppRunner.cpponly callsmozilla::Omnijar::InitwhenUXP_CUSTOM_OMNIis set; esr52 processed-greomniunconditionally. Without it the greomni.ja'schrome.manifest/components.manifest/xpt never register → every XPConnect wrap fails → the first content window cannot be created. Fixed with aMOZ_WIDGET_ANDROIDconditional (patch 0004). goanna.jsmissing from packaged omni.ja —mobile/android/installer/package-manifest.instill listed esr52's@BINPATH@/greprefs.js; UXP renamed it togoanna.js. The packager only warns about missing manifest entries, so this was silent in the log. Missing goanna.js →pref_ReadPrefFromJarfails →Preferences::Initfails →gCacheData/gObserverTablenever allocated →SIGSEGV@0inAddBoolVarCacheduringnsIOService::Init. Fixed by renaming the manifest entry (invendor/uxp-android/mobile/android/installer/package-manifest.in).- All libxul logging was dead — the largest single debugging
root cause of this port. libxul exports its own
__android_log_print/__android_log_write/__android_log_vprint/__android_log_assert(T,@@xul6-versioned) from the bundled stagefright liblog (media/libstagefright/system/core/liblog/ logd_write.c,FAKE_LOG_DEVICE=Truein moz.build). That stub writes to/dev/log/*(removed since Android L) and falls back to stderr — which is/dev/nullin the app — so every libxul-side__android_log_print,MOZ_LOG, and MOZ_ASSERT message was silently discarded while Java-side logging looked fine. This is why "nothing Gecko-side happened after runGecko" looked real.mozglue/linker/ElfLoader.cpp:30explicitly warns about bundled stub__android_log_*implementations. Fixed by dlopening the realliblog.soinside the stub on__ANDROID__and forwarding__android_log_buf_write/__android_log_bwrite(dlopen inside libxul routes through__wrap_dlopen→SystemElf→ real dlopen). Verified: PM* instrumentation,GeckoConsole,MOZ_LOGmodule output (e.g.nsScreenManagerAndroid) now all reach logcat. browser.jsshipped unpreprocessed — vendoredjar.mnlacked the*marker, so literal#ifdef MOZ_SAFE_BROWSINGlines shipped in the chrome → SyntaxError →BrowserAppundefined → startup dead after window creation. Fixed by markingbrowser.jspreprocessed inmobile/android/chrome/jar.mn.- Missing XPConnect glue / services that esr52-era chrome expects:
Services.androidBridge(added toServices.jsminitTable underMOZ_WIDGET_ANDROID;nsAndroidBridgefactory was already registered inwidget/android/nsWidgetFactory.cpp),Services. telemetry(no-op getter — no nsITelemetry exists in UXP, butSessionStore.jscallsgetHistogramById),UITelemetry.jsm(new module implementingnsIUITelemetryObserver— start/stop/ addEvent; the Java→nativewidget::Telemetryobserver path routes back into it),nsIParentalControlsService::IsAllowedreturningNS_ERROR_NOT_AVAILABLEon Android (abortedBrowserApp.startupmid-way; now returns allowed underANDROID— no Android restriction provider exists), missingprivacy.trackingprotection.{enabled,pbmode.enabled}default prefs (getTrackingModethrew; added tomobile.js), and packaging drift:storage-json.js/blocklist.manifestabsent frompackage-manifest.in(login storage + addon-manager startup failed), plus unguarded imports of modules UXP deleted (ExtensionContent— killed the entirecontent.jsframe script,PresentationDeviceInfoManager,SimpleServiceDiscovery— replaced with a lazy stub so casting code no-ops cleanly).
- No user interaction verified. The app reaches steady state,
renders, and completes real HTTP/HTTPS navigations driven by VIEW
intents, but taps/typing are untested because the emulator's
system_serverANR dialogs (and the recurring "built for an older version of Android" notice for targetSdk=23) block input dispatch. Driving the UI interactively needs a real arm64 device or a KVM host. - Compositor depth is partially verified.
nsWindow,nsAppShell, the docshell/viewer path, and full tab lifecycle events (incl. THUMBNAIL captures of loaded pages) all execute; screenshots confirm the chrome UI but loaded content pages have not been screenshot-verified past the persistent system dialog overlay. - Tab content does not present on emulator (2026-10-02). The
compositor produces real frames — tabs-tray thumbnails show rendered
pages — but the live
LayerViewSurfaceView stays white for every tab (about:addons,about:config,example.comalike). This is the presentation-layer failure behind the reported blankabout:addons; seedocs/ABOUT-ADDONS-BLANK.mdfor the full evidence chain and the chrome.manifest instrumentation recipe. - Rebranded to unofficial "New Moon" identity (2026-10-01):
MOZ_APP_BASENAME=NewMoon,MOZ_APP_VENDOR=Moonchild,ANDROID_PACKAGE_NAME=org.palemoon.community, display name "New Moon" — per Pale Moon's TRADEMARK notice, official "Pale Moon" branding requires Moonchild permission and this is a community port.MOZ_APP_IDnow uses Pale Moon's real GUID{8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}+UXP_APPCOMPAT_GUID=1so Pale Moon-targeted extensions/themes install without compat hacks;MOZ_APP_UA_NAME=Palemoon. New branding dirvendor/uxp-android/mobile/android/branding/newmoon/with generated crescent-moon launcher/favicon/about assets. Verified in the built APK: aapt badgingorg.palemoon.community/ label "New Moon", brand.properties in omni.ja. Gotcha: after changingconfvars.sh,mobile/android/basegenerated sources regenerate butclasses.dexcan stay stale —javacconstant-foldsAppConstants.ANDROID_PACKAGE_NAMEintocontent://URIs, and a stale fold producedcontent://org.mozilla.fennec_ubuntu.db.browserSecurityExceptions on first launch (provider permission denials, fatalGeckoBackgroundThreadcrash). Fix: deleteobjdir/mobile/android/base/{generated,*classes*,*.jar,classes.dex}and rebuild + repackage. Verified: 0fennec_ubuntuliterals in the new dex, clean launch under pid of the new package. - Signed with the auto-generated debug key only.
- The UI is the Fennec-derived pm4a mobile frontend (XUL/XBL chrome:
browser.xul+ bindings inside omni.ja) on the full Goanna/UXP platform — not the desktop Pale Moon browser chrome. XUL does map to Android here: the XUL/XBL frontend ships, its window instantiates at runtime, and the chrome JS runs — the gap to "full Pale Moon UI" is the chrome content itself (mobile chrome vsbrowser/desktop chrome), not the XUL platform. - Support-library AAR
extra_jarsthat resolve toNoneare still filtered in the backend; androidx/Gradle frontend rework not done. ANDROID_TOOLSmaps to the SDKemulator/dir (notools/dir in modern SDKs).- Two benign packaging warnings remain: "nothing matches overlay file
sync_avatar_default.png/sync_promo.png" — the drawables still land in the APK. - Crash-path diagnostics remain in the tree (Android-gated):
mozglue/linker/ElfLoader.cpp(moz_pmlogexport),mfbt/Assertions.cpp(assert → logcat),memory/mozallocabort → logcat. They log only on crashes/fatals and are worth keeping until first interactive use is stable; all temporary instrumentation has been removed.
- Interactive verification on a real arm64 device (or a faster emulator host): page loads via intent are verified (HTTP + HTTPS with full tab lifecycle); remaining is interactive use — typing URLs, tapping links — blocked on this emulator by ANR dialogs and the targetSdk=23 notice; watch for ndk_translation-specific behavior that won't reproduce on hardware.
Pale Moon branding/product pass— done (unofficial "New Moon" branding + Pale Moon app GUID/UA); official "Pale Moon" branding needs Moonchild's permission and remains available viaMOZ_OFFICIAL_BRANDING_DIRECTORY.- Java frontend SDK modernization (targetSdk, Gradle 8, API 34) — replace make-driven javac/aapt + support libs with androidx + Gradle.
- Desktop Pale Moon browser chrome (
browser/XUL) on Android, if the mobile Fennec chrome is deemed insufficient for the "full Pale Moon UI" goal — large effort; the Fennec chrome is already XUL/XBL and fully executing. - Release signing path + l10n/crashreporter overrides audit.