Where everything lives on a head unit, and why the flash memory has a write budget that must last fifteen years — the constraint that explains CarWatchdog and Garage Mode.
Intermediate6 minStorage · Partitions · I/O
Flash memory wears out. Each cell can be written a finite number of times, and a
vehicle has to keep working for fifteen years without anyone replacing it.
That single physical fact explains several parts of the platform that otherwise
look like arbitrary bureaucracy.
Batch. Accumulate in memory, write once. One transaction of 200 records
instead of 200 transactions.
Batching, concretelykotlin
private val pending = ArrayDeque<Reading>()fun record(r: Reading) { pending += r if (pending.size >= 200) flush()}private fun flush() = db.runInTransaction { dao.insertAll(pending.toList()) pending.clear()}
Do not log to files in production.logcat is an in-memory ring buffer and
costs no flash. Writing your own log files is the most common cause of I/O
overuse, and it is almost never necessary.
Defer bulk work to . The quota there is far larger,
deliberately — that is where syncing, compaction and cache warming belong.
Bound every cache. An unbounded on-disk cache is a slow leak that eventually
triggers the watchdog.
Prefer append to rewrite. Rewriting a whole file to change one field
multiplies writes by the file size.
/data is encrypted, and Android uses file-based encryption — different
files can be locked with different keys.
Storage that works before unlockkotlin
// Available as soon as the device boots — no user neededval deviceContext = context.createDeviceProtectedStorageContext()val vehiclePrefs = deviceContext.getSharedPreferences("vehicle", MODE_PRIVATE)// Only after the user unlocksval userPrefs = context.getSharedPreferences("user", MODE_PRIVATE)
Putting something in the wrong one produces a service that works in testing and
fails on a cold boot before anyone signs in — a classic automotive bug, because
on a phone someone always unlocks quickly.