1.9 KiB
Storage monitor redesign
Stock behavior proven from DEX
TPTvService.apk!/classes.dex,
TVStorageMonitorService$2.run(), code_off=0x2ad380, polls /data using
legacy getBlockSize/getAvailableBlocks/getBlockCount. Static constants are
exactly 524,288,000 bytes and 1,073,741,824 bytes. It also reads
persist.odm.tpv.sys.emmc_lifetime; 80–90%, 90–100% and exceeded return true.
Capacity and health are then conflated:
- below 500,000 KiB-ish bytes: critical cleanup + UI;
- below 1 GiB while health is not critical: low-space UI;
- at or above 1 GiB while health is critical:
MEMORY_CRITICALcleanup anyway.
The same service contains a global cache sweep over all installed packages and
a separate 150 MiB /data/vendor/user_setting cleanup branch. Polling normally
runs every 30 seconds; a 300-second assignment is immediately overwritten by
30 seconds at DEX PCs 0x02de–0x02e6.
Replacement policy
Use StatFs.getAvailableBytes() and Android StorageManager low/full
thresholds for the actual /data filesystem. Enter LOW after two low samples;
enter CRITICAL immediately at the full threshold. Clear only after three
samples above max(low+256 MiB, low*1.25). Notify/broadcast on state transition,
not every poll, and rate-limit repeated user UI. Poll every ten minutes in OK,
one minute in LOW/CRITICAL, plus platform storage broadcasts.
eMMC lifetime and PRE_EOL are a separate health state with separate wording, telemetry and escalation. A wear bucket must never claim that filesystem space is low. Unknown health data is not “healthy” or “critical”.
Do not automatically clear every application's cache. Preserve the
user_setting check only as a separately named OEM-data policy, with its own
threshold, metrics and user impact; it must not drive the internal-storage UI.
tools/test_storage_state.py exercises entry debounce, critical transition,
hysteresis, deduplication, unknown measurements and health/capacity separation.