blob: afe056029797e79de0ae62159d40ae7553f47093 [file] [log] [blame] [edit]
#![cfg(test)]
use crate::sys::{lender_msg, lender_region};
use core::ffi::CStr;
use tipc::{Deserialize, Handle, MMapFlags, Serialize, Serializer, TipcError, UnsafeSharedBuf};
#[allow(bad_style)]
#[allow(dead_code)] // Needed because not all variants of the `lender_command` enum are used.
#[allow(deref_nullptr)] // https://github.com/rust-lang/rust-bindgen/issues/1651
mod sys {
include!(env!("BINDGEN_INC_FILE"));
}
test::init!();
const LENDER_PORT: &[u8] = b"com.android.memref.lender\0";
#[test]
fn recv_ref() {
// Connect to the lender service.
let port = CStr::from_bytes_with_nul(LENDER_PORT).unwrap();
let lender = Handle::connect(port).unwrap();
// Request the shared buffer from the lender service.
let remote_handle = request_remote_buf(&lender);
// Try to mmap the shared buffer into process memory.
//
// NOTE: Try to map with size 2 in order to test the logic for rounding up to a
// multiple of the page size. The lender service will always allocate a buffer
// of exactly one page, but we only ever read/write the first two bytes, so this
// should still map correctly.
let remote_buf =
remote_handle.mmap(2, MMapFlags::ReadWrite).expect("Failed to map the shared buffer");
// Run the main test logic.
test_read_write(&lender, remote_buf);
}
#[test]
fn drop_shared_buf_handle() {
// Connect to the lender service.
let port = CStr::from_bytes_with_nul(LENDER_PORT).unwrap();
let lender = Handle::connect(port).unwrap();
// Request the shared buffer from the lender service.
let remote_handle = request_remote_buf(&lender);
// Map the buffer into memory and then drop the `Handle` associated with it.
// This should not invalidate the buffer.
let remote_buf =
remote_handle.mmap(2, MMapFlags::ReadWrite).expect("Failed to map the shared buffer");
std::mem::drop(remote_handle);
// Run the main test logic to verify that the shared buffer is still valid after
// closing the associated handle.
test_read_write(&lender, remote_buf);
}
/// Makes the initial request to the lender service for the remote buffer.
fn request_remote_buf(lender: &Handle) -> Handle {
// Send a command to the lender service telling it we want to receive a shared
// memory buffer.
lender
.send(&lender_msg { cmd: sys::lender_command_LENDER_LEND_BSS, region: Default::default() })
.unwrap();
// Receive the memref from the lender service.
let recv_buf = &mut [0; 0][..];
let resp = lender.recv::<MemrefResponse>(recv_buf).unwrap();
resp.handle
}
/// Runs the logic to test writing to and reading from the shared buffer.
fn test_read_write(lender: &Handle, remote_buf: UnsafeSharedBuf) {
// Check the initial state of the remote buffer after mapping.
//
// SAFETY: Reading a single `u8` from the remote buffer.
assert_eq!(4096, remote_buf.len());
assert_eq!(0, unsafe { remote_buf.ptr().read() });
// Write to the shared buffer and then ask the lender service to read from the
// buffer and send back to us the value it sees.
//
// SAFETY: Writing a single `u8` to the shared buffer.
unsafe { remote_buf.ptr().write(7) };
lender
.send(&lender_msg {
cmd: sys::lender_command_LENDER_READ_BSS,
region: lender_region { offset: 0, size: 1 },
})
.unwrap();
let recv_buf = &mut [0; 1][..];
let resp = lender.recv::<ReadResponse>(recv_buf).unwrap();
// Verify that the lender service read the same value that we wrote.
assert_eq!(7, resp.value);
// Send the lender service a value to write into the buffer. We tell it to write
// into the second byte of the buffer so that we can also verify that the first
// byte is not modified.
lender
.send(&WriteRequest {
msg: lender_msg {
cmd: sys::lender_command_LENDER_WRITE_BSS,
region: lender_region { offset: 1, size: 1 },
},
value: 123,
})
.unwrap();
let recv_buf = &mut [0; 0][..];
lender.recv::<WriteResponse>(recv_buf).unwrap();
// Verify that the value we sent was written to the specified offset in the
// shared buffer.
//
// SAFETY: Reading the first two bytes of the shared buffer.
assert_eq!(7, unsafe { remote_buf.ptr().read() });
assert_eq!(123, unsafe { remote_buf.ptr().offset(1).read() });
// Reset the buffer since it's shared between test runs.
//
// SAFETY: Writing to the first two bytes of the shared buffer.
unsafe {
remote_buf.ptr().write(0);
remote_buf.ptr().offset(1).write(0);
}
remote_buf.unmap();
}
impl<'s> Serialize<'s> for lender_msg {
fn serialize<'a: 's, S: Serializer<'s>>(
&'a self,
serializer: &mut S,
) -> Result<S::Ok, S::Error> {
// SAFETY: `lender_msg` is generated from the C header and already matches the
// expected layout.
unsafe { serializer.serialize_as_bytes(self) }
}
}
impl Default for lender_region {
fn default() -> Self {
lender_region { offset: 0, size: 0 }
}
}
/// Response type for the `LENDER_LEND_BSS` command.
struct MemrefResponse {
handle: Handle,
}
impl Deserialize for MemrefResponse {
type Error = TipcError;
const MAX_SERIALIZED_SIZE: usize = 0;
fn deserialize(_bytes: &[u8], handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
assert_eq!(1, handles.len());
let handle = handles[0].take().unwrap();
Ok(MemrefResponse { handle })
}
}
/// Response type for the `LENDER_READ_BSS` command.
struct ReadResponse {
value: u8,
}
impl Deserialize for ReadResponse {
type Error = TipcError;
const MAX_SERIALIZED_SIZE: usize = 1;
fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
Ok(ReadResponse { value: bytes[0] })
}
}
/// Request type for the `LENDER_WRITE_BSS` command, which includes an additional
/// byte value to write.
struct WriteRequest {
msg: lender_msg,
value: u8,
}
impl<'s> Serialize<'s> for WriteRequest {
fn serialize<'a: 's, S: Serializer<'s>>(
&'a self,
serializer: &mut S,
) -> Result<S::Ok, S::Error> {
self.msg.serialize(serializer)?;
// SAFETY: Serializing a single `u8` value is always safe.
unsafe { serializer.serialize_as_bytes(&self.value) }
}
}
/// Empty response type for the `LENDER_WRITE_BSS` command.
struct WriteResponse;
impl Deserialize for WriteResponse {
type Error = TipcError;
const MAX_SERIALIZED_SIZE: usize = 0;
fn deserialize(_bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
Ok(WriteResponse)
}
}