What Is the vphoned Guest Daemon in vphone-cli and How Does It Work?
The vphoned guest daemon is a LaunchDaemon that runs inside iOS virtual machines created by vphone-cli, implementing a length-prefixed JSON protocol over vsock (port 1337) to handle HID events, file operations, clipboard access, and auto-updates from the host.
The vphoned daemon serves as the bridge between the host macOS system and guest iOS virtual machines in the Lakr233/vphone-cli ecosystem. Written in Objective-C and running as a LaunchDaemon inside the virtualized iOS environment, it exposes a comprehensive control interface that enables automation, input simulation, and file management from the host side.
Architecture Overview
The vphoned subsystem splits responsibilities between the host-side Swift client and the guest-side Objective-C daemon:
- Host-side client (
sources/vphone-cli/VPhoneControl.swift): Opens a vsock connection, sends a hello handshake, queues asynchronous requests, parses responses, and implements retry logic on failure. - Guest daemon (
scripts/vphoned/vphoned.m): Listens on vsock port 1337, parses incoming length-prefixed JSON messages, dispatches them to feature modules, and returns JSON replies. - Feature modules (
scripts/vphoned/*.h/.m): Implement concrete operations for HID (vphoned_hid.m), files (vphoned_files.m), clipboard (vphoned_clipboard.m), keychain (vphoned_keychain.m), apps (vphoned_apps.m), and location (vphoned_location.m). - Protocol definition (
scripts/vphoned/vphoned_protocol.h): Declares JSON keys (t,id,v, etc.) and helper utilities for message framing.
Connection Lifecycle and Protocol Flow
The vphone-control protocol operates over a virtio socket (vsock) connection to port 1337. The interaction follows a strict seven-step sequence:
-
Host initiates vsock:
VPhoneControl.connect(device:)creates aVZVirtioSocketConnectionto CID ANY, port 1337 (source:VPhoneControl.swift, lines 45-57). -
Handshake: The host sends a
helloJSON containing the protocol version and optionallybin_hash(SHA-256 of the host binary) via thewriteMessagemethod (source:VPhoneControl.swift, lines 75-80). -
Guest replies: The daemon reads the length-prefixed JSON using
readMessageand responds with its capabilities, IP address, iOS version, and aneed_updateflag if the binary hashes differ (source:vphoned.m, lines 88-108). -
Auto-update: If
need_updateis true and the variant permits updates, the host streams the binary via anupdatemessage with raw payload. The daemon writes it to/var/root/Library/Caches/vphonedviareceive_updateand exits (source:VPhoneControl.swiftlines 40-68 andvphoned.mlines 42-84). -
Read loop: After handshake completion, the host starts a background read loop (
startReadLoop) that continuously parses incoming JSON and dispatches it to pending request callbacks or fire-and-forget handlers (source:VPhoneControl.swift, lines 78-85). -
Command dispatch: Each JSON
tvalue maps to a function in the appropriate feature module. For example, a"hid"command reachesvphoned_hid.mwhich invokesvp_hid_keyorvp_hid_press(source:vphoned.m, lines 88-100). -
Response: The daemon replies with JSON containing
t:"ok"(ort:"err"on failure) and echoes the requestid. The host resolves the pendingContinuationand delivers the result to the caller.
Core Feature Modules
Individual capabilities are implemented in separate translation units within scripts/vphoned/:
HID Simulation (vphoned_hid.m)
Handles human interface device events by calling vp_hid_key (for press/release with boolean state) or vp_hid_press (for simple press). The module processes JSON commands with page and usage fields corresponding to USB HID usage tables.
File Operations (vphoned_files.m)
Implements remote file system access including directory listing, file retrieval, upload, deletion, and renaming. The host can request operations like "file_list" with a path parameter, receiving an "entries" array in response.
Clipboard Management (vphoned_clipboard.m)
Supports bidirectional clipboard synchronization for both text and image data. The daemon can get current clipboard contents or set new values from host commands.
Keychain Access (vphoned_keychain.m)
Provides iOS keychain enumeration and entry addition capabilities, allowing automated certificate and credential management within the virtual machine.
App Management (vphoned_apps.m)
Handles app listing, launch, termination, and foreground application queries. This enables automated UI testing and app lifecycle management from the host.
Location Services (vphoned_location.m)
Receives GPS coordinate updates from the host and injects them into the iOS location subsystem, enabling location-based testing without physical movement.
Auto-Update Mechanism
A distinctive feature of the vphoned guest daemon is its self-updating capability. When the handshake reveals a binary hash mismatch between host and guest, the host initiates a binary transfer:
// Host side: VPhoneControl.swift (lines 40-70)
await control.pushUpdate(fd: socketFD)
The guest receives the new binary through the receive_update function, writes it to CACHE_PATH (typically /var/root/Library/Caches/vphoned), sets executable permissions, and exits cleanly:
// Guest side: vphoned.m (lines 42-84)
if (receive_update(fd, size)) {
exit(0); // launchd restarts the daemon from CACHE_PATH
}
This design ensures the guest daemon stays synchronized with the host tooling without requiring manual VM reconfiguration or image rebuilds.
Error Handling and Resilience
The host-side VPhoneControl class implements robust reconnection logic to handle VM reboots and network interruptions:
- Per-attempt tokens: Each connection attempt is tagged to distinguish stale callbacks from current operations.
- Automatic reconnection: On socket errors, the client schedules a reconnect after a configurable delay (
reconnectDelay). - Pending request cleanup: When disconnected, outstanding requests are cleared with a
ControlError.notConnectederror. - Request timeouts: Different message types apply specific timeouts via
timeoutForRequest, preventing indefinite hangs on slow operations.
Practical Implementation Examples
Sending HID Key Presses
From the host Swift client:
// Send left-control key press
await control.sendHIDPress(page: 0x07, usage: 0x00E0)
This serializes to JSON with "t":"hid" and writes to the vsock connection (implementation: VPhoneControl.swift, lines 74-82).
Guest-Side HID Handling
Inside the daemon (vphoned.m, lines 92-100):
if ([type isEqualToString:@"hid"]) {
uint32_t page = [msg[@"page"] unsignedIntValue];
uint32_t usage = [msg[@"usage"] unsignedIntValue];
NSNumber *down = msg[@"down"];
if (down) {
vp_hid_key(page, usage, [down boolValue]); // press/release
} else {
vp_hid_press(page, usage); // simple press
}
}
Retrieving File Listings
let entries = try await control.listFiles(path: "/var/mobile")
for entry in entries {
print(entry["name"] ?? "unknown")
}
The host builds a "file_list" request; the daemon replies with an "entries" array (implementation: VPhoneControl.swift, lines 82-87 and vphoned_files.m).
Summary
- The vphoned guest daemon runs as a LaunchDaemon inside vphone-cli's iOS virtual machines, listening on vsock port 1337.
- It implements a length-prefixed JSON protocol for host-to-guest communication, defined in
vphoned_protocol.hand handled invphoned.m. - Feature modules separate concerns: HID input (
vphoned_hid.m), file operations (vphoned_files.m), clipboard (vphoned_clipboard.m), and more. - The auto-update mechanism allows the daemon to replace itself at
/var/root/Library/Caches/vphonedand restart via launchd when the host binary changes. - The host-side
VPhoneControlSwift class manages connection lifecycle, reconnection logic, and provides async/await APIs for all daemon operations.
Frequently Asked Questions
How does vphoned handle protocol version mismatches?
During the initial handshake, both host and guest exchange protocol version identifiers in the hello message. If the versions are incompatible, the connection is terminated gracefully. For binary version mismatches detected via bin_hash comparison, the daemon sets a need_update flag, triggering the auto-update flow where the host streams a compatible binary before normal operations resume.
What happens if the vsock connection drops during a file transfer?
The host-side VPhoneControl monitors the socket for read/write errors and enters a reconnection state with a configurable delay (reconnectDelay). Pending requests, including active file transfers, receive a ControlError.notConnected error through their async continuations. The client must retry the operation after the automatic reconnection completes, as the daemon does not maintain transfer state across connections.
Can the auto-update feature be disabled for vphoned?
The auto-update behavior depends on the specific vphone-cli variant and build configuration. While the protocol supports skipping updates if the need_update flag is ignored by the host, the daemon is designed to eventually require matching binary versions for protocol stability. The update mechanism writes to CACHE_PATH and relies on launchd to restart the service, so disabling system-level LaunchDaemon management would prevent updates but also impair normal restart functionality.
Which iOS versions does the vphoned guest daemon support?
The daemon targets modern iOS versions capable of running within the Virtualization.framework environment used by vphone-cli. Specific compatibility depends on the feature modules: HID simulation relies on private IOKit APIs available in iOS 14+, while file operations use standard Foundation APIs available across all supported virtualized iOS versions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →