Skip to content

doc: Multi-Profile system documentation#20751

Open
criticalAY wants to merge 1 commit intoankidroid:mainfrom
criticalAY:mp/doc
Open

doc: Multi-Profile system documentation#20751
criticalAY wants to merge 1 commit intoankidroid:mainfrom
criticalAY:mp/doc

Conversation

@criticalAY
Copy link
Copy Markdown
Contributor

Purpose / Description

Document how mulit-profile works and how the folder structure looks like

Fixes

NA

Approach

NA

How Has This Been Tested?

NA

Learning (optional, can help others)

Always document first so that we don't mess up later

Checklist

Please, go through these checks before submitting the PR.

  • You have a descriptive commit message with a short title (first line, max 50 chars).
  • You have commented your code, particularly in hard-to-understand areas
  • You have performed a self-review of your own code
  • UI changes: include screenshots of all affected screens (in particular showing any new or changed strings)
  • UI Changes: You have tested your change using the Google Accessibility Scanner

Comment thread docs/multiprofile/README.md Outdated
Comment thread docs/multiprofile/README.md Outdated
Comment thread docs/multiprofile/README.md Outdated
Comment thread docs/multiprofile/README.md Outdated
@criticalAY criticalAY added Needs Author Reply Waiting for a reply from the original author and removed Needs Review labels Apr 18, 2026
@criticalAY criticalAY added Needs Review and removed Needs Author Reply Waiting for a reply from the original author labels Apr 21, 2026
Copy link
Copy Markdown
Member

@david-allison david-allison left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more of a document review: I really appreciate this exists as it gives me a great 'quick' reference to get back up to speed.

Feel free to merge at your discretion.

Comments can be turned into TODOs on this document, or an issue could be added


| Term | What it is | Where it lives |
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---|
| **ProfileId** | Immutable string identifier. Either the literal `"default"` or `"p_" + 8 hex chars` (e.g. `p_a1b2c3d4`). Used as the folder name on disk. **Never the user's display name.** | In-memory; persisted as a key in the global registry. |
Copy link
Copy Markdown
Member

@david-allison david-allison Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProfileId isn't really just in-memory, it's also on in-disk identifier, and stored in the Global Profile Registry

| **ProfileId** | Immutable string identifier. Either the literal `"default"` or `"p_" + 8 hex chars` (e.g. `p_a1b2c3d4`). Used as the folder name on disk. **Never the user's display name.** | In-memory; persisted as a key in the global registry. |
| **ProfileMetadata** | User-visible data about a profile: `displayName`, `version`, `createdTimestamp`. Serialized as JSON. | Value stored under the ProfileId key in the global registry. |
| **Global Profile Registry** | A single `SharedPreferences` file shared across the whole app. Contains the registered profiles (ProfileId -> metadata JSON) and the bookkeeping key `last_active_profile_id`. | `shared_prefs/profiles_prefs.xml` |
| **Profile-namespaced SharedPreferences** | The normal per-profile user settings (sync key, username, deckPath, deck options, etc.). Every pref file is prefixed with `profile_<profileId>_` by `ProfileContextWrapper`, so profiles cannot see each other's settings. | `shared_prefs/profile_<profileId>_*.xml` |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every pref file

Maybe 'filename'?


## Global Profile Registry

Stored in `shared_prefs/profiles_prefs.xml`. Conceptually:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be clear here and above: use the full path of shared_prefs/profiles_prefs.xml

├── p_a1b2c3d4 = {"displayName":"Alice", "version":1, "created":"2026-01-15T08:24:00Z"}
└── p_e5f6g7h8 = {"displayName":"Bob", "version":1, "created":"2026-02-03T14:10:00Z"}

Everything else about a profile (its files, its settings, its collection) is derived from the ProfileId key and lives elsewhere on disk.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a TODO: There is a solid rationale for moving the sync username and hkey here (from memory, upstream does this, AND it means we can show the associated AnkiWeb account on the select profile screen)

├── databases/ # Default profile (legacy layout)
├── files/ # Default profile (legacy layout)
├── cache/ # Default profile (legacy layout)
├── p_a1b2c3d4/ # Alice's profile root (ProfileId, not display name)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider moving profiles to a /profiles/ directory so the folders don't pollute the namespace


## External storage (`/storage/emulated/0/Android/data/<pkg>/files/`)

This is where the actual Anki collections live (`collection.anki2`, `collection.media/`, backups). The location is controlled by `PREF_COLLECTION_PATH` (the `"deckPath"` preference) inside each profile's namespaced preferences.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this can be any location on non-Play variants of the app

/storage/emulated/0/AnkiDroid is the default


### Profile Deletion

Deletion follows a **disk-first, registry-last** pattern: if the app crashes mid-way, the registry entry still points at the remaining files so the user can retry cleanup.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a warning here for security:

  • If AnkiDroid is using MANAGE_EXTERNAL_STORAGE
  • Then AnkiDroid could be used to delete arbitrary files on-disk

@david-allison david-allison added the Needs Author Reply Waiting for a reply from the original author label Apr 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs Author Reply Waiting for a reply from the original author Needs Review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants