Skip to content

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

struct RSDServiceInfo: Hashable {
    var name: String
    var features: [String]
}

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

enum TransportType: String, Codable {
    case wired
    case localNetwork
    case cloud
    case sameMachine
}

TunnelTransportProtocol

enum TunnelTransportProtocol: String, Codable {
    case tcp
    case quic
    case udp
}

AuthenticationType

enum AuthenticationType: String, Codable {
    case manualPairing
    case sharedAccount
    case implicit
}

DeviceReality

enum DeviceReality: String, Codable {
    case physical
    case virtual
    case simulated
}

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

  1. Plugin entry point: Write a .coredeviceplugin bundle with NSPrincipalClass implementing CoreDeviceServicePluginProtocol. Return a DeviceRepresentationProvider from deviceRepresentationProviders.

  2. Minimal device registration requires:

  3. DeviceIdentifier.uuid(UUID, "domain") -- a UUID + domain string
  4. DeviceInfo(identifier: UUID) with at minimum: .state = .connected, .pairingState = .paired, .transportType = .localNetwork
  5. Empty capabilityImplementations: [:] is valid (no capabilities)
  6. controlsUnderlyingResourceForDevice: false

  7. RSD integration: The existing remotepairingd path uses RSDDeviceWrapper wrapping an OS_remote_device C object. We bypass this entirely by constructing DeviceInfo directly.

  8. Tunnel info: DeviceInfo.tunnelIPAddress (IPv6Address) and tunnelTransportProtocol (.tcp) tell CoreDeviceService where to connect. This is where iosmux injects its proxy endpoint.

  9. Capability implementations: For Xcode to actually use the device (deploy, debug), we need at minimum CreateServiceSocketCapability and InstallAppCapability. These require DeviceCapabilityImplementationProvider from the plugin.

  10. 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 : ServiceDeviceRepresentation : _SwiftObject

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

  1. controlsUnderlyingResourceForDevice is ALWAYS false (xorl %ecx, %ecx) in every call site across the entire CoreDeviceService binary.
  2. capabilityImplementations is ALWAYS empty at init time -- capabilities are populated later via mutateState.
  3. deviceInfo is created from DeviceInfo.init(deviceIdentifier:) -- a minimal constructor that only sets the identifier UUID, then fields are populated later.
  4. 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:

  1. We can subclass ServiceDeviceRepresentation (like RPDR does) for maximum control
  2. OR use the DeviceRepresentationBrowser protocol to deliver bare ServiceDeviceRepresentation objects (which the plugin system supports)
  3. The init pattern is: SDR(deviceIdentifier: .uuid(uuid, domain), deviceInfo: DeviceInfo(identifier: uuid), capabilityImplementations: [:], controlsUnderlyingResourceForDevice: false) then populate fields via mutateState