ios_core/services/instruments/
deviceinfo.rs1use tokio::io::{AsyncRead, AsyncWrite};
4
5use crate::services::dtx::codec::{DtxConnection, DtxError};
6use crate::services::dtx::types::{DtxPayload, NSObject};
7
8#[derive(Debug, Clone)]
10pub struct RunningProcess {
11 pub pid: u64,
12 pub name: String,
13 pub real_app_name: String,
14 pub is_application: bool,
15}
16
17pub struct DeviceInfoClient<S> {
19 conn: DtxConnection<S>,
20 channel_code: i32,
21}
22
23impl<S: AsyncRead + AsyncWrite + Unpin + Send> DeviceInfoClient<S> {
24 pub async fn connect(stream: S) -> Result<Self, DtxError> {
25 let mut conn = DtxConnection::new(stream);
26 let ch = conn.request_channel(super::DEVICE_INFO_SVC).await?;
27 Ok(Self {
28 conn,
29 channel_code: ch,
30 })
31 }
32
33 pub async fn system_attributes(&mut self) -> Result<Vec<plist::Value>, DtxError> {
34 self.get_attrs("sysmonSystemAttributes").await
35 }
36
37 pub async fn process_attributes(&mut self) -> Result<Vec<plist::Value>, DtxError> {
38 self.get_attrs("sysmonProcessAttributes").await
39 }
40
41 pub async fn running_processes(&mut self) -> Result<Vec<RunningProcess>, DtxError> {
43 let msg = self
44 .conn
45 .method_call(self.channel_code, "runningProcesses", &[])
46 .await?;
47 tracing::debug!("runningProcesses response: {:?}", msg.payload);
48
49 let arr = match &msg.payload {
50 DtxPayload::Response(NSObject::Array(a)) => a.clone(),
51 DtxPayload::MethodInvocation { args, .. } => {
52 args.iter()
54 .find_map(|a| {
55 if let NSObject::Array(arr) = a {
56 Some(arr.clone())
57 } else {
58 None
59 }
60 })
61 .unwrap_or_default()
62 }
63 _ => return Ok(vec![]),
64 };
65
66 let mut result = Vec::with_capacity(arr.len());
67 for item in &arr {
68 if let NSObject::Dict(d) = item {
69 let pid = match d.get("pid") {
70 Some(NSObject::Uint(n)) => *n,
71 Some(NSObject::Int(n)) => *n as u64,
72 _ => continue,
73 };
74 let name = d
75 .get("name")
76 .and_then(|v| {
77 if let NSObject::String(s) = v {
78 Some(s.clone())
79 } else {
80 None
81 }
82 })
83 .unwrap_or_default();
84 let real_app_name = d
85 .get("realAppName")
86 .and_then(|v| {
87 if let NSObject::String(s) = v {
88 Some(s.clone())
89 } else {
90 None
91 }
92 })
93 .unwrap_or_default();
94 let is_application = d
95 .get("isApplication")
96 .and_then(|v| {
97 if let NSObject::Bool(b) = v {
98 Some(*b)
99 } else {
100 None
101 }
102 })
103 .unwrap_or(false);
104 result.push(RunningProcess {
105 pid,
106 name,
107 real_app_name,
108 is_application,
109 });
110 }
111 }
112 Ok(result)
113 }
114
115 async fn get_attrs(&mut self, method: &str) -> Result<Vec<plist::Value>, DtxError> {
116 let msg = self
117 .conn
118 .method_call(self.channel_code, method, &[])
119 .await?;
120 tracing::debug!("{method} response: {:?}", msg.payload);
121 match &msg.payload {
122 DtxPayload::Response(NSObject::Array(arr)) => Ok(arr
123 .iter()
124 .map(|v| match v {
125 NSObject::String(s) => plist::Value::String(s.clone()),
126 NSObject::Int(n) => plist::Value::Integer((*n).into()),
127 NSObject::Uint(n) => plist::Value::Integer((*n as i64).into()),
128 _ => plist::Value::String(format!("{v:?}")),
129 })
130 .collect()),
131 _ => Ok(vec![]),
132 }
133 }
134}