Skip to content

fix(android): let open --relaunch accept a package Android restarts at once - #4498

Merged
thymikee merged 3 commits into
mainfrom
fix/android-relaunch-respawn
Nov 13, 2026
Merged

thymikee merged 3 commits into
mainfrom
fix/android-relaunch-respawn

Conversation

@thymikee

@thymikee thymikee commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

Summary

open --relaunch com.android.settings failed with android-app-close-timeout (phase process) on Android 17. A system client of the Settings slice provider restarts Settings right after am force-stop, so the close fence saw a new pid. A relaunch needs only the foreground and exit fences: the process fence runs after them, so once they pass, every process that ran before the stop is gone, and the launch reuses the new one. Both relaunch routes — the session-owner close and the in-open stop — accept a refusal from the process fence alone, through one predicate (passedAndroidRelaunchStopFences). Plain close still refuses a restarted process. help close and commands.md say so.

6 files touched. Fixes #4482.

Validation

  • Tested SHA 753e5a2bd7, base 9676eedac5.
    • Round 1: no CLI syntax in the close description, which MCP shares.
    • Round 2: one shared catch replaces the purpose parameter.
  • New tests fail on base with process remained running after close and pass at head: lifecycle.test.ts (owner-close relaunch) and app-lifecycle-close.test.ts (in-open relaunch). The existing exit/foreground refusals still pass.
  • pnpm exec vitest run --project unit-core packages/platform-android/src packages/command-surface/src/__tests__/command-surface-metadata.test.ts: 137 files, 1413 tests passed. pnpm check:quick: pass.
  • Live: Pixel 9a API 37 emulator (Android 17, Google APIs arm64), T3 device command against a source daemon. Six looping shell clients call content://android.settings.slices, standing in for the system client. Each run reads the Settings am_kill/am_proc_start events from logcat.
Build open com.android.settings --relaunch --foreground (session-owner close)
base 9676eedac5 2/4 failed, android-app-close-timeout, phase process
head 10/10 succeeded. In 8 runs Settings restarted for its content provider 83–233 ms after am_kill; those took 3.1–3.4 s (the 2 s process fence expired and its refusal was accepted). The other 2 had no restart and took 1.7–1.9 s.

Without the stand-in clients, base succeeds on this emulator: the restart depends on timing. open settings --relaunch resolves to an intent and relaunches through am start, so it never reaches the in-open stop. For package targets, open resolution supplies an app id, so relaunches take the owner route. The in-open stop has only its unit test.

🤖 Generated with Claude Code

…t once

On Android 17 a provider or broadcast client restarts Settings right after
am force-stop, so the relaunch close fence saw a new process and refused with
android-app-close-timeout (phase process). A relaunch needs only the processes
that ran before the stop to exit; the launch that follows reuses the new one.
close keeps refusing a restarted process.

Fixes #4482

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 6.23 MB 6.23 MB +387 B
Package (unpacked) 6.23 MB 6.23 MB +387 B
Package (download) 1.89 MB 1.89 MB +153 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 33.4 ms 43.2 ms +9.9 ms
CLI --help 59.9 ms 83.7 ms +23.8 ms

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 6 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/platform-android/src/app-lifecycle.ts">

<violation number="1" location="packages/platform-android/src/app-lifecycle.ts:663">
P2: `expired === 'process'` does not prove Android restarted the package. `waitForAndroidPackageProcessGone` also returns false when its final probe or stability wait reaches the deadline, but this branch treats that unconfirmed timeout as a successful relaunch. Return a distinct “replacement observed” result and accept only that result; keep unconfirmed deadline expirations as failures.

