mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-06 11:48:24 +00:00
Completing a pick on either embedded surface crashed the whole app, every
time. parseResult resolved the picked URIs through
`WebChromeClient.FileChooserParams.parseResult`, which is a WebView *static*:
it boots Chromium in whichever process calls it. WebFileChooserActivity — the
main-process chooser host that exists precisely because the `:napplet`
providers are windowless and have no Activity to launch a picker from —
declares no `android:process`, so that call ran in main while `:napplet`
already held the WebView data directory. AwDataDirLock then threw
Using WebView from more than one process at once with the same data
directory is not supported
as a FATAL EXCEPTION on main. Reproduced on a Pixel 8 / Android 17: the
picker opens, the user selects, and on Done the process dies before the page
is ever handed its file.
The two Activity-owning hosts never hit it because they are themselves
`android:process=":napplet"`, where WebView is already initialised — which is
why the full-screen browser picked files correctly throughout. Cancelling did
not hit it either, so "the picker opened" was never enough to catch this.
The URIs are now read off the result Intent directly. The platform
implementation reads exactly the same two fields (ClipData items, else the
data URI, only on RESULT_OK), so behaviour is unchanged for the single-URI,
multi-select and camera shapes; it just no longer drags WebView into a
process that must not have it.
This also plugs a grant leak. releaseGrants runs *inside* parseResult, after
the line that was throwing, so every crashed capture left the camera apps
holding a live write grant on the capture URI that nothing would ever revoke.
Verified on device after the fix:
- embedded pick: no crash, page reads back all 94,976 bytes of the chosen
PNG with its header intact — so a URI granted to the main process is
readable by the WebView in `:napplet` with no re-granting, as designed
- camera capture: 892,681-byte JPEG with EXIF intact (full resolution, so
EXTRA_OUTPUT is doing its job), delivered under the same name as the
granted URI
- grant/revoke: 0 outstanding grants on the capture authority, 1 while the
camera holds it, 0 again once the result is in
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gs2gi3sZfQ7SHrVm2njLMw