CoreDevice DeviceRepresentation Data Structures¶
Research date: 2026-04-06 Source: macOS 26 beta (Xcode 18 beta), CoreDevice.framework 518.27.0 Method: Symbol demangling + string extraction from CoreDevice.framework on SIP-disabled VM
Overview¶
CoreDeviceService represents devices via a layered architecture:
PluginProtocol
└→ DeviceRepresentationProvider
└→ DeviceRepresentationBrowser
└→ ServiceDeviceRepresentation
├→ DeviceIdentifier
├→ DeviceInfo (CoreDeviceProtocols)
├→ DeviceStateSnapshot
└→ [Capability : [String]]
1. Plugin Loading¶
Search paths (in order)¶
/Library/Developer/PrivateFrameworks/CoreDevice.framework/Versions/A/PlugIns
/Library/Developer/CoreDevice/PlugIns
/AppleInternal/Library/Developer/CoreDevice/PlugIns
~/Library/Developer/CoreDevice/PlugIns (likely, per NSBundle conventions)
Plugin bundle format¶
- Extension:
.coredeviceplugin - Standard NSBundle with
Contents/MacOS/<binary>,Contents/Info.plist - Key Info.plist field:
NSPrincipalClass(e.g.DeviceSpecPlugin.DeviceSpecPlugin) - Example:
DeviceSpecPlugin.coredeviceplugin(ships with Xcode)
PluginProtocol (CoreDevice.PluginProtocol)¶
protocol PluginProtocol {
var identifier: String { get }
var isAppleInternal: Bool { get }
init() async
}
CoreDeviceServicePluginProtocol (extends PluginProtocol)¶
protocol CoreDeviceServicePluginProtocol: PluginProtocol {
var deviceRepresentationProviders: [DeviceRepresentationProvider] { get }
var hostCapabilityImplementationProviders: [HostCapabilityImplementationProvider] { get }
var deviceCapabilityImplementationProviders: [DeviceCapabilityImplementationProvider] { get }
}
// Default implementations return [] for all three properties.
2. Device Discovery Chain¶
DeviceRepresentationProvider¶
protocol DeviceRepresentationProvider {
var deviceRepresentationBrowser: DeviceRepresentationBrowser { get }
func consider(offer: DeviceRepresentationIdentityManagementOffer) // default: no-op
}
DeviceRepresentationBrowser¶
protocol DeviceRepresentationBrowser {
func start(
on: DispatchQueue?,
invokingWithDiscoveredDeviceRepresentation: (ServiceDeviceRepresentation) -> Void,
invokingIfCancelled: () -> Void
) throws
}
DeviceRepresentationIdentityManagementOffer¶
class DeviceRepresentationIdentityManagementOffer {
var discoveredAt: DispatchTime
var device: ServiceDeviceRepresentation
func accept() -> DeviceRepresentationIdentityControl
func decline()
}
3. ServiceDeviceRepresentation (the core device record)¶
class ServiceDeviceRepresentation {
// Constructor
init(
deviceIdentifier: DeviceIdentifier,
deviceInfo: DeviceInfo, // CoreDeviceProtocols.DeviceInfo
capabilityImplementations: [Capability : [String]],
controlsUnderlyingResourceForDevice: Bool
)
// Identity
var deviceIdentifier: DeviceIdentifier
var selfReportedDeviceIdentifier: DeviceIdentifier
var effectiveDeviceIdentifier: DeviceIdentifier?
var effectiveOrSelfReportedDeviceIdentifier: DeviceIdentifier
var identifierForLogging: String
// State
var deviceInfo: DeviceInfo // CoreDeviceProtocols.DeviceInfo
var currentStateSnapshot: DeviceStateSnapshot
var capabilities: Set<Capability>
var controlsUnderlyingResourceForDevice: Bool
var hasBeenMarkedForRemoval: Bool
var description: String
// Ordering
var orderingPriority: Int
static var defaultOrderingPriority: Int
static var providerOrderingPriority: Int
// Metadata
var _additionalMetadataProviders: OSAllocatedUnfairLock<[AdditionalMetadataProvider]>
// Lifecycle
func updateState()
func mutateState(using: (inout DeviceStateSnapshot) -> Void) -> DeviceStateSnapshot
func markForRemoval()
func underlyingResourceDestroyed()
// Callbacks
func addDeviceRepresentationStateChangedHandler(
on: DispatchQueue?,
invoking: (DeviceIdentifier, DeviceStateSnapshot) -> Void
)
func setDeviceRepresentationRemovalHandler(
on: DispatchQueue?,
invoking: @Sendable (UUID) -> Void
)
// Static
static var defaultClientCallbackQ: DispatchQueue
}
4. DeviceIdentifier (enum)¶
enum DeviceIdentifier: Hashable, Codable, CustomStringConvertible {
case ecid(UInt64)
case uuid(UUID, String) // UUID + domain string
var uuidRepresentation: UUID
}
5. DeviceStateSnapshot (struct, Codable, Equatable)¶
struct DeviceStateSnapshot: Codable, Equatable {
init(
deviceInfo: DeviceInfo,
capabilityImplementations: [Capability : [String]],
monotonicIdentifier: Int64
)
var deviceInfo: DeviceInfo // mutable
var capabilities: Set<Capability> // computed from capabilityImplementations
var capabilityImplementations: [Capability : [String]] // mutable
var monotonicIdentifier: Int64
}
6. DeviceInfo (CoreDeviceProtocols.DeviceInfo) -- FULL FIELD LIST¶
The central data structure. All fields extracted from property descriptors:
struct DeviceInfo {
// === Required ===
var identifier: UUID // unique device UUID
var serviceDeviceIdentifier: DeviceIdentifier // CoreDevice.DeviceIdentifier
var state: DeviceState // .unavailable | .disconnected | .connecting | .connected
var pairingState: PairingState // .unpaired | .pairingInProgress | .paired | .unsupported
var isMobileDeviceOnly: Bool
var visibilityClass: DeviceVisibilityClass // .default | .wirelessPairableDevices | .devicesBeingProvisioned
var preparednessState: DevicePreparedness // OptionSet: .powerAssertionTaken | .developerModeEnabledIfRequired | .developerDiskImageServicesEnabled | .extendedDeviceInfoLoaded | .all
var potentialHostnames: [String]
var tags: [String]
var defaultUserCredentials: Set<DefaultUserCredential>
var providerSpecificValues: [String : String]
var areDeveloperDiskImageServicesAvailable: Bool
// === Optional identity ===
var name: String?
var udid: String?
var ecid: UInt64?
var serialNumber: String?
var hardwareModel: String? // e.g. "D84AP"
var productType: String? // e.g. "iPhone16,2"
var thinningProductType: String?
var marketingName: String? // e.g. "iPhone 15 Pro Max"
// === Type / Platform ===
var deviceType: DeviceType? // .iPhone | .iPad | .iPodTouch | .mac | .appleWatch | .appleTV | .homePod | .realityDevice | .computeModule
var platform: DevicePlatform? // .iOS | .tvOS | .watchOS | .macOS | .xrOS
var reality: DeviceReality? // .physical | .virtual | .simulated
var supportedDeviceFamilies: [UInt64]?
var utType: UTType?
// === OS info ===
var osBuild: String?
var osBuildUpdate: BuildUpdate?
var osBuildVersions: OSBuildVersions?
var osVersion: String?
var osVersionNumber: VersionNumber?
var releaseType: String?
var hasInternalOSBuild: Bool?
var rootFileSystemIsWritable: Bool?
var remoteServicesVersion: String?
// === Hardware ===
var cpuType: CPUType?
var cpuCount: CPUCount?
var supportedCPUTypes: [CPUType]?
var internalStorageCapacity: UInt64?
var isProductionFused: Bool?
var supportsCheckedAllocations: Bool?
// === Security / Pairing ===
var authenticationType: AuthenticationType? // .manualPairing | .sharedAccount | .implicit
var developerModeStatus: DeveloperModeStatus? // .enabled(UInt64) | .disabled | .unsupported | .unknown(CoreDeviceError)
// === Connection / Tunnel ===
var transportType: TransportType? // .wired | .localNetwork | .cloud | .sameMachine
var tunnelIPAddress: IPv6Address?
var tunnelIPAddressString: String?
var tunnelTransportProtocol: TunnelTransportProtocol? // .tcp | .quic | .udp
var lastConnectionDate: Date?
var localHostnames: [String]?
// === RSD (RemoteServiceDiscovery) ===
var rsdDeviceInfo: RSDDeviceInfo?
var rsdServices: [RSDServiceInfo]?
// === Display / UI ===
var displayInfo: DisplayInfo?
var screenViewingURL: URL?
// === Users ===
var users: Set<DeviceUser>?
var nanoRegistryPairedDeviceUDIDs: [String]? // paired Apple Watch UDIDs
// === Provider ===
var provider: String?
var additionalMetadata: [String : CodableValue]
// === Boot ===
var bootState: BootState? // .booting | .booted | .shuttingDown | .shutdown | .recoveryOS | .dfu | .paused | .panic | .unknown
var snapshotBootState: SnapshotBootState?
// === VM-specific ===
var virtualMachineSnapshotInfo: VirtualMachineSnapshotInfo?
// === Computed (extension) ===
var id: UUID // == identifier
var isDarwinos: Bool
// === Static ===
static var hostnameAdditionalMetadataDomain: String
static var userManagedAdditionalMetadataDomain: String
// === Constructor ===
init(identifier: UUID)
}
7. Supporting Types¶
RSDDeviceInfo¶
struct RSDDeviceInfo: Codable, Hashable, Equatable {
var name: String
var uuid: UUID
init(name: String, uuid: UUID)
init(from: OS_remote_device) // wraps C remote_device obj
}
RSDServiceInfo¶
RSDDeviceWrapper¶
class RSDDeviceWrapper {
init(remoteDevice: OS_remote_device, deviceIdentifier: DeviceIdentifier)
var remoteDevice: OS_remote_device
var deviceInfo: DeviceInfo
func addDeviceStateChangedHandler(on: DispatchQueue?, invoking: (UUID, DeviceStateSnapshot) -> Void)
func setDeviceRemovalHandler(on: DispatchQueue?, invoking: @Sendable (UUID) -> Void)
}
DeviceState (CoreDeviceProtocols)¶
enum DeviceState: String, Codable {
case unavailable
case disconnected
case connecting
case connected
}
PairingState¶
enum PairingState: String, Comparable, CaseIterable, Codable {
case unpaired
case pairingInProgress
case paired
case unsupported
}
TransportType¶
TunnelTransportProtocol¶
AuthenticationType¶
DeviceReality¶
DeviceVisibilityClass¶
enum DeviceVisibilityClass: String, Codable {
case `default`
case wirelessPairableDevices
case devicesBeingProvisioned
}
DevicePreparedness (OptionSet)¶
struct DevicePreparedness: OptionSet {
static let powerAssertionTaken: DevicePreparedness
static let developerModeEnabledIfRequired: DevicePreparedness
static let developerDiskImageServicesEnabled: DevicePreparedness
static let extendedDeviceInfoLoaded: DevicePreparedness
static let all: DevicePreparedness
}
DeveloperModeStatus¶
enum DeveloperModeStatus {
case enabled(UInt64)
case disabled
case unsupported
case unknown(CoreDeviceError)
}
BootState (CoreDeviceProtocols)¶
enum BootState: String, Codable {
case booting
case booted
case shuttingDown
case shutdown
case recoveryOS
case dfu
case paused
case panic
case unknown
}
DevicePlatform (CoreDeviceProtocols)¶
enum DevicePlatform: String, Comparable, Codable {
case iOS
case tvOS
case watchOS
case macOS
case xrOS
var displayName: String
var xbsPlatformCode: String
var trainProgram: TrainProgram
func defaultDeviceType() -> DeviceType
func osMarketingName(for: DeviceType?) -> String
init?(productName: String)
init?(utType: UTType)
}
DeviceType (CoreDeviceProtocols)¶
enum DeviceType: String, Codable, Identifiable {
case mac
case iPhone
case iPad
case iPodTouch
case appleWatch
case appleTV
case homePod
case realityDevice
case computeModule
var platform: DevicePlatform
var id: String
}
8. Capability System¶
Capability is an opaque type (likely a struct wrapping a String identifier). Capabilities are stored as [Capability : [String]] where the value is a list of implementation identifiers.
Known capability action identifiers (strings)¶
com.apple.coredevice.action.acquireusageassertion
com.apple.coredevice.action.appinstall
com.apple.coredevice.action.connect
com.apple.coredevice.action.createservicesocket
com.apple.coredevice.action.darwinnotificationobserve
com.apple.coredevice.action.darwinnotificationpost
com.apple.coredevice.action.default.user.credentials
com.apple.coredevice.action.disableddiservicesaction
com.apple.coredevice.action.disconnect
com.apple.coredevice.action.enableddiservices
com.apple.coredevice.action.enterdfu
com.apple.coredevice.action.exportvirtualmachinearchive
com.apple.coredevice.action.fetchddimetadata
com.apple.coredevice.action.fetchdyldsharedcachefiles
com.apple.coredevice.action.fetchmachodylibs
com.apple.coredevice.action.filenodedetails
com.apple.coredevice.action.gettrainname
com.apple.coredevice.action.listfiles
com.apple.coredevice.action.listusageassertions
com.apple.coredevice.action.lockstate
com.apple.coredevice.action.pair
com.apple.coredevice.action.provisiondevice
com.apple.coredevice.action.receivefiles
com.apple.coredevice.action.removehostddis
com.apple.coredevice.action.removeprovisioneddevice
com.apple.coredevice.action.rsyncfiles
com.apple.coredevice.action.snapshotcreation
com.apple.coredevice.action.snapshotfetchscreenshots
com.apple.coredevice.action.snapshotremove
com.apple.coredevice.action.snapshotresume
com.apple.coredevice.action.snapshotsetname
com.apple.coredevice.action.tags
com.apple.coredevice.action.transferfiles
com.apple.coredevice.action.unpair
com.apple.coredevice.action.updatehostddis
Known capability types (from class names)¶
ApplicationControlCapability InstallRootCapability
AuthListingIdentifiersCapability InternalRestoreOSCapability
BootCapability KeyboardHIDCapability
ButtonHIDCapability ListAppsCapability
CollectDeviceDiagnosticsCapability ListFilesCapability
CreateServiceConnectionCapability ListProcessesCapability
CreateServiceSocketCapability ListRootsCapability
DefaultUserCredentialsCapability LockStateCapability
DigitizerHIDCapability ManageHostDDIsCapability
DisplayInfoCapability MobileGestaltQueryCapability
EnterDFUCapability OrientationControlCapability
ExportVirtualMachineArchiveCapability PauseVirtualMachineCapability
FeatureFlagsCapability PointerHIDCapability
FetchAppIconsCapability PostDarwinNotificationCapability
FetchDDIMetadataCapability ProcessControlCapability
FetchSymbolsCapability RebootCapability
FirmwareVariableCapability ResumeVirtualMachineFromPauseCapability
GamepadHIDCapability ScrollHIDCapability
HIDDeviceCapability SendMemoryWarningCapability
InstallAppCapability SendSignalCapability
ShutdownCapability TransferFilesCapability
SnapshotCreationCapability UninstallAppCapability
SnapshotFetchScreenshotsCapability UninstallRootCapability
SnapshotRemoveCapability UniversalHIDServicePoolCapability
SnapshotResumeCapability TagsCapability
SnapshotSetNameCapability TrainNameForBuildUpdateCapability
9. UseAssertionProvidingDeviceRepresentation Protocol¶
This protocol (used by remotepairingd devices) extends the basic device representation:
protocol UseAssertionProvidingDeviceRepresentation: _RSDDeviceWrapperConvertible {
func acquireUsageAssertion(forRequest: TunnelAssertionRequest)
func releaseAssertion(identifiedBy: UUID)
func listAllAssertions() -> [UsageAssertionInformation]
func releaseAllAssertions()
func fetchExtendedInfoIfRequired(
completingOnQueue: DispatchQueue?,
handler: (Result<DeviceStateSnapshot, Error>) -> Void
)
}
10. ServiceDeviceManager (how devices are registered)¶
class ServiceDeviceManager {
init(
clientManager: ClientManager,
pluginManager: CoreDeviceServicePluginManagerProtocol,
fullInitializationTime: DispatchTimeInterval = ...
)
func install(browser: DeviceRepresentationBrowser)
func deviceStateSnapshot(forDeviceIdentifiedBy: UUID) -> DeviceStateSnapshot?
func deviceStateSnapshot(for: DeviceIdentifier) -> DeviceStateSnapshot?
}
Check-in flow¶
// Plugin browser calls callback with ServiceDeviceRepresentation
// ServiceDeviceManager publishes DeviceManagerCheckInCompleteEvent:
struct DeviceManagerCheckInCompleteEvent {
var checkInRequestIdentifier: UUID
var initialDeviceSnapshots: [DeviceStateSnapshot]
var serviceFullyInitialized: Bool
}
11. Key Architectural Insights for iosmux¶
-
Plugin entry point: Write a
.coredevicepluginbundle withNSPrincipalClassimplementingCoreDeviceServicePluginProtocol. Return aDeviceRepresentationProviderfromdeviceRepresentationProviders. -
Minimal device registration requires:
DeviceIdentifier.uuid(UUID, "domain")-- a UUID + domain stringDeviceInfo(identifier: UUID)with at minimum:.state = .connected,.pairingState = .paired,.transportType = .localNetwork- Empty
capabilityImplementations: [:]is valid (no capabilities) -
controlsUnderlyingResourceForDevice: false -
RSD integration: The existing remotepairingd path uses
RSDDeviceWrapperwrapping anOS_remote_deviceC object. We bypass this entirely by constructingDeviceInfodirectly. -
Tunnel info:
DeviceInfo.tunnelIPAddress(IPv6Address) andtunnelTransportProtocol(.tcp) tell CoreDeviceService where to connect. This is where iosmux injects its proxy endpoint. -
Capability implementations: For Xcode to actually use the device (deploy, debug), we need at minimum
CreateServiceSocketCapabilityandInstallAppCapability. These requireDeviceCapabilityImplementationProviderfrom the plugin. -
RemotePairingDeviceRepresentationBrowser IS the real remotepairingd path. See section 12 below.
12. Class Hierarchy Discovery (from live disassembly)¶
Date: 2026-04-06 Method: LLDB attach to CoreDeviceService PID on SIP-disabled macOS 26 VM + full disassembly of call sites
Key finding: inheritance¶
RemotePairingDeviceRepresentation is a subclass of ServiceDeviceRepresentation, NOT a wrapper around it. This means the real code allocates RPDR via swift_allocObject with the RPDR metatype, then calls super.init (SDR.init) internally.
Instance sizes¶
ServiceDeviceRepresentation: 88 bytes (6 ivars)RemotePairingDeviceRepresentation: 1136 bytes (~1048 bytes of additional state)
SDR ivars (from ObjC metadata)¶
| Offset | Name | Size |
|---|---|---|
| 16 | _stateStorage |
8 |
| 24 | _markedForRemovalStorage |
8 |
| 32 | _identitySource |
8 |
| 40 | _additionalMetadataProviders |
8 |
| 48+ | selfReportedDeviceIdentifier |
variable |
| 87 | controlsUnderlyingResourceForDevice |
1 |
RemotePairingDeviceRepresentationBrowser ivars¶
| Offset | Name |
|---|---|
| 16 | _deviceManagementQueue |
| 24 | _mutableState |
| 32 | _cache |
RPDR.init call site (disassembled from CoreDeviceService)¶
The super.init call from RemotePairingDeviceRepresentation.init to ServiceDeviceRepresentation.init:
; === Setup before SDR.init call ===
callq DeviceInfo.init(deviceIdentifier:) ; create DeviceInfo from DeviceIdentifier
movq %rdi, __swiftEmptyArrayStorage ; load empty array storage
callq <internal_func> ; create empty [Capability: [String]]
movq <deviceIdentifier>, %rdi ; arg1: deviceIdentifier
movq <deviceInfo>, %rsi ; arg2: deviceInfo (from DeviceInfo.init)
movq %rax, %rdx ; arg3: capabilityImplementations (EMPTY dict)
xorl %ecx, %ecx ; arg4: controlsUnderlyingResourceForDevice = FALSE
movq <self>, %r13 ; self: pre-allocated RPDR object
callq SDR.init(deviceIdentifier:deviceInfo:capabilityImplementations:controlsUnderlyingResourceForDevice:)
Register mapping (Swift x86_64 calling convention, confirmed by disassembly)¶
| Register | SDR.init parameter |
|---|---|
%rdi |
deviceIdentifier: DeviceIdentifier |
%rsi |
deviceInfo: DeviceInfo |
%rdx |
capabilityImplementations: [Capability: [String]] |
%ecx |
controlsUnderlyingResourceForDevice: Bool |
%r13 |
self (the allocated object) |
Critical observations from ALL 3 call sites¶
controlsUnderlyingResourceForDeviceis ALWAYSfalse(xorl %ecx, %ecx) in every call site across the entire CoreDeviceService binary.capabilityImplementationsis ALWAYS empty at init time -- capabilities are populated later viamutateState.deviceInfois created fromDeviceInfo.init(deviceIdentifier:)-- a minimal constructor that only sets the identifier UUID, then fields are populated later.- The caller retains the result and immediately calls setup methods (
addDeviceRepresentationStateChangedHandler, etc.)
Stubs resolved (CoreDeviceService -> CoreDevice)¶
| CDS file addr | Resolved symbol |
|---|---|
0x1000b0bce |
CoreDevice.ServiceDeviceRepresentation.init(deviceIdentifier:deviceInfo:capabilityImplementations:controlsUnderlyingResourceForDevice:) |
0x1000b0c52 |
type metadata accessor for CoreDevice.DeviceIdentifier |
0x1000b0c9a |
type metadata accessor for CoreDevice.DeviceStateSnapshot |
0x1000b1a62 |
CoreDeviceProtocols.DeviceInfo.init(deviceIdentifier:) |
0x1000b1b0a |
type metadata accessor for CoreDeviceProtocols.DeviceInfo |
0x1000b18ca |
dispatch thunk of RemotePairing.ConnectableDevice.isWirelesslyPairableDevice.getter |
0x1000b18e2 |
dispatch thunk of RemotePairing.ConnectableDevice.registerForStateChange(on:usingHandler:) |
Implication for iosmux plugin¶
Since RemotePairingDeviceRepresentation is a SUBCLASS of ServiceDeviceRepresentation, the real code does NOT create bare SDR objects -- it creates specialized subclasses. For our plugin:
- We can subclass
ServiceDeviceRepresentation(like RPDR does) for maximum control - OR use the
DeviceRepresentationBrowserprotocol to deliver bareServiceDeviceRepresentationobjects (which the plugin system supports) - The init pattern is:
SDR(deviceIdentifier: .uuid(uuid, domain), deviceInfo: DeviceInfo(identifier: uuid), capabilityImplementations: [:], controlsUnderlyingResourceForDevice: false)then populate fields viamutateState