Files
ARIA-AGENT/host-agent/android/README.md
T
duffyduckandClaude Opus 4.8 47cc1b7f08 feat(android-agent): Sperre-Erkennung — Steuern nur entsperrt (v0.0.0.7)
Erkenntnis aus dem Live-Test: bei gesperrtem Bildschirm greifen Gesten/Tasten
nicht (Android-Sicherheit), der Agent meldete aber still 'ok' -> Verwirrung
(home,home,home, Screenshot zeigt trotzdem alte App). Fix: KeyguardManager.
isKeyguardLocked() gate fuer Steuer-Aktionen (ui_tap/text/swipe/key/app_launch)
-> klare Meldung 'Geraet ist gesperrt - bitte entsperren'. Sehen (screenshot/
ui_dump/info) bleibt auch gesperrt erlaubt. README-Hinweis ergaenzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-25 13:44:49 +02:00

10 KiB
Raw Permalink Blame History

ARIA Android-Agent

Ein nativer Android-Agent (eigene APK), der ARIA erlaubt, ein Smartphone fernzusteuern — inkl. Bedienen fremder App-UIs (z.B. „ARIA, richte auf dem Handy ein E-Mail-Konto ein"). Gegenstück zum Desktop-host-agent (Linux/macOS/ Windows), aber Android ist kein Unix-Shell-System — deshalb ein anderes Action-Set (UI-Automation statt beliebiger Shell-Kommandos).

Verbindet sich wie die ARIA-App ausgehend zum RVS (gleicher Token/Raum), Verbindungs-Setup per QR-Scan oder manueller Eingabe. Taucht in der Diagnostic unter Satelliten → Host-Agenten 💻 auf (host_hello mit os="Android …" + Android-Caps).

Warum nativ (Kotlin), nicht Termux/RN

  • UI-Automation (fremde Apps bedienen) geht auf Android nur über einen AccessibilityService — den kann nur eine native App bereitstellen.
  • Screenshots einer laufenden Session: MediaProjection (native).
  • Dauerbetrieb: Foreground-Service mit Notification (native).
  • Termux gäbe nur Shell + termux-api (SMS/Anruf/Standort …), kein Bedienen anderer App-UIs. Für „E-Mail-Konto durchklicken" reicht das nicht.

Tech: Kotlin, OkHttp-WebSocket (RVS-Client), CameraX/ML-Kit (QR), AccessibilityService (Input), MediaProjection (Screenshot). Build via Docker (Android-SDK + Gradle) → APK. Nur Linux baut APKs (Docker), Deploy manuell.

Action-Set (host_command → host_result)

Android-spezifisch (statt exec/read/write des Desktop-Agents):

Action Was
screenshot Bildschirmfoto (MediaProjection) — ARIA sieht den Schirm
ui_dump Sichtbare UI als Baum (Texte, Buttons, Felder + Koordinaten) — ARIAs „Augen" für gezieltes Tippen
ui_tap Tippen (x,y ODER auf ein Element aus ui_dump)
ui_text Text in das fokussierte/angegebene Feld schreiben
ui_swipe Wischen/Scrollen
ui_key Systemtasten (BACK, HOME, ENTER …)
app_launch App per Paketname starten (z.B. E-Mail-App)
app_list installierte Apps auflisten
info Gerät: Modell, Android-Version, Akku, Netz, IP
notify Benachrichtigung anzeigen
(später) sms_send, call, location, clipboard (je nach Bedarf + Berechtigung)

ARIA-Flow „E-Mail einrichten": app_launch (Mail-App) → screenshot/ui_dump (sehen, was da ist) → ui_tap/ui_text (durchklicken) → wieder ui_dump prüfen, bis fertig. Genau das agentische Muster wie beim Endian-Fix, nur mit Handy-UI.

⚠️ Gerät muss ENTSPERRT sein, damit ARIA es steuern kann. Gesten und Systemtasten (ui_tap/ui_text/ui_swipe/ui_key/app_launch) greifen bei gesperrtem Bildschirm nicht — Android-Sicherheit. Der Agent erkennt das und meldet „Gerät ist gesperrt — bitte erst entsperren", statt still „ok" zu sagen. Sehen (screenshot, ui_dump, info) funktioniert dagegen auch bei gesperrtem Gerät.

Dauerbetrieb — Foreground-Service vs. Push (FCM)

Der Agent muss immer erreichbar sein, obwohl Android Hintergrundprozesse aggressiv killt (Doze, App-Standby, OEM-Batterie-Manager wie Xiaomi/Huawei). Zwei Wege, deine WhatsApp-Intuition trifft ins Schwarze:

A) Foreground-Service (persistente WebSocket) — der einfache Start:

  • Dauerhafte RVS-Verbindung + Foreground-Notification („Agent aktiv").
  • Braucht: FOREGROUND_SERVICE, Akku-Optimierung ausnehmen (REQUEST_IGNORE_BATTERY_OPTIMIZATIONS — User whitelistet die App), RECEIVE_BOOT_COMPLETED + BootReceiver (Neustart nach Reboot), Auto-Reconnect (haben wir im Protokoll schon).
  • Reutzt unser bestehendes host_hello/host_command/host_result 1:1.
  • Nachteil: etwas Akku; manche OEMs killen trotzdem → „Autostart" manuell erlauben.

B) Self-hosted Push (KEIN Google!) — genau wie WhatsApp, aber auf eigenem Server:

  • UnifiedPush + self-hosted ntfy: Auf dem ARIA-Server läuft ntfy (freier, self-hostbarer Push-Server). Der Agent nutzt UnifiedPush (offener Standard, de-Google-Welt/F-Droid) mit dem ntfy-Distributor auf dem Handy. Will ARIA etwas, POSTet die Bridge/RVS an ntfy → weckt die App → sie holt den Befehl vom RVS, arbeitet, antwortet. Läuft auch auf Custom-ROMs OHNE Google Play Services.
  • Akkuschonend wie FCM, aber ohne jede Google-Abhängigkeit. Nur ein Dienst mehr (ntfy) im Stack + der Push-Auslöser serverseitig.

