Files
philips-tv-speicher-voll/diagnostics/deep-forensics/philips/epg-reverse-agent.md

33 KiB
Raw Blame History

Statische Reverse-Analyse von EpgDatabase.db

Stand: 2026-08-25
Zielplattform: Philips TPM191E, Firmware TPM191E_R.211.000.103.000, Android TV 12
Hauptartefakt: diagnostics/raw/storage/channels.apk

Umfang und Beweisgrade

Diese Untersuchung war ausschließlich lokal und lesend. Es wurden keine ADB-Gerätebefehle und keine Reparatur-, Lösch-, Reset- oder Rebuild-Aktion auf dem Fernseher ausgeführt. Untersucht wurden die vorhandenen APK-/DEX-Artefakte, deren binäres Manifest und Ressourcen sowie bereits zuvor abgelegte Diagnoseausgaben.

Die Kennzeichnungen bedeuten:

  • BEWIESEN: direkt aus Manifest, DEX-Bytecode, SQL-Literal oder vorhandener Rohdiagnose ableitbar.
  • SEHR WAHRSCHEINLICH: mehrere direkte Belege ergeben dieselbe Erklärung; eine verbleibende Laufzeitunsicherheit besteht.
  • PLAUSIBEL: technisch gut passende Interpretation, deren Entwicklerabsicht oder Laufzeitwirkung nicht direkt belegt ist.
  • NICHT VERIFIZIERBAR: mit den lokal vorhandenen Artefakten nicht entscheidbar.

Kurzfazit

  1. BEWIESEN: org.droidtv.channels verwaltet EpgDatabase.db über org.droidtv.channels.epg.bcepg.EpgDatabaseHelper, eine Unterklasse von android.database.sqlite.SQLiteOpenHelper. Der Konstruktor übergibt den Datenbanknamen EpgDatabase.db und die Schemaversion 6.
  2. BEWIESEN: Die vorgesehene zeitbasierte Stale-Cleanup-Kette endet in EpgProvider$deleteStaleDataRunnable.run(). Dieses Runnable berechnet zwei Grenzwerte und protokolliert sie, führt aber keinerlei Löschung aus. Es gibt darin weder SQLiteDatabase.delete/execSQL noch ContentResolver.delete/applyBatch noch einen Aufruf der vorhandenen echten Zeit-Löschmethoden.
  3. BEWIESEN: Der beim Provider-Start ausgeführte Logpfad wird nach 120.000 ms ausgelöst. Die vorhandenen Boot-Logs passen exakt zum Bytecode, beweisen aber keine gelöschte Zeile.
  4. BEWIESEN: Die Rebuild-Pfade löschen Zeilen, komprimieren die SQLite-Datei jedoch nicht. In allen vier DEX-Dateien von channels.apk fehlen Literale beziehungsweise Referenzen für VACUUM, PRAGMA auto_vacuum, incremental_vacuum und wal_checkpoint.
  5. BEWIESEN: Die bisher kleinen Zeilenzahlen betreffen nur indextable, nowtable, nexttable und fastipnownexttable; sie begrenzen weder scheduletable noch die beiden FVP-Tabellen. Eine lesende Abfrage des Join-Endpunkts antenna/scheduletable lief länger als 120 Sekunden und musste clientseitig abgebrochen werden. Aktive Schedule-/FVP-Daten können daher einen wesentlichen Teil der 1,62 GiB belegen.
  6. SEHR WAHRSCHEINLICH: Der wirkungslose Stale-Cleanup ist ein konkreter Mechanismus, durch den alte Schedule-Daten anwachsen können. Ob die Dateigröße überwiegend aus lebenden Schedule-/FVP-Zeilen, freien Seiten oder interner Fragmentierung besteht, ist ohne freelist_count/dbstat beziehungsweise DB-Kopie offen.
  7. BEWIESEN: Es gibt interne mutierende Rebuild-URIs, aber keine gefundene Benutzer-Activity, Service-Aktion oder UI-Zeichenkette „EPG zurücksetzen/löschen“. Das Umschalten der TV-Guide-Quelle ist ausdrücklich keine harmlose Reset-Funktion: Ressourcen warnen vor Verlust beziehungsweise Abbruch von Aufnahmen, Erinnerungen und programmierten Aufnahmen.

Analysierte Artefakte

Artefakt SHA-256 Relevanz
diagnostics/raw/storage/channels.apk 3A44BC648624F0CC9CD9FEB4CFC3FD33F41323597718E4FCCFC25FE35504D34F EPG-Provider, Datenbankhelper, Guide-UI, Aufnahme-/Reminder-Verknüpfungen
diagnostics/raw/tvstrings.apk A25724A08369FBF1AE31884044816441C4ABCD9FC0F0116BCDB563FEC44AE923 lokalisierte TV-Guide-Warntexte
diagnostics/raw/TPTvService.apk 75F492EE89906C8C267D685D2B7D0CE02BB09F3A6B4CC8456F8B096B9E441ECD Quersuche nach externen Rebuild-/Cleanup-Aufrufern
diagnostics/raw/eum.apk 3B27806AC60B946C47CCAC1BE7EDAD46938CAE10C43C3F2E1F3EF4F9D2D30B98 Quersuche
diagnostics/raw/storage/gel.apk 29A68E6B09700ED4CCDF312C0B99EEE0C3F67E329A537FE87ED4341A71D383D7 Quersuche
diagnostics/raw/tvwidgets2k15.apk 93876A5FDC637B304BD6EE988A7F7523D957A9B0135AEFD62E3C13A6AC06E496 Quersuche
diagnostics/raw/emmc/usagelogger.apk 7416D0F7017B56F2980A4F3042B49A4A6954D9FBACC7FF995509FB8BD9BF6A15 Quersuche

