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