3.9 KiB
Recommended storage redesign
Decision
Keep /data on internal eMMC. Repair retention/pruning leaks first. Use adopted
USB only for large, reconstructible and non-boot-critical content through
Android's private-volume APIs, always with an internal fallback. Do not make
boot, Package Manager, user unlock or core TV playback depend on USB.
Architecture
- Internal: settings, credentials, TV channel source, favorites, recordings/reminders metadata, small EPG index/mapping and a minimal empty EPG DB.
- Adopted private ext4: optional EPG schedule payload/cache and downloadable
assets only after an OEM platform integration. Android has no ordinary
public API that allocates one arbitrary SQLite file directly in another
app-private adopted-volume root.
getExternalFilesDirs()may expose a secondary/emulated path but is not the desired direct private-ext4 SQLite contract; PackageManager movement moves the package/data as a unit and is not selective. Never use/storage/emulatedFUSE for this database. - At boot, Channels opens its internal minimal DB immediately. An OEM helper
creates/types an app-owned directory below the adopted private volume. A
volume callback activates it only after vold reports
MOUNTEDand an app-owned sentinel/schema/hash check passes. This needs a narrow SELinux type; it is not available on the stock image. - If USB disappears or I/O fails, close adopted SQLite connections, fall back to internal Now/Next/minimal schedule, notify without crashloop, and rebuild adopted cache after reinsertion.
- Split the current monolithic DB at the provider layer: internal
channel/mapping/Now/Next authority, optional external schedule cache. Do not
use cross-volume SQLite
ATTACHas an atomicity assumption. DB operations use a private ext4 directory, normal SQLite locking, fsync/atomic rename and bounded retention. No symlink or global bind mount.
Why this order
The EPG and GEL fixes already recover about 1,84 GiB combined without changing
boot architecture. Official app movement offers little here because the large
listed packages are updated system apps. A whole-/data USB design intersects
early init, vold timing, FBE/fscrypt, SELinux, recovery, factory reset, OTA and
USB power; removal could make the TV unbootable.
Failure and migration protocol
- Feature flag default off; preflight performance and free space.
- Copy only reconstructible schedule rows with SQLite backup into a versioned
temp directory, run
integrity_check, fsync file and directory, then atomically switch an app-level generation marker; retain internal fallback. - Never migrate recording/reminder DB or channel/favorite authority blindly.
- Maintain last-known-good schema version and garbage-collect old adopted generations only after successful reopen.
- USB missing/slow/corrupt is a tested normal state, not a boot failure.
- Removal mid-query/write must close the external pool, discard the incomplete generation and continue with internal Now/Next. Reinsertion never reuses a DB until UUID, schema, integrity and generation checks pass.
- Adopted media is device-bound/encrypted and not a portable backup. Factory reset, reformat, UUID change and OTA migration are explicit test cases.
Classification
Leak fixes: SUPPORTED APP/FIRMWARE FIX. Movable ordinary apps: ANDROID
PLATFORM BEHAVIOR. Selective EPG private-volume path: POSSIBLE WITH PATCH.
Bind mount/symlink: HIGH-RISK HACK. Whole /data: NOT PRACTICAL.
Release gates
Random-write latency and fsync p95 must remain within an OEM-defined TV UI budget; 1,000 removal/reinsert cycles, standby power cuts, full-volume writes, corruption, factory reset and OTA must leave Live TV and the internal provider usable. Without OEM source, SELinux policy and a recoverable image build this remains architecture documentation, not a deployable patch.