Open Bug 2064088 Opened 2 months ago Updated 1 month ago

Add option to avoid clearing profile when connecting to Firefox for Android

Categories

(Testing :: geckodriver, enhancement, P3)

enhancement

Tracking

(Not tracked)

People

(Reporter: jdescottes, Unassigned, NeedInfo)

References

Details

(Whiteboard: [webdriver:backlog])

Attachments

(1 obsolete file)

https://searchfox.org/firefox-main/rev/7c611117298561f542198076e70e641d4dd080bc/testing/geckodriver/src/android.rs#397

self.process.device.clear_app_data(&self.process.package)?;

At the moment, geckodriver will always wipe the application data when connecting. We will require an extra flag on the firefox-devtools-mcp side for now, but hopefully we can change this behavior ?

That has been introduced in Bug 1525126, so it's always been the case it seems.

(note I couldn't search for duplicates on https://github.com/mozilla/geckodriver/issues because GH is currently down for me, apologies if this is a duplicate)

To be sure is that related to connecting to an already running instance of Firefox on Android, or a new one?

(In reply to Henrik Skupin [:whimboo][⌚️UTC+2] from comment #2)

To be sure is that related to connecting to an already running instance of Firefox on Android, or a new one?

A new one, we don't support connecting to an existing Android instance with the MCP at the moment.

Ok, so geckodriver executes adb shell pm clear <package> on Android targets during session initialization. While this ensures a clean environment for pure automated testing, it causes unintended data destruction when geckodriver is used in persistent or long-running environments such as a Model Context Protocol (MCP) server.

pm clear behaves as an OS-level factory reset for the entire application package sandbox. This wipes out state completely unrelated to the unique Gecko browser profile (rust_mozprofile) being pushed for the session.

Specifically, it destroys:

  1. Android SharedPreferences: Wipes out app-level UI themes, engineer/QA debug options, and Nimbus/A/B testing flags.
  2. App System Permissions: Revokes all OS-level user grants (Camera, Microphone, Storage, Location) which can break subsequent automated workflows unless manually re-granted via ADB.
  3. Telemetry/Glean State: Clears the local database and persistent identifiers managed by the Glean SDK, destroying any pending outbox payloads.
  4. Component Databases: Resets Firefox Account sync metadata, push notification tokens (FCM), and custom search engine lists.

For usual testing purposes when using geckodriver this aggressive wipe is still desired. However, for users leveraging geckodriver as a backend for persistent tooling, this silently destroys their global package configuration every time a new session starts.

We should preserve the clean-slate behavior for traditional testing while providing an escape hatch for non-destructive environments.

I propose introducing a new boolean capability, androidKeepAppStorage, nested under moz:firefoxOptions.

  • Behavior when false (Default, keeping current testing behavior intact): Geckodriver continues to run pm clear to ensure absolute test isolation.

  • Behavior when true: Geckodriver skips the pm clear step entirely. It will rely purely on directory-level isolation by pushing a fresh rust_mozprofile and launching Fenix pointing directly to it. This leaves the global Android package state, permissions, and app preferences untouched.

cf Henrik's comment on Github:

Tabs, history, bookmarks and others are part of the Firefox profile, while only certain app settings including permissions are getting removed.

To be verified because based on the user report, more was deleted: (In reply to John from Bug 2063831 comment #0)

Steps to reproduce:

  1. Use Firefox for Android (org.mozilla.firefox) normally on a personal device — accumulate tabs, history, logins, bookmarks, extensions.
  2. Connect the device over adb.
  3. Run any geckodriver-backed automation against that package. I hit this via the official MCP server: npx @mozilla/firefox-devtools-mcp@latest --android-device auto
  4. Start a session (any command that launches Firefox, e.g. navigating a page).

Actual results:

All app user data is destroyed. Onboarding re-runs on next launch; history, open tabs, saved logins, bookmarks, extensions and settings are gone. No warning, no confirmation prompt, no mention in any documentation I read before running it.
[...]

It's possible that part of this confusion comes from the profile being pushed for the test ?

(In reply to Julian Descottes [:jdescottes] from comment #5)

It's possible that part of this confusion comes from the profile being pushed for the test ?

Probably. I cannot believe that we would duplicate all that data in the profile and the app settings.

As note to myself... once implemented we need to add the new androidKeepAppStorage capability to https://developer.mozilla.org/en-US/docs/Web/WebDriver/Reference/Capabilities/firefoxOptions.

I thought more about that since my last comments and meanwhile I think having a capability for this flag might not be the right choice. Doing so would allow individual tests to opt out of starting Firefox in a clean state and instead reuse settings from a previous session. That could introduce unintended side effects and, in the worst case, allow access to previously stored data or granted permissions.

Instead, I think this should be a geckodriver command-line argument. That way, it can only be specified by the entity launching geckodriver (such as the MCP server) rather than by individual test sessions. This keeps the decision at the process level and avoids making it configurable on a per-session basis. I suggest to use --android-keep-app-data for that.

Julian, here is a try build for geckodriver with the --android-keep-app-data argument added. Could you please check back if that fixes the issues which are not related to this data that is stored in the Firefox profile itself?

https://treeherder.mozilla.org/jobs?repo=try&revision=6932b2b5dfe02c3bf9ca4765c750245a990400b3

Flags: needinfo?(jdescottes)

By default geckodriver clears the whole application data via pm clear
when creating a new session on Android. This wipes package-level state such
as app settings, granted permissions, and other data unrelated to the Gecko
profile, which is undesirable when geckodriver is used as a backend by eg.
a Model Context Protocol (MCP) server.

The patch adds a new --android-keep-app-data command-line argument. When
set, geckodriver skips clearing the application data and relies purely on
directory-level isolation via the pushed profile. By default the app data is
still cleared to keep the clean-slate behavior for testing.

Using a command-line argument rather than a capability ensures the behavior
is controlled by the entity running geckodriver, and cannot be toggled by
an individual session, which could otherwise leak data across sessions.

Assignee: nobody → hskupin
Status: NEW → ASSIGNED

(In reply to Henrik Skupin [:whimboo][⌚️UTC+2] from comment #9)

Julian, here is a try build for geckodriver with the --android-keep-app-data argument added. Could you please check back if that fixes the issues which are not related to this data that is stored in the Firefox profile itself?

https://treeherder.mozilla.org/jobs?repo=try&revision=6932b2b5dfe02c3bf9ca4765c750245a990400b3

Tested today with a custom MCP build, this works well. However it seems that Android profiles do not store as a much information as Desktop profiles as I was still presented with my tabs / bookmarks / passwords / history etc...

On Android simply pushing a temporary profile doesn't grant the isolation we assumed. It seems that it only contains cookies, web storage and certificates.

Moreover, all data for Firefox for Android is stored in app_data, including the current profile. So when we run pm clear we really do wipe everything.

Flags: needinfo?(jdescottes)
Blocks: 2065207

Thanks Julian. This now opens the question how we should best isolate different runs. With the attached patch only parts of the stored data will not be cleared but other parts (as stored in the profile) will be left. This is not what I would expect and the number of data as stored in the profile vs. app-data could as well change in the future.

Maybe we need to rewrite parts of geckodriver and support the option of re-using the current data (profile) similar to desktop? When selected it would not remove app-data and the default profile under app-data at all. And if not specified everything will be reset.

I would actually prefer such a solution as a half-baked option where we are not clear about which data will still remain. Lets discuss in our triage meeting today.

Whiteboard: [webdriver:triage]

We should probably first check exactly what's used by the profile on Android. Let me get back to the Android folks to get all the needed information.

Flags: needinfo?(hskupin)

I did an investigation with Claude and here is what I found out:

Data storage across the supported Android packages

All the supported Android apps share the same GeckoView engine and the same profile-path mechanism: Gecko's profile lives under the app's private data dir at /data/data/<applicationId>/files/mozilla/ (the path derives from Android's getFilesDir(), exported as HOME, with mozilla/ appended in nsXREDirProvider). On Android ProfD == ProfLD and there's no profiles.ini / profile manager.

What differs between packages is (a) the package ID (Android sandboxing keeps each app's profile separate) and (b) how much data is persisted vs. treated as private/ephemeral, and who owns the user-facing data.

Key distinction: Gecko profile vs. app-layer storage

The Gecko profile only holds engine-level state (prefs, cookies, permissions, DOM/quota storage, extension storage, cache). The user-facing data — history, bookmarks, logins — is NOT in the Gecko profile. It's an application-layer responsibility, exposed by GeckoView as delegate APIs
(HistoryDelegate, Autocomplete.StorageDelegate); note GeckoView has no bookmarks concept at all.

Per package

  • fenix (org.mozilla + .firefox* / .fenix*)
    Persistent normal sessions + non-persistent private sessions (usePrivateMode). History/bookmarks/logins are stored by application-services (places/logins), i.e. outside the Gecko profile.

  • focus / klar (org.mozilla.focus / org.mozilla.klar)
    Same codebase, two product flavors (branding/market). Privacy-first: the defining behavior is erase-on-demand tabsUseCases.removeAllTabs() via the erase shortcut activities) rather than durable browsing data.

  • geckoview_example (org.mozilla.geckoview_example)
    Persistent engine profile. Implements the delegates only in-memory: history in a HashSet<String>, logins in a HashMap — both lost on restart. No bookmarks.

  • test_runner (org.mozilla.geckoview.test_runner)
    Ephemeral: the harness injects a fresh -profile <path> per run (runjunit.py) and wipes it afterwards. Registers no history/login delegate, so there is no history/bookmarks/logins storage at all.

Summary

Package applicationId Gecko profile history / bookmarks / logins
fenix org.mozilla.* (.firefox*/.fenix*) persistent (+ private sessions) application-services (places/logins); no bookmarks in Gecko
focus / klar org.mozilla.focus / org.mozilla.klar persistent, erase-on-demand app-layer, wiped on erase
geckoview_example org.mozilla.geckoview_example persistent in-memory only (lost on restart); no bookmarks
test_runner org.mozilla.geckoview.test_runner ephemeral (per-run, wiped) none

Kaya, could you verify that the above details are correct and what's happening on Android?

Regarding clearing the profile or not, Kaya filed bug 2047550 for the MCP to add support for --connect-existing on Android as well - and we discussed that in comment 2 and 3. Maybe that's the way to go and geckodriver should support that mode for Android and not only for desktop platforms.

Flags: needinfo?(hskupin) → needinfo?(kkaya)
Attachment #9628711 - Attachment is obsolete: true

Another solution and as long as we haven't gotten a reply to get a better picture of profile handling on mobile, we can support the --connect-existing flag in geckodriver which would as well not remove any user data for the package to start. I filed bug 2071804 for that.

See Also: → 2071804
Whiteboard: [webdriver:triage]
Assignee: hskupin → nobody
Status: ASSIGNED → NEW
Priority: -- → P3
Whiteboard: [webdriver:backlog]
You need to log in before you can comment on or make changes to this bug.