4.0 KiB
Developer Mode via AMFI XPC
How iOS developer mode is enabled programmatically, based on TrollStore's implementation.
XPC Service
Mach service: com.apple.amfi.xpc
AMFI (Apple Mobile File Integrity) daemon exposes an XPC endpoint for developer mode control on iOS 16+.
Required Entitlement
com.apple.private.amfi.developer-mode-control = true
Without this entitlement the XPC connection to amfid is rejected.
Message Protocol
Messages are serialized using private CoreFoundation-XPC bridge functions:
extern xpc_object_t _CFXPCCreateXPCMessageWithCFObject(CFTypeRef obj);
extern CFTypeRef _CFXPCCreateCFObjectFromXPCMessage(xpc_object_t obj);
Request
NSDictionary with a single key:
@{@"action": @(action)}
Actions
| Action | Value | Behavior |
|---|---|---|
kAMFIActionArm |
0 | Arm developer mode — takes effect on next reboot, user must select "Turn On" |
kAMFIActionDisable |
1 | Disable developer mode immediately |
kAMFIActionStatus |
2 | Query current state |
Response
XPC reply dict contains a "cfreply" key holding the CF-serialized response:
xpc_object_t cfReply = xpc_dictionary_get_value(reply, "cfreply");
NSDictionary *dict = _CFXPCCreateCFObjectFromXPCMessage(cfReply);
Response fields:
| Key | Type | Description |
|---|---|---|
success |
BOOL | Whether the XPC call succeeded |
status |
BOOL | Current developer mode state (for Status action) |
armed |
BOOL | Whether armed for reboot (for Arm action) |
error |
NSString | Error description if success is false |
Arming Flow
- Query status (
kAMFIActionStatus) - If already enabled, done
- Send arm (
kAMFIActionArm) - Device must reboot; user selects "Turn On" in the prompt
- Developer mode is now active
Arming does not enable developer mode immediately. It sets a flag that triggers the enable prompt on the next reboot. Disabling (kAMFIActionDisable) takes effect immediately.
TrollStore Reference
Source: references/TrollStore/RootHelper/devmode.m
TrollStore separates privileges: the main app has no AMFI entitlement; all privileged operations go through RootHelper which has com.apple.private.amfi.developer-mode-control.
Key functions:
checkDeveloperMode()— returns current state, YES on iOS <16 (devmode doesn't exist)armDeveloperMode(BOOL *alreadyEnabled)— check + arm in one callstartConnection()— creates and resumes XPC connection tocom.apple.amfi.xpcsendXPCRequest()— CF dict → XPC message → sync reply → CF dict
vphoned Implementation
Added as devmode capability in vphoned guest agent:
Protocol Messages
Status query:
{"t": "devmode", "action": "status"}
→ {"t": "ok", "enabled": true}
Enable (arm):
{"t": "devmode", "action": "enable"}
→ {"t": "ok", "already_enabled": false, "msg": "developer mode armed, reboot to activate"}
Entitlements
Added to scripts/vphoned/entitlements.plist:
<key>com.apple.private.amfi.developer-mode-control</key>
<true/>
Host-Side API (VPhoneControl.swift)
let status = try await control.sendDevModeStatus() // -> DevModeStatus (enabled: Bool)
let result = try await control.sendDevModeEnable() // -> DevModeEnableResult (alreadyEnabled: Bool, message: String)
Both methods use sendRequest() with pending request tracking — the response is returned via async throws, not logged to console. Callers (e.g. VPhoneMenuConnect) display results as NSAlert sheets on the VM window.