mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-30 07:37:38 +00:00
- Leaving uses MarmotManager.leave in the app and amy: the heir is chosen among the members (a listed admin who already left no longer counts), the last member of a group can leave (it used to throw), and amy no longer publishes the step-down commit a second time. - The member menu and revokeMarmotGroupAdmin use MarmotGroupPermissions, so demotion is checked against the members rather than the list's length. - The feed asks MarmotAppEvent.isTimelineRow and the edit overlay asks MarmotMessageEdit instead of keeping their own copies of those rules. - The media policy is built with EncryptedMediaPolicyV2.forBlossom, so amy's set-policy accepts a base URL without a trailing slash too. - Group creation moves from CreateGroupScreen into BaseAccountViewModel.createMarmotGroup, and drops the profile commit that repeated the name already set at epoch 0. - Removed: the unused commons viewmodels.MarmotGroupFeedViewModel and the MIP-04 send path nothing reached. - cordn: the exposure card and amy stop calling the deprecated differsFromMarmot; CordnRuntimeTest moves to commons/src/jvmTest. - AGENTS.md keeps a short version of the two-process rules; the detail moves to android-expert's references (31.6 KB of Codex's 32 KB). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSSNWvwXdNnNwYnLoEvNcq
33 lines
1.9 KiB
Markdown
33 lines
1.9 KiB
Markdown
# The two Android processes
|
|
|
|
Moved from `AGENTS.md`, which keeps the short version.
|
|
|
|
The Android app is **not single-process**. Android instantiates the one `Amethyst`
|
|
Application class (there is no per-process Application in the manifest) in **both**:
|
|
|
|
- **main** — the normal app: UI, account, signer, `LocalCache`, relay client.
|
|
`Amethyst.instance` (`AppModules`) is built here.
|
|
- **`:napplet`** — the sandboxed WebView host for NIP-5D napplets / NIP-5A nSites
|
|
(`NappletHostActivity`, declared `android:process=":napplet"`). It holds **no**
|
|
account or keys; `Amethyst.onCreate()` early-returns here so `Amethyst.instance`
|
|
is **left unset** (touching it throws `UninitializedPropertyAccessException`).
|
|
The sandbox runtime lives in its own module **`:nappletHost`** (depends on
|
|
`:commons`, `:commonsUI` — the shell's web contract and Compose resources — and
|
|
quartz; **never** `:amethyst`) so it *cannot* import
|
|
`Amethyst`/`LocalCache`/`Account` — the broker-side (signer, gateways, registry)
|
|
stays in `:amethyst` and the two halves talk over Messenger IPC.
|
|
|
|
Consequences — don't get caught assuming one process:
|
|
|
|
- **Processes don't share memory.** Every `object`/companion/`static` is a
|
|
*separate copy per process*: `LocalCache` (an `object`), `NappletLaunchRegistry`,
|
|
etc. The populated `LocalCache` lives only in **main**; the sandbox neither
|
|
builds nor should reference it (a stray reference would lazily create a second,
|
|
empty cache there).
|
|
- **Don't assume `Amethyst.instance` exists.** Any code reachable from `:napplet`
|
|
(the host activity, content server, or an Application lifecycle callback like
|
|
`onTrimMemory`) must guard on the process and never reach for `instance`.
|
|
- **Cross-process state goes over Messenger IPC**, never a shared singleton — this
|
|
is why the broker (main) owns `NappletLaunchRegistry` and the sandbox only relays
|
|
an opaque token. See `amethyst/plans/archive/2026-06-22-napplet-nsite-security.md`.
|