| // Copyright (C) 2024 The Android Open Source Project | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| //! Rust wrapper for `ANativeWindow` and related types. | |
| use binder::{ | |
| binder_impl::{BorrowedParcel, UnstructuredParcelable}, | |
| impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable, | |
| unstable_api::{status_result, AsNative}, | |
| StatusCode, | |
| }; | |
| use nativewindow_bindgen::{ | |
| AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire, ANativeWindow_getFormat, | |
| ANativeWindow_getHeight, ANativeWindow_getWidth, ANativeWindow_readFromParcel, | |
| ANativeWindow_release, ANativeWindow_writeToParcel, | |
| }; | |
| use std::error::Error; | |
| use std::fmt::{self, Debug, Display, Formatter}; | |
| use std::ptr::{null_mut, NonNull}; | |
| /// Wrapper around an opaque C `ANativeWindow`. | |
| #[derive(PartialEq, Eq)] | |
| pub struct Surface(NonNull<ANativeWindow>); | |
| impl Surface { | |
| /// Returns the current width in pixels of the window surface. | |
| pub fn width(&self) -> Result<u32, ErrorCode> { | |
| // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because | |
| // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` | |
| // and we have not yet released it. | |
| let width = unsafe { ANativeWindow_getWidth(self.0.as_ptr()) }; | |
| width.try_into().map_err(|_| ErrorCode(width)) | |
| } | |
| /// Returns the current height in pixels of the window surface. | |
| pub fn height(&self) -> Result<u32, ErrorCode> { | |
| // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because | |
| // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` | |
| // and we have not yet released it. | |
| let height = unsafe { ANativeWindow_getHeight(self.0.as_ptr()) }; | |
| height.try_into().map_err(|_| ErrorCode(height)) | |
| } | |
| /// Returns the current pixel format of the window surface. | |
| pub fn format(&self) -> Result<AHardwareBuffer_Format::Type, ErrorCode> { | |
| // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because | |
| // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` | |
| // and we have not yet released it. | |
| let format = unsafe { ANativeWindow_getFormat(self.0.as_ptr()) }; | |
| format.try_into().map_err(|_| ErrorCode(format)) | |
| } | |
| } | |
| impl Drop for Surface { | |
| fn drop(&mut self) { | |
| // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because | |
| // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` | |
| // and we have not yet released it. | |
| unsafe { ANativeWindow_release(self.0.as_ptr()) } | |
| } | |
| } | |
| impl Debug for Surface { | |
| fn fmt(&self, f: &mut Formatter) -> fmt::Result { | |
| f.debug_struct("Surface") | |
| .field("width", &self.width()) | |
| .field("height", &self.height()) | |
| .field("format", &self.format()) | |
| .finish() | |
| } | |
| } | |
| impl Clone for Surface { | |
| fn clone(&self) -> Self { | |
| // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because | |
| // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` | |
| // and we have not yet released it. | |
| unsafe { ANativeWindow_acquire(self.0.as_ptr()) }; | |
| Self(self.0) | |
| } | |
| } | |
| impl UnstructuredParcelable for Surface { | |
| fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> { | |
| let status = | |
| // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because | |
| // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` | |
| // and we have not yet released it. | |
| unsafe { ANativeWindow_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) }; | |
| status_result(status) | |
| } | |
| fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> { | |
| let mut buffer = null_mut(); | |
| let status = | |
| // SAFETY: Both pointers must be valid because they are obtained from references. | |
| // `ANativeWindow_readFromParcel` doesn't store them or do anything else special | |
| // with them. If it returns success then it will have allocated a new | |
| // `ANativeWindow` and incremented the reference count, so we can use it until we | |
| // release it. | |
| unsafe { ANativeWindow_readFromParcel(parcel.as_native(), &mut buffer) }; | |
| status_result(status)?; | |
| Ok(Self( | |
| NonNull::new(buffer) | |
| .expect("ANativeWindow_readFromParcel returned success but didn't allocate buffer"), | |
| )) | |
| } | |
| } | |
| impl_deserialize_for_unstructured_parcelable!(Surface); | |
| impl_serialize_for_unstructured_parcelable!(Surface); | |
| // SAFETY: The underlying *ANativeWindow can be moved between threads. | |
| unsafe impl Send for Surface {} | |
| // SAFETY: The underlying *ANativeWindow can be used from multiple threads concurrently. | |
| unsafe impl Sync for Surface {} | |
| /// An error code returned by methods on [`Surface`]. | |
| #[derive(Copy, Clone, Debug, Eq, PartialEq)] | |
| pub struct ErrorCode(i32); | |
| impl Error for ErrorCode {} | |
| impl Display for ErrorCode { | |
| fn fmt(&self, f: &mut Formatter) -> fmt::Result { | |
| write!(f, "Error {}", self.0) | |
| } | |
| } |