- Architecture and feature overview in docs/ARCHITECTURE.md - Gradle 9.8 / AGP 9.4 / Kotlin 2.4 with version catalog and convention plugins - Modules :app, :core:*, :device-profiles, :feature:* (placeholder screens) - Flavors core (no INTERNET, enforced by a build check) and full - Material You theme, navigation, expert mode and dry-run settings (DataStore) - Pixel 8-10 device detection, unit tests, GPLv3 license, English README with Obtainium badge Co-Authored-By: Claude Opus 5.5 <[email protected]>
16 KiB
Pixelwall – Architektur- und Feature-Übersicht
Status: Entwurf v0.1 (vor Implementierungsbeginn) Zielgeräte: Google Pixel 8 – Pixel 10, Stock-Android 15/16, ohne Root Lizenz: GPLv3 · Vertrieb: F-Droid (reproducible builds)
1. Leitprinzipien
- Nichts ohne Bestätigung. Jede schreibende Aktion durchläuft dieselbe Pipeline (Plan → Kompatibilitätsprüfung → Bestätigung → Snapshot → Ausführen → Verifizieren → Protokoll). Der Dry-Run-Modus bricht nach der Bestätigung ab und zeigt nur den Plan.
- Alles ist rückgängig machbar. Vor jeder Änderung wird der Ist-Zustand gesichert; jede Operation kennt ihre Umkehrung.
- Transparenz über Rechte. Jede Einstellung nennt die nötige Berechtigungsstufe (Normal / Shizuku / ADB-Grant). Nicht verfügbare Funktionen werden ausgegraut mit Begründung, nie ausgeblendet.
- Offline und ohne Tracking. Keine Analytics, keine Google-Bibliotheken (kein GMS, kein Firebase),
keine
INTERNET-Berechtigung im Flavorcore(siehe §9). - Gerätewissen ist Daten, nicht Code. Pixel-spezifische Pfade, Settings-Keys und
Besonderheiten liegen in
:device-profiles; neue Hersteller kommen als weiteres Profil hinzu.
2. Modulstruktur
:app Application, Navigation, Hilt-Root, Theme (Material 3 / Dynamic Color)
:core:model Reine Kotlin-Datentypen (Finding, Risk, Operation, Profile, PrivilegeLevel …)
:core:domain Use Cases, Regelwerk/Checks, Scoring, Change-Pipeline (reines Kotlin, JVM-testbar)
:core:data Room (Änderungsprotokoll, Snapshots, Profile, Tracker-DB), DataStore, Repositories
:core:system Lesender Zugriff auf Android-APIs (PackageManager, Settings, KeyguardManager …)
:core:privileged PrivilegedExecutor-Interface + Implementierungen: Shizuku, WRITE_SECURE_SETTINGS, Fake
:core:ui Gemeinsame Compose-Komponenten (SettingCard, RiskBadge, PrivilegeChip, ScoreRing)
:core:testing Fakes, Test-Fixtures, Hilt-Testmodule
:device-profiles DeviceProfile-API + Pixel-Profil (Android 15/16) + Generic-AOSP-Fallback
:feature:dashboard Audit & Score
:feature:permissions Matrix Apps × Berechtigungen, AppOps, zeitlich begrenzte Rechte
:feature:network Privates DNS, Funk-/Scan-Einstellungen, (optional) Firewall
:feature:system System- & Google-Einstellungen, Google-Konto-Checkliste, inaktive Apps
:feature:profiles Profile, Import/Export, Regeln/Automatisierung
:feature:trackers Tracker-Analyse (Exodus-Signaturen)
:feature:monitor Hintergrund-Watcher, Zugriffs-Zeitleiste
:feature:changelog Änderungsprotokoll, Undo, „Alles zurücksetzen“
:feature:onboarding Rechte-Einrichtung (Shizuku, ADB-Anleitung), Expertenmodus
:core wird gegenüber der Vorgabe in Untermodule aufgeteilt, damit Domain-Logik und Scoring
ohne Android-Abhängigkeit als schnelle JVM-Unit-Tests laufen.
Abhängigkeitsrichtung: feature → domain → model, data/system/privileged → domain (Interfaces).
Features kennen sich gegenseitig nicht; Navigation läuft über :app.
Build: Gradle Version Catalog (gradle/libs.versions.toml), Convention Plugins in build-logic/
(android-library, compose, hilt, feature). minSdk 34, targetSdk = aktuellste stabile API.
3. Berechtigungsstufen
| Stufe | Wie | Kann | Grenzen |
|---|---|---|---|
| Normal | keine Zusatzrechte | Lesen (Settings.Global/Secure lesbar, PackageManager, KeyguardManager, Build-Infos), Deep-Links per Intent | keine Änderungen an fremden Apps/Systemwerten |
| ADB-Grant | einmalig adb shell pm grant <pkg> android.permission.WRITE_SECURE_SETTINGS |
Settings.Secure/Global.put* direkt aus der App, auch ohne laufendes Shizuku |
kein pm, appops, cmd |
| Shizuku | Shizuku-API (Shell-UID 2000) | pm grant/revoke, appops set/get, settings put, cmd …, dumpsys |
Shizuku muss nach jedem Neustart neu gestartet werden (Wireless Debugging) |
enum class PrivilegeLevel { NORMAL, ADB_GRANT, SHIZUKU }
interface PrivilegedExecutor {
val level: StateFlow<PrivilegeLevel> // aktuell verfügbare Stufe
suspend fun putSetting(ns: SettingsNamespace, key: String, value: String?): ExecResult
suspend fun shell(command: ShellCommand): ExecResult // nur Shizuku; typisierte Befehle, kein freier String
}
ShellCommandist eine sealed class (PmRevoke,PmGrant,AppOpsSet,CmdWifi…), keine freien Strings → keine Injection, im Expertenmodus als roher Befehl darstellbar.- Implementierungen:
ShizukuExecutor,SecureSettingsExecutor,CompositeExecutor(wählt die niedrigste ausreichende Stufe),FakeExecutor(Tests, Dry-Run-Vorschau). - Fehlerfälle als typisierte Ergebnisse:
ShizukuNotRunning,PermissionMissing,CommandFailed(exitCode, stderr),UnsupportedOnDevice(reason).
4. Change-Pipeline & Undo
ChangeRequest ─► Planner ─► CompatibilityChecker ─► Bestätigungsdialog
│ (Dry-Run: Ende, Plan anzeigen)
▼
SnapshotStore ◄── Ist-Werte lesen
▼
PrivilegedExecutor.apply ─► Verify (neu lesen) ─► ChangeLog (Room)
- Operation (sealed):
PutSetting(ns, key, new),SetPermission(pkg, perm, granted),SetAppOp(pkg, op, mode),SetPrivateDns(mode, host),ForceHibernate(pkg)… Jede Operation liefertfun inverse(snapshot): Operation. - ChangeSet = atomare Gruppe (z. B. ein Profil anwenden). Schlägt eine Operation fehl, werden die bereits ausgeführten des Sets zurückgerollt.
- Undo: pro Operation, pro ChangeSet und global („Alles zurücksetzen“ = alle offenen ChangeSets in umgekehrter Reihenfolge, Ausgangszustand = erster Snapshot je Key).
- Drift-Erkennung: Der Watcher vergleicht Soll (letzte Änderung) mit Ist und meldet, wenn ein System-Update oder der Nutzer etwas zurückgesetzt hat.
- Zeitlich begrenzte Rechte sind normale ChangeSets mit
expiresAt; ein WorkManager-Job (+ exakter Alarm als Backup) führt das Undo aus.
5. Regelwerk & Scoring
Ein Check ist deklarativ beschrieben und gerätespezifisch parametrisiert:
data class CheckDefinition(
val id: CheckId, // z. B. "network.private_dns"
val category: Category, // PERMISSIONS, NETWORK, SYSTEM, GOOGLE, APPS
val risk: Risk, // LOW, MEDIUM, HIGH
val requiredLevelToRead: PrivilegeLevel,
val fix: Fix?, // Operationen oder DeepLink
val compatibilityTags: Set<CompatTag>, // ANDROID_AUTO, BANKING, WEARABLE, FIND_MY_DEVICE …
)
Ergebnis je Check: PASS, FAIL, UNKNOWN (nicht lesbar ohne höhere Stufe), UNSUPPORTED.
Score (Vorschlag, in Unit-Tests festgeschrieben):
- Gewicht: HIGH = 10, MEDIUM = 5, LOW = 2
- Teilscore = 100 × (Summe Gewichte PASS) / (Summe Gewichte PASS + FAIL); UNKNOWN/UNSUPPORTED zählen nicht
- Gesamtscore = gewichteter Mittelwert der Teilscores (System 30 %, Berechtigungen 25 %, Netzwerk 20 %, Apps 15 %, Google 10 %)
- Harte Deckel: z. B. keine Bildschirmsperre → Gesamtscore max. 40; Patch > 90 Tage alt → max. 70
Geplante Audit-Checks (Stufe zum Lesen):
| Check | Quelle | Stufe |
|---|---|---|
| Bildschirmsperre | KeyguardManager.isDeviceSecure |
Normal |
| Verschlüsselung | DevicePolicyManager.storageEncryptionStatus (FBE) |
Normal |
| Patch-Stand | Build.VERSION.SECURITY_PATCH vs. Referenzdatum im Regelwerk |
Normal |
| Bootloader / Verified Boot | ro.boot.verifiedbootstate, ro.boot.flash.locked (über Shizuku getprop, sonst Key-Attestation) |
Normal/Shizuku |
| Entwickleroptionen, USB-Debugging | Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, ADB_ENABLED |
Normal |
| Unbekannte Quellen | Apps mit REQUEST_INSTALL_PACKAGES + AppOp-Status |
Normal/Shizuku |
| Privates DNS | Settings.Global private_dns_mode/_specifier |
Normal |
| 2G erlaubt | TelephonyManager.getAllowedNetworkTypesForReason (Shell) |
Shizuku |
| WLAN-/BT-Scanning | wifi_scan_always_enabled, ble_scan_always_enabled |
Normal |
| Werbe-ID | nur Deep-Link (GMS-intern, keine API ohne GMS-Bibliothek) | Normal (manuell) |
| Sperrbildschirm-Benachrichtigungen | lock_screen_show_notifications, …_allow_private_notifications |
Normal |
| Smart Lock / Trust Agents | enabled_trust_agents |
Normal/Shizuku |
| Bedienungshilfen-Dienste | enabled_accessibility_services |
Normal |
| Geräteadministratoren | DevicePolicyManager.activeAdmins |
Normal |
| VPN-Status | ConnectivityManager + always_on_vpn_app |
Normal |
| Benachrichtigungszugriff | enabled_notification_listeners |
Normal |
| Memory Tagging (MTE), Titan M2, Privater Bereich | Geräteprofil + Properties | Normal/Shizuku |
Hinweis: Lesbarkeit einzelner Secure-Keys wurde für Apps mit targetSdk ≥ 31 eingeschränkt; das
Geräteprofil hält je Android-Version fest, welche Keys lesbar sind, sonst fällt der Check auf
Shizuku zurück oder ergibt UNKNOWN.
6. Geräteprofile (:device-profiles)
interface DeviceProfile {
fun matches(device: DeviceInfo): Boolean // Hersteller, Modell (shiba, husky, tokay, caiman, komodo, comet, …), SDK
val settingsKeys: Map<SettingId, SettingKeySpec> // Namespace, Key, Werte, ab/bis API
val deepLinks: Map<DeepLinkId, IntentSpec> // Action/Component inkl. Fallbacks
val features: Map<FeatureId, FeatureSupport> // Supported / Unsupported(reasonRes)
}
- Profile als Kotlin-DSL (typsicher, testbar), nicht als JSON → keine Laufzeit-Parsing-Fehler.
PixelProfile(Android 15/16),AospFallbackProfilefür unbekannte Geräte.- Deep-Links mit Fallback-Kette (spezifische Pixel-Seite → AOSP-Action →
Settings.ACTION_SETTINGS). - Unit-Tests stellen sicher, dass jedes Feature für jedes Profil eine Aussage hat.
7. Features (Kurzfassung)
- Dashboard: Score-Ring, Teilscores, Befundliste nach Risiko, Ein-Klick-Fix/Deep-Link.
- Berechtigungen: Matrix (LazyColumn mit fixierter App-Spalte, horizontal scrollbare
Berechtigungen), Filter (System/Nutzer, unbenutzt seit X Tagen via
UsageStatsManager, Trackeranzahl), Massenaktionen, AppOps über Shizuku, zeitlich begrenzte Rechte. - Tracker: Exodus-Signaturen als Asset in Room; Erkennung über Klassennamen aus den
DEX-Dateien der APKs (
sourceDirlesbar, eigener schlanker DEX-String-Parser, kein Netz). - Netzwerk: Privates DNS mit Presets + Validierung (Hostname-Syntax; Erreichbarkeit nur
ohne Netz-Berechtigung nicht prüfbar → Verify über
LinkProperties.isPrivateDnsActive), 2G, Scanning, NFC, offene WLANs. Firewall: siehe §9. - System & Google: Schalter wo technisch möglich, sonst Deep-Link + Checkliste (Google-Konto-Seiten öffnen im Browser, Häkchen lokal gespeichert).
- Profile: Ausgewogen / Streng / Paranoid / Unterwegs-Auto als Mengen von Operationen; eigene Profile; Export als JSON mit SHA-256-Prüfsumme und Ed25519-Signatur (Schlüssel lokal im Android Keystore erzeugt); Regeln (WLAN-SSID, Zeitfenster) über WorkManager/Broadcasts.
- Überwachung: periodischer WorkManager-Job (≥ 6 h, nur bei nicht-niedrigem Akku) +
PACKAGE_ADDED-Receiver; Zugriffsverlauf überappops/dumpsys(Shizuku), da die Privacy-Dashboard-API (PermissionManagerUsage) System-API ist.
8. Qualität & Tests
- JVM-Unit-Tests: Scoring, Check-Auswertung, Operation-Inversen, Profil-Diffs, Import-Validierung, DEX-Parser.
- Instrumented Tests (Emulator API 34/35/36): Dashboard laden, Änderung mit
FakeExecutoranwenden + Undo, Dry-Run. - Compose-UI-Tests inkl. Semantik für TalkBack; Screenshot-Prüfung bei 200 % Schriftgröße.
- Lint/Detekt im Build;
strings.xmlde/en, Lint-Regel gegen Hardcoded-Texte. - F-Droid: keine proprietären Abhängigkeiten, feste Versionen,
dependenciesInfo { includeInApk = false }.
9. Bekannte Grenzen & offene Fragen
Technisch nicht (vollständig) möglich ohne Root – wird als Deep-Link/Checkliste umgesetzt:
- Werbe-ID löschen, Google-Nutzungs-/Diagnosedaten, Google-Konto-Aktivitäten (GMS-intern bzw. Web).
- Kamera-/Mikrofon-Kacheln programmatisch in die Schnelleinstellungen legen (nur eigene Kacheln
per
requestAddTileService); die Sensorsperre selbst ist via Shizuku (cmd sensor_privacy) zu prüfen. - Ein paar Shell-Befehle (2G, Sensor-Privacy) müssen auf echten Pixel-Geräten verifiziert werden;
bis dahin
UNSUPPORTEDmit Begründung.
Entscheidungen (2026-10-15):
- Name/Package: App „Pixelwall“, applicationId
org.pixelwall.app, Namespaceorg.pixelwall.*. - Firewall: zwei Product Flavors.
core: ohneINTERNET. Firewall nur als Sperre pro App (WLAN/Mobil/Roaming) perVpnService.full: mitINTERNET. Zusätzlich DNS-Weiterleitung mit lokalem Logging, Hosts-Blocklisten und optionale Regelwerk-Updates (standardmäßig aus). Hinweis in der UI: Es kann nur ein VPN gleichzeitig aktiv sein.
- Build-Umgebung: JDK 21 und Android-SDK-Kommandozeilentools werden nur für den Nutzer installiert (
~/Android/Sdk).
Noch zu klären (blockiert nichts):
QUERY_ALL_PACKAGES: nötig für Audit und Tracker-Analyse; auf F-Droid unproblematisch.- Exodus-Daten: Lizenz der Tracker-Signaturen vor dem Bündeln prüfen (Attribution in der App).
9a. Verteilung: F-Droid und Obtainium
Pixelwall soll direkt über Obtainium aus den Releases auf git.mrblake.cc (Gitea) aktualisierbar sein:
- Releases mit APK-Assets: Jeder Git-Tag
vX.Y.Zbekommt ein Gitea-Release mitpixelwall-core-vX.Y.Z.apkundpixelwall-full-vX.Y.Z.apk(universelle APKs, kein ABI-Split nötig). In Obtainium wählt man den Flavor per APK-Filter-Regex (corebzw.full). - Versionen:
versionName= Tag ohne „v“;versionCodesteigt streng monoton (SchemaMAJOR*10000 + MINOR*100 + PATCH), damit Obtainium Updates sicher erkennt. - Stabiler Signaturschlüssel: Release-Keystore liegt außerhalb des Repos; Pfad und Passwörter kommen aus
Umgebungsvariablen bzw.
~/.gradle/gradle.properties. Ein Schlüsselwechsel würde Updates brechen. - Getrennte applicationIds (
org.pixelwall.app,org.pixelwall.app.full): beide Flavors parallel installierbar. - Ein Gradle-Task
distlegt die signierten, korrekt benannten APKs plus SHA-256-Prüfsummen indist/ab; das Hochladen ins Gitea-Release erfolgt per API nur nach ausdrücklicher Freigabe. - README und Release-Texte (Titel, Notes) sind englisch.
- Zugangsdaten (
.giteatoken) sind per.gitignoreausgeschlossen und werden nie committet oder ausgegeben.
10. Meilensteine
| # | Inhalt | Abnahme |
|---|---|---|
| M1 | Projektgerüst: Module, Version Catalog, Convention Plugins, Hilt, Theme, Navigation, de/en | ./gradlew assembleDebug test lint grün |
| M2 | Audit/Dashboard (nur lesend), Geräteprofil Pixel, Scoring | Unit-Tests Scoring/Checks |
| M3 | Berechtigungsmatrix (lesend + Deep-Links) | UI-Tests Matrix |
| M4 | Shizuku + ADB-Grant + Change-Pipeline + Undo + Dry-Run + Expertenmodus | Tests mit FakeExecutor |
| M5 | Netzwerk (Privates DNS, Funk), ggf. Firewall | – |
| M6 | Profile, Import/Export, Regeln, Kompatibilitätswarnungen | – |
| M7 | Tracker-Analyse | DEX-Parser-Tests |
| M8 | Überwachung, Zeitleiste | WorkManager-Tests |
| M9 | Release-Pipeline: Signatur, dist-Task, Gitea-Release für Obtainium, F-Droid-Metadaten; finale README und Release-Notes auf Englisch |
Obtainium installiert & aktualisiert |