• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 { cmd: sys::lender_command_LENDER_LEND_BSS, region: Default::default() })
66         .unwrap();
67 
68     // Receive the memref from the lender service.
69     let recv_buf = &mut [0; 0][..];
70     let resp = lender.recv::<MemrefResponse>(recv_buf).unwrap();
71 
72     resp.handle
73 }
74 
75 /// Runs the logic to test writing to and reading from the shared buffer.
test_read_write(lender: &Handle, remote_buf: UnsafeSharedBuf)76 fn test_read_write(lender: &Handle, remote_buf: UnsafeSharedBuf) {
77     // Check the initial state of the remote buffer after mapping.
78     //
79     // SAFETY: Reading a single `u8` from the remote buffer.
80     assert_eq!(4096, remote_buf.len());
81     assert_eq!(0, unsafe { remote_buf.ptr().read() });
82 
83     // Write to the shared buffer and then ask the lender service to read from the
84     // buffer and send back to us the value it sees.
85     //
86     // SAFETY: Writing a single `u8` to the shared buffer.
87     unsafe { remote_buf.ptr().write(7) };
88 
89     lender
90         .send(&lender_msg {
91             cmd: sys::lender_command_LENDER_READ_BSS,
92             region: lender_region { offset: 0, size: 1 },
93         })
94         .unwrap();
95 
96     let recv_buf = &mut [0; 1][..];
97     let resp = lender.recv::<ReadResponse>(recv_buf).unwrap();
98 
99     // Verify that the lender service read the same value that we wrote.
100     assert_eq!(7, resp.value);
101 
102     // Send the lender service a value to write into the buffer. We tell it to write
103     // into the second byte of the buffer so that we can also verify that the first
104     // byte is not modified.
105     lender
106         .send(&WriteRequest {
107             msg: lender_msg {
108                 cmd: sys::lender_command_LENDER_WRITE_BSS,
109                 region: lender_region { offset: 1, size: 1 },
110             },
111             value: 123,
112         })
113         .unwrap();
114 
115     let recv_buf = &mut [0; 0][..];
116     lender.recv::<WriteResponse>(recv_buf).unwrap();
117 
118     // Verify that the value we sent was written to the specified offset in the
119     // shared buffer.
120     //
121     // SAFETY: Reading the first two bytes of the shared buffer.
122     assert_eq!(7, unsafe { remote_buf.ptr().read() });
123     assert_eq!(123, unsafe { remote_buf.ptr().offset(1).read() });
124 
125     // Reset the buffer since it's shared between test runs.
126     //
127     // SAFETY: Writing to the first two bytes of the shared buffer.
128     unsafe {
129         remote_buf.ptr().write(0);
130         remote_buf.ptr().offset(1).write(0);
131     }
132 
133     remote_buf.unmap();
134 }
135 
136 impl<'s> Serialize<'s> for lender_msg {
serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>137     fn serialize<'a: 's, S: Serializer<'s>>(
138         &'a self,
139         serializer: &mut S,
140     ) -> Result<S::Ok, S::Error> {
141         // SAFETY: `lender_msg` is generated from the C header and already matches the
142         // expected layout.
143         unsafe { serializer.serialize_as_bytes(self) }
144     }
145 }
146 
147 impl Default for lender_region {
default() -> Self148     fn default() -> Self {
149         lender_region { offset: 0, size: 0 }
150     }
151 }
152 
153 /// Response type for the `LENDER_LEND_BSS` command.
154 struct MemrefResponse {
155     handle: Handle,
156 }
157 
158 impl Deserialize for MemrefResponse {
159     type Error = TipcError;
160     const MAX_SERIALIZED_SIZE: usize = 0;
161 
deserialize(_bytes: &[u8], handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>162     fn deserialize(_bytes: &[u8], handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
163         assert_eq!(1, handles.len());
164         let handle = handles[0].take().unwrap();
165         Ok(MemrefResponse { handle })
166     }
167 }
168 
169 /// Response type for the `LENDER_READ_BSS` command.
170 struct ReadResponse {
171     value: u8,
172 }
173 
174 impl Deserialize for ReadResponse {
175     type Error = TipcError;
176     const MAX_SERIALIZED_SIZE: usize = 1;
177 
deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>178     fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
179         Ok(ReadResponse { value: bytes[0] })
180     }
181 }
182 
183 /// Request type for the `LENDER_WRITE_BSS` command, which includes an additional
184 /// byte value to write.
185 struct WriteRequest {
186     msg: lender_msg,
187     value: u8,
188 }
189 
190 impl<'s> Serialize<'s> for WriteRequest {
serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>191     fn serialize<'a: 's, S: Serializer<'s>>(
192         &'a self,
193         serializer: &mut S,
194     ) -> Result<S::Ok, S::Error> {
195         self.msg.serialize(serializer)?;
196 
197         // SAFETY: Serializing a single `u8` value is always safe.
198         unsafe { serializer.serialize_as_bytes(&self.value) }
199     }
200 }
201 
202 /// Empty response type for the `LENDER_WRITE_BSS` command.
203 struct WriteResponse;
204 
205 impl Deserialize for WriteResponse {
206     type Error = TipcError;
207     const MAX_SERIALIZED_SIZE: usize = 0;
208 
deserialize(_bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>209     fn deserialize(_bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
210         Ok(WriteResponse)
211     }
212 }
213