xref: /aosp_15_r20/external/crosvm/tube_transporter/src/lib.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker // Do nothing on unix as tube_transporter is windows only.
6*bb4ee6a4SAndroid Build Coastguard Worker #![cfg(windows)]
7*bb4ee6a4SAndroid Build Coastguard Worker 
8*bb4ee6a4SAndroid Build Coastguard Worker //! This IPC crate is used by the broker process to send boot data across the
9*bb4ee6a4SAndroid Build Coastguard Worker //! different crosvm child processes on Windows.
10*bb4ee6a4SAndroid Build Coastguard Worker 
11*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt::Display;
13*bb4ee6a4SAndroid Build Coastguard Worker 
14*bb4ee6a4SAndroid Build Coastguard Worker use base::deserialize_and_recv;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::named_pipes::BlockingMode;
16*bb4ee6a4SAndroid Build Coastguard Worker use base::named_pipes::FramingMode;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::named_pipes::PipeConnection;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::serialize_and_send;
19*bb4ee6a4SAndroid Build Coastguard Worker use base::set_alias_pid;
20*bb4ee6a4SAndroid Build Coastguard Worker use base::set_duplicate_handle_tube;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::DuplicateHandleTube;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::FromRawDescriptor;
23*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
24*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
25*bb4ee6a4SAndroid Build Coastguard Worker use base::TubeError;
26*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
27*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
28*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
29*bb4ee6a4SAndroid Build Coastguard Worker 
30*bb4ee6a4SAndroid Build Coastguard Worker pub mod packed_tube;
31*bb4ee6a4SAndroid Build Coastguard Worker 
32*bb4ee6a4SAndroid Build Coastguard Worker pub type TransportTubeResult<T> = std::result::Result<T, TubeTransportError>;
33*bb4ee6a4SAndroid Build Coastguard Worker 
34*bb4ee6a4SAndroid Build Coastguard Worker /// Contains information for a child process to set up the Tube for use.
35*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize, Debug)]
36*bb4ee6a4SAndroid Build Coastguard Worker pub struct TubeTransferData {
37*bb4ee6a4SAndroid Build Coastguard Worker     // Tube to be sent to the child process.
38*bb4ee6a4SAndroid Build Coastguard Worker     pub tube: Tube,
39*bb4ee6a4SAndroid Build Coastguard Worker     // Used to determine what the Tube's purpose is.
40*bb4ee6a4SAndroid Build Coastguard Worker     pub tube_token: TubeToken,
41*bb4ee6a4SAndroid Build Coastguard Worker }
42*bb4ee6a4SAndroid Build Coastguard Worker 
43*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, ThisError)]
44*bb4ee6a4SAndroid Build Coastguard Worker pub enum TubeTransportError {
45*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Serializing and sending failed: {0}")]
46*bb4ee6a4SAndroid Build Coastguard Worker     SerializeSendError(TubeError),
47*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Serializing and recving failed: {0}")]
48*bb4ee6a4SAndroid Build Coastguard Worker     DeserializeRecvError(TubeError),
49*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Tube with token {0} not found")]
50*bb4ee6a4SAndroid Build Coastguard Worker     TubeNotFound(TubeToken),
51*bb4ee6a4SAndroid Build Coastguard Worker }
52*bb4ee6a4SAndroid Build Coastguard Worker 
53*bb4ee6a4SAndroid Build Coastguard Worker /// The target child process will use this decide what a Tube's purpose is.
54*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
55*bb4ee6a4SAndroid Build Coastguard Worker pub enum TubeToken {
56*bb4ee6a4SAndroid Build Coastguard Worker     Bootstrap,
57*bb4ee6a4SAndroid Build Coastguard Worker     Control,
58*bb4ee6a4SAndroid Build Coastguard Worker     Ipc,
59*bb4ee6a4SAndroid Build Coastguard Worker     VhostUser,
60*bb4ee6a4SAndroid Build Coastguard Worker }
61*bb4ee6a4SAndroid Build Coastguard Worker 
62*bb4ee6a4SAndroid Build Coastguard Worker impl Display for TubeToken {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result63*bb4ee6a4SAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64*bb4ee6a4SAndroid Build Coastguard Worker         write!(f, "{:?}", self)
65*bb4ee6a4SAndroid Build Coastguard Worker     }
66*bb4ee6a4SAndroid Build Coastguard Worker }
67*bb4ee6a4SAndroid Build Coastguard Worker 
68*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize, Debug)]
69*bb4ee6a4SAndroid Build Coastguard Worker pub struct TransportData {
70*bb4ee6a4SAndroid Build Coastguard Worker     dh_tube: Option<Tube>,
71*bb4ee6a4SAndroid Build Coastguard Worker     alias_pid: Option<u32>,
72*bb4ee6a4SAndroid Build Coastguard Worker     // A list Tubes and related metadata to transfer. This list should not be emptied, since
73*bb4ee6a4SAndroid Build Coastguard Worker     // that would cause a Tube to drop and thus closing the Tube.
74*bb4ee6a4SAndroid Build Coastguard Worker     tube_transfer_data_list: Vec<TubeTransferData>,
75*bb4ee6a4SAndroid Build Coastguard Worker }
76*bb4ee6a4SAndroid Build Coastguard Worker 
77*bb4ee6a4SAndroid Build Coastguard Worker /// Used by the Broker process to transport Tubes to a target child process.
78*bb4ee6a4SAndroid Build Coastguard Worker pub struct TubeTransporter {
79*bb4ee6a4SAndroid Build Coastguard Worker     pipe_connection: PipeConnection,
80*bb4ee6a4SAndroid Build Coastguard Worker     transport_data: TransportData,
81*bb4ee6a4SAndroid Build Coastguard Worker }
82*bb4ee6a4SAndroid Build Coastguard Worker 
83*bb4ee6a4SAndroid Build Coastguard Worker impl TubeTransporter {
84*bb4ee6a4SAndroid Build Coastguard Worker     /// WARNING: PipeConnection must be a message mode, blocking pipe.
new( pipe_connection: PipeConnection, tube_transfer_data_list: Vec<TubeTransferData>, alias_pid: Option<u32>, dh_tube: Option<Tube>, ) -> TubeTransporter85*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(
86*bb4ee6a4SAndroid Build Coastguard Worker         pipe_connection: PipeConnection,
87*bb4ee6a4SAndroid Build Coastguard Worker         tube_transfer_data_list: Vec<TubeTransferData>,
88*bb4ee6a4SAndroid Build Coastguard Worker         alias_pid: Option<u32>,
89*bb4ee6a4SAndroid Build Coastguard Worker         dh_tube: Option<Tube>,
90*bb4ee6a4SAndroid Build Coastguard Worker     ) -> TubeTransporter {
91*bb4ee6a4SAndroid Build Coastguard Worker         TubeTransporter {
92*bb4ee6a4SAndroid Build Coastguard Worker             pipe_connection,
93*bb4ee6a4SAndroid Build Coastguard Worker             transport_data: TransportData {
94*bb4ee6a4SAndroid Build Coastguard Worker                 dh_tube,
95*bb4ee6a4SAndroid Build Coastguard Worker                 alias_pid,
96*bb4ee6a4SAndroid Build Coastguard Worker                 tube_transfer_data_list,
97*bb4ee6a4SAndroid Build Coastguard Worker             },
98*bb4ee6a4SAndroid Build Coastguard Worker         }
99*bb4ee6a4SAndroid Build Coastguard Worker     }
100*bb4ee6a4SAndroid Build Coastguard Worker 
101*bb4ee6a4SAndroid Build Coastguard Worker     /// Sends tubes to the other end of the pipe. Note that you must provide the destination
102*bb4ee6a4SAndroid Build Coastguard Worker     /// PID so that descriptors can be sent.
serialize_and_transport(&self, child_pid: u32) -> TransportTubeResult<()>103*bb4ee6a4SAndroid Build Coastguard Worker     pub fn serialize_and_transport(&self, child_pid: u32) -> TransportTubeResult<()> {
104*bb4ee6a4SAndroid Build Coastguard Worker         serialize_and_send(
105*bb4ee6a4SAndroid Build Coastguard Worker             |buf| self.pipe_connection.write(buf),
106*bb4ee6a4SAndroid Build Coastguard Worker             &self.transport_data,
107*bb4ee6a4SAndroid Build Coastguard Worker             /* target_pid= */ Some(child_pid),
108*bb4ee6a4SAndroid Build Coastguard Worker         )
109*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(TubeTransportError::SerializeSendError)?;
110*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
111*bb4ee6a4SAndroid Build Coastguard Worker     }
112*bb4ee6a4SAndroid Build Coastguard Worker 
push_tube(&mut self, tube: Tube, tube_token: TubeToken)113*bb4ee6a4SAndroid Build Coastguard Worker     pub fn push_tube(&mut self, tube: Tube, tube_token: TubeToken) {
114*bb4ee6a4SAndroid Build Coastguard Worker         self.transport_data
115*bb4ee6a4SAndroid Build Coastguard Worker             .tube_transfer_data_list
116*bb4ee6a4SAndroid Build Coastguard Worker             .push(TubeTransferData { tube, tube_token });
117*bb4ee6a4SAndroid Build Coastguard Worker     }
118*bb4ee6a4SAndroid Build Coastguard Worker }
119*bb4ee6a4SAndroid Build Coastguard Worker 
120*bb4ee6a4SAndroid Build Coastguard Worker /// Used by the child process to read Tubes sent from the Broker.
121*bb4ee6a4SAndroid Build Coastguard Worker pub struct TubeTransporterReader {
122*bb4ee6a4SAndroid Build Coastguard Worker     reader_pipe_connection: PipeConnection,
123*bb4ee6a4SAndroid Build Coastguard Worker }
124*bb4ee6a4SAndroid Build Coastguard Worker 
125*bb4ee6a4SAndroid Build Coastguard Worker impl TubeTransporterReader {
126*bb4ee6a4SAndroid Build Coastguard Worker     /// WARNING: PipeConnection must be a message mode, blocking pipe.
create_tube_transporter_reader(pipe_connection: PipeConnection) -> Self127*bb4ee6a4SAndroid Build Coastguard Worker     pub fn create_tube_transporter_reader(pipe_connection: PipeConnection) -> Self {
128*bb4ee6a4SAndroid Build Coastguard Worker         TubeTransporterReader {
129*bb4ee6a4SAndroid Build Coastguard Worker             reader_pipe_connection: pipe_connection,
130*bb4ee6a4SAndroid Build Coastguard Worker         }
131*bb4ee6a4SAndroid Build Coastguard Worker     }
132*bb4ee6a4SAndroid Build Coastguard Worker 
read_tubes(&self) -> TransportTubeResult<TubeTransferDataList>133*bb4ee6a4SAndroid Build Coastguard Worker     pub fn read_tubes(&self) -> TransportTubeResult<TubeTransferDataList> {
134*bb4ee6a4SAndroid Build Coastguard Worker         let res: TransportData =
135*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY: We provide a valid buffer to `read()`
136*bb4ee6a4SAndroid Build Coastguard Worker             deserialize_and_recv(|buf| unsafe { self.reader_pipe_connection.read(buf) })
137*bb4ee6a4SAndroid Build Coastguard Worker                 .map_err(TubeTransportError::DeserializeRecvError)?;
138*bb4ee6a4SAndroid Build Coastguard Worker 
139*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(tube) = res.dh_tube {
140*bb4ee6a4SAndroid Build Coastguard Worker             let dh_tube = DuplicateHandleTube::new(tube);
141*bb4ee6a4SAndroid Build Coastguard Worker             set_duplicate_handle_tube(dh_tube);
142*bb4ee6a4SAndroid Build Coastguard Worker         }
143*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(alias_pid) = res.alias_pid {
144*bb4ee6a4SAndroid Build Coastguard Worker             set_alias_pid(alias_pid);
145*bb4ee6a4SAndroid Build Coastguard Worker         }
146*bb4ee6a4SAndroid Build Coastguard Worker         Ok(TubeTransferDataList(res.tube_transfer_data_list))
147*bb4ee6a4SAndroid Build Coastguard Worker     }
148*bb4ee6a4SAndroid Build Coastguard Worker }
149*bb4ee6a4SAndroid Build Coastguard Worker 
150*bb4ee6a4SAndroid Build Coastguard Worker impl FromRawDescriptor for TubeTransporterReader {
151*bb4ee6a4SAndroid Build Coastguard Worker     /// Creates a TubeTransporterReader from a raw descriptor.
152*bb4ee6a4SAndroid Build Coastguard Worker     /// # Safety
153*bb4ee6a4SAndroid Build Coastguard Worker     /// 1. descriptor is valid & ownership is released to the TubeTransporterReader
154*bb4ee6a4SAndroid Build Coastguard Worker     ///
155*bb4ee6a4SAndroid Build Coastguard Worker     /// # Avoiding U.B.
156*bb4ee6a4SAndroid Build Coastguard Worker     /// 1. The underlying pipe is a message pipe in wait mode.
from_raw_descriptor(descriptor: RawDescriptor) -> Self157*bb4ee6a4SAndroid Build Coastguard Worker     unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
158*bb4ee6a4SAndroid Build Coastguard Worker         TubeTransporterReader::create_tube_transporter_reader(PipeConnection::from_raw_descriptor(
159*bb4ee6a4SAndroid Build Coastguard Worker             descriptor,
160*bb4ee6a4SAndroid Build Coastguard Worker             FramingMode::Message,
161*bb4ee6a4SAndroid Build Coastguard Worker             BlockingMode::Wait,
162*bb4ee6a4SAndroid Build Coastguard Worker         ))
163*bb4ee6a4SAndroid Build Coastguard Worker     }
164*bb4ee6a4SAndroid Build Coastguard Worker }
165*bb4ee6a4SAndroid Build Coastguard Worker 
166*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
167*bb4ee6a4SAndroid Build Coastguard Worker pub struct TubeTransferDataList(Vec<TubeTransferData>);
168*bb4ee6a4SAndroid Build Coastguard Worker 
169*bb4ee6a4SAndroid Build Coastguard Worker impl TubeTransferDataList {
get_tube(&mut self, token: TubeToken) -> TransportTubeResult<Tube>170*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_tube(&mut self, token: TubeToken) -> TransportTubeResult<Tube> {
171*bb4ee6a4SAndroid Build Coastguard Worker         Ok(self
172*bb4ee6a4SAndroid Build Coastguard Worker             .0
173*bb4ee6a4SAndroid Build Coastguard Worker             .remove(
174*bb4ee6a4SAndroid Build Coastguard Worker                 match self
175*bb4ee6a4SAndroid Build Coastguard Worker                     .0
176*bb4ee6a4SAndroid Build Coastguard Worker                     .iter()
177*bb4ee6a4SAndroid Build Coastguard Worker                     .position(|tube_data| tube_data.tube_token == token)
178*bb4ee6a4SAndroid Build Coastguard Worker                 {
179*bb4ee6a4SAndroid Build Coastguard Worker                     Some(pos) => pos,
180*bb4ee6a4SAndroid Build Coastguard Worker                     None => return Err(TubeTransportError::TubeNotFound(token)),
181*bb4ee6a4SAndroid Build Coastguard Worker                 },
182*bb4ee6a4SAndroid Build Coastguard Worker             )
183*bb4ee6a4SAndroid Build Coastguard Worker             .tube)
184*bb4ee6a4SAndroid Build Coastguard Worker     }
185*bb4ee6a4SAndroid Build Coastguard Worker }
186*bb4ee6a4SAndroid Build Coastguard Worker 
187*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
188*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
189*bb4ee6a4SAndroid Build Coastguard Worker     use std::thread;
190*bb4ee6a4SAndroid Build Coastguard Worker 
191*bb4ee6a4SAndroid Build Coastguard Worker     use base::named_pipes::pair;
192*bb4ee6a4SAndroid Build Coastguard Worker     use base::named_pipes::BlockingMode;
193*bb4ee6a4SAndroid Build Coastguard Worker     use base::named_pipes::FramingMode;
194*bb4ee6a4SAndroid Build Coastguard Worker     use base::Event;
195*bb4ee6a4SAndroid Build Coastguard Worker     use base::EventWaitResult;
196*bb4ee6a4SAndroid Build Coastguard Worker     use winapi::um::processthreadsapi::GetCurrentProcessId;
197*bb4ee6a4SAndroid Build Coastguard Worker 
198*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
199*bb4ee6a4SAndroid Build Coastguard Worker 
200*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_send_tubes_through_tube_transporter()201*bb4ee6a4SAndroid Build Coastguard Worker     fn test_send_tubes_through_tube_transporter() {
202*bb4ee6a4SAndroid Build Coastguard Worker         let (broker_pipe_connection_server, child_process_pipe) = pair(
203*bb4ee6a4SAndroid Build Coastguard Worker             &FramingMode::Message,
204*bb4ee6a4SAndroid Build Coastguard Worker             &BlockingMode::Wait,
205*bb4ee6a4SAndroid Build Coastguard Worker             /* timeout= */ 0,
206*bb4ee6a4SAndroid Build Coastguard Worker         )
207*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
208*bb4ee6a4SAndroid Build Coastguard Worker 
209*bb4ee6a4SAndroid Build Coastguard Worker         // Start a thread to simulate a new process. This thread will attempt to read the Tubes
210*bb4ee6a4SAndroid Build Coastguard Worker         // from the pipe.
211*bb4ee6a4SAndroid Build Coastguard Worker         let child_join_handle = thread::Builder::new()
212*bb4ee6a4SAndroid Build Coastguard Worker             .name("Sandboxed child process listening thread".to_string())
213*bb4ee6a4SAndroid Build Coastguard Worker             .spawn(move || {
214*bb4ee6a4SAndroid Build Coastguard Worker                 let child_process_pipe = child_process_pipe;
215*bb4ee6a4SAndroid Build Coastguard Worker                 let transporter_reader =
216*bb4ee6a4SAndroid Build Coastguard Worker                     TubeTransporterReader::create_tube_transporter_reader(child_process_pipe);
217*bb4ee6a4SAndroid Build Coastguard Worker                 transporter_reader.read_tubes().unwrap()
218*bb4ee6a4SAndroid Build Coastguard Worker             })
219*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
220*bb4ee6a4SAndroid Build Coastguard Worker 
221*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY: This kernel function just returns the current PID.
222*bb4ee6a4SAndroid Build Coastguard Worker         //
223*bb4ee6a4SAndroid Build Coastguard Worker         // We want to get the current PID as a sanity check for the `OpenProcess` call
224*bb4ee6a4SAndroid Build Coastguard Worker         // when duplicating a handle through a Tube.
225*bb4ee6a4SAndroid Build Coastguard Worker         let current_pid = unsafe { GetCurrentProcessId() };
226*bb4ee6a4SAndroid Build Coastguard Worker 
227*bb4ee6a4SAndroid Build Coastguard Worker         // We want the test to drop device_tube_1 and 2 after transportation is complete. Since
228*bb4ee6a4SAndroid Build Coastguard Worker         // Tubes have many SafeDescriptors, we still want Tubes to work even if their original
229*bb4ee6a4SAndroid Build Coastguard Worker         // handles are closed.
230*bb4ee6a4SAndroid Build Coastguard Worker         let (main_tube_1, main_tube_2) = {
231*bb4ee6a4SAndroid Build Coastguard Worker             let (main_tube_1, device_tube_1) = Tube::pair().unwrap();
232*bb4ee6a4SAndroid Build Coastguard Worker             let (main_tube_2, device_tube_2) = Tube::pair().unwrap();
233*bb4ee6a4SAndroid Build Coastguard Worker 
234*bb4ee6a4SAndroid Build Coastguard Worker             let tube_transporter = TubeTransporter::new(
235*bb4ee6a4SAndroid Build Coastguard Worker                 broker_pipe_connection_server,
236*bb4ee6a4SAndroid Build Coastguard Worker                 vec![
237*bb4ee6a4SAndroid Build Coastguard Worker                     TubeTransferData {
238*bb4ee6a4SAndroid Build Coastguard Worker                         tube: device_tube_1,
239*bb4ee6a4SAndroid Build Coastguard Worker                         tube_token: TubeToken::Control,
240*bb4ee6a4SAndroid Build Coastguard Worker                     },
241*bb4ee6a4SAndroid Build Coastguard Worker                     TubeTransferData {
242*bb4ee6a4SAndroid Build Coastguard Worker                         tube: device_tube_2,
243*bb4ee6a4SAndroid Build Coastguard Worker                         tube_token: TubeToken::Ipc,
244*bb4ee6a4SAndroid Build Coastguard Worker                     },
245*bb4ee6a4SAndroid Build Coastguard Worker                 ],
246*bb4ee6a4SAndroid Build Coastguard Worker                 /* alias_pid= */
247*bb4ee6a4SAndroid Build Coastguard Worker                 None,
248*bb4ee6a4SAndroid Build Coastguard Worker                 /* dh_tube= */
249*bb4ee6a4SAndroid Build Coastguard Worker                 None,
250*bb4ee6a4SAndroid Build Coastguard Worker             );
251*bb4ee6a4SAndroid Build Coastguard Worker 
252*bb4ee6a4SAndroid Build Coastguard Worker             // TODO: we just test within the same process here, so we send to ourselves.
253*bb4ee6a4SAndroid Build Coastguard Worker             tube_transporter
254*bb4ee6a4SAndroid Build Coastguard Worker                 .serialize_and_transport(current_pid)
255*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("serialize and transporting failed");
256*bb4ee6a4SAndroid Build Coastguard Worker 
257*bb4ee6a4SAndroid Build Coastguard Worker             (main_tube_1, main_tube_2)
258*bb4ee6a4SAndroid Build Coastguard Worker         };
259*bb4ee6a4SAndroid Build Coastguard Worker 
260*bb4ee6a4SAndroid Build Coastguard Worker         let tube_data_list = child_join_handle.join().unwrap().0;
261*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(tube_data_list.len(), 2);
262*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(tube_data_list[0].tube_token, TubeToken::Control);
263*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(tube_data_list[1].tube_token, TubeToken::Ipc);
264*bb4ee6a4SAndroid Build Coastguard Worker 
265*bb4ee6a4SAndroid Build Coastguard Worker         // Test sending a string through the Tubes
266*bb4ee6a4SAndroid Build Coastguard Worker         tube_data_list[0]
267*bb4ee6a4SAndroid Build Coastguard Worker             .tube
268*bb4ee6a4SAndroid Build Coastguard Worker             .send(&"hello main 1".to_string())
269*bb4ee6a4SAndroid Build Coastguard Worker             .expect("tube 1 failed to send");
270*bb4ee6a4SAndroid Build Coastguard Worker         tube_data_list[1]
271*bb4ee6a4SAndroid Build Coastguard Worker             .tube
272*bb4ee6a4SAndroid Build Coastguard Worker             .send(&"hello main 2".to_string())
273*bb4ee6a4SAndroid Build Coastguard Worker             .expect("tube 2 failed to send.");
274*bb4ee6a4SAndroid Build Coastguard Worker 
275*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(main_tube_1.recv::<String>().unwrap(), "hello main 1");
276*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(main_tube_2.recv::<String>().unwrap(), "hello main 2");
277*bb4ee6a4SAndroid Build Coastguard Worker 
278*bb4ee6a4SAndroid Build Coastguard Worker         // Test sending a handle through a Tube. Note that the Tube in `tube_data_list[1]` can't
279*bb4ee6a4SAndroid Build Coastguard Worker         // send a handle across because `CHILD_PID` isn't mapped to a real process.
280*bb4ee6a4SAndroid Build Coastguard Worker         let event_handle = Event::new().unwrap();
281*bb4ee6a4SAndroid Build Coastguard Worker 
282*bb4ee6a4SAndroid Build Coastguard Worker         tube_data_list[0]
283*bb4ee6a4SAndroid Build Coastguard Worker             .tube
284*bb4ee6a4SAndroid Build Coastguard Worker             .send(&event_handle)
285*bb4ee6a4SAndroid Build Coastguard Worker             .expect("tube 1 failed to send");
286*bb4ee6a4SAndroid Build Coastguard Worker 
287*bb4ee6a4SAndroid Build Coastguard Worker         let duped_handle = main_tube_1.recv::<Event>().unwrap();
288*bb4ee6a4SAndroid Build Coastguard Worker 
289*bb4ee6a4SAndroid Build Coastguard Worker         event_handle.signal().unwrap();
290*bb4ee6a4SAndroid Build Coastguard Worker 
291*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(
292*bb4ee6a4SAndroid Build Coastguard Worker             duped_handle
293*bb4ee6a4SAndroid Build Coastguard Worker                 .wait_timeout(std::time::Duration::from_millis(2000))
294*bb4ee6a4SAndroid Build Coastguard Worker                 .unwrap(),
295*bb4ee6a4SAndroid Build Coastguard Worker             EventWaitResult::Signaled
296*bb4ee6a4SAndroid Build Coastguard Worker         ));
297*bb4ee6a4SAndroid Build Coastguard Worker     }
298*bb4ee6a4SAndroid Build Coastguard Worker }
299