Skip to content

ADFA-4128 (4/11): quickbuild:runtime — swapping code in the running app - #1716

Open
fryanpan wants to merge 2 commits into
feature/ADFA-4128-qb-03-protocolfrom
feature/ADFA-4128-qb-04-runtime
Open

ADFA-4128 (4/11): quickbuild:runtime — swapping code in the running app#1716
fryanpan wants to merge 2 commits into
feature/ADFA-4128-qb-03-protocolfrom
feature/ADFA-4128-qb-04-runtime

Conversation

@fryanpan

@fryanpan fryanpan commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Part 4/11 of the stacked split of #1669 (requested by Akash). Base: feature/ADFA-4128-qb-03-protocol. Stack overview + review mechanics: PR 1 (#1713). Terms are defined in quickbuild/README.md (lands in PR 1).

Lets a running app take on new code, resources and assets without being reinstalled. This is what makes a save feel instant instead of costing a full rebuild.

flowchart TB
    host["CoGo deploy channel<br/>(core deploy slice, PR 6)"] -- "AIDL onPayload:<br/>dex/resources/assets as fds" --> client
    subgraph rt["<b>This PR: :quickbuild:runtime — Java-only AAR inside the proxy app</b>"]
        client["QuickBuildClient<br/>binds out to CoGo by package<br/><i>QuickBuildClient.java</i>"] --> store["payload persistence<br/>all-or-nothing on disk, quarantine<br/><i>PayloadPersistence.java</i>"]
        store --> cl["classloader routing<br/>payload classes win<br/><i>LoaderRouter.java</i>"]
        store --> res["resource swap, 3 strategies:<br/>ResourcesLoader 30+, shim 28/29,<br/>unsupported below<br/><i>ResourceSwapStrategy.java</i>"]
        store --> assets["asset overlay<br/>DirectoryAssetsProvider, API 30+<br/><i>DirectoryAssetsProvider.java</i>"]
        keep["keep-alive service<br/>defeats the cached-app freezer<br/><i>QuickBuildKeepAliveService.java</i>"]
        conf["reload confirmation<br/>render-proof resumed /<br/>apply-time ack backgrounded<br/><i>QuickBuildRuntime.java</i>"]
    end
    client -- "reportReloaded / reportCrash" --> host
    user["user's classes, running process"] -. "loaded via" .-> cl
    classDef thisPrBox fill:#dbeafe,stroke:#93c5fd,color:#1e3a5f
    classDef inPr fill:#ffffff,stroke:#64748b,color:#000
    class rt thisPrBox
    class client,store,cl,res,assets,keep,conf inPr
Loading

What to review

  • PayloadPersistence.java — all-or-nothing deploy; quarantines a payload that fails partway. Correctness-critical.
  • ResourceSwapStrategy.java — three swap paths by API level: 30+, 28/29, unsupported.
    • The 28/29 shim's success path is JVM-untestable [unverified on device].
  • DirectoryAssetsProvider.java — asset overlay; cannot hide deletions, and needs API 30+.
  • QuickBuildRuntime.java — reload confirmation: render-proof resumed, apply-time ack backgrounded. Skim QuickBuildClient.java, LoaderRouter.java, QuickBuildKeepAliveService.java.

How this PR Was Tested

  • 33 test files, heavy on persistence atomicity, quarantine, and the three resource strategies.
  • [verified 2026-08-21] At this cut: :quickbuild:runtime:test green (only protocol below it) — 33 suites, 220 tests per variant across all 6 variants (1,320 executions), 0 failures, 0 errors. Coverage 93.2% line / 95.8% branch.
  • End-to-end evidence: PR 11.

Coverage (JaCoCo at the stack tip, single run):

Package Line Branch Note
com.itsaky.androidide.quickbuild.runtime 93.2% 95.8% 19 of 26 files; 7 device-only, excluded by design
NON-UI TOTAL 93.2% 95.8% 702 lines, 401 branches

The 7 exclusions are the device-only Android and binder glue — QuickBuildRuntime, QuickBuildClient, QuickBuildAppComponentFactory, PayloadStore, ResourceStore, StatusOverlay, ActivityTracker — each named with its reason in quickbuild/runtime/build.gradle.kts and covered by the device walks instead.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Kj9YeCDHGp9DU8LPtfWJ7W

@fryanpan
fryanpan force-pushed the feature/ADFA-4128-qb-04-runtime branch from 4a636ca to c5d01ab Compare August 22, 2026 06:41
fryanpan and others added 2 commits August 21, 2026 23:56
…rces and assets into the running process

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kj9YeCDHGp9DU8LPtfWJ7W
- Stale pendingReloadGeneration mis-blaming later crashes: the backgrounded
  apply now assigns the pending slot too (Generations.pendingAfterApply), and
  BootProbation.generationToBlame refuses a pending value the store has moved
  past. Covered by BootProbationTest.aPendingReloadTheStoreMovedPastIsNotBlamed
  (fails without the fix) and GenerationsTest.aBackgroundedApplyClearsThePendingSlotItAlreadyAcked.
- failReload swallowing every pre-apply failure: the newer-generation guard is
  now a three-way Generations.onReloadFailure — never-applied failures skip the
  rollback/quarantine but still reportCrash + banner; only a failure superseded
  by a newer live generation stays silent. Covered by
  GenerationsTest.aFailureTheStoreNeverAdoptedStillReports.
- Binder-thread setProviders + immediate provider close racing main-thread
  inflation: ResourceStore now performs the field swap, setProviders and the
  close of the replaced provider on the main thread (inline when already there,
  so the boot restore path still lands before first inflation; Looper FIFO keeps
  a posted swap ahead of the posted recreate). Pure threading with no JVM seam —
  justified in swapProvidersOnMain's doc; device-covered.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kj9YeCDHGp9DU8LPtfWJ7W
@fryanpan
fryanpan force-pushed the feature/ADFA-4128-qb-04-runtime branch from c5d01ab to 94537bf Compare August 22, 2026 07:04
@fryanpan
fryanpan marked this pull request as ready for review August 23, 2026 02:31

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant