Files
amethyst/nappletHost
Vitor PamplonaandClaude Opus 5 f11bdb8e49 fix(browser): stop the embedded file pick from killing the app
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
2026-08-26 00:05:13 -04:00
..