Kiosk Operations Runbook (Android Device Owner)

Operator-facing procedures for provisioning, recovering, updating, Wi-Fi, and decommissioning osd kiosk tablets. Any team member can follow these without the original developer present.

osd runs as an Android Device Owner kiosk: the tablet is locked into osd (lock-task), osd is the home launcher, and reboots return to osd. The only way to remove Device Owner is a factory reset — there is no "uninstall".

Target devices: Redmi Pad 2 Pro (HyperOS, primary), Lenovo Tab M11 / Samsung Tab A9+ (fallback).


PIN reference (know which PIN does what)

PIN Purpose Set where Default

Shift-PIN

Front door → connects the tablet to a specific Dienst

Admin panel, per event (Story 9.14), synced to the tablet

none — admin chooses 6 digits

Firmen-PIN (company)

"Neuen Dienst anlegen" offline when no Dienst is synced

Front door or Settings → Firmen-PIN (Story 9.10)

none — first entry sets it (set-on-first-use), same as the Wartungs-PIN

Wartungs-/Admin-PIN

Maintenance escape hatch + gated Settings (enrollment, device settings, lock-screen text, restart, update policy)

Set-on-first-use in the maintenance overlay

none — first entry sets it

The maintenance escape hatch: 10 quick taps on the version label in Settings (only on a provisioned Device-Owner tablet) open the Wartungs-PIN dialog → a small launcher (Settings / Files / Camera / Notes / Maps) — the only way to reach Android Settings or files from inside the locked kiosk. It auto-relocks after ~5 min, on exit, or on reboot. (This replaces the earlier hidden top-right long-press gesture.)


Procedure 1 — Provision a new tablet

Preconditions (do these first):

  • Set the tablet’s Android system locale to Deutsch (Deutschland) before the factory reset — the setup-wizard text and the expected-output below are German, and a mismatched locale causes needless troubleshooting. (osd’s provisioning also sets PROVISIONING_LOCALE/TIME_ZONE, but the wizard runs before that.)

  • Have the latest provision.png from the GitLab release open on a second device (phone/laptop screen) ready to show the tablet camera. Download it from the release’s package URL (API form, anon-reachable): https://gitlab.com/api/v4/projects/70262263/packages/generic/releases/<version>/provision.png

  • A field-event Wi-Fi or phone hotspot the tablet can join (the wizard downloads the ~143 MB APK over it).

Steps (QR path — preferred):

  1. Factory reset the tablet (Settings → System → Reset, or Recovery). On HyperOS the recovery menu may be Chinese — use a translate-camera app.

  2. On the welcome screen, do NOT sign in. Tap the screen 6× on the same spot → the QR-provisioning flow opens.

  3. Connect to Wi-Fi when prompted.

  4. Enable the camera if asked, then scan provision.png.

  5. The wizard shows „Dieses Gerät gehört Ihrer Organisation" ("owned by business"), downloads + installs osd, runs the provisioning handshake, and boots into the osd kiosk. Expect ≤ 5 min on 50 Mbps.

    • Expected end state: the osd logo screen with „Einsatzbereitschaft herstellen" + a Settings gear. No Android home, no app drawer.

  6. Enrol the device: Settings (gear → Wartungs-PIN, set it now on first use) → Geräte-Einschreibung → enter the enrollment token + device name → confirm the GPG fingerprint against the org key holder (Epic 4 trust anchor). This binds the device + GPG trust.

Steps (adb path — fallback, when the QR flow won’t take): Works only on an un-provisioned tablet (once provisioned, USB adb stays unauthorized and Wireless debugging can’t pair — see Procedure 2 / the adb-on-kiosk limitation). On a fresh factory-reset tablet:

  1. Skip all accounts in the wizard.

  2. Settings → enable Developer optionsUSB-Debugging.

  3. adb install -r app-universal-release.apk

  4. adb shell dpm set-device-owner de.eventsanitaeter.es_dashboard/.OsdDeviceAdminReceiver

  5. Reboot → osd kiosk. Then enrol as in step 6 above.

Failure mode — "boots into kiosk but enrolment fails" (bricked-but-locked): server unreachable, enrollment token exhausted, or the GPG fingerprint dialog was dismissed → the tablet is now locked into osd without enrolment and cannot sync or document for a real Dienst. **Only recovery is Procedure 2 (factory reset

  • reprovision).** Fix the root cause first (server reachable? fresh token? right fingerprint?) before reprovisioning.


Procedure 2 — Recover a stuck tablet

Match the symptom → remediation:

Symptom Remediation

Black screen / frozen

Physical power-button long-press 8—​12 s → force-reboot → reboot loads osd.

Android home screen instead of osd

Device Owner was lost → factory reset + reprovision (Procedure 1).

osd crash-loops ("ES Dashboard keeps stopping")

Global Actions (power long-press) → power off → power on. If it still loops after 2 reboots → factory reset + reprovision. Known cause: a device provisioned from v0.10.17/v0.10.18 has a buggy OTA watcher (self-reinstall loop) — do not provision from those tags; use v0.10.19 or later. If reachable, clearing osd’s cache (not data) removes the cached APK and breaks the loop while keeping enrolment.

"Kiosk degraded" banner in Settings (Story 9.2 kiosk:degraded)

Device Owner lost (e.g. HyperOS OS update). Read the crash log in Settings for diagnostics → factory reset + reprovision.

Sync indicator shows pending ops AND the tablet must be reset

Operator decision: accept data loss and reset (factory reset wipes the op-queue) or wait for sync to drain if the tablet is still partly usable. If the device is too broken to even reach the sync indicator, accept the loss and proceed.

Forgotten Firmen-/Wartungs-PIN, locked out

The Wartungs-PIN gates the escape hatch; if forgotten, the maintenance gesture can still be triggered but not satisfied → recovery is factory reset + reprovision.

adb-on-kiosk limitation: on a provisioned HyperOS tablet, USB adb stays unauthorized (the auth dialog is suppressed under lock-task) and Wireless debugging pairing fails. So adb is not a recovery tool on a live kiosk — the in-app ADB-enable verb (Settings, Story 9.7) is the only way to turn adb on, and OTA is the only reliable way to land a new build. Plan recovery around factory reset + reprovision, not adb.

Factory-reset data loss: a factory reset destroys all local osd data — open protocols, locally-created (offline) Dienste, and queued op_log entries. When the tablet is reachable, verify the sync indicator shows "no pending ops" before resetting. When it is not reachable, accept the loss and proceed.

Recovery-time target: ≤ 20 min to back in the field on representative event Wi-Fi (50 Mbps). This is a target, not a commitment (the earlier 15-min figure was optimistic).


Procedure 3 — Update osd across the fleet

Primary path — in-app OTA (no factory reset):

  1. Settings → „Nach Updates suchen". osd checks the stable latest.json, downloads the new APK, and silently installs it via Device-Owner self-install (kiosk_install_apk) — works inside the kiosk, no operator tap needed beyond starting it. The device relaunches once into the new version.

  2. Cut a release by tagging vX.Y.Z (CI publishes the APK + updates the stable latest.json); devices pick it up on the next check.

OTA bootstrap reality: the OTA-endpoint fix lives in the binary, so a device on a pre-fix build can’t OTA to the fix — the first device with the fix must be sideloaded once, then it can OTA onward. Never provision/keep devices on v0.10.17/v0.10.18 (broken OTA watcher); v0.10.19+ is safe.

Fallback path — if OTA fails (signature mismatch, downgrade attempt, disk full): re-trigger from Settings; if still failing, sideload the APK via the adb path on a reset device (Procedure 1), or escalate to Procedure 5. There is no factory-reset-as-update cost in the normal path.

System (Android OS) updates are separate: Settings → Gerät → System-Updates (Story 9.11) sets the policy (Aufschieben / Zeitfenster / Automatisch). A freshly-provisioned kiosk defaults to Aufschieben (postpone, ≤ 30 days) so an OS update never reboots a tablet mid-shift. (Whether HyperOS honours the policy is still being verified on-device.)


Procedure 4 — Change Wi-Fi mid-event

A Sanitäter opens osd Settings → WLAN (Story 9.5), scans available networks, and joins — no operator escort, no kiosk exit. If the WLAN section is unavailable (Device Owner lost), Procedure 2 applies.

Status: the in-app WLAN section is Story 9.5 (not yet shipped). Until it lands, set Wi-Fi during provisioning (Procedure 1 step 3), or reach Android Wi-Fi settings via the maintenance escape hatch (10 taps on the version label in Settings → Wartungs-PIN → Settings).


Procedure 5 — Decommission / fleet-wide QR reissue

Decommission a tablet:

  1. Admin side: revoke the device in the admin panel (Epic 5 — device off-boarding).

  2. Tablet side: factory reset — the only way to remove Device Owner (the DPC cannot be uninstalled while provisioned).

Fleet-wide reissue (keystore rotation): when the production signing keystore is rotated (Story 7.1, or any future rotation), every previously-printed QR becomes stale — the QR encodes the signing-cert checksum. All tablets must be reprovisioned with the new provision.png. Fleet-wide impact; schedule during a downtime window.


See also

  • Release / branch state + decisions: docs/superpowers/plans/RELEASE-PLAN.md (in-repo; not published to the portal)

  • Architecture: _bmad-output/planning-artifacts/architecture.md (Addendum: Android Kiosk Deployment)

  • Onboarding (first login + enrolment): docs/ONBOARDING.md — Story 7.4, not yet written; it will reference this runbook for the provisioning prerequisite.