Skip to content

feat: support Apple Vision Pro simulator slimming and speed up no-reboot slims - #56

Merged
Interlap01 merged 2 commits into
MobAI-App:feat/tvos-watchos-slimmingfrom
Jeehut:visionos-and-faster-no-reboot
Oct 8, 2026
Merged

Interlap01 merged 2 commits into
MobAI-App:feat/tvos-watchos-slimmingfrom
Jeehut:visionos-and-faster-no-reboot

Conversation

@Jeehut

@Jeehut Jeehut commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Thank you for #54! This PR builds on it with two commits: Apple Vision Pro support and a faster on --no-reboot.

There is no tvOS code here, but I had #54's tvOS profile tested on a tvOS 27.0 simulator: the remote, the game controller and the Home screen still work, with about half the processes and 35 to 57 % less memory across two separate runs.

visionOS has two special cases. CoreSimulator still names its runtime xrOS, so parseRuntime maps that to visionOS. And visionOS needs com.apple.mobileassetd, because the simulated surroundings are mobile assets. Without it the simulator boots into a black space around the Home View. Apps still launch and UI tests still pass, so a boot check alone misses it. It now stays enabled, like homed on watchOS in #54.

Stock Without mobileassetd Slim with this PR
visionOS stock Home View visionOS without mobileassetd: black space around the Home View visionOS slim with this PR: surroundings and Home View intact

I had this tested on visionOS 27.0 simulators in two independent runs. Slim, a simulator runs 88 processes and uses about 1.2 GB, still at 60 fps. Taps, a second window and an immersive space worked, a reboot kept the profile, and off restored stock. A single stock measurement showed 218 processes and 2.8 GB. Repeating it failed because every stock boot pushed my Mac's load above 150, while no slim boot did. CPU at rest stays around 30 % even when slim, because rendering the surroundings keeps backboardd busy. Only 27.0 was tested.

The --no-reboot commit fixes a real problem. On my Mac, busy with builds and other simulators, on --no-reboot on a visionOS simulator hit a 10-minute limit three times in a row. The old path runs two launchctl spawns per daemon, and each one is slow on a busy host. Now one launchctl unload -w stops up to 64 daemons, and only the daemons it missed take the per-label path. A full live slim of a stock visionOS simulator now takes about 9 s while a UI test keeps tapping the app, and every tap still arrives. On a fresh iOS 27.0 simulator it took 4 s instead of 16 s. The commit does not depend on #54 and also applies to main alone.

An earlier build of these changes has been slimming visionOS and tvOS test simulators on that Mac since October 5. Every --no-reboot slim since then worked on the first try.

Jeehut added 2 commits October 6, 2026 15:32
`on --no-reboot` runs a `launchctl disable` and a `launchctl bootout`
spawn per label, 340 spawns for the full 170-label profile. A spawn is
cheap on a quiet Mac but can take seconds on a host busy with other
simulators and builds, and a live slim then needs minutes.

`launchctl unload -w` takes many job plists at once: it writes the same
persistent disable override as `disable` and removes the loaded job
like `bootout`. Simulator processes see the host file system, so the
plists under the runtime's RuntimeRoot can be passed by path, in chunks
of 64. `Device` now carries its `RuntimeID` to find that RuntimeRoot.

A plist is only used when its own `Label` key matches the label, so a
misnamed file can never unload a daemon outside the allowlist. The state
is read back afterwards (`print-disabled` and `launchctl list`), and
anything still enabled or loaded takes the existing per-label path. A
chunk that outlasts its spawn timeout ends the batch, so a slow host
keeps its remaining budget for that path.
Builds on the Apple TV and Apple Watch support: CoreSimulator names the
visionOS runtime `xrOS`, so `parseRuntime` now maps it to the `visionOS`
platform, and every command, the JSON output, and the macOS app pick it
up through the existing platform plumbing.

**visionOS keeps `com.apple.mobileassetd` enabled.** The simulated
surroundings and the Home View are mobile assets. With mobileassetd
disabled a visionOS 27.0 simulator boots to a black space with no Home
View, while apps still launch, so a boot check alone does not notice it.
`desiredForDevice` skips it like homed on watchOS, so slimming,
verification, status totals, and the app's count agree, and a device
slimmed before this exception gets the service back on its next `on`.

**Persistence gate.** visionOS 2.5 is the release generation of iOS
18.5, following the tvOS and watchOS cutoffs. Like those, it is not an
independent measurement; every platform is still read back after boot.
@Interlap01

Copy link
Copy Markdown
Contributor

Lgtm. Thank you!

@Interlap01
Interlap01 merged commit 68d6876 into MobAI-App:feat/tvos-watchos-slimming Oct 8, 2026
1 check passed
Interlap01 added a commit that referenced this pull request Oct 8, 2026
* feat: support Apple TV and Apple Watch simulator slimming

* feat: support Apple Vision Pro simulator slimming and speed up no-reboot slims (#56)

* perf: stop a no-reboot slim's daemons with one launchctl spawn

`on --no-reboot` runs a `launchctl disable` and a `launchctl bootout`
spawn per label, 340 spawns for the full 170-label profile. A spawn is
cheap on a quiet Mac but can take seconds on a host busy with other
simulators and builds, and a live slim then needs minutes.

`launchctl unload -w` takes many job plists at once: it writes the same
persistent disable override as `disable` and removes the loaded job
like `bootout`. Simulator processes see the host file system, so the
plists under the runtime's RuntimeRoot can be passed by path, in chunks
of 64. `Device` now carries its `RuntimeID` to find that RuntimeRoot.

A plist is only used when its own `Label` key matches the label, so a
misnamed file can never unload a daemon outside the allowlist. The state
is read back afterwards (`print-disabled` and `launchctl list`), and
anything still enabled or loaded takes the existing per-label path. A
chunk that outlasts its spawn timeout ends the batch, so a slow host
keeps its remaining budget for that path.

* feat: support Apple Vision Pro simulator slimming

Builds on the Apple TV and Apple Watch support: CoreSimulator names the
visionOS runtime `xrOS`, so `parseRuntime` now maps it to the `visionOS`
platform, and every command, the JSON output, and the macOS app pick it
up through the existing platform plumbing.

**visionOS keeps `com.apple.mobileassetd` enabled.** The simulated
surroundings and the Home View are mobile assets. With mobileassetd
disabled a visionOS 27.0 simulator boots to a black space with no Home
View, while apps still launch, so a boot check alone does not notice it.
`desiredForDevice` skips it like homed on watchOS, so slimming,
verification, status totals, and the app's count agree, and a device
slimmed before this exception gets the service back on its next `on`.

**Persistence gate.** visionOS 2.5 is the release generation of iOS
18.5, following the tvOS and watchOS cutoffs. Like those, it is not an
independent measurement; every platform is still read back after boot.

* fix: reuse the resolved device for batch unloads and note the visionOS no-reboot cutoff

EnableSlimNoReboot already resolves the device, so unloadInBatch takes its
RuntimeID instead of running a second simctl list. listDevicesInSet sets
RuntimeID in its main loop, and the --no-reboot help names visionOS < 2.5.

---------

Co-authored-by: Cihat Gündüz <github@cihatguenduez.de>
@Jeehut
Jeehut deleted the visionos-and-faster-no-reboot branch October 12, 2026 14:18
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.

2 participants