iOS 26.4 VM location simulation failure
Superseded (2026-09-28): the app hook is gone.
libvlocation.dyliband its SystemHook load were removed, andlocation.set/location.clear/location.currentare IcliKit'ssimulateLocation/clearSimulatedLocation/currentLocationagain, which prove a request by reading the fix back (seeResearch/vphoned_http_api.md). The 2.0.4 bundle used below was the first with the former EXP patches in the JB flow (228326d), including thehv_vmm_presentconcealment. With it on, bluetoothd crash-loops and locationd blocks on the throttled Bluetooth service (issue #438), which fits theinvalid location/invalid latest selected hypothesisfusion failure recorded here.standardnow leaves the concealment and the iPhone17,3 identity rewrites off; only the camera patches remain from EXP. Re-run the reproduction below on a VM restored withstandardto confirm.
Host location never reached the guest (2026-10-07)
Every VM log that recorded Sync Host Location had the host working and the
guest refusing: VPhoneLocation.app was authorized and wrote fixes, vphone-vm
forwarded them, and every location.set failed with Location Services are turned off (issue596-ip18, unlocktest-iphone, nettest-01, discard-a/b). vphone-vm
only printed the error and the menu checkmark stayed on. Three separate causes
turned up on new standard iPhone17,3 iOS 27.0 (24A435) VMs.
The guest's Location Services switch is off. Setup Assistant's Location
Services pane turns it on, so a guest whose Setup Assistant was skipped, or not
yet finished, has it off and locationd gives no client a location, a simulated
one included. location.set and location.current fail with the code location_services_off, the VM
window says so once, and vphone-vm offers the last Mac fix again every 10 s.
Turning the switch on in the guest's Settings brought the Mac's coordinate in
6 s later with the Mac standing still (fresh and simulated true), and Maps
drew its blue dot there. vphoned turns the switch on too, through location.services {enabled:true}
(+[CLLocationManager setLocationServicesEnabled:] with
com.apple.locationd.authorizeapplications, verified on 2026-10-07; the call
does nothing without the entitlement). On a cloned iOS 27.0 guest (2026-11-07)
location.services read {"enabled":true}; {enabled:false} returned
{"enabled":false} and location.set and location.current then failed with
location_services_off; {enabled:true} (twice) returned {"enabled":true}
and location.set answered simulating: true, simulated: true. A
non-Boolean enabled is ignored and the call reads, as for
power.low_power_mode.
The Mac's locationd turned the helper away. It keys VPhoneLocation.app by
bundle identifier and stores the code requirement the first client registered
with; an ad hoc signature's implicit requirement is its cdhash. While a helper
with the stored requirement runs, a helper from another build is refused
silently (#registration stored requirement is not equal to this new requirement, then #registration can't continue) and never gets an
authorization status, so it sends nothing. Two machines on different bundles
could not both sync, and a helper of a new build was refused as long as an old
one ran. StageBundle.sh now signs the helper with designated => identifier "com.vphone.bundle.location"; locationd accepted that requirement once no
cdhash-signed helper was running, and the helper went from NotDetermined to
AuthorizedAlways without a prompt.
locationd can deadlock as it starts. It was first seen on headless starts,
where the VM's locationd hung within a second on every boot tried; more boots
showed windowed starts hang too, less often. Every CoreLocation client then
waits on com.apple.locationd.synchronous and location RPCs time out after
120 s. vphoned now restarts such a locationd; see
Research/Guest/locationd_startup_deadlock.md.
Sync Host Location is now a machine setting, syncsHostLocation in
config.plist, off when absent, in a window and headless alike (headless used
to start it unconditionally).
Reproduction (2026-09-25)
The running 26.4 VM uses the jb firmware variant and iOS 26.4.0. Its
guest agent is the 2.0.4 bundle's vphoned. Location Services are enabled,
and Maps has While Using permission. The VM has no working Wi-Fi switch.
- Open Maps and request the current position. The button spins without a blue dot.
- Send
PUT /v1/locationwith latitude35.681236and longitude139.767125. Most requests fail after five seconds withno location within 5 s; a single earlier request returned a fresh simulated reading, but Maps still did not obtain a position. - Set the same coordinate through Xcode's independent path:
xcrun devicectl device simulate location coordinate --device <VM UDID> --latitude 35.681236 --longitude 139.767125. This command reports success, whileGET /v1/locationstill times out and Maps still spins. - Clear the Xcode simulation with
xcrun devicectl device simulate location clear --device <VM UDID>.
locationd logs received daemon-side request to start location simulation
and emits @ClxSimulated, Fix every second. At the same time it repeatedly
logs LCOutputBuffer,getLatestDaemonLocation,invalid location and
#fusion,getLatestPredictedFusedLocation,invalid latest selected hypothesis.
The TimeZone system-service reader is authorized. The guest agent's
com.apple.locationd.simulation entitlement is present. Developer Mode is
enabled. These observations put the failure after simulation request delivery
and before a usable CoreLocation result reaches clients.
Probes already ruled out
- Removing IcliKit's clear-on-readback-failure kept the simulation active, but did not produce a location for Maps or the authorized reader.
- Appending two identical points with timestamps one second apart did not produce a location.
- The guest's
CLSimulationManagerresponds tosetSimulatedWifiPower:andstartWifiSimulation. Calling both before starting location simulation did not produce a location. - A
locationdprocess exit seen during testing coincided with restoring a temporary guest agent. The restarted original agent reproduced the failure; the exit is not evidence of the root cause.
These observations predate the application hook below. No Apple binary patch was needed for the workaround.
Separate host-sync issue
The host CLLocationManager returned kCLErrorDomain code 1 while its
authorization status was Not Determined. The menu's Sync Host Location
checkmark only records the requested mode; it does not establish that macOS
has supplied a coordinate or that the guest accepted one. This does not
explain preset failure, which also reproduces through the HTTP API and
devicectl.
Cause and fix (2026-09-30). locationd never answers a client whose
executable sits in a generic bundle. From VPhone.bundle/Contents/MacOS,
requestWhenInUseAuthorization neither prompts nor changes the status, and the
usage descriptions in the bundle's Info.plist are never read. A probe showed the
same for every .bundle layout (BNDL, APPL, with or without
CFBundleExecutable, with an embedded __info_plist); only an executable
inside an .app, or a bare one outside any bundle, was prompted. vphone-vm now
starts Contents/Helpers/VPhoneLocation.app (vphone-location, an
LSUIElement app) when Sync Host Location is on. The helper asks for
permission with its own localized InfoPlist.strings and writes one JSON line
per authorization change or fix; it exits when vphone-vm closes its stdin.
Application-level workaround (2026-09-25)
libvlocation.dylib is loaded by SystemHook into newly launched apps. It
overrides CLLocationManager updates for authorized clients while vphoned's
location state file exists. The HTTP location.set endpoint publishes that
file atomically and returns promptly; the locationd simulation request is
best effort. Clearing removes the override. This route intentionally bypasses
the iOS 26.4 locationd fusion problem described above.
Live verification on the 26.4 VM moved Maps' blue dot from Tokyo Station to
Apple Park. A subsequent Maps launch without a test environment variable
loaded /usr/lib/libvlocation.dylib through SystemHook and showed the blue dot
near Apple Park. This confirms delivery to Maps, beyond an API success reply.