# How to Use XPC Services with the Container Tool for Inter-Process Communication

> Learn to use XPC services with the container tool for secure inter-process communication. Discover how it enables container lifecycle management via XPCMessage objects and XPCClient connections.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: how-to-guide
- Published: 2026-07-12

---

**The Container tool uses the ContainerXPC Swift package to establish secure, sandboxed connections between `container-apiserver` and helper services, enabling container lifecycle management through serialized `XPCMessage` objects sent over `XPCClient` connections.**

The `apple/container` repository implements a robust inter-process communication layer using macOS XPC services to isolate privileged container operations from the user-facing CLI. By leveraging the **ContainerXPC** package, the tool creates type-safe bridges between the API server and per-container helpers that manage VMs, networking, and image storage.

## Understanding the XPC Service Architecture

The Container tool relies on three specialized XPC helpers that run with minimal privileges and register with **launchd**:

- **`container-core-images`**: Manages image storage and content addressing
- **`container-network-vmnet`**: Implements the virtual network stack and IP allocation  
- **`container-runtime-linux`**: One instance per container, handling VM lifecycle, process execution, and resource statistics

Each helper exposes an anonymous XPC endpoint that clients discover through the `ContainerXPC` package, serializing method calls into `XPCMessage` objects transmitted over `XPCClient` connections.

## Connecting to XPC Services

The client-server workflow follows a four-step pattern implemented in [`Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift`](https://github.com/apple/container/blob/main/Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift).

### Step 1: Create the XPC Client

The client initialization requires a launchd service label matching the helper's identifier. For runtime operations, this follows the pattern `com.apple.container.RuntimeLinuxHelper.{containerID}`.

### Step 2: Request an Endpoint

The client calls the `createEndpoint` route to obtain an anonymous XPC endpoint. This handshake, implemented in `RuntimeClient.create`, establishes the durable connection for the container's lifetime.

### Step 3: Invoke Routes with XPCMessage

Each operation maps to a case in the `RuntimeRoutes` enum defined in [`Sources/Services/Runtime/RuntimeClient/RuntimeRoutes.swift`](https://github.com/apple/container/blob/main/Sources/Services/Runtime/RuntimeClient/RuntimeRoutes.swift). The client constructs an `XPCMessage` with the route's raw string value and serializes arguments using type-safe setters like `setArray` and `setDictionary`.

### Step 4: Receive Responses

The server side in [`Sources/Services/RuntimeLinux/Server/RuntimeService.swift`](https://github.com/apple/container/blob/main/Sources/Services/RuntimeLinux/Server/RuntimeService.swift) decodes incoming messages, dispatches them to appropriate handlers using `XPCClientSession` tracking, and returns payload data such as PIDs, status structs, or JSON-encoded statistics.

## Practical Code Examples

The following Swift examples demonstrate interacting with the XPC layer using the public APIs exposed by the Container tool.

### Creating a Runtime Client

Use `RuntimeClient.create` to register the helper and establish a connection:

```swift
import ContainerXPC
import ContainerRuntime

/// `containerID` is the identifier of the container you want to control.
func makeRuntimeClient(containerID: String) async throws -> RuntimeClient {
    // The helper label is derived from the container ID.
    let helperLabel = "com.apple.container.RuntimeLinuxHelper.\(containerID)"

    // Register the helper (launchd will start it if needed) and obtain a client.
    return try await RuntimeClient.create(
        id: containerID,
        runtime: helperLabel,
        timeout: .seconds(10)
    )
}

```

### Launching a Process Inside a Container

Send a `createProcess` message to start executable workloads:

```swift
func startProcess(in client: RuntimeClient,
                  command: [String],
                  env: [String: String] = [:]) async throws -> Int {
    // Build the request message for the `createProcess` route.
    var request = XPCMessage(route: RuntimeRoutes.createProcess.rawValue)
    request.setArray(command, forKey: "argv")
    request.setDictionary(env, forKey: "env")

    // Send the request and decode the PID from the reply.
    let response = try await client.send(request)
    return try response.getInt(forKey: "pid")
}

```

The [`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift) implementation validates the request and spawns the process within the container's VM.

### Querying Container Statistics

Retrieve resource utilization metrics via the `statistics` route:

```swift
func fetchStatistics(from client: RuntimeClient) async throws -> ContainerStatistics {
    // No arguments are needed for the `statistics` route.
    let request = XPCMessage(route: RuntimeRoutes.statistics.rawValue)
    let reply = try await client.send(request)

    // Decode the JSON-encoded statistics payload.
    let json = try reply.getData(forKey: "json")
    return try JSONDecoder().decode(ContainerStatistics.self, from: json)
}

```

The server encodes CPU, memory, and I/O metrics as JSON before transmission over the XPC connection.

### Shutting Down the Helper

Gracefully terminate the XPC service when removing a container:

```swift
func shutdownHelper(_ client: RuntimeClient) async throws {
    let request = XPCMessage(route: RuntimeRoutes.shutdown.rawValue)
    // Ignore reply – just ensure the helper exits.
    _ = try await client.send(request)
}

```

Calling `shutdown` triggers cleanup routines in [`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift) and releases the XPC endpoint.

## Summary

- The **ContainerXPC** package provides the Swift interface for macOS XPC communication in the Container tool
- Three specialized helpers (`container-core-images`, `container-network-vmnet`, `container-runtime-linux`) handle isolated subsystems with minimal privileges
- `RuntimeClient.create` in [`Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift`](https://github.com/apple/container/blob/main/Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift) manages connection establishment and endpoint acquisition
- The `RuntimeRoutes` enum defines type-safe RPC endpoints including `createProcess`, `statistics`, and `shutdown`
- All XPC messages use the `XPCMessage` class with typed accessors like `setArray`, `getInt`, and `getData` for serialization

## Frequently Asked Questions

### What is the ContainerXPC package?

**ContainerXPC** is the Swift package within the `apple/container` repository that wraps macOS XPC APIs, providing `XPCClient` and `XPCMessage` classes for type-safe inter-process communication between the container CLI and privileged helper services.

### How does the RuntimeClient establish a connection?

`RuntimeClient.create(id:runtime:timeout:)` registers the helper with launchd using the provided service label, calls the `createEndpoint` route to obtain an anonymous XPC endpoint, and returns a configured client instance ready for method invocation.

### What routes are available in RuntimeRoutes?

The `RuntimeRoutes` enum in [`Sources/Services/Runtime/RuntimeClient/RuntimeRoutes.swift`](https://github.com/apple/container/blob/main/Sources/Services/Runtime/RuntimeClient/RuntimeRoutes.swift) defines routes including `createProcess`, `start`, `stop`, `kill`, `statistics`, and `shutdown`, with each case's raw value representing the XPC message route identifier.

### How is error handling implemented in XPC communication?

The XPC layer propagates Swift errors through the `XPCClient` connection, handling timeouts, permission denials, and serialization failures, while [`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift) validates incoming messages and returns structured error responses before terminating the helper on critical failures.