diff options
author | 2024-01-24 15:26:35 +0000 | |
---|---|---|
committer | 2024-01-24 15:26:35 +0000 | |
commit | d52639e35beec399f3f777b2e3b87ef2b456d770 (patch) | |
tree | fd309818939b7d6e50bb52bda49055aa4e2fcf92 | |
parent | 0e622d7b92bf17ba23dfdf840cc51868e305dfba (diff) | |
parent | 8ee0ef1f38b8a1e41ccb540cfb29f9a301f403db (diff) |
Merge "Add Rust support for Surface unstructured parcelable." into main
-rw-r--r-- | aidl/gui/android/view/Surface.aidl | 2 | ||||
-rw-r--r-- | libs/nativewindow/rust/src/lib.rs | 4 | ||||
-rw-r--r-- | libs/nativewindow/rust/src/surface.rs | 140 | ||||
-rw-r--r-- | libs/nativewindow/rust/sys/nativewindow_bindings.h | 1 |
4 files changed, 145 insertions, 2 deletions
diff --git a/aidl/gui/android/view/Surface.aidl b/aidl/gui/android/view/Surface.aidl index bb3faaff79..668671760c 100644 --- a/aidl/gui/android/view/Surface.aidl +++ b/aidl/gui/android/view/Surface.aidl @@ -17,4 +17,4 @@ package android.view; -@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable Surface cpp_header "gui/view/Surface.h" ndk_header "android/native_window_aidl.h"; +@JavaOnlyStableParcelable @NdkOnlyStableParcelable @RustOnlyStableParcelable parcelable Surface cpp_header "gui/view/Surface.h" ndk_header "android/native_window_aidl.h" rust_type "nativewindow::Surface"; diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index aab7df0c2c..22ad83463c 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -16,6 +16,8 @@ extern crate nativewindow_bindgen as ffi; +pub mod surface; + pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; use binder::{ @@ -210,7 +212,7 @@ impl Drop for HardwareBuffer { } impl Debug for HardwareBuffer { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("HardwareBuffer").field("id", &self.id()).finish() } } diff --git a/libs/nativewindow/rust/src/surface.rs b/libs/nativewindow/rust/src/surface.rs new file mode 100644 index 0000000000..c812612d40 --- /dev/null +++ b/libs/nativewindow/rust/src/surface.rs @@ -0,0 +1,140 @@ +// 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 {} + +/// 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) + } +} diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h index 4525a42502..5689f7df94 100644 --- a/libs/nativewindow/rust/sys/nativewindow_bindings.h +++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h @@ -19,3 +19,4 @@ #include <android/hardware_buffer_aidl.h> #include <android/hdr_metadata.h> #include <android/native_window.h> +#include <android/native_window_aidl.h> |