Files
philips-tv-speicher-voll/patches/epg-stale-cleanup/PATCH-PLAN.md

3.4 KiB
Raw Blame History

Patch plan – bounded EPG retention

Target

/system/priv-app/channels/channels.apk, DEX class org.droidtv.channels.epg.bcepg.EpgProvider$deleteStaleDataRunnable plus a small helper in EpgDatabaseHelper. Original APK SHA-256: 3A44BC648624F0CC9CD9FEB4CFC3FD33F41323597718E4FCCFC25FE35504D34F.

Policy

  • Keep the clock API explicitly in epoch milliseconds, then convert once to epoch seconds before touching the database. The physical starttime and endtime values in both the old and freshly reacquired databases are epoch seconds. Use TimeUnit.MILLISECONDS.toSeconds(nowMillis) and TimeUnit.DAYS.toSeconds(7); never compare a millisecond cutoff to the DB.
  • Retain seven past days for backward-guide/recording metadata compatibility; retain all future events. Make the value OEM-configurable in 1–30 days.
  • Now/Next may be deleted after endtime < now-2h; FVP rows must also respect their expiry semantics.

Algorithm

Ensure scheduletable(endtime) remains indexed. Once per day, initially 5–15 minutes after provider startup and only while no acquisition transaction is active, delete at most 2.000 rows per transaction:

long nowMillis = clock.millis();
long cutoffSeconds = TimeUnit.MILLISECONDS.toSeconds(nowMillis)
        - TimeUnit.DAYS.toSeconds(retentionDays);
do {
  int n = db.deleteByIdBatch(
      "scheduletable", "endtime < ?", cutoffSeconds, "endtime", 2000);
  metrics.addDeleted(n);
  if (n == 2000) SystemClock.sleep(100);
} while (n == 2000 && powerAndLoadPolicy.permitsMaintenance());

deleteByIdBatch must run one transaction containing an index-ordered ID selection with LIMIT ? and a delete by those IDs. Do not build a 2.000- placeholder SQL string; use a temp-ID table or DELETE ... WHERE _id IN (SELECT _id ... ORDER BY endtime LIMIT 2000) with bound cutoff. Commit each batch so rollback journal/lock duration is bounded.

The fixed Runnable should call this helper and log cutoff, unit, rows, duration, DB bytes and remaining old-row count—not the misleading word “Deleting” before any mutation. Schedule a unique daily WorkManager job with KEEP, not a chain.

Phase 6 deliberately limits the first production change to scheduletable. Now/Next are tiny and FVP expiry semantics are not sufficiently proven for a shared delete rule. They can be added only after table-specific retention tests.

Auto-vacuum / power / locks

The DB is auto_vacuum=FULL; small daily batches prevent the massive page-move storm seen after years of accumulation. Use normal SQLite transactions and busy_timeout/bounded retry with jitter; never delete while acquisition owns a write transaction. A power loss can roll back one batch only. Do not VACUUM during Live TV. For a one-time legacy migration, offer the already validated compact-rebuild workflow with backup and atomic rename.

Smali plan

Replace the Runnable body after cutoff computation with a typed call to the new helper; do not inline a shell or raw concatenated SQL payload. If adding DEX methods is impractical, redirect to the already present EpgProgramPump.deleteScheduleProgramsByTime(long) only after correcting its unit and adding batching; its current unbounded delete is unsuitable for a 3-million-row legacy DB.

Acceptance

See patches/REGRESSION-TEST-PLAN.md. Key gate: after a 30-day synthetic soak, oldest row >= cutoff (within one batch), DB growth plateaus, current/future EPG, favorites and recording/reminder tables remain correct.