Skip to main content

ios_core/services/
mod.rs

1//! Feature-gated iOS device service implementations.
2//!
3//! Enable features in your `Cargo.toml` to pull in only the services you need:
4//!
5//! ```toml
6//! [dependencies]
7//! ios-core = { version = "0.1.5", features = ["afc", "syslog", "screenshot"] }
8//! ```
9//!
10//! ## Available features
11//!
12//! | Feature | Module | Description |
13//! |---------|--------|-------------|
14//! | `afc` | [`afc`] | Apple File Conduit — device filesystem access |
15//! | `apps` | [`apps`] | App install/uninstall/launch/kill (InstallationProxy + appservice) |
16//! | `arbitration` | [`arbitration`] | Exclusive device access claim/release |
17//! | `companion` | [`companion`] | Paired accessory discovery (Apple Watch) |
18//! | `notificationproxy` | [`notificationproxy`] | Device notification subscribe/post |
19//! | `crashreport` | [`crashreport`] | Crash log download and management (requires `afc`) |
20//! | `springboard` | [`springboard`] | Icon layout, wallpaper, orientation |
21//! | `mcinstall` | [`mcinstall`] | Configuration profile install/remove |
22//! | `heartbeat` | [`heartbeat`] | Connection keepalive |
23//! | `file_relay` | [`file_relay`] | Diagnostic bundle archive |
24//! | `syslog` | [`syslog`] | Real-time system log streaming |
25//! | `screenshot` | [`screenshot`] | Screen capture / MJPEG stream |
26//! | `misagent` | [`misagent`] | Provisioning profile management |
27//! | `amfi` | [`amfi`] | Developer mode / code-signing trust |
28//! | `dtx` | [`dtx`] | DTX RPC codec (base for instruments/testmanager) |
29//! | `instruments` | [`instruments`] | CPU/GPU/FPS/network/energy monitoring (requires `dtx`) |
30//! | `testmanager` | [`testmanager`] | XCTest execution framework (requires `dtx`) |
31//! | `accessibility_audit` | [`accessibility_audit`] | AX audit and element interaction (requires `dtx`) |
32//! | `debugserver` | [`debugserver`] | LLDB remote debug server |
33//! | `fileservice` | [`fileservice`] | iOS 17+ XPC file service |
34//! | `deviceinfo` | [`deviceinfo`] | iOS 17+ XPC device info |
35//! | `diagnosticsservice` | [`diagnosticsservice`] | iOS 17+ XPC diagnostics service |
36//! | `imagemounter` | [`imagemounter`] | DeveloperDiskImage mount |
37//! | `pcap` | [`pcap`] | Network packet capture |
38//! | `power_assertion` | [`power_assertion`] | Prevent device sleep |
39//! | `preboard` | [`preboard`] | Stashbag commit/rollback |
40//! | `idam` | [`idam`] | Identity and device auth |
41//! | `fetchsymbols` | [`fetchsymbols`] | Debug symbol download |
42//! | `ostrace` | [`ostrace`] | OS trace relay process listing |
43//! | `prepare` | [`prepare`] | Supervised device preparation (requires `afc`+`mcinstall`) |
44//! | `restore` | [`restore`] | Recovery/restore mode operations |
45//! | `dproxy` | [`dproxy`] | DTX debug proxy recording (requires `dtx`) |
46//! | `webinspector` | [`webinspector`] | Safari/WebView remote debugging |
47
48macro_rules! service_error {
49    ($name:ident $(,)?) => {
50        service_error!($name, before {}, between {}, after {});
51    };
52    ($name:ident, before { $($before:tt)* } $(,)?) => {
53        service_error!($name, before { $($before)* }, between {}, after {});
54    };
55    ($name:ident, between { $($between:tt)* } $(,)?) => {
56        service_error!($name, before {}, between { $($between)* }, after {});
57    };
58    ($name:ident, after { $($after:tt)* } $(,)?) => {
59        service_error!($name, before {}, between {}, after { $($after)* });
60    };
61    ($name:ident, before { $($before:tt)* }, between { $($between:tt)* } $(,)?) => {
62        service_error!($name, before { $($before)* }, between { $($between)* }, after {});
63    };
64    ($name:ident, before { $($before:tt)* }, after { $($after:tt)* } $(,)?) => {
65        service_error!($name, before { $($before)* }, between {}, after { $($after)* });
66    };
67    ($name:ident, between { $($between:tt)* }, after { $($after:tt)* } $(,)?) => {
68        service_error!($name, before {}, between { $($between)* }, after { $($after)* });
69    };
70    ($name:ident, before { $($before:tt)* }, between { $($between:tt)* }, after { $($after:tt)* } $(,)?) => {
71        #[doc = concat!("Error type for ", stringify!($name), ".")]
72        #[derive(Debug, thiserror::Error)]
73        pub enum $name {
74            $($before)*
75            /// Underlying I/O error.
76            #[error("IO error: {0}")]
77            Io(#[from] std::io::Error),
78            /// Plist serialization or parsing error.
79            #[error("plist error: {0}")]
80            Plist(#[from] plist::Error),
81            $($between)*
82            /// Service protocol error.
83            #[error("protocol error: {0}")]
84            Protocol(String),
85            $($after)*
86        }
87    };
88    ($name:ident, $($after:tt)*) => {
89        service_error!($name, before {}, between {}, after { $($after)* });
90    };
91}
92
93pub mod backup2;
94#[cfg(any(
95    feature = "apps",
96    feature = "deviceinfo",
97    feature = "diagnosticsservice",
98    feature = "fileservice"
99))]
100pub(crate) mod coredevice;
101pub mod device_link;
102pub(crate) mod plist_frame;
103
104#[cfg(feature = "afc")]
105pub mod afc;
106
107#[cfg(feature = "house_arrest")]
108pub mod house_arrest;
109
110#[cfg(feature = "arbitration")]
111pub mod arbitration;
112
113#[cfg(feature = "apps")]
114pub mod apps;
115
116#[cfg(feature = "companion")]
117pub mod companion;
118
119#[cfg(feature = "notificationproxy")]
120pub mod notificationproxy;
121
122#[cfg(feature = "crashreport")]
123pub mod crashreport;
124
125#[cfg(feature = "springboard")]
126pub mod springboard;
127
128#[cfg(feature = "mcinstall")]
129pub mod mcinstall;
130
131#[cfg(feature = "heartbeat")]
132pub mod heartbeat;
133
134#[cfg(feature = "file_relay")]
135pub mod file_relay;
136
137#[cfg(feature = "syslog")]
138pub mod syslog;
139
140#[cfg(feature = "screenshot")]
141pub mod screenshot;
142
143#[cfg(feature = "misagent")]
144pub mod misagent;
145
146#[cfg(feature = "amfi")]
147pub mod amfi;
148
149#[cfg(feature = "dtx")]
150pub mod dtx;
151
152#[cfg(feature = "instruments")]
153pub mod instruments;
154
155#[cfg(feature = "testmanager")]
156pub mod testmanager;
157
158#[cfg(feature = "accessibility_audit")]
159pub mod accessibility_audit;
160
161#[cfg(feature = "fileservice")]
162pub mod fileservice;
163
164#[cfg(feature = "deviceinfo")]
165pub mod deviceinfo;
166
167#[cfg(feature = "diagnosticsservice")]
168pub mod diagnosticsservice;
169
170#[cfg(feature = "debugserver")]
171pub mod debugserver;
172
173#[cfg(feature = "pcap")]
174pub mod pcap;
175
176#[cfg(feature = "power_assertion")]
177pub mod power_assertion;
178
179#[cfg(feature = "preboard")]
180pub mod preboard;
181
182#[cfg(feature = "idam")]
183pub mod idam;
184
185#[cfg(feature = "fetchsymbols")]
186pub mod fetchsymbols;
187
188#[cfg(feature = "ostrace")]
189pub mod ostrace;
190
191#[cfg(feature = "prepare")]
192pub mod prepare;
193
194#[cfg(feature = "restore")]
195pub mod restore;
196
197#[cfg(feature = "dproxy")]
198pub mod dproxy;
199
200#[cfg(feature = "webinspector")]
201pub mod webinspector;
202
203#[cfg(feature = "mobileactivation")]
204pub mod mobileactivation;
205pub mod simlocation;
206
207#[cfg(feature = "imagemounter")]
208pub mod imagemounter;
209
210// Always-available modules
211#[cfg(feature = "diagnostics")]
212pub mod diagnostics;
213
214#[cfg(test)]
215mod tests {
216    service_error!(
217        MacroSmokeError,
218        after {
219        #[error("extra error: {0}")]
220        Extra(String),
221        },
222    );
223
224    #[test]
225    fn service_error_macro_preserves_common_variants_and_display() {
226        let io_error: MacroSmokeError =
227            std::io::Error::from(std::io::ErrorKind::Interrupted).into();
228        assert!(matches!(io_error, MacroSmokeError::Io(_)));
229
230        // Plist variant now wraps plist::Error via #[from]
231        let plist_err: MacroSmokeError =
232            plist::from_bytes::<plist::Value>(br#"<?xml version="1.0"?><plist><dict>"#)
233                .unwrap_err()
234                .into();
235        assert!(matches!(plist_err, MacroSmokeError::Plist(_)));
236        assert!(plist_err.to_string().starts_with("plist error: "));
237
238        assert_eq!(
239            MacroSmokeError::Protocol("bad frame".into()).to_string(),
240            "protocol error: bad frame"
241        );
242        assert_eq!(
243            MacroSmokeError::Extra("specific".into()).to_string(),
244            "extra error: specific"
245        );
246    }
247}