C) FCM (Google) — optional: Wer ein Stock-Android mit Play Services hat und Googles Push-Kanal will, kann FCM statt ntfy nehmen (bester Akku auf GMS-Geräten). Braucht Firebase-Projekt + Play Services. Nur eine Option, keine Pflicht.

Custom-ROM ohne Google: → Weg A (eigener Socket) oder B (self-hosted ntfy). Beide brauchen KEIN Google. Für Stefans dediziertes Ziel-Handy ist A sogar oft die einfachste Dauerlösung (unser eigener „Push" über den RVS-Socket).

Hybrid (ideal, End-Ausbau): Im Leerlauf nur Push (max. Akku). Ein Push weckt die App → sie öffnet die RVS-Verbindung, hält sich per Wakelock für die Interaktion wach (mehrere Befehle flüssig, z.B. E-Mail-Setup durchklicken) → schläft nach ein paar Sekunden Ruhe wieder ein. So WhatsApp-Akku UND schnelle Multi-Befehl-Sessions. Der Push kommt dabei von B (self-hosted ntfy) oder C (FCM) — freie Wahl. Erste Push-Latenz aus tiefem Doze ~1–3 s; danach bleibt der Socket die Session offen.

Empfehlung: Meilenstein 1–3 mit A (Foreground-Service) — läuft sofort und nutzt alles Vorhandene, damit wir schnell einen funktionierenden Agenten haben, ganz ohne externe Dienste. Dann Push-Hybrid mit self-hosted ntfy (B) als Akku-Ausbau — KEIN Google. FCM (C) nur optional für Stock-Android. Action-Set/Protokoll bleiben identisch, nur der Wecker ändert sich.

Sicherheit

  • Reagiert nur auf den eigenen RVS-Raum (Token); Setup per QR/manuell.
  • CONTROL_ENABLED-Schalter in der App (Default AUS) — erst wenn Stefan es bewusst aktiviert, führt der Agent Aktionen aus.
  • AccessibilityService + MediaProjection müssen vom User explizit in den Android-Einstellungen freigegeben werden (kein stiller Zugriff möglich).
  • Alle Aktionen werden protokolliert (In-App-Log + optional an ARIA).
  • Voller Gerätezugriff — nur auf eigenen/anvertrauten Geräten nutzen.

Meilensteine

  1. ✅ Verbinden + sichtbar — Gradle-Projekt, AndroidManifest, RVS-WS-Client, Foreground-Service, Connect-UI (QR-Scan + manuell), host_hello/host_ping. → Agent erscheint in der Diagnostic. info funktioniert.
  2. ✅ Sehen — MediaProjection-Screenshot (ScreenCapturer, gleicher {format,bytes,base64}-Vertrag wie der Desktop-Agent → host_screenshot) + ui_dump (AriaAccessibilityService, nur lesend → Brain-Tool host_ui_dump). Freigabe einmalig in der App: „Bildschirm-Zugriff erlauben" + „Bedienungshilfe öffnen". → ARIA sieht den Schirm und liest die UI-Elemente mit Koordinaten.
  3. ✅ Steuern — ui_tap/ui_text/ui_swipe/ui_key/app_launch über den AccessibilityService (canPerformGestures, dispatchGesture, ACTION_SET_TEXT, performGlobalAction) → Brain-Tools host_ui_tap/_text/_swipe/_key/ host_app_launch. Tap-Koordinaten = die x/y aus ui_dump (echte Pixel), NICHT aus dem (skalierten) Screenshot. → ARIA bedient Apps (E-Mail-Setup).
  4. Feinschliff — app_list/notify, Build-Härtung, release_agent.sh.

Bauen

APK-Builds laufen nur unter Linux — deshalb im Docker-Container. Du brauchst nichts Android-spezifisches installiert, nur Docker. Android-SDK, Gradle und Build-Tools zieht der Container selbst (Dockerfile.build).

cd host-agent/android
./build.sh

build.sh baut das Image aria-android-agent-build und lässt darin gradle assembleDebug laufen. Ergebnis:

host-agent/android/dist/aria-android-agent.apk

Das ist ein Debug-APK: auto-signiert mit dem Android-Debug-Key, also direkt installierbar — ohne eigenen Keystore, ohne Play Store.

Auf dem Handy installieren

  1. dist/aria-android-agent.apk aufs Zielgerät kopieren (USB, Cloud, adb install dist/aria-android-agent.apk, …).
  2. Antippen → Android fragt nach „Unbekannte Quellen / Aus dieser Quelle installieren erlauben" → erlauben.
  3. App öffnen → verbinden (QR/manuell), „Steuerung erlauben" an, für M2 zusätzlich „Bildschirm-Zugriff erlauben" + „Bedienungshilfe öffnen".

Was der erste Build kostet

Der erste Lauf lädt viel (JDK-Image, Gradle, Android-SDK, Dependencies) und dauert entsprechend — mehrere Minuten. Folge-Builds sind schnell (Docker-Layer + Gradle-Cache im Image). Häufige Stolperer:

  • Docker fehlt / kein Zugriff → docker-Rechte prüfen (docker ps).
  • Overlay-on-Overlay auf einem Live-ISO („invalid argument" beim Image-Bau) — gleiches Problem wie beim Desktop-Agent auf dem Mint-Live-System; von einer installierten Linux-Kiste bauen.
  • Kotlin-/Manifest-Fehler beim allerersten Bau eines neuen Meilensteins: den Gradle-Fehler posten, das glätten wir schnell.

Version setzen

Bis es release.sh gibt, wird die Version in app/build.gradle gepflegt (versionCode / versionName). Aktuell 1 / 0.2.0 (M1+M2).

Release

Das APK ist kein Teil des Git-Trees (blaeht sonst die History dauerhaft auf) — es wird als Release-Asset an einen Tag gehaengt. Das macht release_agent.sh (liegt eine Ebene hoeher, in host-agent/):

cd host-agent
./release_agent.sh 0.2.0

Das Skript (wie die release.sh der Haupt-App, Version als Parameter):

  • setzt die Version (host_agent.py → AGENT_VERSION, app/build.gradle → versionName/versionCode),
  • baut Linux-Binary + Android-APK per Docker,
  • committet den Version-Bump, taggt agent-v<version> (eigener Namespace, kollidiert nicht mit den App-Tags v<version>) und pusht,
  • legt ein Gitea-Release an und laedt die Assets hoch: aria-host-agent-linux-x64, aria-host-agent-android-agent-v<version>.apk, optional -macos / -windows.exe (falls in host-agent/dist/ vorgebaut).

Gitea-Zugang (GITEA_URL, GITEA_REPO, GITEA_USER) kommt aus der Umgebung oder einer .env; das Kennwort wird interaktiv abgefragt. Binaries landen unter „Releases", nie im Tree.

Status: M1–M3 fertig — verbinden, info, screenshot, ui_dump (sehen) und ui_tap/ui_text/ui_swipe/ui_key/app_launch (steuern); release_agent.sh vorhanden. Damit läuft der volle Ablauf sehen→steuern (z.B. E-Mail-Konto einrichten). Nächstes: Feinschliff (M4).