1*cf78ab8cSAndroid Build Coastguard Worker // Copyright 2023 Google LLC
2*cf78ab8cSAndroid Build Coastguard Worker //
3*cf78ab8cSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*cf78ab8cSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*cf78ab8cSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*cf78ab8cSAndroid Build Coastguard Worker //
7*cf78ab8cSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*cf78ab8cSAndroid Build Coastguard Worker //
9*cf78ab8cSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*cf78ab8cSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*cf78ab8cSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*cf78ab8cSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*cf78ab8cSAndroid Build Coastguard Worker // limitations under the License.
14*cf78ab8cSAndroid Build Coastguard Worker
15*cf78ab8cSAndroid Build Coastguard Worker //! The internal structure of CaptureInfo and CaptureMaps
16*cf78ab8cSAndroid Build Coastguard Worker //!
17*cf78ab8cSAndroid Build Coastguard Worker //! CaptureInfo is the internal structure of any Capture that includes
18*cf78ab8cSAndroid Build Coastguard Worker //! the protobuf structure. CaptureMaps contains mappings of
19*cf78ab8cSAndroid Build Coastguard Worker //! ChipIdentifier and <FacadeIdentifier, Kind> to CaptureInfo.
20*cf78ab8cSAndroid Build Coastguard Worker
21*cf78ab8cSAndroid Build Coastguard Worker use bytes::Bytes;
22*cf78ab8cSAndroid Build Coastguard Worker
23*cf78ab8cSAndroid Build Coastguard Worker use std::collections::btree_map::{Iter, Values};
24*cf78ab8cSAndroid Build Coastguard Worker use std::collections::BTreeMap;
25*cf78ab8cSAndroid Build Coastguard Worker use std::fs::{File, OpenOptions};
26*cf78ab8cSAndroid Build Coastguard Worker use std::io::{Error, ErrorKind, Result};
27*cf78ab8cSAndroid Build Coastguard Worker use std::sync::mpsc::channel;
28*cf78ab8cSAndroid Build Coastguard Worker use std::sync::mpsc::{Receiver, Sender};
29*cf78ab8cSAndroid Build Coastguard Worker use std::sync::{Arc, Mutex};
30*cf78ab8cSAndroid Build Coastguard Worker use std::thread;
31*cf78ab8cSAndroid Build Coastguard Worker use std::time::{SystemTime, UNIX_EPOCH};
32*cf78ab8cSAndroid Build Coastguard Worker
33*cf78ab8cSAndroid Build Coastguard Worker use super::pcap_util::{write_pcap_header, write_pcapng_header, LinkType};
34*cf78ab8cSAndroid Build Coastguard Worker use log::{info, warn};
35*cf78ab8cSAndroid Build Coastguard Worker
36*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::{common::ChipKind, model::Capture as ProtoCapture};
37*cf78ab8cSAndroid Build Coastguard Worker use protobuf::well_known_types::timestamp::Timestamp;
38*cf78ab8cSAndroid Build Coastguard Worker
39*cf78ab8cSAndroid Build Coastguard Worker use crate::events::{ChipAdded, ChipRemoved, Event};
40*cf78ab8cSAndroid Build Coastguard Worker use crate::resource::clone_captures;
41*cf78ab8cSAndroid Build Coastguard Worker
42*cf78ab8cSAndroid Build Coastguard Worker use crate::captures::captures_handler::handle_packet;
43*cf78ab8cSAndroid Build Coastguard Worker use crate::captures::pcap_util::PacketDirection;
44*cf78ab8cSAndroid Build Coastguard Worker use crate::devices::chip::ChipIdentifier;
45*cf78ab8cSAndroid Build Coastguard Worker
46*cf78ab8cSAndroid Build Coastguard Worker /// Internal Capture struct
47*cf78ab8cSAndroid Build Coastguard Worker pub struct CaptureInfo {
48*cf78ab8cSAndroid Build Coastguard Worker /// Some(File) if the file is opened and capture is actively happening.
49*cf78ab8cSAndroid Build Coastguard Worker /// None if the file is not opened.
50*cf78ab8cSAndroid Build Coastguard Worker pub file: Option<File>,
51*cf78ab8cSAndroid Build Coastguard Worker // Following items will be returned as ProtoCapture. (state: file.is_some())
52*cf78ab8cSAndroid Build Coastguard Worker id: ChipIdentifier,
53*cf78ab8cSAndroid Build Coastguard Worker /// ChipKind (BLUETOOTH, WIFI, or UWB)
54*cf78ab8cSAndroid Build Coastguard Worker pub chip_kind: ChipKind,
55*cf78ab8cSAndroid Build Coastguard Worker /// Device name
56*cf78ab8cSAndroid Build Coastguard Worker pub device_name: String,
57*cf78ab8cSAndroid Build Coastguard Worker /// Size of pcap file
58*cf78ab8cSAndroid Build Coastguard Worker pub size: usize,
59*cf78ab8cSAndroid Build Coastguard Worker /// Number of packet records
60*cf78ab8cSAndroid Build Coastguard Worker pub records: i32,
61*cf78ab8cSAndroid Build Coastguard Worker /// Timestamp as seconds
62*cf78ab8cSAndroid Build Coastguard Worker pub seconds: i64,
63*cf78ab8cSAndroid Build Coastguard Worker /// Timestamp as sub-nanoseconds
64*cf78ab8cSAndroid Build Coastguard Worker pub nanos: i32,
65*cf78ab8cSAndroid Build Coastguard Worker /// Boolean status of whether the device is connected to netsim
66*cf78ab8cSAndroid Build Coastguard Worker pub valid: bool,
67*cf78ab8cSAndroid Build Coastguard Worker /// Extension (pcap or pcapng)
68*cf78ab8cSAndroid Build Coastguard Worker pub extension: String,
69*cf78ab8cSAndroid Build Coastguard Worker }
70*cf78ab8cSAndroid Build Coastguard Worker
71*cf78ab8cSAndroid Build Coastguard Worker /// Captures contains a recent copy of all chips and their ChipKind, chip_id,
72*cf78ab8cSAndroid Build Coastguard Worker /// and owning device name.
73*cf78ab8cSAndroid Build Coastguard Worker ///
74*cf78ab8cSAndroid Build Coastguard Worker /// Information for any recent or ongoing captures is also stored in the ProtoCapture.
75*cf78ab8cSAndroid Build Coastguard Worker pub struct Captures {
76*cf78ab8cSAndroid Build Coastguard Worker /// A mapping of chip id to CaptureInfo.
77*cf78ab8cSAndroid Build Coastguard Worker ///
78*cf78ab8cSAndroid Build Coastguard Worker /// BTreeMap is used for chip_id_to_capture, so that the CaptureInfo can always be
79*cf78ab8cSAndroid Build Coastguard Worker /// ordered by ChipId. ListCaptureResponse will produce a ordered list of CaptureInfos.
80*cf78ab8cSAndroid Build Coastguard Worker pub chip_id_to_capture: BTreeMap<ChipIdentifier, Arc<Mutex<CaptureInfo>>>,
81*cf78ab8cSAndroid Build Coastguard Worker sender: Sender<CapturePacket>,
82*cf78ab8cSAndroid Build Coastguard Worker }
83*cf78ab8cSAndroid Build Coastguard Worker
84*cf78ab8cSAndroid Build Coastguard Worker impl CaptureInfo {
85*cf78ab8cSAndroid Build Coastguard Worker /// Create an instance of CaptureInfo
new(chip_kind: ChipKind, chip_id: ChipIdentifier, device_name: String) -> Self86*cf78ab8cSAndroid Build Coastguard Worker pub fn new(chip_kind: ChipKind, chip_id: ChipIdentifier, device_name: String) -> Self {
87*cf78ab8cSAndroid Build Coastguard Worker let extension = match chip_kind {
88*cf78ab8cSAndroid Build Coastguard Worker ChipKind::UWB => "pcapng".to_string(),
89*cf78ab8cSAndroid Build Coastguard Worker _ => "pcap".to_string(),
90*cf78ab8cSAndroid Build Coastguard Worker };
91*cf78ab8cSAndroid Build Coastguard Worker CaptureInfo {
92*cf78ab8cSAndroid Build Coastguard Worker id: chip_id,
93*cf78ab8cSAndroid Build Coastguard Worker chip_kind,
94*cf78ab8cSAndroid Build Coastguard Worker device_name,
95*cf78ab8cSAndroid Build Coastguard Worker size: 0,
96*cf78ab8cSAndroid Build Coastguard Worker records: 0,
97*cf78ab8cSAndroid Build Coastguard Worker seconds: 0,
98*cf78ab8cSAndroid Build Coastguard Worker nanos: 0,
99*cf78ab8cSAndroid Build Coastguard Worker valid: true,
100*cf78ab8cSAndroid Build Coastguard Worker file: None,
101*cf78ab8cSAndroid Build Coastguard Worker extension,
102*cf78ab8cSAndroid Build Coastguard Worker }
103*cf78ab8cSAndroid Build Coastguard Worker }
104*cf78ab8cSAndroid Build Coastguard Worker
105*cf78ab8cSAndroid Build Coastguard Worker /// Creates a pcap file with headers and store it under temp directory.
106*cf78ab8cSAndroid Build Coastguard Worker ///
107*cf78ab8cSAndroid Build Coastguard Worker /// The lifecycle of the file is NOT tied to the lifecycle of the struct
108*cf78ab8cSAndroid Build Coastguard Worker /// Format: /tmp/netsimd/$USER/pcaps/netsim-{chip_id}-{device_name}-{chip_kind}.{extension}
start_capture(&mut self) -> Result<()>109*cf78ab8cSAndroid Build Coastguard Worker pub fn start_capture(&mut self) -> Result<()> {
110*cf78ab8cSAndroid Build Coastguard Worker if self.file.is_some() {
111*cf78ab8cSAndroid Build Coastguard Worker return Ok(());
112*cf78ab8cSAndroid Build Coastguard Worker }
113*cf78ab8cSAndroid Build Coastguard Worker let mut filename = netsim_common::system::netsimd_temp_dir();
114*cf78ab8cSAndroid Build Coastguard Worker filename.push("pcaps");
115*cf78ab8cSAndroid Build Coastguard Worker std::fs::create_dir_all(&filename)?;
116*cf78ab8cSAndroid Build Coastguard Worker filename.push(format!(
117*cf78ab8cSAndroid Build Coastguard Worker "netsim-{:?}-{:}-{:?}.{}",
118*cf78ab8cSAndroid Build Coastguard Worker self.id, self.device_name, self.chip_kind, self.extension
119*cf78ab8cSAndroid Build Coastguard Worker ));
120*cf78ab8cSAndroid Build Coastguard Worker let mut file = OpenOptions::new().write(true).truncate(true).create(true).open(filename)?;
121*cf78ab8cSAndroid Build Coastguard Worker let link_type = match self.chip_kind {
122*cf78ab8cSAndroid Build Coastguard Worker ChipKind::BLUETOOTH => LinkType::BluetoothHciH4WithPhdr,
123*cf78ab8cSAndroid Build Coastguard Worker ChipKind::BLUETOOTH_BEACON => LinkType::BluetoothHciH4WithPhdr,
124*cf78ab8cSAndroid Build Coastguard Worker ChipKind::WIFI => LinkType::Ieee80211RadioTap,
125*cf78ab8cSAndroid Build Coastguard Worker ChipKind::UWB => LinkType::FiraUci,
126*cf78ab8cSAndroid Build Coastguard Worker _ => return Err(Error::new(ErrorKind::Other, "Unsupported link type")),
127*cf78ab8cSAndroid Build Coastguard Worker };
128*cf78ab8cSAndroid Build Coastguard Worker let size = match self.extension.as_str() {
129*cf78ab8cSAndroid Build Coastguard Worker "pcap" => write_pcap_header(link_type, &mut file)?,
130*cf78ab8cSAndroid Build Coastguard Worker "pcapng" => write_pcapng_header(link_type, &mut file)?,
131*cf78ab8cSAndroid Build Coastguard Worker _ => return Err(Error::new(ErrorKind::Other, "Incorrect Extension for file")),
132*cf78ab8cSAndroid Build Coastguard Worker };
133*cf78ab8cSAndroid Build Coastguard Worker let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards");
134*cf78ab8cSAndroid Build Coastguard Worker self.size = size;
135*cf78ab8cSAndroid Build Coastguard Worker self.records = 0;
136*cf78ab8cSAndroid Build Coastguard Worker self.seconds = timestamp.as_secs() as i64;
137*cf78ab8cSAndroid Build Coastguard Worker self.nanos = timestamp.subsec_nanos() as i32;
138*cf78ab8cSAndroid Build Coastguard Worker self.file = Some(file);
139*cf78ab8cSAndroid Build Coastguard Worker Ok(())
140*cf78ab8cSAndroid Build Coastguard Worker }
141*cf78ab8cSAndroid Build Coastguard Worker
142*cf78ab8cSAndroid Build Coastguard Worker /// Closes file by removing ownership of self.file.
143*cf78ab8cSAndroid Build Coastguard Worker ///
144*cf78ab8cSAndroid Build Coastguard Worker /// Capture info will still retain the size and record count
145*cf78ab8cSAndroid Build Coastguard Worker /// So it can be downloaded easily when GetCapture is invoked.
stop_capture(&mut self)146*cf78ab8cSAndroid Build Coastguard Worker pub fn stop_capture(&mut self) {
147*cf78ab8cSAndroid Build Coastguard Worker self.file = None;
148*cf78ab8cSAndroid Build Coastguard Worker }
149*cf78ab8cSAndroid Build Coastguard Worker
150*cf78ab8cSAndroid Build Coastguard Worker /// Returns a Capture protobuf from CaptureInfo
get_capture_proto(&self) -> ProtoCapture151*cf78ab8cSAndroid Build Coastguard Worker pub fn get_capture_proto(&self) -> ProtoCapture {
152*cf78ab8cSAndroid Build Coastguard Worker let timestamp =
153*cf78ab8cSAndroid Build Coastguard Worker Timestamp { seconds: self.seconds, nanos: self.nanos, ..Default::default() };
154*cf78ab8cSAndroid Build Coastguard Worker ProtoCapture {
155*cf78ab8cSAndroid Build Coastguard Worker id: self.id.0,
156*cf78ab8cSAndroid Build Coastguard Worker chip_kind: self.chip_kind.into(),
157*cf78ab8cSAndroid Build Coastguard Worker device_name: self.device_name.clone(),
158*cf78ab8cSAndroid Build Coastguard Worker state: Some(self.file.is_some()),
159*cf78ab8cSAndroid Build Coastguard Worker size: self.size as i32,
160*cf78ab8cSAndroid Build Coastguard Worker records: self.records,
161*cf78ab8cSAndroid Build Coastguard Worker timestamp: Some(timestamp).into(),
162*cf78ab8cSAndroid Build Coastguard Worker valid: self.valid,
163*cf78ab8cSAndroid Build Coastguard Worker ..Default::default()
164*cf78ab8cSAndroid Build Coastguard Worker }
165*cf78ab8cSAndroid Build Coastguard Worker }
166*cf78ab8cSAndroid Build Coastguard Worker }
167*cf78ab8cSAndroid Build Coastguard Worker
168*cf78ab8cSAndroid Build Coastguard Worker struct CapturePacket {
169*cf78ab8cSAndroid Build Coastguard Worker chip_id: ChipIdentifier,
170*cf78ab8cSAndroid Build Coastguard Worker packet: Bytes,
171*cf78ab8cSAndroid Build Coastguard Worker packet_type: u32,
172*cf78ab8cSAndroid Build Coastguard Worker direction: PacketDirection,
173*cf78ab8cSAndroid Build Coastguard Worker }
174*cf78ab8cSAndroid Build Coastguard Worker
175*cf78ab8cSAndroid Build Coastguard Worker impl Captures {
176*cf78ab8cSAndroid Build Coastguard Worker /// Create an instance of Captures, which includes 2 empty hashmaps
new() -> Self177*cf78ab8cSAndroid Build Coastguard Worker pub fn new() -> Self {
178*cf78ab8cSAndroid Build Coastguard Worker let (sender, rx) = channel::<CapturePacket>();
179*cf78ab8cSAndroid Build Coastguard Worker let _ =
180*cf78ab8cSAndroid Build Coastguard Worker thread::Builder::new().name("capture_packet_handler".to_string()).spawn(move || {
181*cf78ab8cSAndroid Build Coastguard Worker while let Ok(CapturePacket { chip_id, packet, packet_type, direction }) = rx.recv()
182*cf78ab8cSAndroid Build Coastguard Worker {
183*cf78ab8cSAndroid Build Coastguard Worker handle_packet(chip_id, &packet, packet_type, direction);
184*cf78ab8cSAndroid Build Coastguard Worker }
185*cf78ab8cSAndroid Build Coastguard Worker });
186*cf78ab8cSAndroid Build Coastguard Worker Captures {
187*cf78ab8cSAndroid Build Coastguard Worker chip_id_to_capture: BTreeMap::<ChipIdentifier, Arc<Mutex<CaptureInfo>>>::new(),
188*cf78ab8cSAndroid Build Coastguard Worker sender,
189*cf78ab8cSAndroid Build Coastguard Worker }
190*cf78ab8cSAndroid Build Coastguard Worker }
191*cf78ab8cSAndroid Build Coastguard Worker
192*cf78ab8cSAndroid Build Coastguard Worker /// Sends a captured packet to the output processing thread.
send( &self, chip_id: ChipIdentifier, packet: &Bytes, packet_type: u32, direction: PacketDirection, )193*cf78ab8cSAndroid Build Coastguard Worker pub fn send(
194*cf78ab8cSAndroid Build Coastguard Worker &self,
195*cf78ab8cSAndroid Build Coastguard Worker chip_id: ChipIdentifier,
196*cf78ab8cSAndroid Build Coastguard Worker packet: &Bytes,
197*cf78ab8cSAndroid Build Coastguard Worker packet_type: u32,
198*cf78ab8cSAndroid Build Coastguard Worker direction: PacketDirection,
199*cf78ab8cSAndroid Build Coastguard Worker ) {
200*cf78ab8cSAndroid Build Coastguard Worker let _ = self.sender.send(CapturePacket {
201*cf78ab8cSAndroid Build Coastguard Worker chip_id,
202*cf78ab8cSAndroid Build Coastguard Worker packet: packet.clone(),
203*cf78ab8cSAndroid Build Coastguard Worker packet_type,
204*cf78ab8cSAndroid Build Coastguard Worker direction,
205*cf78ab8cSAndroid Build Coastguard Worker });
206*cf78ab8cSAndroid Build Coastguard Worker }
207*cf78ab8cSAndroid Build Coastguard Worker
208*cf78ab8cSAndroid Build Coastguard Worker /// Returns true if key exists in Captures.chip_id_to_capture
contains(&self, key: ChipIdentifier) -> bool209*cf78ab8cSAndroid Build Coastguard Worker pub fn contains(&self, key: ChipIdentifier) -> bool {
210*cf78ab8cSAndroid Build Coastguard Worker self.chip_id_to_capture.contains_key(&key)
211*cf78ab8cSAndroid Build Coastguard Worker }
212*cf78ab8cSAndroid Build Coastguard Worker
213*cf78ab8cSAndroid Build Coastguard Worker /// Returns an Option of lockable and mutable CaptureInfo with given key
get(&mut self, key: ChipIdentifier) -> Option<&mut Arc<Mutex<CaptureInfo>>>214*cf78ab8cSAndroid Build Coastguard Worker pub fn get(&mut self, key: ChipIdentifier) -> Option<&mut Arc<Mutex<CaptureInfo>>> {
215*cf78ab8cSAndroid Build Coastguard Worker self.chip_id_to_capture.get_mut(&key)
216*cf78ab8cSAndroid Build Coastguard Worker }
217*cf78ab8cSAndroid Build Coastguard Worker
218*cf78ab8cSAndroid Build Coastguard Worker /// Inserts the given CatpureInfo into Captures hashmaps
insert(&mut self, capture: CaptureInfo)219*cf78ab8cSAndroid Build Coastguard Worker pub fn insert(&mut self, capture: CaptureInfo) {
220*cf78ab8cSAndroid Build Coastguard Worker let chip_id = capture.id;
221*cf78ab8cSAndroid Build Coastguard Worker let arc_capture = Arc::new(Mutex::new(capture));
222*cf78ab8cSAndroid Build Coastguard Worker self.chip_id_to_capture.insert(chip_id, arc_capture.clone());
223*cf78ab8cSAndroid Build Coastguard Worker }
224*cf78ab8cSAndroid Build Coastguard Worker
225*cf78ab8cSAndroid Build Coastguard Worker /// Returns true if chip_id_to_capture is empty
is_empty(&self) -> bool226*cf78ab8cSAndroid Build Coastguard Worker pub fn is_empty(&self) -> bool {
227*cf78ab8cSAndroid Build Coastguard Worker self.chip_id_to_capture.is_empty()
228*cf78ab8cSAndroid Build Coastguard Worker }
229*cf78ab8cSAndroid Build Coastguard Worker
230*cf78ab8cSAndroid Build Coastguard Worker /// Returns an iterable object of chip_id_to_capture hashmap
iter(&self) -> Iter<ChipIdentifier, Arc<Mutex<CaptureInfo>>>231*cf78ab8cSAndroid Build Coastguard Worker pub fn iter(&self) -> Iter<ChipIdentifier, Arc<Mutex<CaptureInfo>>> {
232*cf78ab8cSAndroid Build Coastguard Worker self.chip_id_to_capture.iter()
233*cf78ab8cSAndroid Build Coastguard Worker }
234*cf78ab8cSAndroid Build Coastguard Worker
235*cf78ab8cSAndroid Build Coastguard Worker /// Removes a CaptureInfo with given key from Captures
236*cf78ab8cSAndroid Build Coastguard Worker ///
237*cf78ab8cSAndroid Build Coastguard Worker /// When Capture is removed, remove from each map and also invoke closing of files.
remove(&mut self, key: &ChipIdentifier)238*cf78ab8cSAndroid Build Coastguard Worker pub fn remove(&mut self, key: &ChipIdentifier) {
239*cf78ab8cSAndroid Build Coastguard Worker if let Some(arc_capture) = self.chip_id_to_capture.get(key) {
240*cf78ab8cSAndroid Build Coastguard Worker let mut capture = arc_capture.lock().expect("Failed to acquire lock on CaptureInfo");
241*cf78ab8cSAndroid Build Coastguard Worker // Valid is marked false when chip is disconnected from netsim
242*cf78ab8cSAndroid Build Coastguard Worker capture.valid = false;
243*cf78ab8cSAndroid Build Coastguard Worker capture.stop_capture();
244*cf78ab8cSAndroid Build Coastguard Worker } else {
245*cf78ab8cSAndroid Build Coastguard Worker info!("key does not exist in Captures");
246*cf78ab8cSAndroid Build Coastguard Worker }
247*cf78ab8cSAndroid Build Coastguard Worker // CaptureInfo is not removed even after chip is removed
248*cf78ab8cSAndroid Build Coastguard Worker }
249*cf78ab8cSAndroid Build Coastguard Worker
250*cf78ab8cSAndroid Build Coastguard Worker /// Returns Values of chip_id_to_capture hashmap values
values(&self) -> Values<ChipIdentifier, Arc<Mutex<CaptureInfo>>>251*cf78ab8cSAndroid Build Coastguard Worker pub fn values(&self) -> Values<ChipIdentifier, Arc<Mutex<CaptureInfo>>> {
252*cf78ab8cSAndroid Build Coastguard Worker self.chip_id_to_capture.values()
253*cf78ab8cSAndroid Build Coastguard Worker }
254*cf78ab8cSAndroid Build Coastguard Worker }
255*cf78ab8cSAndroid Build Coastguard Worker
256*cf78ab8cSAndroid Build Coastguard Worker impl Default for Captures {
default() -> Self257*cf78ab8cSAndroid Build Coastguard Worker fn default() -> Self {
258*cf78ab8cSAndroid Build Coastguard Worker Self::new()
259*cf78ab8cSAndroid Build Coastguard Worker }
260*cf78ab8cSAndroid Build Coastguard Worker }
261*cf78ab8cSAndroid Build Coastguard Worker
262*cf78ab8cSAndroid Build Coastguard Worker /// Create a thread to process events that matter to the Capture resource.
263*cf78ab8cSAndroid Build Coastguard Worker ///
264*cf78ab8cSAndroid Build Coastguard Worker /// We maintain a CaptureInfo for each chip that has been
265*cf78ab8cSAndroid Build Coastguard Worker /// connected to the simulation. This procedure monitors ChipAdded
266*cf78ab8cSAndroid Build Coastguard Worker /// and ChipRemoved events and updates the collection of CaptureInfo.
267*cf78ab8cSAndroid Build Coastguard Worker ///
spawn_capture_event_subscriber(event_rx: Receiver<Event>, capture: bool)268*cf78ab8cSAndroid Build Coastguard Worker pub fn spawn_capture_event_subscriber(event_rx: Receiver<Event>, capture: bool) {
269*cf78ab8cSAndroid Build Coastguard Worker let _ =
270*cf78ab8cSAndroid Build Coastguard Worker thread::Builder::new().name("capture_event_subscriber".to_string()).spawn(move || loop {
271*cf78ab8cSAndroid Build Coastguard Worker match event_rx.recv() {
272*cf78ab8cSAndroid Build Coastguard Worker Ok(Event::ChipAdded(ChipAdded { chip_id, chip_kind, device_name, .. })) => {
273*cf78ab8cSAndroid Build Coastguard Worker let mut capture_info =
274*cf78ab8cSAndroid Build Coastguard Worker CaptureInfo::new(chip_kind, chip_id, device_name.clone());
275*cf78ab8cSAndroid Build Coastguard Worker if capture {
276*cf78ab8cSAndroid Build Coastguard Worker if let Err(err) = capture_info.start_capture() {
277*cf78ab8cSAndroid Build Coastguard Worker warn!("{err:?}");
278*cf78ab8cSAndroid Build Coastguard Worker }
279*cf78ab8cSAndroid Build Coastguard Worker }
280*cf78ab8cSAndroid Build Coastguard Worker clone_captures().write().unwrap().insert(capture_info);
281*cf78ab8cSAndroid Build Coastguard Worker info!("Capture event: ChipAdded chip_id: {chip_id} device_name: {device_name}");
282*cf78ab8cSAndroid Build Coastguard Worker }
283*cf78ab8cSAndroid Build Coastguard Worker Ok(Event::ChipRemoved(ChipRemoved { chip_id, .. })) => {
284*cf78ab8cSAndroid Build Coastguard Worker clone_captures().write().unwrap().remove(&chip_id);
285*cf78ab8cSAndroid Build Coastguard Worker info!("Capture event: ChipRemoved chip_id: {chip_id}");
286*cf78ab8cSAndroid Build Coastguard Worker }
287*cf78ab8cSAndroid Build Coastguard Worker _ => {}
288*cf78ab8cSAndroid Build Coastguard Worker }
289*cf78ab8cSAndroid Build Coastguard Worker });
290*cf78ab8cSAndroid Build Coastguard Worker }
291