visionOS 26.4 environment backgrounds
This change extends the native UI bring-up on RealityDevice14,1, userland
23O247 and the cloudOS/PCC 26.4 research kernel. The source baseline is upstream
main 8c5aa439, whose marketing version remains 2.15.2.
The later V201 pacing correction raises this existing
native environment path from the initial 30 fps checkpoint to about 60 fps.
Three independent missing pieces
RealityEnvironmentcould not look upcom.apple.surfboard.environmentservice. On 2026-11-08, both kernel and launchd logs recorded the exact lookup denial (159). The app then trapped in+[BSServiceConnection(NSXPCConnection) NSXPCConnectionWithEndpoint:configurator:]because the endpoint was nil. This is a current native crash, distinct from the earlier UIKit launch watchdog in the initial bring-up.- The native app's
SystemEnvironmentSceneAsset.stategetter checksSFBSIsRunningOnPhysicalHardware. On a virtual device, the nativeRealityEnvironment/ShowEnvironmentsOnSimulatorfeature flag must be on before ordinary environments can be selected. This gate is separate from asset availability; enabling it does not claim that a download has finished. - Selecting an environment presents Apple's “Adjust Immersion” instruction. A VM has no physical Digital Crown. Its native immersion level must be adjustable from the host for the environment to become visible.
Installation and reversal
Both new patches are independently selectable and off in every shipped preset. They are limited to the reviewed 26.4 userland/26.4 kernel pair.
system-launchd-exp-visionos_environment_ipcrequires the existing scoped UXM adapter. Its independent root-owned marker is/usr/lib/vphone-visionos-environment-ipc. It permits only the native app at/Applications/RealityEnvironment.app/RealityEnvironment, with signing identifiercom.apple.RealityEnvironmentand a kernel-validated audit token, to look up the single service above. Other operations, callers, services, return values and errno retain the original adapter behavior. Opt-out removes this marker alone; it does not modify the native server's authorization.system-featureflags-exp-visionos_environmentschanges onlyShowEnvironmentsOnSimulator/Enabledin/System/Library/FeatureFlags/Domain/RealityEnvironment.plist. Before changing it, the installer stores its Boolean/absence and feature-entry presence in/usr/share/vphone/VisionOSEnvironments.plist. Rollback restores the owned field and retains unrelated metadata. Invalid values and conflictingDevelopmentPhaseentries fail without changing the domain.
The existing native-UI selections and manual camera-plugin preference described in the bring-up recipe remain prerequisites. This change does not claim a fresh restore validates the whole recipe.
The existing lab's old darwinos preset name no longer resolves on current
main. Its desired selection was migrated to visionos, retaining the working
UI allowances and adding these two choices. The new preset's unrelated TXM
remap and kernel GLES choices were blocked for this existing VM, keeping its
installed boot chain. Its original receipt was preserved: the manually deployed
guest files and readbacks, rather than a rewritten receipt, certify this test.
Native immersion control
Device > Environment Immersion offers Passthrough, Half Immersion (50%), and
Full Environment. It appears only when the connected agent advertises
visionos_immersion. Select an environment in native Home View first. A cloud
icon still means the asset must download normally.
The agent exposes visionos.immersion.get and visionos.immersion.set with a
finite numeric level in [0, 1]. Booleans and numeric strings are rejected.
Only the visionOS agent variant receives the native
com.apple.surfboard.immersion-client entitlement. Bundle admission checks that
it does not leak into the iOS, tvOS or watchOS variants or the host.
The bridge dynamically loads SurfBoardServices, checks the device identity and method ABI, and calls the existing authenticated service:
The system-environment type is uint8_t(0), also used by Apple's own app. The
setter takes float, type, double(0.25) animation duration and an NSError
completion. The getter independently returns (float, NSError *).
A successful set response contains requested_level, the independently
observed level, available and applied. During the short native animation,
the observed level may still be between the old and requested values. The menu
does not claim that acknowledgement is an observation of a settled state.
Timeouts report uncertainty and preserve heap-owned state for late callbacks.
No compositor image, physical pose, projection or tracking state is injected.
The tempting setAbsoluteImmersionLevel: API follows the native dial curve:
in the observed VM, a request of 1 initially targeted about 0.3. The explicit
type-0 setter above was therefore used and independently read back as 1.0.
Runtime evidence and validation
The existing VM displayed Apple's preinstalled White Sands environment at
about 30 fps in the actual host window. Its normal WBDisplayTap composite
(intent 0, no separate composite) contained 921,446 nonblack pixels out of
921,600 at 1280 × 720, with nonzero alpha throughout. The Wolf asset was
already present under PreinstalledAssetsV2/RequiredByOs; no replacement image
or host-rendered wallpaper was used.

Real agent requests for 0, 0.5 and 1 settled to matching independent readbacks.
Requests for -0.1, 1.1, Boolean true and string "1" were rejected while the
native level remained unchanged. A subsequent cold boot again displayed White
Sands after selecting it in native Home and adjusting immersion. The native OS
started that boot at level 0, so this is support for the selection and controls,
not a promise to restore immersion automatically at startup. After refreshing
AMFI admission, the rebuilt host's localized Device > Environment Immersion
menu was exercised directly: Passthrough, Half Immersion and Full Environment
settled to independent native readbacks of 0, 0.5 and 1 respectively. White Sands
rendered in that rebuilt host at about 30 fps. The final native composite had
921,440 nonblack pixels and 921,600 nonzero-alpha pixels at 1280 × 720.
Validation includes 73 patch-selection/catalogue/plist-inverse tests, IPC scope and ABI forwarding tests, native immersion tests under AddressSanitizer (including failure, malformed ABI, timeout and late completion), host menu connection lifecycle tests, method catalogue/schema checks, and full bundle build/admission. Physical passthrough cameras, tracking and stereo output remain outside this test. Other environments still require their genuine assets.
All local source, build output, temporary data and evidence are on the external
volume. Investigation root:
/Volumes/ZHITAI/Data/VPhone/Builds/visionos-background.
Key records are evidence/environment-denials.jsonl,
evidence/RealityEnvironment-current.ips,
evidence/native-service-crash-evidence.json,
native-investigation/findings.md, native-investigation/immersion-control.md,
evidence/white-sands-full.png, evidence/immersion-rpc-validation.json,
evidence/menu-{passthrough,half,full}-readback.json,
evidence/menu-final-frame.json and evidence/menu-final.png.
The crash's retained REA Evidence ID is
ev_6ca47d092453315a43913e526850396d5d05880b3524425581af25ed32739cd7.