Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8ee0ef1f authored by Andrew Walbran's avatar Andrew Walbran
Browse files

Add Rust support for Surface unstructured parcelable.

Bug: 307535208
Test: m rust
Change-Id: I4bb57b773ab7c1884d0341a3bc7dd100c3636bde
parent 0e622d7b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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";
+3 −1
Original line number Diff line number Diff line
@@ -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()
    }
}
+140 −0
Original line number Diff line number Diff line
// 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)
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -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>