Maintain the extension platform
July 29, 2026 · View on GitHub
Start from the failure the user can see, then follow the call path to the first owning component. To build an independent APK, use the extension developer guide instead.
Where did the flow stop?
An external extension call has four stages:
discover extension Service -> user authorizes -> invoke Hook -> host applies result
| Visible symptom | Start here | Closest validation |
|---|---|---|
| Service discovery returns an empty list | AndroidExtensionDiscovery | ExternalExtensionIpcTest |
| It appears, but cannot be enabled or disconnects after an update | ExtensionPluginRepositoryImpl, AndroidBoundExtensionTransport | ExtensionTrustStoreTest, ExtensionConnectionStateTest, and ExternalExtensionIpcTest |
| A Hook is not called, times out, or is incompatible | ExtensionRuntime, ExtensionContractCatalog | ExtensionRuntimeTest |
| The Hook succeeds but UI, Room, or playback does not change | The calling repository and its importer or renderer | The adjacent repository/importer test |
For Emby/Jellyfin subscription, refresh, or playback failures, start at SubscriptionProviderRepositoryImpl. They are built-in extensions and do not use Android IPC.
Answer four questions before editing
- Which user action triggers this flow?
- Which
HookSpecdoes it invoke? - Who validates and applies the result?
- What is the smallest visible acceptance result?
If any answer is missing, the flow usually still lacks a real host caller or result applicator.
Three boundaries
- An extension returns candidate data; it does not directly modify Room, UI, or the player.
- One extension's failure must not delete another extension's data or its own last successful data.
- Built-in and APK extensions share the same Hook contracts; only the APK path crosses Android IPC.
Use Current architecture and code map to trace a complete path, Change by task before editing, and Extension UI quality gates for any plugin-facing phone, tablet, or TV change. Read Current status and release gate only when deciding whether a capability is open or releasable.