ios_core/services/ostrace/
mod.rs1use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
7
8pub const SERVICE_NAME: &str = "com.apple.os_trace_relay";
9pub const SHIM_SERVICE_NAME: &str = "com.apple.os_trace_relay.shim.remote";
10
11service_error!(OsTraceError);
12
13pub struct OsTraceClient<S> {
14 stream: S,
15}
16
17impl<S: AsyncRead + AsyncWrite + Unpin> OsTraceClient<S> {
18 pub fn new(stream: S) -> Self {
19 Self { stream }
20 }
21
22 pub async fn get_pid_list(&mut self) -> Result<plist::Dictionary, OsTraceError> {
23 let request = plist::Dictionary::from_iter([(
24 "Request".to_string(),
25 plist::Value::String("PidList".into()),
26 )]);
27 send_plist(&mut self.stream, &plist::Value::Dictionary(request)).await?;
28
29 let _marker = self.stream.read_u8().await?;
30 recv_prefixed_plist(&mut self.stream).await
31 }
32}
33
34async fn send_plist<S: AsyncWrite + Unpin>(
35 stream: &mut S,
36 value: &plist::Value,
37) -> Result<(), OsTraceError> {
38 let mut buf = Vec::new();
39 plist::to_writer_xml(&mut buf, value)?;
40 stream.write_all(&(buf.len() as u32).to_be_bytes()).await?;
41 stream.write_all(&buf).await?;
42 stream.flush().await?;
43 Ok(())
44}
45
46async fn recv_prefixed_plist<S: AsyncRead + Unpin>(
47 stream: &mut S,
48) -> Result<plist::Dictionary, OsTraceError> {
49 let len = stream.read_u32().await? as usize;
50 const MAX_PLIST_SIZE: usize = 8 * 1024 * 1024;
51 if len > MAX_PLIST_SIZE {
52 return Err(OsTraceError::Protocol(format!(
53 "plist length {len} exceeds max {MAX_PLIST_SIZE}"
54 )));
55 }
56
57 let mut buf = vec![0u8; len];
58 stream.read_exact(&mut buf).await?;
59 Ok(plist::from_bytes(&buf)?)
60}