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:

  1. Host initiates vsock: VPhoneControl.connect(device:) creates a VZVirtioSocketConnection to CID ANY, port 1337 (source: VPhoneControl.swift, lines 45-57).

  2. Handshake: The host sends a hello JSON containing the protocol version and optionally bin_hash (SHA-256 of the host binary) via the writeMessage method (source: VPhoneControl.swift, lines 75-80).

  3. Guest replies: The daemon reads the length-prefixed JSON using readMessage and responds with its capabilities, IP address, iOS version, and a need_update flag if the binary hashes differ (source: vphoned.m, lines 88-108).

  4. Auto-update: If need_update is true and the variant permits updates, the host streams the binary via an update message with raw payload. The daemon writes it to /var/root/Library/Caches/vphoned via receive_update and exits (source: VPhoneControl.swift lines 40-68 and vphoned.m lines 42-84).

  5. 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).

  6. Command dispatch: Each JSON t value maps to a function in the appropriate feature module. For example, a "hid" command reaches vphoned_hid.m which invokes vp_hid_key or vp_hid_press (source: vphoned.m, lines 88-100).

  7. Response: The daemon replies with JSON containing t:"ok" (or t:"err" on failure) and echoes the request id. The host resolves the pending Continuation and 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.notConnected error.
  • 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.h and handled in vphoned.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/vphoned and restart via launchd when the host binary changes.
  • The host-side VPhoneControl Swift 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →