Repository navigation
feat(droidguard): Support Play Integrity over remote DroidGuard (#2851) - #3941
Open
MilindChatrabhuji wants to merge 25 commits into
Open
MilindChatrabhuji wants to merge 25 commits into
MilindChatrabhuji wants to merge 25 commits into
Conversation
## Summary - Implement `guardWithRequest` on the bounded executor and close its handle on every completion path. - Reuse remote server state through the existing `init` / repeated `snapshot` / `close` lifecycle. - Centralize HTTP request encoding, timeouts, non-success status handling, and connection cleanup. ## Verification - `./gradlew.bat :play-services-droidguard-core:testDebugUnitTest --tests org.microg.gms.droidguard.core.RemoteDroidGuardHttpClientTest --tests org.microg.gms.droidguard.core.RemoteDroidGuardSessionTest --offline` - BUILD SUCCESSFUL; 4 focused tests pass, and the task compiles the module and AIDL. - `git diff --check` passes. This verifies local transport/session behavior. A real server/device Play Integrity flow remains unverified. Related issue: microg#2851.
… ci] Keep each initialization pending until session setup finishes, including when a synchronous snapshot overtakes one-way init dispatch. Bind snapshot metadata to the observed generation and close late sessions after handle shutdown. Validation: five maintained JVM tests passed. A loopback HTTP replay of the actual RemoteHandleImpl source with disposable platform stubs improved from 1/4 to 4/4 scenarios: pending begin, snapshot before init dispatch, close during begin, and completed reinitialization. No full Gradle, Binder, device, Play Integrity, or Dott scooter acceptance claim.
Retain the successful three-class, twelve-case Gradle run and VtmDefaultDebug APK receipt for product 7a648d5 plus the original lifecycle test patch. Keep the tested source separate from later PR revisions; no production file is changed.
Move result delivery inside the existing task's cleanup finally boundary. A slow remote close no longer delays the completed callback; fallback, rejection, logging and cleanup on callback failure are preserved. Record the focused production-class loopback replay and controlled callback-latency results, preserving the concurrent integrated Android report.
Add a DroidGuardClient that returns Task<DroidGuardHandle> and then uses snapshot, isOpened, and close against a begin/snapshot/close session backend. Loopback interop covers retained-handle reuse and rejects a single-attest server that has no session. This does not mint Play Integrity or device results. Co-authored-by: woahwhattheheck <woahwhattheheck@users.noreply.github.com>
Copy the public String map into a session map so handle.snapshot compiles and still reuses the retained remote session. Co-authored-by: woahwhattheheck <woahwhattheheck@users.noreply.github.com>
Keep begin, snapshot, and close ordered within one retained session while allowing other sessions to progress independently. Prevent close from retiring remote state during an in-flight snapshot. Direct production-class loopback execution reproduces both overlaps on the parent and removes both with this change. The maintained session class passes four focused JUnit checks. JVM evidence and Android/device limits are recorded in SESSION_SERIALIZATION.md. Preserve the latest retained handle client and snapshot map repair.
Return failed Tasks when the supplied executor rejects initial admission. Keep begin, snapshot, result publication and close in one accepted getResults worker, so a second dispatch cannot strand the result Task or the opened remote session. Use trySetException after task publication to avoid duplicate completion when a listener throws. Preserve result-before-close ordering and existing per-session serialization. Extend RemoteDroidGuardHandleInteropTest with rejected-admission and accept-once executor cases. The three existing interop cases remain unchanged. With the actual microG TaskImpl, full current client/session/HTTP classes and the existing loopback server, parent 04fbd91 passes 3/5 and fails both new cases (RejectedExecutionException and DuplicateTaskCompletionException); this change passes 5/5. The accepted-worker case observes result completion before close and exactly one executor submission. Focused JVM validation used retained OpenJDK 17, Kotlin 2.2.21 and JUnit 4.13.2. Executed source blob 2836391; test blob dc2b839. Android packaging and device acceptance remain separate.
Add a default-disabled provider and authenticated host adapter for the existing begin/snapshot/close protocol. Retain actual core handles, check readiness, preserve initialization metadata, and return native result bytes through an explicit response envelope. Runtime caller checks restrict the bridge to authorized local operators; the ordinary service broker is unchanged. Bound active and closing sessions, work queues, operation waits, and idle lifetime. Reject overlapping work for one session before occupying a global worker, so another session can progress. Close failed native setup and late initialization results. Compile the complete changed Kotlin production classes for JVM 1.8 and execute six focused scenarios with retained Robolectric API29 and a recording VM boundary: 6 passed. Exercise the production Python HTTP/subprocess adapter with ten requests and seven content-command fixtures. The setup guide records source blobs, outcomes, donor credit, and execution limits. No APK, installed-provider, Google VM, Play Integrity, or Dott ride result is asserted.
The native runtime can return encoded error bytes through a successful snapshot response. Clarify that an explicit provider error status becomes an HTTP error; Base64 validity alone does not establish attestation success.
Generate a test-only public API JAR from the active JDK module and resolve jdk.httpserver in unit-test JVMs. The ordinary module task passes all 17 maintained cases on validation tree 4866ca6 in run37234495146, without an init script, filters, or APK assembly. No production dependencies or API behavior change.
Preflight request-target bytes, form-body bytes, and adapter field counts before opening a connection. Preserve the existing response cap and cover accepted and rejected protocol boundaries.
…og#2851) - Support multi-step challenge-response DroidGuard sessions over remote HTTP/ADB bridge for Google Play Integrity API. - Implement RemoteDroidGuardSession, RemoteDroidGuardHttpClient, RemoteDroidGuardHandleClient, and RemoteDroidGuardInitialization synchronization barrier. - Implement server-side DroidGuardSessionStore and DroidGuardSessionProvider with concurrency gating, active operation tracking, and idle reaping. - Provide authenticated Python HTTP adapter (droidguard_server.py) and comprehensive self-hosting setup guide (REMOTE_DROIDGUARD_SETUP.md). - Fix Kotlin reserved keyword escaping in DroidGuardSessionProvider. - Include comprehensive unit test suite (27 unit tests) and Python server protocol integration tests.
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Google Play Integrity API evaluates multi-step DroidGuard sessions (\�egin\ -> \snapshot\ -> \close). This PR adds full support for offloading multi-step Play Integrity DroidGuard evaluations to a remote helper device, accompanied by an authenticated HTTP bridge server and a complete deployment guide.
Key Changes
Claiming the bounty on issue #2851.