Skip to content

v0.9.0 — in-app downloads land on O_DIRECT internal storage

Choose a tag to compare

@Helldez Helldez released this 18 Jul 18:05
e8a6614

In-app downloads now use O_DIRECT-capable internal storage

Downloading a model in the app — from the catalog or a pasted URL — used to write to the app's external files dir, an emulated/FUSE volume where O_DIRECT silently returns wrong data. The engine caught it and fell back to buffered I/O, so every in-app-downloaded model lost the streaming advantage the engine exists for (measured on device: o_direct=0). The system DownloadManager cannot write to internal storage by design, so it is replaced.

DownloadWorker is a foreground WorkManager transfer that streams the gguf over HTTP straight into filesDir/models (real f2fs, where O_DIRECT works — the same dir the file picker imports to). Validated end-to-end on device (OnePlus 15R): a ~20 GB model downloaded in-app now loads in direct (O_DIRECT) mode.

What changed

  • Downloads land on internal storage → real O_DIRECT, not buffered. Fixes #67.
  • Resume: an interrupted .part resumes from its offset with a Range request, following Hugging Face's resolve → CDN redirect manually so the header survives (instead of restarting a multi-GB transfer from zero).
  • No temporary second copy: a download needs free space equal to the model size, not double.
  • Rename-on-complete, so a half-finished download is never listed as runnable.
  • UI: the MiB counter sits on its own line so a long model name can't ellipsize it away; the bar clears when nothing is in flight; Cancel no longer races back to "downloading".

This mirrors the mechanism in Google's own AI Edge Gallery (HttpURLConnection + Range + WorkManager foreground worker).

Known limitation (#69): if the OS kills the app while it is in the background mid-download, Android 14 blocks WorkManager from restarting the foreground transfer until you reopen the app. The .part is preserved and resumes when you re-trigger the download — no bytes are lost, but it does not continue on its own.

Install: sideload app-dev-debug.apk (dev flavor; keeps all-files access so it can also read adb-pushed models). Models already downloaded by older builds keep working.