1 #![cfg(test)]
2 
3 use crate::sys::{lender_msg, lender_region};
4 use core::ffi::CStr;
5 use tipc::{Deserialize, Handle, MMapFlags, Serialize, Serializer, TipcError, UnsafeSharedBuf};
6 
7 #[allow(bad_style)]
8 #[allow(dead_code)] // Needed because not all variants of the `lender_command` enum are used.
9 #[allow(deref_nullptr)] // https://github.com/rust-lang/rust-bindgen/issues/1651
10 mod sys {
11     include!(env!("BINDGEN_INC_FILE"));
12 }
13 
14 test::init!();
15 
16 const LENDER_PORT: &[u8] = b"com.android.memref.lender\0";
17 
18 #[test]
recv_ref()19 fn recv_ref() {
20     // Connect to the lender service.
21     let port = CStr::from_bytes_with_nul(LENDER_PORT).unwrap();
22     let lender = Handle::connect(port).unwrap();
23 
24     // Request the shared buffer from the lender service.
25     let remote_handle = request_remote_buf(&lender);
26 
27     // Try to mmap the shared buffer into process memory.
28     //
29     // NOTE: Try to map with size 2 in order to test the logic for rounding up to a
30     // multiple of the page size. The lender service will always allocate a buffer
31     // of exactly one page, but we only ever read/write the first two bytes, so this
32     // should still map correctly.
33     let remote_buf =
34         remote_handle.mmap(2, MMapFlags::ReadWrite).expect("Failed to map the shared buffer");
35 
36     // Run the main test logic.
37     test_read_write(&lender, remote_buf);
38 }
39 
40 #[test]
drop_shared_buf_handle()41 fn drop_shared_buf_handle() {
42     // Connect to the lender service.
43     let port = CStr::from_bytes_with_nul(LENDER_PORT).unwrap();
44     let lender = Handle::connect(port).unwrap();
45 
46     // Request the shared buffer from the lender service.
47     let remote_handle = request_remote_buf(&lender);
48 
49     // Map the buffer into memory and then drop the `Handle` associated with it.
50     // This should not invalidate the buffer.
51     let remote_buf =
52         remote_handle.mmap(2, MMapFlags::ReadWrite).expect("Failed to map the shared buffer");
53     std::mem::drop(remote_handle);
54 
55     // Run the main test logic to verify that the shared buffer is still valid after
56     // closing the associated handle.
57     test_read_write(&lender, remote_buf);
58 }
59 
60 /// Makes the initial request to the lender service for the remote buffer.
request_remote_buf(lender: &Handle) -> Handle61 fn request_remote_buf(lender: &Handle) -> Handle {
62     // Send a command to the lender service telling it we want to receive a shared
63     // memory buffer.
64     lender
65         .send(&lender_msg {
66             cmd: sys::lender_command_LENDER_LEND_BSS as u64,
67             region: Default::default(),
68         })
69         .unwrap();
70 
71     // Receive the memref from the lender service.
72     let recv_buf = &mut [0; 0][..];
73     let resp = lender.recv::<MemrefResponse>(recv_buf).unwrap();
74 
75     resp.handle
76 }
77 
78 /// Runs the logic to test writing to and reading from the shared buffer.
test_read_write(lender: &Handle, remote_buf: UnsafeSharedBuf)79 fn test_read_write(lender: &Handle, remote_buf: UnsafeSharedBuf) {
80     // Check the initial state of the remote buffer after mapping.
81     //
82     // SAFETY: Reading a single `u8` from the remote buffer.
83     assert_eq!(4096, remote_buf.len());
84     assert_eq!(0, unsafe { remote_buf.ptr().read() });
85 
86     // Write to the shared buffer and then ask the lender service to read from the
87     // buffer and send back to us the value it sees.
88     //
89     // SAFETY: Writing a single `u8` to the shared buffer.
90     unsafe { remote_buf.ptr().write(7) };
91 
92     lender
93         .send(&lender_msg {
94             cmd: sys::lender_command_LENDER_READ_BSS as u64,
95             region: lender_region { offset: 0, size: 1 },
96         })
97         .unwrap();
98 
99     let recv_buf = &mut [0; 1][..];
100     let resp = lender.recv::<ReadResponse>(recv_buf).unwrap();
101 
102     // Verify that the lender service read the same value that we wrote.
103     assert_eq!(7, resp.value);
104 
105     // Send the lender service a value to write into the buffer. We tell it to write
106     // into the second byte of the buffer so that we can also verify that the first
107     // byte is not modified.
108     lender
109         .send(&WriteRequest {
110             msg: lender_msg {
111                 cmd: sys::lender_command_LENDER_WRITE_BSS as u64,
112                 region: lender_region { offset: 1, size: 1 },
113             },
114             value: 123,
115         })
116         .unwrap();
117 
118     let recv_buf = &mut [0; 0][..];
119     lender.recv::<WriteResponse>(recv_buf).unwrap();
120 
121     // Verify that the value we sent was written to the specified offset in the
122     // shared buffer.
123     //
124     // SAFETY: Reading the first two bytes of the shared buffer.
125     assert_eq!(7, unsafe { remote_buf.ptr().read() });
126     assert_eq!(123, unsafe { remote_buf.ptr().offset(1).read() });
127 
128     // Reset the buffer since it's shared between test runs.
129     //
130     // SAFETY: Writing to the first two bytes of the shared buffer.
131     unsafe {
132         remote_buf.ptr().write(0);
133         remote_buf.ptr().offset(1).write(0);
134     }
135 
136     remote_buf.unmap();
137 }
138 
139 impl<'s> Serialize<'s> for lender_msg {
serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>140     fn serialize<'a: 's, S: Serializer<'s>>(
141         &'a self,
142         serializer: &mut S,
143     ) -> Result<S::Ok, S::Error> {
144         // SAFETY: `lender_msg` is generated from the C header and already matches the
145         // expected layout.
146         unsafe { serializer.serialize_as_bytes(self) }
147     }
148 }
149 
150 impl Default for lender_region {
default() -> Self151     fn default() -> Self {
152         lender_region { offset: 0, size: 0 }
153     }
154 }
155 
156 /// Response type for the `LENDER_LEND_BSS` command.
157 struct MemrefResponse {
158     handle: Handle,
159 }
160 
161 impl Deserialize for MemrefResponse {
162     type Error = TipcError;
163     const MAX_SERIALIZED_SIZE: usize = 0;
164 
deserialize(_bytes: &[u8], handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>165     fn deserialize(_bytes: &[u8], handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
166         assert_eq!(1, handles.len());
167         let handle = handles[0].take().unwrap();
168         Ok(MemrefResponse { handle })
169     }
170 }
171 
172 /// Response type for the `LENDER_READ_BSS` command.
173 struct ReadResponse {
174     value: u8,
175 }
176 
177 impl Deserialize for ReadResponse {
178     type Error = TipcError;
179     const MAX_SERIALIZED_SIZE: usize = 1;
180 
deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>181     fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
182         Ok(ReadResponse { value: bytes[0] })
183     }
184 }
185 
186 /// Request type for the `LENDER_WRITE_BSS` command, which includes an additional
187 /// byte value to write.
188 struct WriteRequest {
189     msg: lender_msg,
190     value: u8,
191 }
192 
193 impl<'s> Serialize<'s> for WriteRequest {
serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>194     fn serialize<'a: 's, S: Serializer<'s>>(
195         &'a self,
196         serializer: &mut S,
197     ) -> Result<S::Ok, S::Error> {
198         self.msg.serialize(serializer)?;
199 
200         // SAFETY: Serializing a single `u8` value is always safe.
201         unsafe { serializer.serialize_as_bytes(&self.value) }
202     }
203 }
204 
205 /// Empty response type for the `LENDER_WRITE_BSS` command.
206 struct WriteResponse;
207 
208 impl Deserialize for WriteResponse {
209     type Error = TipcError;
210     const MAX_SERIALIZED_SIZE: usize = 0;
211 
deserialize(_bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>212     fn deserialize(_bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
213         Ok(WriteResponse)
214     }
215 }
216