(Based on your team's feedback about Android close-fence deadlines.)</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

@apex-sentinel-staging

apex-sentinel-staging Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Apex Sentinel

Verdict: approve

Since the last review: 0 new · 0 still open · 0 no longer raised

No findings.

2 findings below minor not shown (user_settings.min_severity).

Reviewed with this repository's own Sentinel configuration (d2426fffdf78).

Feedback goes in the review comment threads, as a reply under the inline comment of a finding:

Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if it is wrong — I will re-check the cited code.

Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.

Comment @apex-sentinel-staging review on this conversation to run a full review.

Earlier reviews

Review of 14c49027 · 12.11.2026 18:06 UTC

Apex Sentinel

Verdict: approve

Since the last review: 0 new · 0 still open · 0 no longer raised

No findings.

Reviewed with this repository's own Sentinel configuration (9676eedac5b0).

Review of 7fff7a63 · 12.11.2026 17:53 UTC

Apex Sentinel

Verdict: approve

No findings.

1 finding below minor not shown (user_settings.min_severity).

Reviewed with this repository's own Sentinel configuration (9676eedac5b0).

…ts expiry

Address review: a process-fence expiry can be a slow probe, not a proven
restart. A relaunch needs only the foreground and exit fences, so the in-open
stop no longer runs the process fence, and the owner close accepts a refusal
from that fence alone. The close description no longer carries CLI syntax,
which MCP tool descriptions reject.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@thymikee

Copy link
Copy Markdown
Member Author

This PR is ready at 14c4902. I found no problems in the code, and all 22 checks are green with none failing. There are no conflicts, and nothing else blocks the merge. The review thread about process-phase expiry (#4498) no longer applies at this head: the in-open route skips the process fence (app-lifecycle.ts:731), and the owner-close route accepts a refusal only after the exit fence has passed (app-lifecycle.ts:627), so you can resolve it.

Not blocking, and you can take or leave these: the live run in the PR body used open com.android.settings --relaunch, which takes the owner-close route, and that route still waits out the 2 s process fence before it drops the refusal, so the reported 1–2 s looks like a run where the restart did not happen, and a log line from a head run that did restart on that route would settle it. The in-open route (app-lifecycle.ts:223 and :360) changed too and was not run live. Also, one rule (a relaunch needs only the foreground and exit fences) now lives in two places, the purpose parameter for the in-open stops and the details.phase === 'process' catch at lifecycle.ts:119, so would one shared catch for both routes be simpler? I did not run the unit tests or any device. The live evidence is from the PR body.

Address review: the in-open stops skipped the process fence through a purpose
parameter while the owner close caught its refusal. Both routes now catch a
refusal from the process fence alone through passedAndroidRelaunchStopFences.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@thymikee

Copy link
Copy Markdown
Member Author

Thanks. Both notes were right.

Live evidence for the catch path, at 753e5a2bd7. You were right that the earlier 1–2 s runs never hit a restart inside the fence. I re-ran with six looping slice-provider clients and read Settings' am_kill/am_proc_start events from logcat for each run (open com.android.settings --relaunch --foreground, session-owner route). Result: 10 of 10 succeeded. In 8 runs, Settings restarted for its content provider 83–233 ms after am_kill. Those runs took 3.1–3.4 s: the 2 s process fence expired, and its refusal was accepted. The other 2 runs had no restart and took 1.7–1.9 s. The PR body has the table.

In-open route. open settings --relaunch resolves to an intent and relaunches through am start, so it never reaches the in-open stop. For package targets, open resolution supplies an app id, so relaunches take the owner route. I found no CLI open that reaches app-lifecycle.ts:223/:360 on this setup, so that route has only its unit test, which fails on base.

One rule. Done. The purpose parameter is gone. Both in-open stops call stopAndroidPackageForRelaunch, which catches through the same passedAndroidRelaunchStopFences predicate as the owner close in lifecycle.ts. The in-open route now also waits out the 2 s fence when Settings restarts, the same cost the owner route already pays.

@thymikee

Copy link
Copy Markdown
Member Author

I found no problems in 753e5a2. It keeps the earlier clean review at 14c4902 (#4498 (comment)), and the process expiry no longer asserts a restart. The process fence is reached only after the foreground and exit fences pass, so open --relaunch accepts a package Android restarts at once without claiming a restart it did not see.

The review thread on that process expiry is fixed at this head, so the author can resolve it: #4498 (comment)

CI is green, with 22 checks and none failing. There are no conflicts. I did not run the unit tests or a device. Nothing else must happen before merge.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Nov 13, 2026
@thymikee
thymikee merged commit 4aae9ba into main Nov 13, 2026
22 checks passed
@thymikee
thymikee deleted the fix/android-relaunch-respawn branch November 13, 2026 09:20
thymikee added a commit that referenced this pull request Nov 13, 2026
…baseline

* origin/main:
  ci: use smaller runners for control and publishing jobs (#4492)
  docs(help): point verification at read-only commands, not bare find (#4497)
  fix(android): let open --relaunch accept a package Android restarts at once (#4498)
  fix(snapshot): name the captured Android app in the snapshot header (#4499)
  feat(proxy): configure trusted public upload origins (#4501)
  fix(android): restore screenshot demo permission state (#4477)
  feat(harmonyos): support app uninstall beside deploy (#4292)
  fix(ios): confirm foldable rotation from the lit panel in either simulator set (#4343) (#4440)
  chore: mark 0.21.37 as released
  fix(ios): make back the verified left-edge swipe (#4460)
  fix(ios): mark zero-area nodes unmeasured and point their press refusal at scroll --until (#4495)
  fix(ios): never repeat a synthesized gesture that may have run (#4474)
  fix(capture): publish cropped screenshots atomically after scaling (#4478)
  ci(android): reuse cached system images across emulator workflows (#4490)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Android] open --relaunch com.android.settings fails: "process remained running after close"

1 participant