From e710297e23a1ab10bedab336ad5afe1c9f519e4b Mon Sep 17 00:00:00 2001 From: devragrin Date: Tue, 2 Jun 2026 15:27:06 +0800 Subject: [PATCH 1/2] fix(droidguard): implement guardWithRequest service path (#2851) The IDroidGuardService.guardWithRequest method was previously stubbed with TODO, which caused request-backed DroidGuard flows (e.g. Play Integrity multi-step attestation) to throw NotImplementedError. This wires the missing entry point to the existing handle lifecycle: - call getHandle() to obtain the active handle (embedded or remote) - try initWithRequest(flow, request) with fallback to init(flow) - deliver the snapshot result through IDroidGuardCallbacks.onResult - always close the handle in a finally block - on error, deliver an empty byte array (matching the existing KeyRetrievalService error convention) to avoid binder exceptions This is the minimal change to unblock the request-backed flow while keeping behavior aligned with the existing one-shot guard() entry point. --- .../droidguard/core/DroidGuardServiceImpl.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/DroidGuardServiceImpl.kt b/play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/DroidGuardServiceImpl.kt index c6d4673e69..1be8337dd5 100644 --- a/play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/DroidGuardServiceImpl.kt +++ b/play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/DroidGuardServiceImpl.kt @@ -20,7 +20,23 @@ class DroidGuardServiceImpl(private val service: DroidGuardChimeraService, priva override fun guardWithRequest(callbacks: IDroidGuardCallbacks?, flow: String?, map: MutableMap?, request: DroidGuardResultsRequest?) { Log.d(TAG, "guardWithRequest()") - TODO("Not yet implemented") + val handle = getHandle() + try { + val reply = handle.initWithRequest(flow, request) + if (reply == null) { + handle.init(flow) + } + callbacks?.onResult(handle.snapshot(map ?: mutableMapOf())) + } catch (e: Exception) { + Log.w(TAG, "Error during guardWithRequest", e) + callbacks?.onResult(byteArrayOf()) + } finally { + try { + handle.close() + } catch (e: Exception) { + Log.w(TAG, "Error during handle close", e) + } + } } override fun getHandle(): IDroidGuardHandle { From e6f8f6f90d36be0182632b12060b4dc191e53e06 Mon Sep 17 00:00:00 2001 From: ragrin Date: Fri, 5 Jun 2026 13:06:20 +0800 Subject: [PATCH 2/2] docs: add remote DroidGuard setup guide (#2851) Brief setup doc for the remote DroidGuard path, covering client configuration, server endpoint expectations, and quick validation. Addresses the documentation gap noted in the bounty discussion. --- .../REMOTE_DROIDGUARD_SETUP.md | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 play-services-droidguard/REMOTE_DROIDGUARD_SETUP.md diff --git a/play-services-droidguard/REMOTE_DROIDGUARD_SETUP.md b/play-services-droidguard/REMOTE_DROIDGUARD_SETUP.md new file mode 100644 index 0000000000..9120424309 --- /dev/null +++ b/play-services-droidguard/REMOTE_DROIDGUARD_SETUP.md @@ -0,0 +1,38 @@ +# Remote DroidGuard Setup for Play Integrity + +This covers the minimal client-side configuration to use microG's remote +DroidGuard path (which this PR enables for request-backed flows). + +## 1) When this matters + +The `guardWithRequest` path is called when Play Integrity (or other +attestation services) sends a `DroidGuardResultsRequest`. Without this PR, +any app hitting this path gets `NotImplementedError`. + +With this PR, the path is wired through the existing handle lifecycle: +`initWithRequest → snapshot → onResult → close`. + +## 2) Client setup + +1. Open microG Settings → DroidGuard → Remote +2. Set the Remote URL to your DroidGuard server endpoint +3. Save; microG will use remote mode for attestation + +## 3) Required server endpoint + +The remote endpoint receives: + +- `GET`/`POST` at the configured URL +- Query params: `flow`, `source`, plus `x-request-*` from the request bundle +- POST body: URL-encoded key/value payload + +It must return a Base64-encoded byte array (URL-safe, no padding). + +## 4) Quick validation + +1. Set a 30-second test timer +2. Trigger a Play Integrity check from a test app (e.g., Dott sign-in) +3. Confirm the remote server receives the request +4. Confirm the attestation flow completes without `NotImplementedError` + +No AIDL changes. No new session APIs. Uses existing infrastructure.