channels.apk enthält vier DEX-Dateien: classes.dex, classes2.dex, classes3.dex und classes4.dex. Die hier relevante Implementierung liegt überwiegend in channels.apk!/classes4.dex.

Für die reproduzierbare Extraktion wurden die lokalen, dependency-freien Hilfsprogramme dex_probe.py, axml_dump.py und resource_strings.py in diesem Verzeichnis verwendet. Sie dekompilieren nicht heuristisch, sondern lesen DEX-Index-/Klassendaten, Bytecode-Referenzen, binäres Android-Manifest und Resource-Stringpools.

Datenbankname, Helper und Version

Helper

  • BEWIESEN: Klasse Lorg/droidtv/channels/epg/bcepg/EpgDatabaseHelper;
  • BEWIESEN: Superklasse Landroid/database/sqlite/SQLiteOpenHelper;
  • BEWIESEN: Konstruktor EpgDatabaseHelper.<init>(android.content.Context) lädt das Literal EpgDatabase.db, setzt die CursorFactory auf null und den Versionsparameter auf 6, bevor SQLiteOpenHelper.<init>(Context,String,CursorFactory,int) aufgerufen wird.
  • BEWIESEN: onCreate(SQLiteDatabase) ruft ausschließlich createTables(SQLiteDatabase) auf.
  • BEWIESEN: In der Helper-Klasse gibt es keine Overrides von onConfigure() oder onOpen().

Schema v6

EpgDatabaseHelper.createTables(SQLiteDatabase) enthält folgende physischen Tabellen:

Tabelle Exakte Spalten aus dem DDL
mappingtable mappingid INTEGER PRIMARY KEY AUTOINCREMENT, presetid INTEGER, svlid INTEGER, svlrecid INTEGER
indextable dbitindex INTEGER PRIMARY KEY AUTOINCREMENT, satnum, sid, tsid, onid, pfshd, sdtguidanceinfo TEXT, dpsid, dptsid, pkgid, presetnumber, presetid, favoriteNumber, channelname TEXT, logoid, svlid, svlrecid, browsable (nicht als TEXT markierte Felder jeweils INTEGER)
nowtable _id INTEGER PRIMARY KEY AUTOINCREMENT, eventid, presetid, eventname TEXT, version, starttime, endtime, shortinfo TEXT, extendedinfo TEXT, languageid, linktype, targetindex, genre, scrambled, rating, guidanceinfo TEXT
nexttable identisch zu nowtable
scheduletable _id INTEGER PRIMARY KEY AUTOINCREMENT, eventid, presetid, eventname TEXT, version, starttime, endtime, shortinfo TEXT, extendedinfo TEXT, languageid, genre, scrambled, rating, guidanceinfo TEXT
fvpscheduletable channelid, onid, sid, eventid, crid, Start-/Endzeit, Titel-/Synopsis-, Genre-/Rating-, Bild-/On-Demand-, Accessibility-, Delivery-, Video- und Expiry-Felder; zusammengesetzter Primärschlüssel (channelid,starttime,endtime)
fvpnownexttable wie FVP-Schedule mit zusätzlichem nownext, restartstatus und FVP-Now/Next-Feldern; zusammengesetzter Primärschlüssel (channelid,starttime,endtime)
channelmapversiontable id INTEGER PRIMARY KEY, majorversion INTEGER, minorversion INTEGER, favouriteversion INTEGER
fastipnownexttable _id INTEGER PRIMARY KEY AUTOINCREMENT, channelid, eventid, programId, nownext, Start-/Endzeit, Titel-/Synopsis-, Genre-/Rating-, Audio-/Video-, lastmodified- und expiretime-Felder

Die vollständigen, ungekürzten DDL-Literale stehen in epg-dex-context.txt, insbesondere im Kontext von EpgDatabaseHelper.createTables().

Definierte Indizes:

  • mappingindex(svlid,svlrecid)
  • indexdbit(satnum,sid,tsid,onid)
  • indexpresetid(presetid,presetnumber)
  • indexnowendtime(endtime), indexnowevent(presetid)
  • indexnextendtime(endtime), indexnextevent(presetid)
  • indexschedendtime(endtime), indexschedstarttime(starttime), indexschedpresetid(presetid), indexschedeventid(presetid,eventid)
  • ixfvpschedpresetidstet(channelid,starttime,endtime)
  • ixfvpnownext(channelid,starttime,endtime)

BEWIESEN: nownexttable ist trotz des URI-Pfads keine durch createTables() angelegte physische Tabelle. EpgProvider.query() bildet diesen Endpunkt über den Join

