blob: 2b08c1bcb9ceeb95a53b75a69a060f9b9b47bc3e [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> {
Ren-Pei Zeng5e2ebfb2024-10-23 08:31:33 +000088 // 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 }
Andrew Walbran0a3eb862024-09-18 13:49:04 +010094 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`.
116 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.
124 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.
129 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.
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
Andrew Walbran9487efd2024-08-20 18:37:59 +0100142 /// 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.
148 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`.
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.
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.
178 pub fn into_raw(self) -> NonNull<ffi::native_handle_t> {
179 let raw = self.0;
180 forget(self);
181 raw
182 }
183}
184
185impl Clone for NativeHandle {
186 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
192impl Drop for NativeHandle {
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
Andrew Walbran9639e122024-10-22 18:27:38 +0100203impl From<AidlNativeHandle> for NativeHandle {
204 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
210impl From<NativeHandle> for AidlNativeHandle {
211 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
Andrew Walbran9487efd2024-08-20 18:37:59 +0100218// SAFETY: `NativeHandle` owns the `native_handle_t`, which just contains some integers and file
219// descriptors, which aren't tied to any particular thread.
220unsafe 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.
224unsafe impl Sync for NativeHandle {}
Andrew Walbran0a3eb862024-09-18 13:49:04 +0100225
226#[cfg(test)]
227mod test {
228 use super::*;
229 use std::fs::File;
230
231 #[test]
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]
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]
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]
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 }
Andrew Walbran9639e122024-10-22 18:27:38 +0100268
269 #[test]
Ren-Pei Zeng5e2ebfb2024-10-23 08:31:33 +0000270 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]
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]
Andrew Walbran9639e122024-10-22 18:27:38 +0100293 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 }
Andrew Walbran0a3eb862024-09-18 13:49:04 +0100307}