brizental pushed to branch mullvad-browser-149.0a1-16.0-2 at The Tor Project / Applications / Mullvad Browser Commits: d6edcc3d by Beatriz Rizental at 2026-03-24T15:02:29-03:00 BB 43243 [android]: Start GeckoEngineSession early when Marionette enabled This is in the process of being uplifted. Bug 2021884: https://bugzilla.mozilla.org/show_bug.cgi?id=2021884 Differential Revision: https://phabricator.services.mozilla.com/D286676 - - - - - 4e336f51 by Beatriz Rizental at 2026-03-24T15:02:30-03:00 BB 43243: Modify mozharness scripts for Base Browser - - - - - 4 changed files: - mobile/android/fenix/app/src/main/java/org/mozilla/fenix/FenixApplication.kt - testing/mozharness/configs/android/android14-x86_64.py - testing/mozharness/configs/android/android_common.py - testing/mozharness/scripts/android_emulator_unittest.py Changes: ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/FenixApplication.kt ===================================== @@ -498,6 +498,12 @@ open class FenixApplication : Application(), Provider, ThemeProvider { logElapsedTime(logger, "Starting Relay feature integration") { components.relayFeatureIntegration.start() } + + // If running Marionette tests a GeckoEngineSession needs to be + // started and that must happen on the main thread. + logElapsedTime(logger, "Maybe setup Marionette") { + maybeSetupMarionette() + } } } @@ -666,6 +672,13 @@ open class FenixApplication : Application(), Provider, ThemeProvider { FxNimbus.initialize { nimbus } } + private fun maybeSetupMarionette() { + // If Marionette is enabled, start a GeckoEngineSession immediatelly. + if (System.getenv("MOZ_MARIONETTE") == "1") { + components.core.engine.speculativeCreateSession(components.appStore.state.mode.isPrivate) + } + } + /** * Initiate Megazord sequence! Megazord Battle Mode! * ===================================== testing/mozharness/configs/android/android14-x86_64.py ===================================== @@ -11,8 +11,9 @@ config = { "emulator_avd_name": "mozemulator-android34-x86_64", "emulator_process_name": "qemu-system-x86_64", "emulator_extra_args": [ - "-gpu", - "on", + "-no-window", + "-no-audio", + "-no-boot-anim", "-skip-adb-auth", "-verbose", "-show-kernel", ===================================== testing/mozharness/configs/android/android_common.py ===================================== @@ -315,6 +315,19 @@ config = { "--deviceSerial=%(device_serial)s", ], }, + "marionette": { + "run_filename": "runtests.py", + "testsdir": "marionette/harness/marionette_harness", + "install": True, + "options": [ + "-vv", + "--address=127.0.0.1:2828", + "--app=fennec", + ], + "tests": [ + "%(abs_marionette_manifest_dir)s/unit-tests.toml", + ], + }, }, # end suite_definitions "structured_suites": [ "mochitest-media", ===================================== testing/mozharness/scripts/android_emulator_unittest.py ===================================== @@ -7,15 +7,18 @@ import copy import datetime import json import os +import socket import subprocess import sys +import tempfile +import time # load modules from parent dir here = os.path.abspath(os.path.dirname(__file__)) sys.path.insert(1, os.path.dirname(here)) from mozharness.base.log import WARNING -from mozharness.base.script import BaseScript, PreScriptAction +from mozharness.base.script import BaseScript, PostScriptAction, PreScriptAction from mozharness.mozilla.automation import TBPL_RETRY from mozharness.mozilla.mozbase import MozbaseMixin from mozharness.mozilla.testing.android import AndroidMixin @@ -26,7 +29,7 @@ from mozharness.mozilla.testing.codecoverage import ( from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options SUITE_DEFAULT_E10S = ["geckoview-junit", "mochitest", "reftest"] -SUITE_NO_E10S = ["cppunittest", "gtest", "jittest", "xpcshell"] +SUITE_NO_E10S = ["cppunittest", "gtest", "jittest", "xpcshell", "marionette"] SUITE_REPEATABLE = ["mochitest", "reftest", "xpcshell"] @@ -178,6 +181,15 @@ class AndroidEmulatorTest( "times in which case the test must contain at least one of the given tags.", }, ], + [ + ["--package-name"], + { + "action": "store", + "default": None, + "dest": "package_name", + "help": "The Android package name for the app being installed.", + }, + ], ] + copy.deepcopy(testing_config_options) + copy.deepcopy(code_coverage_config_options) @@ -228,6 +240,7 @@ class AndroidEmulatorTest( self.enable_isolated_zygote_process = c.get("enable_isolated_zygote_process") self.extra_prefs = c.get("extra_prefs") self.test_tags = c.get("test_tags") + self.package_name = c.get("package_name") or self.query_package_name() def query_abs_dirs(self): if self.abs_dirs: @@ -329,6 +342,16 @@ class AndroidEmulatorTest( "error_summary_file": error_summary_file, "xpcshell_extra": c.get("xpcshell_extra", ""), "gtest_dir": os.path.join(dirs["abs_test_install_dir"], "gtest"), + "abs_marionette_manifest_dir": os.path.join( + dirs["abs_test_install_dir"], + "marionette", + "tests", + "testing", + "marionette", + "harness", + "marionette_harness", + "tests", + ), } user_paths = self._get_mozharness_test_paths(self.test_suite) @@ -345,7 +368,7 @@ class AndroidEmulatorTest( if "%(app)" in option: # only query package name if requested - cmd.extend([option % {"app": self.query_package_name()}]) + cmd.extend([option % {"app": self.package_name}]) else: option = option % str_format_values if option: @@ -409,6 +432,7 @@ class AndroidEmulatorTest( self.config["suite_definitions"][self.test_suite].get("tests"), None, try_tests, + str_format_values=str_format_values, ) ) @@ -449,6 +473,7 @@ class AndroidEmulatorTest( }, ), ("xpcshell", {"xpcshell": "xpcshell"}), + ("marionette", {"marionette": "marionette"}), ] suites = [] for category, all_suites in all: @@ -473,6 +498,61 @@ class AndroidEmulatorTest( # in the base class, this checks for mozinstall, but we don't use it pass + def _configure_marionette_virtualenv(self, action): + dirs = self.query_abs_dirs() + requirements = os.path.join( + dirs["abs_test_install_dir"], "config", "marionette_requirements.txt" + ) + if not os.path.isfile(requirements): + self.fatal(f"Could not find marionette requirements file: {requirements}") + + self.register_virtualenv_module(requirements=[requirements]) + + def _marionette_setup(self): + adb = self.query_exe("adb") + + self.run_command([adb, "forward", "tcp:2828", "tcp:2828"]) + + with tempfile.NamedTemporaryFile(suffix=".yaml") as tmp_file: + tmp_file.write( + b"""args: +- --marionette +- --remote-allow-system-access +""" + ) + tmp_file.flush() + + remote_path = f"/data/local/tmp/{self.package_name}-geckoview-config.yaml" + self.run_command([adb, "push", tmp_file.name, remote_path]) + + self.run_command([ + adb, + "shell", + "am", + "start", + "-S", + "-W", + "-n", + f"{self.package_name}/org.mozilla.gecko.BrowserApp", + ]) + + # Wait for Marionette to be ready + for attempt in range(5): + try: + self.info( + f"Checking Marionette on 127.0.0.1:2828 (attempt {attempt + 1}/5)" + ) + socket.create_connection(("127.0.0.1", 2828), 10).close() + self.info("Marionette is reachable") + break + except OSError: + if attempt == 4: + self.fatal( + "Timed out waiting for 127.0.0.1:2828 to become reachable" + ) + self.info("Marionette not reachable yet, retrying in 10s") + time.sleep(10) + @PreScriptAction("create-virtualenv") def pre_create_virtualenv(self, action): dirs = self.query_abs_dirs() @@ -488,6 +568,9 @@ class AndroidEmulatorTest( if requirements: self.register_virtualenv_module(requirements=[requirements]) + if ("marionette", "marionette") in suites: + self._configure_marionette_virtualenv(action) + def download_and_extract(self): """ Download and extract product APK, tests.zip, and host utils. @@ -525,6 +608,9 @@ class AndroidEmulatorTest( for per_test_suite, suite in suites: self.test_suite = suite + if self.test_suite == "marionette": + self._marionette_setup() + try: cwd = self._query_tests_dir(self.test_suite) except Exception: @@ -594,6 +680,19 @@ class AndroidEmulatorTest( % (suite_category, suite, tbpl_status), ) + @PostScriptAction("run-tests") + def marionette_teardown(self, *args, **kwargs): + if ("marionette", "marionette") in self._query_suites(): + adb = self.query_exe("adb") + self.run_command([adb, "shell", "am", "force-stop", self.package_name]) + self.run_command([adb, "uninstall", self.package_name]) + self.run_command([ + adb, + "shell", + "rm", + f"/data/local/tmp/{self.package_name}-geckoview-config.yaml", + ]) + if __name__ == "__main__": test = AndroidEmulatorTest() View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/43a... -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/43a... You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
participants (1)
-
brizental (@brizental)