blob: ee70e3f538bcadc264baa467f5f74a3e9f951759 [file] [log] [blame]
Andrew Walbran9487efd2024-08-20 18:37:59 +01001// Copyright (C) 2024 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Andrew Walbran9639e122024-10-22 18:27:38 +010015use android_hardware_common::{
16 aidl::android::hardware::common::NativeHandle::NativeHandle as AidlNativeHandle,
17 binder::ParcelFileDescriptor,
18};
Andrew Walbran0a3eb862024-09-18 13:49:04 +010019use std::{
20 ffi::c_int,
21 mem::forget,
22 os::fd::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
23 ptr::NonNull,
24};
Andrew Walbran9487efd2024-08-20 18:37:59 +010025
26/// Rust wrapper around `native_handle_t`.
27///
28/// This owns the `native_handle_t` and its file descriptors, and will close them and free it when
29/// it is dropped.
30#[derive(Debug)]
31pub struct NativeHandle(NonNull<ffi::native_handle_t>);
32
33impl NativeHandle {
Andrew Walbran0a3eb862024-09-18 13:49:04 +010034 /// Creates a new `NativeHandle` with the given file descriptors and integer values.
35 ///
36 /// The `NativeHandle` will take ownership of the file descriptors and close them when it is
37 /// dropped.
38 pub fn new(fds: Vec<OwnedFd>, ints: &[c_int]) -> Option<Self> {
39 let fd_count = fds.len();
40 // SAFETY: native_handle_create doesn't have any safety requirements.
41 let handle = unsafe {
42 ffi::native_handle_create(fd_count.try_into().unwrap(), ints.len().try_into().unwrap())
43 };
44 let handle = NonNull::new(handle)?;
45 for (i, fd) in fds.into_iter().enumerate() {
46 // SAFETY: `handle` must be valid because it was just created, and the array offset is
47 // within the bounds of what we allocated above.
48 unsafe {
49 *(*handle.as_ptr()).data.as_mut_ptr().add(i) = fd.into_raw_fd();
50 }
51 }
52 for (i, value) in ints.iter().enumerate() {
53 // SAFETY: `handle` must be valid because it was just created, and the array offset is
54 // within the bounds of what we allocated above. Note that `data` is uninitialized
55 // until after this so we can't use `slice::from_raw_parts_mut` or similar to create a
56 // reference to it so we use raw pointers arithmetic instead.
57 unsafe {
58 *(*handle.as_ptr()).data.as_mut_ptr().add(fd_count + i) = *value;
59 }
60 }
61 // SAFETY: `handle` must be valid because it was just created.
62 unsafe {
63 ffi::native_handle_set_fdsan_tag(handle.as_ptr());
64 }
65 Some(Self(handle))
66 }
67
68 /// Returns a borrowed view of all the file descriptors in this native handle.
69 pub fn fds(&self) -> Vec<BorrowedFd> {
70 self.data()[..self.fd_count()]
71 .iter()
72 .map(|fd| {
73 // SAFETY: The `native_handle_t` maintains ownership of the file descriptor so it
74 // won't be closed until this `NativeHandle` is destroyed. The `BorrowedFd` will
75 // have a lifetime constrained to that of `&self`, so it can't outlive it.
76 unsafe { BorrowedFd::borrow_raw(*fd) }
77 })
78 .collect()
79 }
80
81 /// Returns the integer values in this native handle.
82 pub fn ints(&self) -> &[c_int] {
83 &self.data()[self.fd_count()..]
84 }
85
86 /// Destroys the `NativeHandle`, taking ownership of the file descriptors it contained.
87 pub fn into_fds(self) -> Vec<OwnedFd> {
88 let fds = self.data()[..self.fd_count()]
89 .iter()
90 .map(|fd| {
91 // SAFETY: The `native_handle_t` has ownership of the file descriptor, and
92 // after this we destroy it without closing the file descriptor so we can take over
93 // ownership of it.
94 unsafe { OwnedFd::from_raw_fd(*fd) }
95 })
96 .collect();
97
98 // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed
99 // after this because we own it and forget it.
100 unsafe {
101 assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0);
102 }
103 // Don't drop self, as that would cause `native_handle_close` to be called and close the
104 // file descriptors.
105 forget(self);
106 fds
107 }
108
109 /// Returns a reference to the underlying `native_handle_t`.
110 fn as_ref(&self) -> &ffi::native_handle_t {
111 // SAFETY: All the ways of creating a `NativeHandle` ensure that the `native_handle_t` is
112 // valid and initialised, and lives as long as the `NativeHandle`. We enforce Rust's
113 // aliasing rules by giving the reference a lifetime matching that of `&self`.
114 unsafe { self.0.as_ref() }
115 }
116
117 /// Returns the number of file descriptors included in the native handle.
118 fn fd_count(&self) -> usize {
119 self.as_ref().numFds.try_into().unwrap()
120 }
121
122 /// Returns the number of integer values included in the native handle.
123 fn int_count(&self) -> usize {
124 self.as_ref().numInts.try_into().unwrap()
125 }
126
127 /// Returns a slice reference for all the used `data` field of the native handle, including both
128 /// file descriptors and integers.
129 fn data(&self) -> &[c_int] {
130 let total_count = self.fd_count() + self.int_count();
131 // SAFETY: The data must have been initialised with this number of elements when the
132 // `NativeHandle` was created.
133 unsafe { self.as_ref().data.as_slice(total_count) }
134 }
135
Andrew Walbran9487efd2024-08-20 18:37:59 +0100136 /// Wraps a raw `native_handle_t` pointer, taking ownership of it.
137 ///
138 /// # Safety
139 ///
140 /// `native_handle` must be a valid pointer to a `native_handle_t`, and must not be used
141 /// anywhere else after calling this method.
142 pub unsafe fn from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Self {
143 Self(native_handle)
144 }
145
146 /// Creates a new `NativeHandle` wrapping a clone of the given `native_handle_t` pointer.
147 ///
148 /// Unlike [`from_raw`](Self::from_raw) this doesn't take ownership of the pointer passed in, so
149 /// the caller remains responsible for closing and freeing it.
150 ///
151 /// # Safety
152 ///
153 /// `native_handle` must be a valid pointer to a `native_handle_t`.
154 pub unsafe fn clone_from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Option<Self> {
155 // SAFETY: The caller promised that `native_handle` was valid.
156 let cloned = unsafe { ffi::native_handle_clone(native_handle.as_ptr()) };
157 NonNull::new(cloned).map(Self)
158 }
159
160 /// Returns a raw pointer to the wrapped `native_handle_t`.
161 ///
162 /// This is only valid as long as this `NativeHandle` exists, so shouldn't be stored. It mustn't
163 /// be closed or deleted.
164 pub fn as_raw(&self) -> NonNull<ffi::native_handle_t> {
165 self.0
166 }
167
168 /// Turns the `NativeHandle` into a raw `native_handle_t`.
169 ///
170 /// The caller takes ownership of the `native_handle_t` and its file descriptors, so is
171 /// responsible for closing and freeing it.
172 pub fn into_raw(self) -> NonNull<ffi::native_handle_t> {
173 let raw = self.0;
174 forget(self);
175 raw
176 }
177}
178
179impl Clone for NativeHandle {
180 fn clone(&self) -> Self {
181 // SAFETY: Our wrapped `native_handle_t` pointer is always valid.
182 unsafe { Self::clone_from_raw(self.0) }.expect("native_handle_clone returned null")
183 }
184}
185
186impl Drop for NativeHandle {
187 fn drop(&mut self) {
188 // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed
189 // after this because we own it and are being dropped.
190 unsafe {
191 assert_eq!(ffi::native_handle_close(self.0.as_ptr()), 0);
192 assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0);
193 }
194 }
195}
196
Andrew Walbran9639e122024-10-22 18:27:38 +0100197impl From<AidlNativeHandle> for NativeHandle {
198 fn from(aidl_native_handle: AidlNativeHandle) -> Self {
199 let fds = aidl_native_handle.fds.into_iter().map(OwnedFd::from).collect();
200 Self::new(fds, &aidl_native_handle.ints).unwrap()
201 }
202}
203
204impl From<NativeHandle> for AidlNativeHandle {
205 fn from(native_handle: NativeHandle) -> Self {
206 let ints = native_handle.ints().to_owned();
207 let fds = native_handle.into_fds().into_iter().map(ParcelFileDescriptor::new).collect();
208 Self { ints, fds }
209 }
210}
211
Andrew Walbran9487efd2024-08-20 18:37:59 +0100212// SAFETY: `NativeHandle` owns the `native_handle_t`, which just contains some integers and file
213// descriptors, which aren't tied to any particular thread.
214unsafe impl Send for NativeHandle {}
215
216// SAFETY: A `NativeHandle` can be used from different threads simultaneously, as is is just
217// integers and file descriptors.
218unsafe impl Sync for NativeHandle {}
Andrew Walbran0a3eb862024-09-18 13:49:04 +0100219
220#[cfg(test)]
221mod test {
222 use super::*;
223 use std::fs::File;
224
225 #[test]
226 fn create_empty() {
227 let handle = NativeHandle::new(vec![], &[]).unwrap();
228 assert_eq!(handle.fds().len(), 0);
229 assert_eq!(handle.ints(), &[]);
230 }
231
232 #[test]
233 fn create_with_ints() {
234 let handle = NativeHandle::new(vec![], &[1, 2, 42]).unwrap();
235 assert_eq!(handle.fds().len(), 0);
236 assert_eq!(handle.ints(), &[1, 2, 42]);
237 }
238
239 #[test]
240 fn create_with_fd() {
241 let file = File::open("/dev/null").unwrap();
242 let handle = NativeHandle::new(vec![file.into()], &[]).unwrap();
243 assert_eq!(handle.fds().len(), 1);
244 assert_eq!(handle.ints(), &[]);
245 }
246
247 #[test]
248 fn clone() {
249 let file = File::open("/dev/null").unwrap();
250 let original = NativeHandle::new(vec![file.into()], &[42]).unwrap();
251 assert_eq!(original.ints(), &[42]);
252 assert_eq!(original.fds().len(), 1);
253
254 let cloned = original.clone();
255 drop(original);
256
257 assert_eq!(cloned.ints(), &[42]);
258 assert_eq!(cloned.fds().len(), 1);
259
260 drop(cloned);
261 }
Andrew Walbran9639e122024-10-22 18:27:38 +0100262
263 #[test]
264 fn to_from_aidl() {
265 let file = File::open("/dev/null").unwrap();
266 let original = NativeHandle::new(vec![file.into()], &[42]).unwrap();
267 assert_eq!(original.ints(), &[42]);
268 assert_eq!(original.fds().len(), 1);
269
270 let aidl = AidlNativeHandle::from(original);
271 assert_eq!(&aidl.ints, &[42]);
272 assert_eq!(aidl.fds.len(), 1);
273
274 let converted_back = NativeHandle::from(aidl);
275 assert_eq!(converted_back.ints(), &[42]);
276 assert_eq!(converted_back.fds().len(), 1);
277 }
Andrew Walbran0a3eb862024-09-18 13:49:04 +0100278}