Skip to content

fix(browser): retain Engine ownership until cleanup settles - #295

Closed
andersalm wants to merge 26 commits into
developfrom
fix/131-browser-helper-orphan
Closed

andersalm wants to merge 26 commits into
developfrom
fix/131-browser-helper-orphan

Conversation

@andersalm

@andersalm andersalm commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Runtime keeps each Browser Engine and profile reservation owned until exact terminal cleanup proves that its VM, workers, sockets and ports have retired. Close, failed launch, gateway shutdown and parent death use the same cleanup path. Pending cleanup keeps the writer barrier and existing control journal available for reconciliation. Remote serving now commits the validated cleanup receipt instead of losing it at the terminal-state boundary.

The VZ adapter reports fresh native state and retains TURN, bridge workers, rootfs and profile protections while cleanup is uncertain. It joins owned workers before releasing those protections. An in-flight broken-pipe write is accepted only after explicit launch shutdown, with its actual copied count preserved; other write errors still fail. Helper lifetime follows Runtime, with platform-specific adapters behind the existing Engine/Exit/Carrier contracts and Runtime-only networking.

Browser Reset uses an in-capsule confirmation dialog under the existing sandbox. Cancel preserves the profile. Confirmed Reset requires retired writers and validates the bound local profile path before removal. Retained uninitialized profiles report recovery required and preserve their bytes. The parallel media test barrier now belongs to its exact root/page identity.

Validation and remaining gates:

  • Current source is ff4c9e468a592de44fc2cb2caa54b7cee134af45, tree affc2e5c4530f2542cf7c219e44eb6dd49fedb53, after a normal merge of develop 34b2e5c5. Compatibility review passed and the bounded barrier regression remains intact. Required formatting, whitespace and product-data checks pass.
  • The Unix bridge fixture now creates its temporary directory exclusively. A forced collision failed with the previous allocator, then all four package tests and 1,000 parallel repetitions passed. Independent review confirms that this correction changes test code only.
  • The receipt hand-off correction at b2498bef reproduced the failure before repair, passed both focused boundary tests and independent review, then passed the cached full server suite: 2588 passed, 0 failed, 27 existing ignored, in 458.37 seconds without compilation. Earlier 2e6632ae validation passed 70 VZ release tests and all-target release Clippy for Runtime and VZ.
  • Installed Mac proof at 2e6632ae passed normal decoded WebRTC navigation/input/Close, active managed Home stop, SIGTERM and SIGKILL with restart/profile reads. All thirteen cleanup effects settled within the declared 60000 ms bound. The same principal's committed cookie, localStorage and IndexedDB state survived; retired-page actions failed and new generations closed fully. The confirmed Reset journey retains its historical 0d4493db binding. Independent raw review accepts these scoped results; exact artifacts and receipts are in #131.

The preceding dbae canonical gate passed the full server suite (2589 passed, 27 existing ignored), then failed at the Unix bridge fixture. Its original EINVAL error remains recorded in #131; the duplicate-directory defect is separately reproduced and repaired. The frozen candidate passed one Runtime-only release build and installation, with exact built/installed parity. All 26 matching component bindings were reused at their actual producer sources. Current normal use, active SIGTERM/restart, SIGKILL/orphan recovery and actual managed Home stop passed with profile reopening and exact native cleanup. Independent raw review accepts all four current journeys and the final kernel absence census. The final canonical pre-push gate passed for the exact frozen head. It passed formatting, product-data checks, all-target checks and Clippy, the full server suite (2589 passed, 0 failed, 27 existing ignored), 228 Runtime binary tests, 115 VZ library tests, 70 VZ supervisor tests, the Unix bridge suite and the other selected package targets. The remote task branch now matches this head. The PR is ready for human review after the current posted cross-family PASS; all ten platform CI jobs passed. Current posted Opus review is PASS for this head. Nonblocking follow-ups are tracked by #87 for recovery guidance, #289 for backpressure and #293 for concurrent-spawn qualification, with common lifetime implementation owned by #131. Platform CI passed all ten jobs at the exact frozen head. The requested human approval by @irzhywau remains required before normal merge.

Current-base compatibility was checked after develop advanced to d430a133: a clean simulated normal merge retains all 61 reviewed task-path blobs unchanged. Independent source compatibility review passed for the separate startup, installation and Carrier/image-transfer changes. New-base PR #296 CI also passed; existing installed evidence remains bound to ff4c9e46, and the simulated combined tree has no new installed claim. Jetson, broader media, soak, Wallet, manual UX and release qualification retain their owners in #283.

Keep the ownership-pipe writer in Runtime and forward its verified reader through Browser launchers. Reuse the update-controller pipe contract for VM, hosted, native and proof helpers, and flush the crosvm guest before VM termination.

Verify parent loss for TERM, INT and KILL through the real helper spawn path, Runtime provider shutdown, and guest flush ordering. Targeted Rust, Node, product-data and formatting checks pass. Full control-socket and installed VM journeys require operator proof outside the sandbox.
Preserve the read-only seed while giving the owned VZ launch disk private write permissions before guest overlays. Recreate partial clone output before the copy fallback. Add a seed mode, inode and write isolation regression.
Retain Engine obligations when its owner is unavailable or its receipt is incomplete. Preserve partial native evidence across control-service reconciliation and restart. Add bound receipt, pending ownership, replacement/reset refusal and partial absence regressions.

Validation: control-service settlement smoke, product-data/public-copy checks, Rust format checks and diff check pass. Compiled Rust and installed journey proof remain pending.
Acquire the existing profile sidecar lease before checking Runtime ownership. Retain trusted root/profile directory descriptors, reject linked or replaced profile paths, and keep the lease in the blocking unlink worker through cancellation. Preserve scoped Reset receipts and missing-disk idempotence.

Validation: independent Mac/Linux source review, workspace formatting and diff check pass. Writer, link, replacement and cancellation regressions are prepared; compiled and installed proof remain pending.
Keep the single startup result inline and preserve all tested handle transfers. The scoped Clippy expectation documents its bounded use.

Validation: independent usage and ownership review; executable source is byte-identical after removing the attribute.
Pass the validated Engine receipt into Runtime terminal retirement so first remote Close can persist exact cleanup proof and safely release its owner. Preserve native cleanup validation, authority checks and replay ordering.

Verification: the cached prior signed Carrier case failed in 0.92 seconds; both exact signed Carrier and remote cleanup/replay/late-input tests pass after one targeted compile. Independent receipt and call-site review passed. Whitespace, workspace formatting and product-data checks pass.
Use an atomic sequence and exclusive directory creation so parallel tests cannot adopt or remove another fixture. Add a forced-collision regression that preserves the existing owner.
@andersalm

Copy link
Copy Markdown
Contributor Author

Independent adversarial review (Claude Opus via elastos-pr-review, 2026-10-08), head ff4c9e4.
VERDICT: PASS

Blocking findings: none.

I tried to break it in four places and each one refused:

  • Reset (browser_profile_reset.rs:107-176): it opens every directory relative to the one above with no symlink following. It checks file identity and link count, and holds the same lock (profile.ext4.lifetime.lock) that the VZ writer holds. Tests cover symlinked and hard-linked disks, locks and folders, files swapped after the lock is taken, and a dropped request. Each test would fail with the old remove_file.
  • Terminal proof (gateway_browser_sessions.rs:2527-2570): closing a page without all thirteen proof flags, or with a different generation or provider, is refused. The old text-matching "already absent" path is gone (gateway_browser.rs:2829-2870), and tests show the cleanup stays owned.
  • Pipe check (process_lifetime.rs:51-66): a marker whose pipe identity doesn't match fails closed. Only server_infra.rs:1282 hands the pipe to a provider, so the update controller's old marker can't reach the adapter.
  • Engine supervisor on macOS: it now refuses to start engines instead of running without network isolation.

Non-blocking notes:

  1. scripts/browser-vm-control-service.mjs:4243-4247: after a restart, a pending record with no settlement result and a dead launcher stays pending forever. That blocks both Open and Reset for that account, and nothing lets the user or operator recover. This needs a tracked follow-up.
  2. process_lifetime.rs:96-109: on macOS the pipe is created with pipe() and close-on-exec is set afterwards. That used to run only in the update controller; it now runs inside the multithreaded Runtime. A fork on another thread in that gap could inherit the writer, and helpers would then miss end-of-file when Runtime dies.
  3. browser-vz-engine-supervisor copy_stream_until_done: on WouldBlock/TimedOut it retries without checking done. A stalled peer only stops at shutdown, and if the writer is non-blocking the loop spins.

Not checked: I ran no tests or CI. I didn't check the Linux/crosvm and Jetson launcher changes, the full control-service and settlement smoke diffs, whether waitid/si_pid in the native proxy builds on macOS, or how a Home upgraded with old pending records behaves.

@andersalm

Copy link
Copy Markdown
Contributor Author

@irzhywau, please complete the required human review of this PR. CI and independent review passed; #131 records installed lifecycle and current-base compatibility proof.
Your approval is the remaining gate before normal merge and #131 closure.

@andersalm

Copy link
Copy Markdown
Contributor Author

#89 owner review of update_controller/child.rs (8 Oct): a pure move of parent_pipe/pipe_identity/set_cloexec/above_stdio into elastos_common::process_lifetime with the same code (pipe2+O_CLOEXEC on Linux; pipe then set_cloexec elsewhere). The non-Linux CLOEXEC window noted by Opus existed before and is unchanged by this move. No objection from the update side; recheck against develop 5f56bb8 before merge.

@andersalm

Copy link
Copy Markdown
Contributor Author

@irzhywau: PR #295 remains frozen at ff4c9e468a592de44fc2cb2caa54b7cee134af45 with its existing required review request. The 0.8.0 common guest includes the native proxy changed here, so final image production needs this reviewed integration to fix its input identity. Please complete the required human review; OMP owns the normal merge and release integration. #131 retains the installed lifecycle/profile proof; #217 owns the delivery candidate and build checkpoint.

@andersalm

Copy link
Copy Markdown
Contributor Author

Merged into #307, which ships in alpha.15.

@andersalm andersalm closed this Oct 10, 2026
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