indextable AS Dbit LEFT JOIN nowtable AS Now USING(presetid) LEFT JOIN nexttable AS Next USING(presetid)

ab. Frühere Rohnotizen, die nownexttable als physische Tabelle bezeichnen, sind insofern zu präzisieren.

onUpgrade, onDowngrade und vermeintliche Drop-Funktionen

onUpgrade(SQLiteDatabase,int,int)

BEWIESEN: Der Bytecode vergleicht den Parameter newVersion mit 4, 5 und 6:

  • Zielversion 4, 5 oder 6: nur createTables(db); wegen IF NOT EXISTS eine additive/idempotente Schemaanlage.
  • Jede andere Zielversion: DROP TABLE IF EXISTS für indextable, nowtable, nexttable, scheduletable, channelmapversiontable und fastipnownexttable, anschließend createTables(db).

Der Fallback droppt weder mappingtable noch fvpscheduletable noch fvpnownexttable.

onDowngrade(SQLiteDatabase,int,int)

BEWIESEN: Die Methode protokolliert lediglich onDowngrade allowed und nimmt keine Schemaänderung vor.

resetInstance()

BEWIESEN: EpgDatabaseHelper.resetInstance() setzt nur das statische Singleton-Feld mEpgDbHelper auf null. Die Methode löscht weder Datei noch Tabellen oder Zeilen.

dropTables() und dropIndexTable()

Die Namen sind irreführend:

  • BEWIESEN: dropIndexTable() führt innerhalb einer Transaktion SQLiteDatabase.delete("indextable", null, null) aus; die Tabelle selbst bleibt bestehen.
  • BEWIESEN: dropTables() führt SQLiteDatabase.delete(table,null,null) für indextable, nowtable, nexttable, scheduletable, fvpnownexttable, fvpscheduletable, channelmapversiontable und fastipnownexttable aus.
  • BEWIESEN: mappingtable wird von dropTables() nicht geleert. syncOnChannelTableChange() leert und rekonstruiert sie später separat aus der kanonischen Senderliste.
  • BEWIESEN: Keine der beiden Methoden führt anschließend VACUUM oder eine andere Dateikompaktierung aus.

Stale-/Cleanup-Logik

Tatsächliche Aufrufketten

Es existieren zwei Einstiege in dasselbe Runnable:

  1. Provider-Start

    • EpgProvider$1.run() führt zunächst dropIndexTable(), syncChannelTable() und syncOnChannelTableChange() aus.
    • Danach postet die Methode mDeleteStaleDataRunnable mit Handler.postDelayed(..., 120000).
    • Das Literal und die Logmeldung Posting stale data deletion after 2 mins in onCreate stimmen überein.
  2. Alarm/Receiver-Pfad

    • Manifest-Receiver: org.droidtv.channels.epg.bcepg.EpgStaleDataCleanupAlarmReceiver
    • Intent-Action: org.droidtv.channels.epg.bcepg.EpgStaleDataCleanupAlarmReceiver.CLEAR_STALE_DATA
    • Data-Scheme: epgStaleDataCleanup
    • EpgDatabaseHelper.setEpgStaleDataCleanUpAlarm() erstellt einen expliziten Pending-Broadcast und setzt per AlarmManager.setExact() einen RTC-Alarm auf currentTimeMillis + 43.200.000 ms, also 12 Stunden.
    • EpgStaleDataCleanupAlarmReceiver.onReceive() ruft EpgInfoSingleton.cleanEpgStaleData() auf.
    • EpgInfoSingleton$8.run() führt ContentResolver.delete(content://org.droidtv.epgdvb/antenna/staledatacleanup,null,null) aus.
    • EpgProvider.delete() postet dafür EpgProvider$deleteStaleDataRunnable.

BEWIESEN: In allen vier DEX-Dateien von channels.apk gibt es keinen Invoke-Verweis auf EpgDatabaseHelper.setEpgStaleDataCleanUpAlarm(). Der Receiver plant den Alarm nach Empfang nicht erneut. Damit ist die Methode in den lokal sichtbaren direkten Java-Aufrufpfaden verwaist. Ein reflektiver oder aus einem nicht vorhandenen Artefakt kommender Aufruf bleibt NICHT VERIFIZIERBAR.

Das Cleanup-Runnable löscht nichts

Lorg/droidtv/channels/epg/bcepg/EpgProvider$deleteStaleDataRunnable;->run()V enthält im Uhr-definiert-Zweig exakt folgende relevante Operationen:

  1. System.currentTimeMillis()
  2. Subtraktion des Wide-Literals 1800
  3. bei verfügbarem FreeView zusätzlich Subtraktion des Wide-Literals 604800
  4. Ausgabe des Ergebnisses über Log.d("EpgProvider", "Deleting stale data for time " + threshold)

BEWIESEN: Danach folgt keine Datenoperation. Die vollständige Methodenreferenzliste enthält ausschließlich Clock-/FreeView-Abfragen, StringBuilder/Logging und im Uhr-nicht-definiert-Zweig Handler.postDelayed() mit 30000 ms. Sie enthält insbesondere nicht:

  • SQLiteDatabase.delete, execSQL, rawQuery oder eine andere SQLite-Mutation,
  • ContentResolver.delete, applyBatch, update oder insert,
  • EpgProgramPump.deleteChannelProgrambytime() oder deleteScheduleProgramsByTime(),
  • eine native oder sonstige in dieser Methode sichtbare Löschfunktion.

Damit ist der als Stale-Cleanup bezeichnete Uhr-definiert-Pfad in dieser Firmware funktional ein No-op mit Logausgabe.

Einheitenfehler ist zusätzlich sichtbar

  • BEWIESEN: Der Code verwendet System.currentTimeMillis(), subtrahiert die Literale aber direkt als Millisekunden.
  • PLAUSIBEL: 1800 war als 1.800 Sekunden = 30 Minuten und 604800 als 604.800 Sekunden = 7 Tage gemeint; die fehlende Multiplikation mit 1.000 würde daraus 1,8 Sekunden beziehungsweise 10,08 Minuten machen.
  • BEWIESEN: Der vorhandene Boot-Log bestätigt die tatsächliche Einheit: Logzeit 2026-08-25 11:11:48.657, protokollierter Grenzwert 1787649106837 = lokal 2026-08-25 11:11:46.837, also rund 1,82 Sekunden früher.
  • Wegen der vollständig fehlenden Löschoperation ändert selbst dieser falsche Grenzwert derzeit keine Zeilen.

Vorhandene echte Zeit-Löschmethoden sind nicht verdrahtet

Folgende Methoden könnten tatsächlich alte EPG-Zeilen entfernen:

  • EpgProgramPump.deleteChannelProgrambytime(long): drei ContentProviderOperation.newDelete()-Operationen mit endtime < ?, danach applyBatch("org.droidtv.epgdvb", ...); die drei mContentUri-Ziele sind Now, Next und Schedule.
  • EpgProgramPump.deleteScheduleProgramsByTime(long): ContentResolver.delete() für Schedule mit endtime < ?.
  • EpgSyncThread.deleteScheduleProgramsByTime(long): delegiert an die vorige Methode.

BEWIESEN: Es gibt in den vier DEX-Dateien keinen direkten Invoke-Aufrufer für diese drei öffentlichen Methoden. Insbesondere ruft deleteStaleDataRunnable.run() keine davon auf. Ein externer/reflektiver Aufruf ist NICHT VERIFIZIERBAR, aber für die sichtbare Cleanup-Kette nicht vorhanden.

Normale EPG-Synchronisation enthält dagegen selektive Lösch-/Update-Pfade wie deleteProgramsInWindow() und kanalbezogene Abgleiche. Das erklärt, warum aktuelle Tabellen klein sein können, obwohl der globale Zeit-Cleanup wirkungslos ist.

VACUUM, auto_vacuum und Dateigröße

  • BEWIESEN: Quersuche über alle vier channels.apk-DEX-Dateien fand kein Literal beziehungsweise keine Referenz für VACUUM, PRAGMA, auto_vacuum, incremental_vacuum oder wal_checkpoint.
  • BEWIESEN: dropTables() und beide Rebuild-Runnables löschen Zeilen, rufen aber selbst weder VACUUM noch ein Auto-Vacuum-PRAGMA auf.
  • BEWIESEN, aber nicht gerätespezifisch: Die AOSP-libsqlite-Buildkonfiguration ist mindestens im Android-11-Branch mit -DSQLITE_DEFAULT_AUTOVACUUM=1 dokumentiert, also Default FULL. Der Android-12-Quellbaum besitzt dieselbe Buildstruktur. Dieser Primärquellenhinweis stammt aus der parallelen Plattformanalyse, nicht aus dem Philips-APK.
  • SEHR WAHRSCHEINLICH: Falls TP Vision die AOSP-Option unverändert übernommen und die DB sie bei Anlage geerbt hat, kann SQLite freie Endseiten bei Commits automatisch zurückgeben. Die bloße Abwesenheit eines appseitigen VACUUM beweist deshalb nicht, dass ein großer Freelist-Anteil bestehen muss.
  • NICHT VERIFIZIERBAR: Die konkrete Vendor-Buildoption sowie der tatsächliche Headerwert von PRAGMA auto_vacuum, page_count, freelist_count, Seitengröße und WAL-Zustand der laufenden Datenbank, da keine lokale Kopie von EpgDatabase.db vorliegt und diese Teilanalyse keine Gerätezriffe ausgeführt hat.

Vorhandene lokale Rohdiagnose (diagnostics/raw/storage/epg-content-evidence.txt):

Objekt aktuelle Zeilen beobachtete IDs
indextable 358 dbitindex 1.267.806 bis 1.268.163
nowtable 195 _id 4.431.681 bis 4.451.328
nexttable 162 _id 4.026.589 bis 4.027.685
Join-Endpunkt nownexttable 358 kein physischer AUTOINCREMENT-Schlüssel
fastipnownexttable 0 keine aktuellen Zeilen

Die Datenbankdatei wurde dort mit 1.742.053.376 Bytes (ca. 1,62 GiB) protokolliert. Diese Tabelle ist ausdrücklich unvollständig: scheduletable, fvpscheduletable und fvpnownexttable wurden damit nicht gezählt.

  • BEWIESEN: AUTOINCREMENT-Werte in Millionenhöhe bei nur wenigen hundert aktuellen Zeilen zeigen massiven historischen Insert/Delete-Churn.
  • BEWIESEN: Daraus folgt nicht, dass Millionen Zeilen gleichzeitig noch vorhanden sind, aber ebenso wenig, dass die nicht gemessenen Schedule-/FVP-Tabellen klein sind.
  • SEHR WAHRSCHEINLICH: Der defekte Stale-Cleanup kann insbesondere scheduletable über lange Zeit mit abgelaufenen Ereignissen anwachsen lassen.
  • NICHT VERIFIZIERBAR: Der exakte Anteil lebender Schedule-/FVP-Daten, freier Seiten und interner Fragmentierung ohne belastbare Counts beziehungsweise page_count, freelist_count, dbstat oder eine DB-Kopie.

Die frühere Aussage in epg-content-evidence.txt, der Boot-Log zeige eine erfolgte Löschung, wird durch die statische Bytecode-Analyse korrigiert: Er zeigt nur die Ausführung des No-op-Runnables.

Query-/URI-Semantik und Grenzen einer risikoarmen Zählung

Warum antenna/scheduletable --projection _id sehr lange läuft

BEWIESEN: content://org.droidtv.epgdvb/antenna/scheduletable wird nicht direkt auf die physische Tabelle abgebildet. EpgProvider.query() ersetzt den Tabellenausdruck durch:

indextable AS Dbit LEFT JOIN scheduletable AS Schedule USING(presetid)

Für eine Client-Projektion _id ersetzt der Provider die Spalte ausdrücklich durch Dbit.dbitindex AS _id. Die Abfrage zählt oder limitiert damit nicht, sondern liefert eine Join-Zeile pro passendem Schedule-Datensatz. Eine Laufzeit von mehr als 120 Sekunden ist daher mit einer sehr großen Schedule-Menge vereinbar. Sie kann zusätzlich durch Join-/Provider-/SQLite-Latenz beeinflusst sein und ist allein noch kein exakter Rowcount.

Die physische Tabelle ist auch über antenna/scheduletablesync erreichbar. Dieser Pfad vermeidet den Dbit-Join, besitzt aber ebenfalls keinen eingebauten Count- oder Limit-Modus.

Projektion und Selection

  • BEWIESEN: Für nownexttable und scheduletable baut der Provider Join-Ausdrücke und schreibt Projektionsnamen mit Unterstrich in qualifizierte Spalten um, zum Beispiel Schedule_eventid zu Schedule.eventid AS Schedule_eventid.
  • BEWIESEN: Die Sonderprojektion _id wird immer zu Dbit.dbitindex AS _id. Das ist bei Join-Endpunkten beabsichtigt, bei fvpscheduletable aber ungültig, weil dort kein Alias Dbit existiert.
  • BEWIESEN: fvpscheduletable und fvpnownexttable besitzen schemabedingt keine _id-Spalte; ihr Primärschlüssel ist (channelid,starttime,endtime).
  • BEWIESEN: Bestimmte Selection-Strings sind keine SQL-Where-Klauseln, sondern Provider-Kommandos: GetNowNext, GetNowNextNoHidden, GetSchedule und getFastIpNowNextForChannel. Bei GetSchedule setzt der Provider selbst die Bedingung Schedule_presetid = ? AND Schedule_endtime > ? AND Schedule_starttime < ? und sortiert nach Schedule_starttime.
  • BEWIESEN: Für die Join-Endpunkte tokenisiert der Provider eine normale Selection an Whitespace und ersetzt Unterstriche in Tokens durch Punkte. Komplexe Ausdrücke sind daher nicht verlässlich transparent.
  • BEWIESEN: Zwei Distinct-Temp-XML-AIT-Endpunkte bauen SQL sogar per Stringverkettung auf. Sie sind für die Tabellenzählung nicht relevant und keine empfehlenswerte Diagnosefläche.

Sortierung und Limit

  • BEWIESEN: Der fünfte Legacy-Query-Parameter sortOrder wird zu Beginn nur auf den Sonderwert PF_EVENT geprüft. Dieser Wert löst eine EPG-Sync-Notification aus und liefert keinen Cursor.
  • BEWIESEN: Der Client-Sortstring wird danach nicht als freie Sortierung an die abschließende SQLite-Abfrage weitergereicht. Einige interne Pfade setzen stattdessen feste Sortierungen (Dbit_presetnumber, Schedule_starttime, starttime).
  • BEWIESEN: Der letzte Parameter der verwendeten 8-Argument-Überladung SQLiteDatabase.query(..., orderBy, limit) wird immer auf null gesetzt. Es gibt in diesem Provider keinen generischen URI-Queryparameter oder Legacy-Pfad für LIMIT 1.
  • BEWIESEN: Ein LIMIT im Sortstring wäre hier nicht nur unerwünschte SQL-Einschleusung, sondern wegen der Providerlogik auch kein belastbarer Weg.

Gibt es einen legitimen Count-Weg?

  • BEWIESEN: Der Provider implementiert keinen eigenen Count-Endpunkt, kein DatabaseUtils.queryNumEntries() und kein festes SELECT COUNT(*) für Schedule/FVP.
  • NICHT VERIFIZIERBAR: Ob ein Aggregate-Ausdruck wie COUNT(*) AS row_count als Client-Projektion auf jedem URI akzeptiert wird. Die Provider-Umschreibung verwirft oder verändert Projektionen abhängig vom Pfad; auf dem normalen scheduletable-Join ist dies deshalb kein dokumentierter, verlässlicher Vertrag.
  • PLAUSIBEL: Die Spezialpfade antenna/fvpbackwardepg, antenna/fvpnownexttable und antenna/fastipnownexttable reichen Projektionen direkter an SQLite weiter; dort könnte ein Aggregate-Count rein lesend funktionieren. Das ist statisch nicht als Philips-API zugesichert und sollte, falls später überhaupt getestet, nur mit kurzer externer Zeitbegrenzung erfolgen.
  • BEWIESEN: Ein garantiert maximal einzeiliger, aber nicht zählender Leseweg besteht über eine eindeutige Schlüssel-Selection: bei scheduletablesync _id = <bekannter Wert>, bei FVP (channelid,starttime,endtime) mit bekannten Werten. Das beantwortet nur Existenz/Einzeldaten, nicht die Gesamtgröße.

Risikoarme weitere Diagnose bedeutet daher: keine unbeschränkte Ausgabe des Schedule-Joins, keine Sort-/Selection-Injection und keine mutierenden URI-Endpunkte. Sinnvoll sind ausschließlich zeitlich eng begrenzte, indexgestützte Leseselektionen auf der physischen scheduletablesync-Tabelle (starttime/endtime) sowie kurz begrenzte Aggregate-Experimente nur dort, wo die Projektion statisch unverändert durchgereicht wird. Ein vollständiger, verlässlicher Tabellen-/Seitenbefund erfordert letztlich SQLite-Metadaten oder eine lesbare DB-Kopie.

Interne Reset-/Rebuild-Flächen

ContentProvider

Manifest-Komponente:

  • Klasse: org.droidtv.channels.epg.bcepg.EpgProvider
  • Authority: org.droidtv.epgdvb
  • android:exported="true"
  • Im Provider-Element ist keine readPermission oder writePermission deklariert.

Die folgenden URI-Pfade werden in EpgUriMatcher erkannt. Alle werden über ContentResolver.delete() angestoßen und sind deshalb mutierend; sie wurden nicht ausgeführt.

URI Runnable/Funktion Tatsächliche Wirkung
content://org.droidtv.epgdvb/antenna/staledatacleanup EpgProvider$deleteStaleDataRunnable derzeit nur Grenzwertberechnung/Log; keine Löschung
content://org.droidtv.epgdvb/antenna/rebuilddb EpgProvider$rebuildDbRunnable dropIndexTable(), syncChannelTable(), syncOnChannelTableChange(), Acquisition-Notification; selektiver Reindex/Mapping-Abgleich
content://org.droidtv.epgdvb/antenna/rebuilddbonnewchannellist EpgProvider$rebuildDbOnNewChannelListRunnable dropTables(), zusätzlich dropIndexTable(), danach Kanal-/Mapping-Neuaufbau und Notification; umfassende Zeilenleerung der EPG-Ereignistabellen, aber keine Dateikompaktierung

EpgProgramPump.rebuildEpgDataBase() ruft den regulären rebuilddb-URI über ContentResolver.delete() auf. BEWIESEN: Auch diese Methode hat innerhalb der vier DEX-Dateien keinen direkten Invoke-Aufrufer.

Der tatsächlich verdrahtete interne Rebuild erfolgt in EpgInfoSingleton$MyRunnableHandleMessage.run():

  • bei Senderlisten-Update-Ende und Installationsabbruch über REBUILD_CONTENT_URI (rebuilddb),
  • bei CHANNEL_INSTALL_COMPLETE über REBUILD_ONNEWCHLIST_CONTENT_URI (rebuilddbonnewchannellist).

Das ist ein interner Lifecycle-Pfad der Senderinstallation, keine gefundene Benutzerfunktion zum Freigeben von Speicher.

Manifest-Activities, Services und Intent-Actions

Gefundene, EPG-nahe Benutzerkomponenten sind:

  • org.droidtv.channels.ChannelsActivity: org.droidtv.action.GUIDE, org.droidtv.action.DUKTPGUIDE, org.droidtv.intent.action.SHOW_PLANNER, org.droidtv.intent.action.CHANLIST
  • org.droidtv.channels.epg.bcepg.epgui.RecordingsManager: org.droidtv.ACTION.SHOW_RECORDINGS_LIST
  • org.droidtv.channels.epg.bcepg.epgui.NowNextOverview: org.droidtv.ACTION.SHOW_NOWNEXT_OVERVIEW
  • org.droidtv.channels.epg.bcepg.epgui.ScheduleReminder: org.droidtv.ACTION.SET_REMINDER
  • org.droidtv.channels.epg.bcepg.epgui.ScheduleManualRecording: org.droidtv.ACTION.SCHEDULE_MANUAL_RECORDING
  • org.droidtv.channels.epg.bcepg.epgui.ScheduleEventRecording: org.droidtv.ACTION.SCHEDULE_EVENT_RECORDING
  • org.droidtv.channels.epg.bcepg.epgui.ScheduleRecording: org.droidtv.ACTION.SCHEDULE_RECORDING
  • org.droidtv.channels.epg.bcepg.RecordingsUpdateService: Aktion org.droidtv.bcepg.RecordingsUpdateService, ausdrücklich android:exported="false"
  • org.droidtv.channels.epg.search.EPGSearchProvider: Authority org.droidtv.channels.epg.search; Suchprovider, kein Reset-Pfad

BEWIESEN: Keine dieser Manifest-Aktionen ist als EPG-Datenbank-Reset implementiert. In Manifest- und Ressourcenquersuche wurde keine Activity, kein Service und kein expliziter Intent mit der Bedeutung „EPG/Guide database reset/clear/rebuild“ gefunden.

EpgStaleDataCleanupAlarmReceiver hat ein Intent-Filter, aber kein explizites android:exported-Attribut. Bei targetSdkVersion=30 ergibt sich auf der untersuchten Plattform aus dem Intent-Filter typischerweise Exportierbarkeit; die genaue vom PackageManager auf diesem Gerät aufgelöste Export-Eigenschaft ist in dieser rein lokalen Teilanalyse NICHT VERIFIZIERBAR. Für den Befund ist dies unerheblich, weil der Empfänger letztlich nur den No-op-Cleanup auslöst.

Quersuche in weiteren lokalen Philips-APKs

BEWIESEN: TPTvService.apk, eum.apk und usagelogger.apk enthalten gemeinsame EPG-Vertragskonstanten für normale EPG-Datenabfragen, aber keine Treffer für rebuilddb, rebuilddbonnewchannellist, staledatacleanup oder EpgDatabase.db. gel.apk, tvstrings.apk und tvwidgets2k15.apk enthalten ebenfalls keinen solchen Aufrufer. Ein Aufrufer aus einem nicht lokal vorliegenden Paket bleibt NICHT VERIFIZIERBAR.

Abhängigkeiten und Risikoabgrenzung

Senderliste

  • BEWIESEN: Die kanonische Senderliste liegt außerhalb von EpgDatabase.db. EpgDatabaseHelper.syncChannelTable() fragt android.media.tv.TvContract.Channels.CONTENT_URI ab.
  • BEWIESEN: indextable ist ein EPG-interner Spiegel von Sender-/Presetdaten einschließlich presetid, presetnumber, svlid, svlrecid, Name, browsable und favoriteNumber.
  • BEWIESEN: mappingtable ordnet presetid zu svlid/svlrecid zu.
  • BEWIESEN: Die Rebuild-Runnables löschen die kanonische TvContract.Channels-Tabelle nicht; sie lesen sie und bauen EPG-Index/Mapping neu auf.
  • NICHT VERIFIZIERBAR: Ob ein konkreter Laufzeitfehler während des Abgleichs zu sichtbaren temporären Kanal-/EPG-Zuordnungsproblemen führen würde.

Favoriten

  • BEWIESEN: Favoritenlisten werden über einen separaten Provider org.droidtv.tv.provider.favorite angesprochen, unter anderem content://org.droidtv.tv.provider.favorite/FavoriteList sowie Mixed-/Terrestrial-/Cable-/Satellite-Listen.
  • BEWIESEN: EpgDatabase.db enthält nur Spiegel-/Versionsfelder (favoriteNumber, favouriteversion), nicht die externen Favoritentabellen selbst.
  • BEWIESEN: Die EPG-Rebuild-Runnables enthalten keinen direkten Delete-Aufruf gegen den Favoriten-Provider.
  • PLAUSIBEL: Der Reindex kann vorübergehend Darstellung oder Zuordnung beeinflussen, bis die Spiegelwerte erneut synchronisiert sind.

Aufnahmen, geplante Aufnahmen, Erinnerungen und Timer

Die persistenten Aufnahme-/Reminder-Daten liegen ebenfalls außerhalb von EpgDatabase.db:

  • Authority: org.droidtv.playtv.provider.recordremind

  • Datenbank: RecordingsRemindersList.db

  • Aufnahmen: .../RecordingsTable

  • Erinnerungen: .../RemindersTable

  • gemeinsame View: .../RecRemView

  • BEWIESEN: Diese Tabellen kommen weder im v6-Schema von EpgDatabaseHelper noch in dropTables() vor.

  • BEWIESEN: EpgProgramPump registriert einen ContentObserver auf IRecordingsContract.CONTENT_URI_Recordings und korreliert Aufnahmen über Felder wie EventId und ChannelId; Methoden wie syncRecordingDBbyEvent() und RecDynamicEventUpdateHandler aktualisieren Aufnahme-Metadaten bei EPG-Ereignisänderungen.

  • BEWIESEN: Ein URI-basierter EPG-Rebuild besitzt keinen direkten Codepfad, der RecordingsTable oder RemindersTable löscht.

  • NICHT VERIFIZIERBAR: Vollständige Nebenwirkungsfreiheit auf Darstellung, Event-ID-Verknüpfung, Folgeaufnahmen oder Scheduler nach Reakquisition. Das externe Persistieren verhindert nicht, dass neu vergebene Event-/Channel-IDs Beziehungen vorübergehend oder dauerhaft beeinflussen könnten.

TV-Guide-Quelle ist kein sicherer Reset

tvstrings.apk enthält unter anderem die deutsche Warnung:

Wenn Sie zu TV-Guide-Informationen aus dem Internet wechseln, gehen alle Aufnahmen verloren, die Sie mit Informationen der Sendeanstalt aufgenommen haben. Alle Erinnerungen und programmierten Aufnahmen werden abgebrochen.

Die Gegenrichtung warnt ebenfalls vor Verlust von Aufnahmen und Abbruch programmierter Aufnahmen.

  • BEWIESEN: Das Umschalten zwischen Broadcaster- und Internet-Guide ist laut Philips-Ressourcen eine ausdrücklich destruktive Benutzeraktion für Aufnahme-/Timerdaten.
  • BEWIESEN: Es ist nicht mit den internen rebuilddb-URI-Pfaden gleichzusetzen und sollte nicht als Speicherbereinigung vorgeschlagen werden.

Gesamteinordnung zur Speicherwarnung

Die statische Implementierung liefert eine konsistente Ursache für die ungewöhnlich große EPG-Datei:

  1. EPG-Synchronisation erzeugt sehr hohen Insert/Delete-Churn; die hohen AUTOINCREMENT-Werte beweisen Millionen historische Inserts.
  2. Der als periodischer Stale-Cleanup bezeichnete Kernpfad löscht in dieser Firmware tatsächlich nichts.
  3. Der sichtbare 12-Stunden-Alarm-Setter hat keinen direkten Caller und wäre selbst bei Ausführung nur ein einmaliger Einstieg in dasselbe wirkungslose Runnable.
  4. Interne Rebuilds leeren Zeilen, verwenden aber selbst kein VACUUM; ob ein Vendor-/DB-seitig aktives Full-Auto-Vacuum die Datei dabei verkleinert, ist offen.
  5. Nur Now/Next/Index wurden als klein gemessen. Der unbeschränkte Schedule-Join lief länger als 120 Sekunden; Schedule/FVP können daher einen großen lebenden Datenanteil enthalten.

BEWIESEN: EpgDatabase.db ist mit 1,62 GiB der konkrete große Speicherverbraucher. SEHR WAHRSCHEINLICH: Der defekte Stale-Cleanup trägt wesentlich zu ihrem Wachstum bei, insbesondere durch nicht entfernte Schedule-Daten. NICHT VERIFIZIERBAR: Ob die aktuelle Dateigröße überwiegend aus lebenden Schedule-/FVP-Zeilen oder aus freien/fragmentierten Seiten besteht.

NICHT VERIFIZIERBAR: Der genaue Beitrag eines ungewöhnlichen SQLite-Headerzustands, WAL-/Journalresten oder Dateisystembesonderheiten. Dafür wären ausschließlich weitere lesende Datenbank-/Header-Messungen erforderlich; sie waren nicht Teil dieser lokalen APK-Teilanalyse.

Keine Reparaturfreigabe aus diesem Bericht

Die gefundenen ContentResolver.delete()-Endpunkte und Rebuild-Pfade sind zustandsverändernd. Sie wurden nicht ausgeführt und dieser Bericht empfiehlt keinen konkreten Ausführungsbefehl. Insbesondere ist der umfassende New-Channel-List-Rebuild nicht gleichbedeutend mit einer Dateikompaktierung und eine vollständige Nebenwirkungsfreiheit für EPG-Verknüpfungen zu Aufnahmen/Timern ist nicht bewiesen.

Reproduzierbare Belegdateien

  • diagnostics/deep-forensics/philips/epg-dex-context.txt – Helper, DDL, Lifecycle, Provider und Query-Joins
  • diagnostics/deep-forensics/philips/epg-runnable-context.txt – vollständige Referenzkontexte der Provider-Runnables
  • diagnostics/deep-forensics/philips/epg-cleanup-context.txt – Cleanup- und echte Delete-Methoden
  • diagnostics/deep-forensics/philips/epg-stale-context.txt – Alarm-/Receiver-/URI-Kette
  • diagnostics/deep-forensics/philips/epg-sync-thread-context.txt – SyncThread-Methoden
  • diagnostics/deep-forensics/philips/epg-recording-deps-context.txt – Aufnahme-/Reminder-Verträge und Interaktionen
  • diagnostics/deep-forensics/philips/epg-delete-rebuild-string-context.txt – interne Rebuild-Auslösung bei Senderlistenereignissen
  • diagnostics/deep-forensics/philips/channels-manifest.txt – dekodiertes binäres Manifest
  • diagnostics/deep-forensics/philips/tvstrings-epg-matches.txt – relevante TV-Guide-Ressourcen
  • diagnostics/raw/storage/epg-content-evidence.txt – bereits vorhandene Laufzeit-Zeilenzahlen/IDs/Dateigröße
  • diagnostics/bugreport/extracted/files/01790__bugreport-PH9M_EA_5599-STT2.230526.001-2026-08-25-13-26-44.txt – Boot-Log, insbesondere Zeilen um 32807–32812