1 // Copyright (C) 2023 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 //! Pleasant Rust bindings for libnativewindow, including AHardwareBuffer 16 17 extern crate nativewindow_bindgen as ffi; 18 19 mod surface; 20 pub use surface::Surface; 21 22 pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; 23 24 use binder::{ 25 binder_impl::{BorrowedParcel, UnstructuredParcelable}, 26 impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable, 27 unstable_api::{status_result, AsNative}, 28 StatusCode, 29 }; 30 use ffi::{AHardwareBuffer, AHardwareBuffer_readFromParcel, AHardwareBuffer_writeToParcel}; 31 use std::fmt::{self, Debug, Formatter}; 32 use std::mem::ManuallyDrop; 33 use std::ptr::{self, null_mut, NonNull}; 34 35 /// Wrapper around an opaque C `AHardwareBuffer`. 36 #[derive(PartialEq, Eq)] 37 pub struct HardwareBuffer(NonNull<AHardwareBuffer>); 38 39 impl HardwareBuffer { 40 /// Test whether the given format and usage flag combination is allocatable. If this function 41 /// returns true, it means that a buffer with the given description can be allocated on this 42 /// implementation, unless resource exhaustion occurs. If this function returns false, it means 43 /// that the allocation of the given description will never succeed. 44 /// 45 /// Available since API 29 is_supported( width: u32, height: u32, layers: u32, format: AHardwareBuffer_Format::Type, usage: AHardwareBuffer_UsageFlags, stride: u32, ) -> bool46 pub fn is_supported( 47 width: u32, 48 height: u32, 49 layers: u32, 50 format: AHardwareBuffer_Format::Type, 51 usage: AHardwareBuffer_UsageFlags, 52 stride: u32, 53 ) -> bool { 54 let buffer_desc = ffi::AHardwareBuffer_Desc { 55 width, 56 height, 57 layers, 58 format, 59 usage: usage.0, 60 stride, 61 rfu0: 0, 62 rfu1: 0, 63 }; 64 // SAFETY: *buffer_desc will never be null. 65 let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) }; 66 67 status == 1 68 } 69 70 /// Allocates a buffer that matches the passed AHardwareBuffer_Desc. If allocation succeeds, the 71 /// buffer can be used according to the usage flags specified in its description. If a buffer is 72 /// used in ways not compatible with its usage flags, the results are undefined and may include 73 /// program termination. 74 /// 75 /// Available since API level 26. 76 #[inline] new( width: u32, height: u32, layers: u32, format: AHardwareBuffer_Format::Type, usage: AHardwareBuffer_UsageFlags, ) -> Option<Self>77 pub fn new( 78 width: u32, 79 height: u32, 80 layers: u32, 81 format: AHardwareBuffer_Format::Type, 82 usage: AHardwareBuffer_UsageFlags, 83 ) -> Option<Self> { 84 let buffer_desc = ffi::AHardwareBuffer_Desc { 85 width, 86 height, 87 layers, 88 format, 89 usage: usage.0, 90 stride: 0, 91 rfu0: 0, 92 rfu1: 0, 93 }; 94 let mut ptr = ptr::null_mut(); 95 // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail 96 // and return a status, but we check it later. 97 let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut ptr) }; 98 99 if status == 0 { 100 Some(Self(NonNull::new(ptr).expect("Allocated AHardwareBuffer was null"))) 101 } else { 102 None 103 } 104 } 105 106 /// Adopts the given raw pointer and wraps it in a Rust HardwareBuffer. 107 /// 108 /// # Safety 109 /// 110 /// This function takes ownership of the pointer and does NOT increment the refcount on the 111 /// buffer. If the caller uses the pointer after the created object is dropped it will cause 112 /// undefined behaviour. If the caller wants to continue using the pointer after calling this 113 /// then use [`clone_from_raw`](Self::clone_from_raw) instead. from_raw(buffer_ptr: NonNull<AHardwareBuffer>) -> Self114 pub unsafe fn from_raw(buffer_ptr: NonNull<AHardwareBuffer>) -> Self { 115 Self(buffer_ptr) 116 } 117 118 /// Creates a new Rust HardwareBuffer to wrap the given AHardwareBuffer without taking ownership 119 /// of it. 120 /// 121 /// Unlike [`from_raw`](Self::from_raw) this method will increment the refcount on the buffer. 122 /// This means that the caller can continue to use the raw buffer it passed in, and must call 123 /// [`AHardwareBuffer_release`](ffi::AHardwareBuffer_release) when it is finished with it to 124 /// avoid a memory leak. 125 /// 126 /// # Safety 127 /// 128 /// The buffer pointer must point to a valid `AHardwareBuffer`. clone_from_raw(buffer: NonNull<AHardwareBuffer>) -> Self129 pub unsafe fn clone_from_raw(buffer: NonNull<AHardwareBuffer>) -> Self { 130 // SAFETY: The caller guarantees that the AHardwareBuffer pointer is valid. 131 unsafe { ffi::AHardwareBuffer_acquire(buffer.as_ptr()) }; 132 Self(buffer) 133 } 134 135 /// Get the internal |AHardwareBuffer| pointer without decrementing the refcount. This can 136 /// be used to provide a pointer to the AHB for a C/C++ API over the FFI. into_raw(self) -> NonNull<AHardwareBuffer>137 pub fn into_raw(self) -> NonNull<AHardwareBuffer> { 138 let buffer = ManuallyDrop::new(self); 139 buffer.0 140 } 141 142 /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme 143 /// and undocumented circumstances. 144 /// 145 /// Available since API level 31. id(&self) -> u64146 pub fn id(&self) -> u64 { 147 let mut out_id = 0; 148 // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid 149 // because it must have been allocated by `AHardwareBuffer_allocate`, 150 // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet 151 // released it. The id pointer must be valid because it comes from a reference. 152 let status = unsafe { ffi::AHardwareBuffer_getId(self.0.as_ptr(), &mut out_id) }; 153 assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}"); 154 155 out_id 156 } 157 158 /// Get the width of this buffer width(&self) -> u32159 pub fn width(&self) -> u32 { 160 self.description().width 161 } 162 163 /// Get the height of this buffer height(&self) -> u32164 pub fn height(&self) -> u32 { 165 self.description().height 166 } 167 168 /// Get the number of layers of this buffer layers(&self) -> u32169 pub fn layers(&self) -> u32 { 170 self.description().layers 171 } 172 173 /// Get the format of this buffer format(&self) -> AHardwareBuffer_Format::Type174 pub fn format(&self) -> AHardwareBuffer_Format::Type { 175 self.description().format 176 } 177 178 /// Get the usage bitvector of this buffer usage(&self) -> AHardwareBuffer_UsageFlags179 pub fn usage(&self) -> AHardwareBuffer_UsageFlags { 180 AHardwareBuffer_UsageFlags(self.description().usage) 181 } 182 183 /// Get the stride of this buffer stride(&self) -> u32184 pub fn stride(&self) -> u32 { 185 self.description().stride 186 } 187 description(&self) -> ffi::AHardwareBuffer_Desc188 fn description(&self) -> ffi::AHardwareBuffer_Desc { 189 let mut buffer_desc = ffi::AHardwareBuffer_Desc { 190 width: 0, 191 height: 0, 192 layers: 0, 193 format: 0, 194 usage: 0, 195 stride: 0, 196 rfu0: 0, 197 rfu1: 0, 198 }; 199 // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null. 200 unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) }; 201 buffer_desc 202 } 203 } 204 205 impl Drop for HardwareBuffer { drop(&mut self)206 fn drop(&mut self) { 207 // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid 208 // because it must have been allocated by `AHardwareBuffer_allocate`, 209 // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet 210 // released it. 211 unsafe { ffi::AHardwareBuffer_release(self.0.as_ptr()) } 212 } 213 } 214 215 impl Debug for HardwareBuffer { fmt(&self, f: &mut Formatter) -> fmt::Result216 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 217 f.debug_struct("HardwareBuffer").field("id", &self.id()).finish() 218 } 219 } 220 221 impl Clone for HardwareBuffer { clone(&self) -> Self222 fn clone(&self) -> Self { 223 // SAFETY: ptr is guaranteed to be non-null and the acquire can not fail. 224 unsafe { ffi::AHardwareBuffer_acquire(self.0.as_ptr()) }; 225 Self(self.0) 226 } 227 } 228 229 impl UnstructuredParcelable for HardwareBuffer { write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode>230 fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> { 231 let status = 232 // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid 233 // because it must have been allocated by `AHardwareBuffer_allocate`, 234 // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet 235 // released it. 236 unsafe { AHardwareBuffer_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) }; 237 status_result(status) 238 } 239 from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode>240 fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> { 241 let mut buffer = null_mut(); 242 243 let status = 244 // SAFETY: Both pointers must be valid because they are obtained from references. 245 // `AHardwareBuffer_readFromParcel` doesn't store them or do anything else special 246 // with them. If it returns success then it will have allocated a new 247 // `AHardwareBuffer` and incremented the reference count, so we can use it until we 248 // release it. 249 unsafe { AHardwareBuffer_readFromParcel(parcel.as_native(), &mut buffer) }; 250 251 status_result(status)?; 252 253 Ok(Self( 254 NonNull::new(buffer).expect( 255 "AHardwareBuffer_readFromParcel returned success but didn't allocate buffer", 256 ), 257 )) 258 } 259 } 260 261 impl_deserialize_for_unstructured_parcelable!(HardwareBuffer); 262 impl_serialize_for_unstructured_parcelable!(HardwareBuffer); 263 264 // SAFETY: The underlying *AHardwareBuffers can be moved between threads. 265 unsafe impl Send for HardwareBuffer {} 266 267 // SAFETY: The underlying *AHardwareBuffers can be used from multiple threads. 268 // 269 // AHardwareBuffers are backed by C++ GraphicBuffers, which are mostly immutable. The only cases 270 // where they are not immutable are: 271 // 272 // - reallocation (which is never actually done across the codebase and requires special 273 // privileges/platform code access to do) 274 // - "locking" for reading/writing (which is explicitly allowed to be done across multiple threads 275 // according to the docs on the underlying gralloc calls) 276 unsafe impl Sync for HardwareBuffer {} 277 278 #[cfg(test)] 279 mod test { 280 use super::*; 281 282 #[test] create_valid_buffer_returns_ok()283 fn create_valid_buffer_returns_ok() { 284 let buffer = HardwareBuffer::new( 285 512, 286 512, 287 1, 288 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 289 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, 290 ); 291 assert!(buffer.is_some()); 292 } 293 294 #[test] create_invalid_buffer_returns_err()295 fn create_invalid_buffer_returns_err() { 296 let buffer = HardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0)); 297 assert!(buffer.is_none()); 298 } 299 300 #[test] from_raw_allows_getters()301 fn from_raw_allows_getters() { 302 let buffer_desc = ffi::AHardwareBuffer_Desc { 303 width: 1024, 304 height: 512, 305 layers: 1, 306 format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 307 usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0, 308 stride: 0, 309 rfu0: 0, 310 rfu1: 0, 311 }; 312 let mut raw_buffer_ptr = ptr::null_mut(); 313 314 // SAFETY: The pointers are valid because they come from references, and 315 // `AHardwareBuffer_allocate` doesn't retain them after it returns. 316 let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) }; 317 assert_eq!(status, 0); 318 319 // SAFETY: The pointer must be valid because it was just allocated successfully, and we 320 // don't use it after calling this. 321 let buffer = unsafe { HardwareBuffer::from_raw(NonNull::new(raw_buffer_ptr).unwrap()) }; 322 assert_eq!(buffer.width(), 1024); 323 } 324 325 #[test] basic_getters()326 fn basic_getters() { 327 let buffer = HardwareBuffer::new( 328 1024, 329 512, 330 1, 331 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 332 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, 333 ) 334 .expect("Buffer with some basic parameters was not created successfully"); 335 336 assert_eq!(buffer.width(), 1024); 337 assert_eq!(buffer.height(), 512); 338 assert_eq!(buffer.layers(), 1); 339 assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM); 340 assert_eq!( 341 buffer.usage(), 342 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN 343 ); 344 } 345 346 #[test] id_getter()347 fn id_getter() { 348 let buffer = HardwareBuffer::new( 349 1024, 350 512, 351 1, 352 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 353 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, 354 ) 355 .expect("Buffer with some basic parameters was not created successfully"); 356 357 assert_ne!(0, buffer.id()); 358 } 359 360 #[test] clone()361 fn clone() { 362 let buffer = HardwareBuffer::new( 363 1024, 364 512, 365 1, 366 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 367 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, 368 ) 369 .expect("Buffer with some basic parameters was not created successfully"); 370 let buffer2 = buffer.clone(); 371 372 assert_eq!(buffer, buffer2); 373 } 374 375 #[test] into_raw()376 fn into_raw() { 377 let buffer = HardwareBuffer::new( 378 1024, 379 512, 380 1, 381 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 382 AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, 383 ) 384 .expect("Buffer with some basic parameters was not created successfully"); 385 let buffer2 = buffer.clone(); 386 387 let raw_buffer = buffer.into_raw(); 388 // SAFETY: This is the same pointer we had before. 389 let remade_buffer = unsafe { HardwareBuffer::from_raw(raw_buffer) }; 390 391 assert_eq!(remade_buffer, buffer2); 392 } 393 } 394