xref: /aosp_15_r20/frameworks/native/libs/nativewindow/rust/src/handle.rs (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 // 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 
15 use android_hardware_common::{
16     aidl::android::hardware::common::NativeHandle::NativeHandle as AidlNativeHandle,
17     binder::ParcelFileDescriptor,
18 };
19 use std::{
20     ffi::c_int,
21     mem::forget,
22     os::fd::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
23     ptr::NonNull,
24 };
25 
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)]
31 pub struct NativeHandle(NonNull<ffi::native_handle_t>);
32 
33 impl NativeHandle {
34     /// 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.
new(fds: Vec<OwnedFd>, ints: &[c_int]) -> Option<Self>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.
fds(&self) -> Vec<BorrowedFd>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.
ints(&self) -> &[c_int]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.
into_fds(self) -> Vec<OwnedFd>87     pub fn into_fds(self) -> Vec<OwnedFd> {
88         // Unset FDSan tag since this `native_handle_t` is no longer the owner of the file
89         // descriptors after this function.
90         // SAFETY: Our wrapped `native_handle_t` pointer is always valid.
91         unsafe {
92             ffi::native_handle_unset_fdsan_tag(self.as_ref());
93         }
94         let fds = self.data()[..self.fd_count()]
95             .iter()
96             .map(|fd| {
97                 // SAFETY: The `native_handle_t` has ownership of the file descriptor, and
98                 // after this we destroy it without closing the file descriptor so we can take over
99                 // ownership of it.
100                 unsafe { OwnedFd::from_raw_fd(*fd) }
101             })
102             .collect();
103 
104         // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed
105         // after this because we own it and forget it.
106         unsafe {
107             assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0);
108         }
109         // Don't drop self, as that would cause `native_handle_close` to be called and close the
110         // file descriptors.
111         forget(self);
112         fds
113     }
114 
115     /// Returns a reference to the underlying `native_handle_t`.
as_ref(&self) -> &ffi::native_handle_t116     fn as_ref(&self) -> &ffi::native_handle_t {
117         // SAFETY: All the ways of creating a `NativeHandle` ensure that the `native_handle_t` is
118         // valid and initialised, and lives as long as the `NativeHandle`. We enforce Rust's
119         // aliasing rules by giving the reference a lifetime matching that of `&self`.
120         unsafe { self.0.as_ref() }
121     }
122 
123     /// Returns the number of file descriptors included in the native handle.
fd_count(&self) -> usize124     fn fd_count(&self) -> usize {
125         self.as_ref().numFds.try_into().unwrap()
126     }
127 
128     /// Returns the number of integer values included in the native handle.
int_count(&self) -> usize129     fn int_count(&self) -> usize {
130         self.as_ref().numInts.try_into().unwrap()
131     }
132 
133     /// Returns a slice reference for all the used `data` field of the native handle, including both
134     /// file descriptors and integers.
data(&self) -> &[c_int]135     fn data(&self) -> &[c_int] {
136         let total_count = self.fd_count() + self.int_count();
137         // SAFETY: The data must have been initialised with this number of elements when the
138         // `NativeHandle` was created.
139         unsafe { self.as_ref().data.as_slice(total_count) }
140     }
141 
142     /// Wraps a raw `native_handle_t` pointer, taking ownership of it.
143     ///
144     /// # Safety
145     ///
146     /// `native_handle` must be a valid pointer to a `native_handle_t`, and must not be used
147     ///  anywhere else after calling this method.
from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Self148     pub unsafe fn from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Self {
149         Self(native_handle)
150     }
151 
152     /// Creates a new `NativeHandle` wrapping a clone of the given `native_handle_t` pointer.
153     ///
154     /// Unlike [`from_raw`](Self::from_raw) this doesn't take ownership of the pointer passed in, so
155     /// the caller remains responsible for closing and freeing it.
156     ///
157     /// # Safety
158     ///
159     /// `native_handle` must be a valid pointer to a `native_handle_t`.
clone_from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Option<Self>160     pub unsafe fn clone_from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Option<Self> {
161         // SAFETY: The caller promised that `native_handle` was valid.
162         let cloned = unsafe { ffi::native_handle_clone(native_handle.as_ptr()) };
163         NonNull::new(cloned).map(Self)
164     }
165 
166     /// Returns a raw pointer to the wrapped `native_handle_t`.
167     ///
168     /// This is only valid as long as this `NativeHandle` exists, so shouldn't be stored. It mustn't
169     /// be closed or deleted.
as_raw(&self) -> NonNull<ffi::native_handle_t>170     pub fn as_raw(&self) -> NonNull<ffi::native_handle_t> {
171         self.0
172     }
173 
174     /// Turns the `NativeHandle` into a raw `native_handle_t`.
175     ///
176     /// The caller takes ownership of the `native_handle_t` and its file descriptors, so is
177     /// responsible for closing and freeing it.
into_raw(self) -> NonNull<ffi::native_handle_t>178     pub fn into_raw(self) -> NonNull<ffi::native_handle_t> {
179         let raw = self.0;
180         forget(self);
181         raw
182     }
183 }
184 
185 impl Clone for NativeHandle {
clone(&self) -> Self186     fn clone(&self) -> Self {
187         // SAFETY: Our wrapped `native_handle_t` pointer is always valid.
188         unsafe { Self::clone_from_raw(self.0) }.expect("native_handle_clone returned null")
189     }
190 }
191 
192 impl Drop for NativeHandle {
drop(&mut self)193     fn drop(&mut self) {
194         // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed
195         // after this because we own it and are being dropped.
196         unsafe {
197             assert_eq!(ffi::native_handle_close(self.0.as_ptr()), 0);
198             assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0);
199         }
200     }
201 }
202 
203 impl From<AidlNativeHandle> for NativeHandle {
from(aidl_native_handle: AidlNativeHandle) -> Self204     fn from(aidl_native_handle: AidlNativeHandle) -> Self {
205         let fds = aidl_native_handle.fds.into_iter().map(OwnedFd::from).collect();
206         Self::new(fds, &aidl_native_handle.ints).unwrap()
207     }
208 }
209 
210 impl From<NativeHandle> for AidlNativeHandle {
from(native_handle: NativeHandle) -> Self211     fn from(native_handle: NativeHandle) -> Self {
212         let ints = native_handle.ints().to_owned();
213         let fds = native_handle.into_fds().into_iter().map(ParcelFileDescriptor::new).collect();
214         Self { ints, fds }
215     }
216 }
217 
218 // SAFETY: `NativeHandle` owns the `native_handle_t`, which just contains some integers and file
219 // descriptors, which aren't tied to any particular thread.
220 unsafe impl Send for NativeHandle {}
221 
222 // SAFETY: A `NativeHandle` can be used from different threads simultaneously, as is is just
223 // integers and file descriptors.
224 unsafe impl Sync for NativeHandle {}
225 
226 #[cfg(test)]
227 mod test {
228     use super::*;
229     use std::fs::File;
230 
231     #[test]
create_empty()232     fn create_empty() {
233         let handle = NativeHandle::new(vec![], &[]).unwrap();
234         assert_eq!(handle.fds().len(), 0);
235         assert_eq!(handle.ints(), &[]);
236     }
237 
238     #[test]
create_with_ints()239     fn create_with_ints() {
240         let handle = NativeHandle::new(vec![], &[1, 2, 42]).unwrap();
241         assert_eq!(handle.fds().len(), 0);
242         assert_eq!(handle.ints(), &[1, 2, 42]);
243     }
244 
245     #[test]
create_with_fd()246     fn create_with_fd() {
247         let file = File::open("/dev/null").unwrap();
248         let handle = NativeHandle::new(vec![file.into()], &[]).unwrap();
249         assert_eq!(handle.fds().len(), 1);
250         assert_eq!(handle.ints(), &[]);
251     }
252 
253     #[test]
clone()254     fn clone() {
255         let file = File::open("/dev/null").unwrap();
256         let original = NativeHandle::new(vec![file.into()], &[42]).unwrap();
257         assert_eq!(original.ints(), &[42]);
258         assert_eq!(original.fds().len(), 1);
259 
260         let cloned = original.clone();
261         drop(original);
262 
263         assert_eq!(cloned.ints(), &[42]);
264         assert_eq!(cloned.fds().len(), 1);
265 
266         drop(cloned);
267     }
268 
269     #[test]
to_fds()270     fn to_fds() {
271         let file = File::open("/dev/null").unwrap();
272         let original = NativeHandle::new(vec![file.into()], &[42]).unwrap();
273         assert_eq!(original.ints(), &[42]);
274         assert_eq!(original.fds().len(), 1);
275 
276         let fds = original.into_fds();
277         assert_eq!(fds.len(), 1);
278     }
279 
280     #[test]
to_aidl()281     fn to_aidl() {
282         let file = File::open("/dev/null").unwrap();
283         let original = NativeHandle::new(vec![file.into()], &[42]).unwrap();
284         assert_eq!(original.ints(), &[42]);
285         assert_eq!(original.fds().len(), 1);
286 
287         let aidl = AidlNativeHandle::from(original);
288         assert_eq!(&aidl.ints, &[42]);
289         assert_eq!(aidl.fds.len(), 1);
290     }
291 
292     #[test]
to_from_aidl()293     fn to_from_aidl() {
294         let file = File::open("/dev/null").unwrap();
295         let original = NativeHandle::new(vec![file.into()], &[42]).unwrap();
296         assert_eq!(original.ints(), &[42]);
297         assert_eq!(original.fds().len(), 1);
298 
299         let aidl = AidlNativeHandle::from(original);
300         assert_eq!(&aidl.ints, &[42]);
301         assert_eq!(aidl.fds.len(), 1);
302 
303         let converted_back = NativeHandle::from(aidl);
304         assert_eq!(converted_back.ints(), &[42]);
305         assert_eq!(converted_back.fds().len(), 1);
306     }
307 }
308