#!/bin/bash
#
# Fennec build scripts
# Copyright (C) 2020-2024 Matías Zúñiga, Andrew Nayenko, Tavi
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
set -e
if [ -z "$1" ] || [ -z "$2" ]; then
echo "Usage: $0 versionName versionCode" >&1
exit 1
fi
# shellcheck source=paths.sh
source "$(dirname "$0")/paths.sh"
function localize_maven {
# Replace custom Maven repositories with mavenLocal()
find ./* -name '*.gradle' -type f -print0 | xargs -0 \
sed -n -i \
-e '/maven {/{:loop;N;/}$/!b loop;/plugins.gradle.org/!s/maven .*/mavenLocal()/};p'
# Make gradlew scripts call our Gradle wrapper
find ./* -name gradlew -type f | while read -r gradlew; do
echo -e '#!/bin/sh\ngradle "$@"' > "$gradlew"
chmod 755 "$gradlew"
done
}
function apply_patch {
echo "Apply $1"
patch -p1 --no-backup-if-mismatch --quiet < "$1"
}
# Set up Rust
rustup default 1.93.0
#
# Fenix
#
pushd "$fenix"
# Set up the app ID, version name and version code
sed -i \
-e 's|org\.mozilla\.firefox|lol.smesh.felice|' \
-e "s/Config.releaseVersionName(project)/'$1'/" \
-e "s/Config.generateFennecVersionCode(abi)/$2/" \
app/build.gradle
sed -i \
-e '/android:targetPackage/s/org\.mozilla\.firefox/lol.smesh.felice/' \
app/src/release/res/xml/shortcuts.xml
# Disable crash reporting
sed -i -e '/CRASH_REPORTING/s/true/false/' app/build.gradle
# Disable MetricController
sed -i -e '/TELEMETRY/s/true/false/' app/build.gradle
# Let it be Felice
sed -i -e 's/Firefox Daylight/Felice/; s/Firefox/Felice/g' \
app/src/*/res/values*/*strings.xml
# Fenix uses reflection to create a instance of profile based on the text of
# the label, see
# app/src/main/java/org/mozilla/fenix/perf/ProfilerStartDialogFragment.kt#185
sed -i \
-e 's/ProfilerSettings.Firefox/ProfilerSettings.Felice/' \
app/src/main/java/org/mozilla/fenix/perf/ProfilerStartDialogFragment.kt
sed -i \
-e '/Firefox(.*, .*)/s/Firefox/Felice/' \
-e 's/firefox_threads/felice_threads/' \
-e 's/firefox_features/felice_features/' \
app/src/main/java/org/mozilla/fenix/perf/ProfilerUtils.kt
# Replace proprietary artwork
sed -i -e 's|@drawable/animated_splash_screen<|@drawable/splash_screen<|' \
app/src/main/res/values-v*/styles.xml
find "$patches/fenix-overlay" -type f | while read -r src; do
dst=app/src/release/${src#"$patches/fenix-overlay/"}
mkdir -p "$(dirname "$dst")"
cp "$src" "$dst"
done
# Drop the Fennec fox vector; the release overlay provides Felice webps at every density
rm -f app/src/main/res/drawable/ic_firefox.xml
# Route completed .xpi downloads into AddonManager instead of the download-complete snackbar
sed -i \
-e '/^import org\.mozilla\.fenix\.components\.AppStore$/a\
import org.mozilla.fenix.ext.components' \
-e '/\/\/ If the download is just paused/i\
if (downloadJobStatus == Status.COMPLETED \&\&\
(downloadState.contentType == "application\/x-xpinstall" ||\
downloadState.fileName?.endsWith(".xpi") == true)) {\
val safeContext = context ?: return\
val fileUri = "file:\/\/" + downloadState.filePath\
safeContext.components.addonManager.installAddon(\
fileUri,\
mozilla.components.concept.engine.webextension.InstallationMethod.FROM_FILE,\
onSuccess = { },\
onError = { _ -> },\
)\
return\
}\
' app/src/main/java/org/mozilla/fenix/browser/DownloadUtils.kt
# Register as handler for .xpi extension files
sed -i '//i\
\
\
\
\
\
\
\
<\/intent-filter>\
\
\
\
\
\
\
\
\
<\/intent-filter>\
\
\
\
\
\
\
\
\
\
<\/intent-filter>\
' app/src/main/AndroidManifest.xml
# There are a lot of "No cast needed" warnings in the generated code
sed -i -e '/compilerOptions.allWarningsAsErrors/s/true/false/' build.gradle
# Enable about:config
sed -i \
-e 's/aboutConfigEnabled(.*)/aboutConfigEnabled(true)/' \
app/src/*/java/org/mozilla/fenix/*/GeckoProvider.kt
# Disable remote improvements by default
sed -i \
-e '/android:defaultValue=/s/"true"/"false"/' \
app/src/main/res/xml/remote_improvements_preferences.xml
# Add wallpaper URL
echo 'https://gitlab.com/relan/fennecmedia/-/raw/master/wallpapers/android' > .wallpaper_url
# Set up target parameters
case $(echo "$2" | cut -c 6) in
0)
abi=armeabi-v7a
target=arm-linux-androideabi
echo "ARM" > "$llvm/targets_to_build"
rusttarget=arm
rustup target add thumbv7neon-linux-androideabi
rustup target add armv7-linux-androideabi
;;
1)
abi=x86_64
target=x86_64-linux-android
echo "X86" > "$llvm/targets_to_build"
rusttarget=x86_64
rustup target add x86_64-linux-android
;;
2)
abi=arm64-v8a
target=aarch64-linux-android
echo "AArch64" > "$llvm/targets_to_build"
rusttarget=arm64
rustup target add aarch64-linux-android
;;
*)
echo "Unknown target code in $2." >&2
exit 1
;;
esac
sed -i -e "s/include \".*\"/include \"$abi\"/" app/build.gradle
# Disable FUS Service or we'll get errors like:
# Exception while loading configuration for :app: Could not load the value of field `__buildFusService__` of task `:app:compileFenixReleaseKotlin` of type `org.jetbrains.kotlin.gradle.tasks.KotlinCompile`.
echo "kotlin.internal.collectFUSMetrics=false" >> local.properties
popd
#
# Glean
#
pushd "$glean"
echo "rust.targets=linux-x86-64,$rusttarget" >> local.properties
localize_maven
popd
#
# Glean for Application Services
#
pushd "$glean_as"
echo "rust.targets=linux-x86-64,$rusttarget" >> local.properties
localize_maven
popd
#
# Android Components
#
pushd "$android_components"
find "$patches/a-c-overlay" -type f | while read -r src; do
cp "$src" "${src#"$patches/a-c-overlay/"}"
done
# Add the added search engines as `general` engines
sed -i \
-e '/GENERAL_SEARCH_ENGINE_IDS = setOf/a\ "brave",' \
-e '/GENERAL_SEARCH_ENGINE_IDS = setOf/a\ "ddghtml",' \
-e '/GENERAL_SEARCH_ENGINE_IDS = setOf/a\ "ddglite",' \
-e '/GENERAL_SEARCH_ENGINE_IDS = setOf/a\ "metager",' \
-e '/GENERAL_SEARCH_ENGINE_IDS = setOf/a\ "mojeek",' \
-e '/GENERAL_SEARCH_ENGINE_IDS = setOf/a\ "qwantlite",' \
-e '/GENERAL_SEARCH_ENGINE_IDS = setOf/a\ "startpage",' \
components/feature/search/src/main/java/mozilla/components/feature/search/storage/SearchEngineReader.kt
popd
#
# UnifiedPush Android Component
#
pushd "$unifiedpush_ac"
localize_maven
# Set A-C version
echo "mozilla.version=${1%.0}" >> local.properties
# Set A-S version
sed -i -e 's/0.0.1-SNAPSHOT-+/149.0/' gradle/libs.versions.toml
popd
#
# Application Services
#
pushd "$application_services"
rm -vrf components/remote_settings/dumps/*/attachments/search-config-icons/*
find "$patches/a-s-overlay" -type f | while read -r src; do
cp "$src" "${src#"$patches/a-s-overlay/"}"
done
# Remove Mozilla repositories substitution and explicitly add the required ones
apply_patch "$patches/a-s-localize_maven.patch"
# Configure default search engines
apply_patch "$patches/a-s-configure-default-search-engines.patch"
# Break the dependency on older A-C
sed -i -e '/android-components = /s/"146\.0\.1"/"149.0"/' gradle/libs.versions.toml
echo "rust.targets=linux-x86-64,$rusttarget" >> local.properties
sed -i -e '/NDK ez-install/,/^$/d' libs/verify-android-ci-environment.sh
popd
#
# WASI SDK
#
pushd "$wasi"
apply_patch "$mozilla_release/taskcluster/scripts/misc/wasi-sdk.patch"
popd
#
# GeckoView
#
pushd "$mozilla_release"
# Remove unneeded dependecies
apply_patch "$patches/gecko-dependencies.patch"
# Remove Mozilla repositories substitution and explicitly add the required ones
apply_patch "$patches/gecko-localize_maven.patch"
# Replace GMS with microG client library
apply_patch "$patches/gecko-liberate.patch"
# Work-around upstream bug to fix compilation with WASI SDK 20, see
# https://bugzilla.mozilla.org/show_bug.cgi?id=1994063
apply_patch "$patches/gecko-unbreak-wasi-sdk-20-clang.patch"
# Add UnifiedPush support
apply_patch "$unifiedpush_ac/patches/a-c-unifiedpush.patch"
apply_patch "$unifiedpush_ac/patches/fenix-unifiedpush.patch"
# Patch the use of proprietary and tracking libraries
apply_patch "$patches/fenix-liberate.patch"
# Disable search engines configuration fetching from a Mozilla server
apply_patch "$patches/fenix-disable-remote-search-configuration.patch"
sed -i 's|https://firefox.settings.services.allizom.org/v1/buckets/main/collections/search-config/records||g' toolkit/components/search/SearchUtils.sys.mjs
sed -i 's|https://firefox.settings.services.allizom.org/v1/buckets/main-preview/collections/search-config/records||g' toolkit/components/search/SearchUtils.sys.mjs
sed -i 's|https://firefox.settings.services.mozilla.com/v1/buckets/main/collections/search-config/records||g' toolkit/components/search/SearchUtils.sys.mjs
sed -i 's|https://firefox.settings.services.mozilla.com/v1/buckets/main-preview/collections/search-config/records||g' toolkit/components/search/SearchUtils.sys.mjs
# Remove the use of RemoteSettingsCrashPull, the part of the crash reporter
apply_patch "$patches/fenix-disable-crashpull.patch"
# Remove "Sent from Firefox" reference on sharing
apply_patch "$patches/fenix-disable-sent-from-fx.patch"
# Add "Enable UnifiedPush" and "Use UnifiedPush" settings
apply_patch "$patches/fenix-use-unifiedpush.patch"
# Fail on use of prebuilt binary
sed -i 's|https://|hxxps://|' mobile/android/gradle/plugins/nimbus-gradle-plugin/src/main/groovy/org/mozilla/appservices/tooling/nimbus/NimbusGradlePlugin.groovy
# Make Nimbus Gradle Plugin use obj/dist/host/bin/nimbus-fml which we copy
# there manually from A-S. Otherwise Nimbus Gradle Plugin tries to download
# nimbus-fml from Mozilla.
sed -i 's/project.gradle.ext.mozconfig.substs.MOZ_APPSERVICES_IN_TREE/true/' mobile/android/gradle/plugins/nimbus-gradle-plugin/src/main/groovy/org/mozilla/appservices/tooling/nimbus/NimbusGradlePlugin.groovy
# Fix v125 aar output not including native libraries
sed -i \
-e 's/singleVariant("debug")/singleVariant("release")/' \
mobile/android/exoplayer2/build.gradle
sed -i \
-e "s/singleVariant('debug')/singleVariant('release')/" \
mobile/android/geckoview/build.gradle
# Hack the timeout for
# geckoview:generateJNIWrappersForGeneratedWithGeckoBinariesDebug
sed -i \
-e 's/max_wait_seconds=600/max_wait_seconds=1800/' \
mobile/android/gradle.py
# Patch the LLVM source code
# Search clang- in https://android.googlesource.com/platform/ndk/+/refs/tags/ndk-r28b/ndk/toolchains.py
LLVM_SVN='530567'
python3 "$toolchain_utils/llvm_tools/patch_manager.py" \
--svn_version "$LLVM_SVN" \
--patch_metadata_file "$llvm_android/patches/PATCHES.json" \
--src_path "$llvm"
# Fail on use of prebuilt binary
sed -i 's|https://github.com|hxxps://github.com|' python/mozboot/mozboot/android.py
# Make the build system think we installed the emulator and an AVD
mkdir -p "$ANDROID_HOME/emulator"
touch "$ANDROID_HOME/emulator/emulator"
chmod +x "$ANDROID_HOME/emulator/emulator"
mkdir -p "$HOME/.mozbuild/android-device/avd"
# Use terser from Debian
sed -i \
-e 's|terser_path = terser_dir / ".*"|terser_path = Path("/usr/bin/terser")|' \
python/mozbuild/mozpack/files.py
# Configure
cat << EOF > mozconfig
ac_add_options --disable-crashreporter
ac_add_options --disable-debug
ac_add_options --disable-tests
ac_add_options --disable-updater
ac_add_options --enable-application=mobile/android
ac_add_options --enable-release
ac_add_options --enable-update-channel=release
ac_add_options --target=$target
ac_add_options --with-android-ndk="$ANDROID_NDK"
ac_add_options --with-android-sdk="$ANDROID_SDK"
ac_add_options --with-libclang-path="$llvm/out/lib"
ac_add_options --with-java-bin-path="/usr/bin"
ac_add_options --with-gradle=$(command -v gradle)
ac_add_options --with-wasi-sysroot="$wasi/build/install/wasi/share/wasi-sysroot"
ac_add_options CC="$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/clang"
ac_add_options CXX="$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++"
ac_add_options STRIP="$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip"
ac_add_options WASM_CC="$wasi/build/install/wasi/bin/clang"
ac_add_options WASM_CXX="$wasi/build/install/wasi/bin/clang++"
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj
mk_add_options MOZ_MAKE_FLAGS="-j1"
export MOZ_REQUIRE_SIGNING=
EOF
# Disable Gecko Media Plugins and casting
sed -i -e '/gmp-provider/d; /casting.enabled/d' mobile/android/app/geckoview-prefs.js
cat << EOF >> mobile/android/app/geckoview-prefs.js
// Disable Encrypted Media Extensions
pref("media.eme.enabled", false);
// Disable Gecko Media Plugins
pref("media.gmp-provider.enabled", false);
// Avoid openh264 being downloaded
pref("media.gmp-manager.url.override", "data:text/plain,");
// Disable openh264 if it is already downloaded
pref("media.gmp-gmpopenh264.enabled", false);
// Disable RemoteSettingsCrashPull
pref("browser.crashReports.crashPull", false, locked);
pref("browser.crashReports.requestedNeverShowAgain", true, locked);
// Disable mandatory extension signing
pref("xpinstall.signatures.required", false);
// Allow extension installs from any site
pref("xpinstall.whitelist.fileRequest", true);
pref("extensions.langpacks.signatures.required", false);
pref("extensions.experiments.enabled", true);
pref("extensions.install.requireBuiltInCerts", false);
pref("extensions.webextensions.restrictedDomains", "");
pref("xpinstall.whitelist.required", false);
pref("xpinstall.whitelist.directRequest", true);
pref("browser.startup.homepage_override.mstone", "ignore");
EOF
popd
# On cold start with no tabs to restore and no intent URL, open smesh.lol.
# Fenix ignores browser.startup.homepage on Android — this is the only way.
sed -i '/maybeShowSetAsDefaultBrowserPrompt()$/i\
if (!settings().shouldReturnToBrowser) {\
openToBrowserAndLoad(\
searchTermOrURL = "https:\/\/smesh.lol",\
newTab = true,\
from = BrowserDirection.FromGlobal,\
)\
}' "$fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt"