Merge "SF: Simplify layer tracing"
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 01c4723..34ccb21 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -282,6 +282,21 @@
chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu23/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu23/trace
+# Setup synthetic events
+ chmod 0666 /sys/kernel/tracing/synthetic_events
+ chmod 0666 /sys/kernel/debug/tracing/synthetic_events
+
+ # rss_stat_throttled
+ write /sys/kernel/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
+ write /sys/kernel/debug/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
+
+# Set up histogram triggers
+ # rss_stat_throttled (bucket size == 512KB)
+ chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
+ chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger
+ write /sys/kernel/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
+ write /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
+
# Only create the tracing instance if persist.mm_events.enabled
# Attempting to remove the tracing instance after it has been created
# will likely fail with EBUSY as it would be in use by traced_probes.
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index 34f1cbf..5baa4d7 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -32,9 +32,11 @@
bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
void* param);
-// Starts an RPC server on a given port and a given root IBinder object.
-// This function sets up the server, calls readyCallback with a given param, and
-// then joins before returning.
+// Starts an RPC server on a given port and a given root IBinder factory.
+// RunRpcServerWithFactory acts like RunRpcServerCallback, but instead of
+// assigning single root IBinder object to all connections, factory is called
+// whenever a client connects, making it possible to assign unique IBinder
+// object to each client.
bool RunRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
void* factoryContext, unsigned int port);
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 4e048d7..bd2e695 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -17,7 +17,7 @@
//! Trait definitions for binder objects
use crate::error::{status_t, Result, StatusCode};
-use crate::parcel::{OwnedParcel, Parcel};
+use crate::parcel::{Parcel, BorrowedParcel};
use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
use crate::sys;
@@ -129,7 +129,7 @@
/// Handle and reply to a request to invoke a transaction on this object.
///
/// `reply` may be [`None`] if the sender does not expect a reply.
- fn on_transact(&self, code: TransactionCode, data: &Parcel, reply: &mut Parcel) -> Result<()>;
+ fn on_transact(&self, code: TransactionCode, data: &BorrowedParcel<'_>, reply: &mut BorrowedParcel<'_>) -> Result<()>;
/// Handle a request to invoke the dump transaction on this
/// object.
@@ -177,25 +177,25 @@
fn get_extension(&mut self) -> Result<Option<SpIBinder>>;
/// Create a Parcel that can be used with `submit_transact`.
- fn prepare_transact(&self) -> Result<OwnedParcel>;
+ fn prepare_transact(&self) -> Result<Parcel>;
/// Perform a generic operation with the object.
///
- /// The provided [`OwnedParcel`] must have been created by a call to
+ /// The provided [`Parcel`] must have been created by a call to
/// `prepare_transact` on the same binder.
///
/// # Arguments
///
/// * `code` - Transaction code for the operation.
- /// * `data` - [`OwnedParcel`] with input data.
+ /// * `data` - [`Parcel`] with input data.
/// * `flags` - Transaction flags, e.g. marking the transaction as
/// asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY)).
fn submit_transact(
&self,
code: TransactionCode,
- data: OwnedParcel,
+ data: Parcel,
flags: TransactionFlags,
- ) -> Result<OwnedParcel>;
+ ) -> Result<Parcel>;
/// Perform a generic operation with the object. This is a convenience
/// method that internally calls `prepare_transact` followed by
@@ -206,15 +206,15 @@
/// * `flags` - Transaction flags, e.g. marking the transaction as
/// asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY))
/// * `input_callback` A callback for building the `Parcel`.
- fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
+ fn transact<F: FnOnce(BorrowedParcel<'_>) -> Result<()>>(
&self,
code: TransactionCode,
flags: TransactionFlags,
input_callback: F,
) -> Result<Parcel> {
let mut parcel = self.prepare_transact()?;
- input_callback(&mut parcel.borrowed())?;
- self.submit_transact(code, parcel, flags).map(OwnedParcel::into_parcel)
+ input_callback(parcel.borrowed())?;
+ self.submit_transact(code, parcel, flags)
}
}
@@ -475,8 +475,8 @@
/// fn on_transact(
/// &self,
/// code: TransactionCode,
-/// data: &Parcel,
-/// reply: &mut Parcel,
+/// data: &BorrowedParcel,
+/// reply: &mut BorrowedParcel,
/// ) -> Result<()> {
/// // ...
/// }
@@ -655,13 +655,13 @@
/// have the following type:
///
/// ```
-/// # use binder::{Interface, TransactionCode, Parcel};
+/// # use binder::{Interface, TransactionCode, BorrowedParcel};
/// # trait Placeholder {
/// fn on_transact(
/// service: &dyn Interface,
/// code: TransactionCode,
-/// data: &Parcel,
-/// reply: &mut Parcel,
+/// data: &BorrowedParcel,
+/// reply: &mut BorrowedParcel,
/// ) -> binder::Result<()>;
/// # }
/// ```
@@ -676,7 +676,7 @@
/// using the provided function, `on_transact`.
///
/// ```
-/// use binder::{declare_binder_interface, Binder, Interface, TransactionCode, Parcel};
+/// use binder::{declare_binder_interface, Binder, Interface, TransactionCode, BorrowedParcel};
///
/// pub trait IServiceManager: Interface {
/// // remote methods...
@@ -692,8 +692,8 @@
/// fn on_transact(
/// service: &dyn IServiceManager,
/// code: TransactionCode,
-/// data: &Parcel,
-/// reply: &mut Parcel,
+/// data: &BorrowedParcel,
+/// reply: &mut BorrowedParcel,
/// ) -> binder::Result<()> {
/// // ...
/// Ok(())
@@ -847,7 +847,7 @@
$descriptor
}
- fn on_transact(&self, code: $crate::TransactionCode, data: &$crate::Parcel, reply: &mut $crate::Parcel) -> $crate::Result<()> {
+ fn on_transact(&self, code: $crate::TransactionCode, data: &$crate::BorrowedParcel<'_>, reply: &mut $crate::BorrowedParcel<'_>) -> $crate::Result<()> {
match $on_transact(&*self.0, code, data, reply) {
// The C++ backend converts UNEXPECTED_NULL into an exception
Err($crate::StatusCode::UNEXPECTED_NULL) => {
@@ -922,14 +922,14 @@
where
dyn $interface: $crate::Interface
{
- fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+ fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
let binder = $crate::Interface::as_binder(self);
parcel.write(&binder)
}
}
impl $crate::parcel::SerializeOption for dyn $interface + '_ {
- fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
parcel.write(&this.map($crate::Interface::as_binder))
}
}
@@ -988,14 +988,14 @@
}
impl<P: $crate::BinderAsyncPool> $crate::parcel::Serialize for dyn $async_interface<P> + '_ {
- fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+ fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
let binder = $crate::Interface::as_binder(self);
parcel.write(&binder)
}
}
impl<P: $crate::BinderAsyncPool> $crate::parcel::SerializeOption for dyn $async_interface<P> + '_ {
- fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
parcel.write(&this.map($crate::Interface::as_binder))
}
}
@@ -1040,26 +1040,26 @@
}
impl $crate::parcel::Serialize for $enum {
- fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+ fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
parcel.write(&self.0)
}
}
impl $crate::parcel::SerializeArray for $enum {
- fn serialize_array(slice: &[Self], parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+ fn serialize_array(slice: &[Self], parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
let v: Vec<$backing> = slice.iter().map(|x| x.0).collect();
<$backing as binder::parcel::SerializeArray>::serialize_array(&v[..], parcel)
}
}
impl $crate::parcel::Deserialize for $enum {
- fn deserialize(parcel: &$crate::parcel::Parcel) -> $crate::Result<Self> {
+ fn deserialize(parcel: &$crate::parcel::BorrowedParcel<'_>) -> $crate::Result<Self> {
parcel.read().map(Self)
}
}
impl $crate::parcel::DeserializeArray for $enum {
- fn deserialize_array(parcel: &$crate::parcel::Parcel) -> $crate::Result<Option<Vec<Self>>> {
+ fn deserialize_array(parcel: &$crate::parcel::BorrowedParcel<'_>) -> $crate::Result<Option<Vec<Self>>> {
let v: Option<Vec<$backing>> =
<$backing as binder::parcel::DeserializeArray>::deserialize_array(parcel)?;
Ok(v.map(|v| v.into_iter().map(Self).collect()))
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 2ac2d2f..cce55c0 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -50,8 +50,8 @@
//! fn on_transact(
//! service: &dyn ITest,
//! code: TransactionCode,
-//! _data: &Parcel,
-//! reply: &mut Parcel,
+//! _data: &BorrowedParcel,
+//! reply: &mut BorrowedParcel,
//! ) -> binder::Result<()> {
//! match code {
//! SpIBinder::FIRST_CALL_TRANSACTION => {
@@ -115,7 +115,7 @@
pub use crate::binder_async::{BoxFuture, BinderAsyncPool};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
pub use native::{add_service, force_lazy_services_persist, register_lazy_service, Binder};
-pub use parcel::{OwnedParcel, Parcel};
+pub use parcel::{BorrowedParcel, Parcel};
pub use proxy::{get_interface, get_service, wait_for_interface, wait_for_service};
pub use proxy::{AssociateClass, DeathRecipient, Proxy, SpIBinder, WpIBinder};
pub use state::{ProcessState, ThreadState};
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index a91092e..f5d7187 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -18,7 +18,7 @@
AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode,
};
use crate::error::{status_result, status_t, Result, StatusCode};
-use crate::parcel::{Parcel, Serialize};
+use crate::parcel::{BorrowedParcel, Serialize};
use crate::proxy::SpIBinder;
use crate::sys;
@@ -161,8 +161,8 @@
/// # fn on_transact(
/// # service: &dyn IBar,
/// # code: TransactionCode,
- /// # data: &Parcel,
- /// # reply: &mut Parcel,
+ /// # data: &BorrowedParcel,
+ /// # reply: &mut BorrowedParcel,
/// # ) -> binder::Result<()> {
/// # Ok(())
/// # }
@@ -277,8 +277,8 @@
reply: *mut sys::AParcel,
) -> status_t {
let res = {
- let mut reply = Parcel::borrowed(reply).unwrap();
- let data = Parcel::borrowed(data as *mut sys::AParcel).unwrap();
+ let mut reply = BorrowedParcel::from_raw(reply).unwrap();
+ let data = BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap();
let object = sys::AIBinder_getUserData(binder);
let binder: &T = &*(object as *const T);
binder.on_transact(code, &data, &mut reply)
@@ -384,7 +384,7 @@
}
impl<B: Remotable> Serialize for Binder<B> {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
parcel.write_binder(Some(&self.as_binder()))
}
}
@@ -503,8 +503,8 @@
fn on_transact(
&self,
_code: TransactionCode,
- _data: &Parcel,
- _reply: &mut Parcel,
+ _data: &BorrowedParcel<'_>,
+ _reply: &mut BorrowedParcel<'_>,
) -> Result<()> {
Ok(())
}
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index a0e1478..206b90c 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -21,11 +21,10 @@
use crate::proxy::SpIBinder;
use crate::sys;
-use std::cell::RefCell;
use std::convert::TryInto;
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
-use std::ptr;
+use std::ptr::{self, NonNull};
use std::fmt;
mod file_descriptor;
@@ -46,53 +45,41 @@
/// other side of the IPC, and references to live Binder objects that will
/// result in the other side receiving a proxy Binder connected with the
/// original Binder in the Parcel.
-pub enum Parcel {
- /// Owned parcel pointer
- Owned(*mut sys::AParcel),
- /// Borrowed parcel pointer (will not be destroyed on drop)
- Borrowed(*mut sys::AParcel),
-}
-
-/// A variant of Parcel that is known to be owned.
-pub struct OwnedParcel {
- ptr: *mut sys::AParcel,
+///
+/// This type represents a parcel that is owned by Rust code.
+#[repr(transparent)]
+pub struct Parcel {
+ ptr: NonNull<sys::AParcel>,
}
/// # Safety
///
/// This type guarantees that it owns the AParcel and that all access to
-/// the AParcel happens through the OwnedParcel, so it is ok to send across
+/// the AParcel happens through the Parcel, so it is ok to send across
/// threads.
-unsafe impl Send for OwnedParcel {}
+unsafe impl Send for Parcel {}
-/// A variant of Parcel that is known to be borrowed.
+/// Container for a message (data and object references) that can be sent
+/// through Binder.
+///
+/// This object is a borrowed variant of [`Parcel`]. It is a separate type from
+/// `&mut Parcel` because it is not valid to `mem::swap` two parcels.
+#[repr(transparent)]
pub struct BorrowedParcel<'a> {
- inner: Parcel,
+ ptr: NonNull<sys::AParcel>,
_lifetime: PhantomData<&'a mut Parcel>,
}
-impl OwnedParcel {
- /// Create a new empty `OwnedParcel`.
- pub fn new() -> OwnedParcel {
+impl Parcel {
+ /// Create a new empty `Parcel`.
+ pub fn new() -> Parcel {
let ptr = unsafe {
// Safety: If `AParcel_create` succeeds, it always returns
// a valid pointer. If it fails, the process will crash.
sys::AParcel_create()
};
- assert!(!ptr.is_null());
- Self { ptr }
- }
-
- /// Convert the provided parcel to an owned parcel, or return `None` if it
- /// is borrowed.
- pub fn try_from(parcel: Parcel) -> Option<OwnedParcel> {
- match &parcel {
- Parcel::Owned(ptr) => {
- let ptr = *ptr;
- std::mem::forget(parcel);
- Some(OwnedParcel { ptr })
- }
- Parcel::Borrowed(_) => None,
+ Self {
+ ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer")
}
}
@@ -107,108 +94,43 @@
///
/// Additionally, the caller must guarantee that it is valid to take
/// ownership of the AParcel object. All future access to the AParcel
- /// must happen through this `OwnedParcel`.
+ /// must happen through this `Parcel`.
///
- /// Because `OwnedParcel` implements `Send`, the pointer must never point
- /// to any thread-local data, e.g., a variable on the stack, either directly
- /// or indirectly.
- pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<OwnedParcel> {
- ptr.as_mut().map(|ptr| Self { ptr })
+ /// Because `Parcel` implements `Send`, the pointer must never point to any
+ /// thread-local data, e.g., a variable on the stack, either directly or
+ /// indirectly.
+ pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<Parcel> {
+ NonNull::new(ptr).map(|ptr| Self { ptr })
}
/// Consume the parcel, transferring ownership to the caller.
pub(crate) fn into_raw(self) -> *mut sys::AParcel {
- let ptr = self.ptr;
+ let ptr = self.ptr.as_ptr();
let _ = ManuallyDrop::new(self);
ptr
}
- /// Convert this `OwnedParcel` into an owned `Parcel`.
- pub fn into_parcel(self) -> Parcel {
- Parcel::Owned(self.into_raw())
- }
-
/// Get a borrowed view into the contents of this `Parcel`.
pub fn borrowed(&mut self) -> BorrowedParcel<'_> {
+ // Safety: The raw pointer is a valid pointer to an AParcel, and the
+ // lifetime of the returned `BorrowedParcel` is tied to `self`, so the
+ // borrow checker will ensure that the `AParcel` can only be accessed
+ // via the `BorrowParcel` until it goes out of scope.
BorrowedParcel {
- inner: Parcel::Borrowed(self.ptr),
+ ptr: self.ptr,
_lifetime: PhantomData,
}
}
-}
-impl Default for OwnedParcel {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl Clone for OwnedParcel {
- fn clone(&self) -> Self {
- let mut new_parcel = Self::new();
- new_parcel
- .borrowed()
- .append_all_from(&Parcel::Borrowed(self.ptr))
- .expect("Failed to append from Parcel");
- new_parcel
- }
-}
-
-impl<'a> std::ops::Deref for BorrowedParcel<'a> {
- type Target = Parcel;
- fn deref(&self) -> &Parcel {
- &self.inner
- }
-}
-impl<'a> std::ops::DerefMut for BorrowedParcel<'a> {
- fn deref_mut(&mut self) -> &mut Parcel {
- &mut self.inner
- }
-}
-
-/// # Safety
-///
-/// The `Parcel` constructors guarantee that a `Parcel` object will always
-/// contain a valid pointer to an `AParcel`.
-unsafe impl AsNative<sys::AParcel> for Parcel {
- fn as_native(&self) -> *const sys::AParcel {
- match *self {
- Self::Owned(x) | Self::Borrowed(x) => x,
+ /// Get an immutable borrowed view into the contents of this `Parcel`.
+ pub fn borrowed_ref(&self) -> &BorrowedParcel<'_> {
+ // Safety: Parcel and BorrowedParcel are both represented in the same
+ // way as a NonNull<sys::AParcel> due to their use of repr(transparent),
+ // so casting references as done here is valid.
+ unsafe {
+ &*(self as *const Parcel as *const BorrowedParcel<'_>)
}
}
-
- fn as_native_mut(&mut self) -> *mut sys::AParcel {
- match *self {
- Self::Owned(x) | Self::Borrowed(x) => x,
- }
- }
-}
-
-impl Parcel {
- /// Create a new empty `Parcel`.
- ///
- /// Creates a new owned empty parcel that can be written to
- /// using the serialization methods and appended to and
- /// from using `append_from` and `append_from_all`.
- pub fn new() -> Parcel {
- let parcel = unsafe {
- // Safety: If `AParcel_create` succeeds, it always returns
- // a valid pointer. If it fails, the process will crash.
- sys::AParcel_create()
- };
- assert!(!parcel.is_null());
- Self::Owned(parcel)
- }
-
- /// Create a borrowed reference to a parcel object from a raw pointer.
- ///
- /// # Safety
- ///
- /// This constructor is safe if the raw pointer parameter is either null
- /// (resulting in `None`), or a valid pointer to an `AParcel` object.
- pub(crate) unsafe fn borrowed(ptr: *mut sys::AParcel) -> Option<Parcel> {
- ptr.as_mut().map(|ptr| Self::Borrowed(ptr))
- }
}
impl Default for Parcel {
@@ -221,14 +143,77 @@
fn clone(&self) -> Self {
let mut new_parcel = Self::new();
new_parcel
- .append_all_from(self)
+ .borrowed()
+ .append_all_from(self.borrowed_ref())
.expect("Failed to append from Parcel");
new_parcel
}
}
+impl<'a> BorrowedParcel<'a> {
+ /// Create a borrowed reference to a parcel object from a raw pointer.
+ ///
+ /// # Safety
+ ///
+ /// This constructor is safe if the raw pointer parameter is either null
+ /// (resulting in `None`), or a valid pointer to an `AParcel` object.
+ ///
+ /// Since the raw pointer is not restricted by any lifetime, the lifetime on
+ /// the returned `BorrowedParcel` object can be chosen arbitrarily by the
+ /// caller. The caller must ensure it is valid to mutably borrow the AParcel
+ /// for the duration of the lifetime that the caller chooses. Note that
+ /// since this is a mutable borrow, it must have exclusive access to the
+ /// AParcel for the duration of the borrow.
+ pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<BorrowedParcel<'a>> {
+ Some(Self {
+ ptr: NonNull::new(ptr)?,
+ _lifetime: PhantomData,
+ })
+ }
+
+ /// Get a sub-reference to this reference to the parcel.
+ pub fn reborrow(&mut self) -> BorrowedParcel<'_> {
+ // Safety: The raw pointer is a valid pointer to an AParcel, and the
+ // lifetime of the returned `BorrowedParcel` is tied to `self`, so the
+ // borrow checker will ensure that the `AParcel` can only be accessed
+ // via the `BorrowParcel` until it goes out of scope.
+ BorrowedParcel {
+ ptr: self.ptr,
+ _lifetime: PhantomData,
+ }
+ }
+}
+
+/// # Safety
+///
+/// The `Parcel` constructors guarantee that a `Parcel` object will always
+/// contain a valid pointer to an `AParcel`.
+unsafe impl AsNative<sys::AParcel> for Parcel {
+ fn as_native(&self) -> *const sys::AParcel {
+ self.ptr.as_ptr()
+ }
+
+ fn as_native_mut(&mut self) -> *mut sys::AParcel {
+ self.ptr.as_ptr()
+ }
+}
+
+/// # Safety
+///
+/// The `BorrowedParcel` constructors guarantee that a `BorrowedParcel` object
+/// will always contain a valid pointer to an `AParcel`.
+unsafe impl<'a> AsNative<sys::AParcel> for BorrowedParcel<'a> {
+ fn as_native(&self) -> *const sys::AParcel {
+ self.ptr.as_ptr()
+ }
+
+ fn as_native_mut(&mut self) -> *mut sys::AParcel {
+ self.ptr.as_ptr()
+ }
+}
+
// Data serialization methods
-impl Parcel {
+impl<'a> BorrowedParcel<'a> {
/// Data written to parcelable is zero'd before being deleted or reallocated.
pub fn mark_sensitive(&mut self) {
unsafe {
@@ -237,12 +222,12 @@
}
}
- /// Write a type that implements [`Serialize`] to the `Parcel`.
+ /// Write a type that implements [`Serialize`] to the parcel.
pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
parcelable.serialize(self)
}
- /// Writes the length of a slice to the `Parcel`.
+ /// Writes the length of a slice to the parcel.
///
/// This is used in AIDL-generated client side code to indicate the
/// allocated space for an output array parameter.
@@ -255,7 +240,7 @@
}
}
- /// Perform a series of writes to the `Parcel`, prepended with the length
+ /// Perform a series of writes to the parcel, prepended with the length
/// (in bytes) of the written data.
///
/// The length `0i32` will be written to the parcel first, followed by the
@@ -269,7 +254,7 @@
///
/// ```
/// # use binder::{Binder, Interface, Parcel};
- /// # let mut parcel = Parcel::Owned(std::ptr::null_mut());
+ /// # let mut parcel = Parcel::new();
/// parcel.sized_write(|subparcel| {
/// subparcel.write(&1u32)?;
/// subparcel.write(&2u32)?;
@@ -283,14 +268,14 @@
/// [16i32, 1u32, 2u32, 3u32]
/// ```
pub fn sized_write<F>(&mut self, f: F) -> Result<()>
- where for<'a>
- F: Fn(&'a WritableSubParcel<'a>) -> Result<()>
+ where
+ for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
{
let start = self.get_data_position();
self.write(&0i32)?;
{
- let subparcel = WritableSubParcel(RefCell::new(self));
- f(&subparcel)?;
+ let mut subparcel = WritableSubParcel(self.reborrow());
+ f(&mut subparcel)?;
}
let end = self.get_data_position();
unsafe {
@@ -307,8 +292,8 @@
/// Returns the current position in the parcel data.
pub fn get_data_position(&self) -> i32 {
unsafe {
- // Safety: `Parcel` always contains a valid pointer to an `AParcel`,
- // and this call is otherwise safe.
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
+ // `AParcel`, and this call is otherwise safe.
sys::AParcel_getDataPosition(self.as_native())
}
}
@@ -316,8 +301,8 @@
/// Returns the total size of the parcel.
pub fn get_data_size(&self) -> i32 {
unsafe {
- // Safety: `Parcel` always contains a valid pointer to an `AParcel`,
- // and this call is otherwise safe.
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
+ // `AParcel`, and this call is otherwise safe.
sys::AParcel_getDataSize(self.as_native())
}
}
@@ -335,11 +320,11 @@
status_result(sys::AParcel_setDataPosition(self.as_native(), pos))
}
- /// Append a subset of another `Parcel`.
+ /// Append a subset of another parcel.
///
/// This appends `size` bytes of data from `other` starting at offset
- /// `start` to the current `Parcel`, or returns an error if not possible.
- pub fn append_from(&mut self, other: &Self, start: i32, size: i32) -> Result<()> {
+ /// `start` to the current parcel, or returns an error if not possible.
+ pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
let status = unsafe {
// Safety: `Parcel::appendFrom` from C++ checks that `start`
// and `size` are in bounds, and returns an error otherwise.
@@ -354,33 +339,125 @@
status_result(status)
}
- /// Append the contents of another `Parcel`.
- pub fn append_all_from(&mut self, other: &Self) -> Result<()> {
- self.append_from(other, 0, other.get_data_size())
+ /// Append the contents of another parcel.
+ pub fn append_all_from(&mut self, other: &impl AsNative<sys::AParcel>) -> Result<()> {
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
+ // `AParcel`, and this call is otherwise safe.
+ let size = unsafe { sys::AParcel_getDataSize(other.as_native()) };
+ self.append_from(other, 0, size)
}
}
-/// A segment of a writable parcel, used for [`Parcel::sized_write`].
-pub struct WritableSubParcel<'a>(RefCell<&'a mut Parcel>);
+/// A segment of a writable parcel, used for [`BorrowedParcel::sized_write`].
+pub struct WritableSubParcel<'a>(BorrowedParcel<'a>);
impl<'a> WritableSubParcel<'a> {
/// Write a type that implements [`Serialize`] to the sub-parcel.
- pub fn write<S: Serialize + ?Sized>(&self, parcelable: &S) -> Result<()> {
- parcelable.serialize(&mut *self.0.borrow_mut())
+ pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
+ parcelable.serialize(&mut self.0)
+ }
+}
+
+impl Parcel {
+ /// Data written to parcelable is zero'd before being deleted or reallocated.
+ pub fn mark_sensitive(&mut self) {
+ self.borrowed().mark_sensitive()
+ }
+
+ /// Write a type that implements [`Serialize`] to the parcel.
+ pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
+ self.borrowed().write(parcelable)
+ }
+
+ /// Writes the length of a slice to the parcel.
+ ///
+ /// This is used in AIDL-generated client side code to indicate the
+ /// allocated space for an output array parameter.
+ pub fn write_slice_size<T>(&mut self, slice: Option<&[T]>) -> Result<()> {
+ self.borrowed().write_slice_size(slice)
+ }
+
+ /// Perform a series of writes to the parcel, prepended with the length
+ /// (in bytes) of the written data.
+ ///
+ /// The length `0i32` will be written to the parcel first, followed by the
+ /// writes performed by the callback. The initial length will then be
+ /// updated to the length of all data written by the callback, plus the
+ /// size of the length elemement itself (4 bytes).
+ ///
+ /// # Examples
+ ///
+ /// After the following call:
+ ///
+ /// ```
+ /// # use binder::{Binder, Interface, Parcel};
+ /// # let mut parcel = Parcel::new();
+ /// parcel.sized_write(|subparcel| {
+ /// subparcel.write(&1u32)?;
+ /// subparcel.write(&2u32)?;
+ /// subparcel.write(&3u32)
+ /// });
+ /// ```
+ ///
+ /// `parcel` will contain the following:
+ ///
+ /// ```ignore
+ /// [16i32, 1u32, 2u32, 3u32]
+ /// ```
+ pub fn sized_write<F>(&mut self, f: F) -> Result<()>
+ where
+ for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
+ {
+ self.borrowed().sized_write(f)
+ }
+
+ /// Returns the current position in the parcel data.
+ pub fn get_data_position(&self) -> i32 {
+ self.borrowed_ref().get_data_position()
+ }
+
+ /// Returns the total size of the parcel.
+ pub fn get_data_size(&self) -> i32 {
+ self.borrowed_ref().get_data_size()
+ }
+
+ /// Move the current read/write position in the parcel.
+ ///
+ /// # Safety
+ ///
+ /// This method is safe if `pos` is less than the current size of the parcel
+ /// data buffer. Otherwise, we are relying on correct bounds checking in the
+ /// Parcel C++ code on every subsequent read or write to this parcel. If all
+ /// accesses are bounds checked, this call is still safe, but we can't rely
+ /// on that.
+ pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
+ self.borrowed_ref().set_data_position(pos)
+ }
+
+ /// Append a subset of another parcel.
+ ///
+ /// This appends `size` bytes of data from `other` starting at offset
+ /// `start` to the current parcel, or returns an error if not possible.
+ pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+ self.borrowed().append_from(other, start, size)
+ }
+
+ /// Append the contents of another parcel.
+ pub fn append_all_from(&mut self, other: &impl AsNative<sys::AParcel>) -> Result<()> {
+ self.borrowed().append_all_from(other)
}
}
// Data deserialization methods
-impl Parcel {
- /// Attempt to read a type that implements [`Deserialize`] from this
- /// `Parcel`.
+impl<'a> BorrowedParcel<'a> {
+ /// Attempt to read a type that implements [`Deserialize`] from this parcel.
pub fn read<D: Deserialize>(&self) -> Result<D> {
D::deserialize(self)
}
- /// Attempt to read a type that implements [`Deserialize`] from this
- /// `Parcel` onto an existing value. This operation will overwrite the old
- /// value partially or completely, depending on how much data is available.
+ /// Attempt to read a type that implements [`Deserialize`] from this parcel
+ /// onto an existing value. This operation will overwrite the old value
+ /// partially or completely, depending on how much data is available.
pub fn read_onto<D: Deserialize>(&self, x: &mut D) -> Result<()> {
x.deserialize_from(self)
}
@@ -413,9 +490,9 @@
/// });
/// ```
///
- pub fn sized_read<F>(&self, mut f: F) -> Result<()>
+ pub fn sized_read<F>(&self, f: F) -> Result<()>
where
- for<'a> F: FnMut(ReadableSubParcel<'a>) -> Result<()>
+ for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
{
let start = self.get_data_position();
let parcelable_size: i32 = self.read()?;
@@ -430,7 +507,10 @@
}
let subparcel = ReadableSubParcel {
- parcel: self,
+ parcel: BorrowedParcel {
+ ptr: self.ptr,
+ _lifetime: PhantomData,
+ },
end_position: end,
};
f(subparcel)?;
@@ -444,8 +524,8 @@
Ok(())
}
- /// Read a vector size from the `Parcel` and resize the given output vector
- /// to be correctly sized for that amount of data.
+ /// Read a vector size from the parcel and resize the given output vector to
+ /// be correctly sized for that amount of data.
///
/// This method is used in AIDL-generated server side code for methods that
/// take a mutable slice reference parameter.
@@ -463,7 +543,7 @@
Ok(())
}
- /// Read a vector size from the `Parcel` and either create a correctly sized
+ /// Read a vector size from the parcel and either create a correctly sized
/// vector for that amount of data or set the output parameter to None if
/// the vector should be null.
///
@@ -491,7 +571,7 @@
/// A segment of a readable parcel, used for [`Parcel::sized_read`].
pub struct ReadableSubParcel<'a> {
- parcel: &'a Parcel,
+ parcel: BorrowedParcel<'a>,
end_position: i32,
}
@@ -501,7 +581,7 @@
// The caller should have checked this,
// but it can't hurt to double-check
assert!(self.has_more_data());
- D::deserialize(self.parcel)
+ D::deserialize(&self.parcel)
}
/// Check if the sub-parcel has more data to read
@@ -510,11 +590,82 @@
}
}
-// Internal APIs
impl Parcel {
+ /// Attempt to read a type that implements [`Deserialize`] from this parcel.
+ pub fn read<D: Deserialize>(&self) -> Result<D> {
+ self.borrowed_ref().read()
+ }
+
+ /// Attempt to read a type that implements [`Deserialize`] from this parcel
+ /// onto an existing value. This operation will overwrite the old value
+ /// partially or completely, depending on how much data is available.
+ pub fn read_onto<D: Deserialize>(&self, x: &mut D) -> Result<()> {
+ self.borrowed_ref().read_onto(x)
+ }
+
+ /// Safely read a sized parcelable.
+ ///
+ /// Read the size of a parcelable, compute the end position
+ /// of that parcelable, then build a sized readable sub-parcel
+ /// and call a closure with the sub-parcel as its parameter.
+ /// The closure can keep reading data from the sub-parcel
+ /// until it runs out of input data. The closure is responsible
+ /// for calling [`ReadableSubParcel::has_more_data`] to check for
+ /// more data before every read, at least until Rust generators
+ /// are stabilized.
+ /// After the closure returns, skip to the end of the current
+ /// parcelable regardless of how much the closure has read.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// let mut parcelable = Default::default();
+ /// parcel.sized_read(|subparcel| {
+ /// if subparcel.has_more_data() {
+ /// parcelable.a = subparcel.read()?;
+ /// }
+ /// if subparcel.has_more_data() {
+ /// parcelable.b = subparcel.read()?;
+ /// }
+ /// Ok(())
+ /// });
+ /// ```
+ ///
+ pub fn sized_read<F>(&self, f: F) -> Result<()>
+ where
+ for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+ {
+ self.borrowed_ref().sized_read(f)
+ }
+
+ /// Read a vector size from the parcel and resize the given output vector to
+ /// be correctly sized for that amount of data.
+ ///
+ /// This method is used in AIDL-generated server side code for methods that
+ /// take a mutable slice reference parameter.
+ pub fn resize_out_vec<D: Default + Deserialize>(&self, out_vec: &mut Vec<D>) -> Result<()> {
+ self.borrowed_ref().resize_out_vec(out_vec)
+ }
+
+ /// Read a vector size from the parcel and either create a correctly sized
+ /// vector for that amount of data or set the output parameter to None if
+ /// the vector should be null.
+ ///
+ /// This method is used in AIDL-generated server side code for methods that
+ /// take a mutable slice reference parameter.
+ pub fn resize_nullable_out_vec<D: Default + Deserialize>(
+ &self,
+ out_vec: &mut Option<Vec<D>>,
+ ) -> Result<()> {
+ self.borrowed_ref().resize_nullable_out_vec(out_vec)
+ }
+}
+
+// Internal APIs
+impl<'a> BorrowedParcel<'a> {
pub(crate) fn write_binder(&mut self, binder: Option<&SpIBinder>) -> Result<()> {
unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
// `AParcel`. `AsNative` for `Option<SpIBinder`> will either return
// null or a valid pointer to an `AIBinder`, both of which are
// valid, safe inputs to `AParcel_writeStrongBinder`.
@@ -534,7 +685,7 @@
pub(crate) fn read_binder(&self) -> Result<Option<SpIBinder>> {
let mut binder = ptr::null_mut();
let status = unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
// `AParcel`. We pass a valid, mutable out pointer to the `binder`
// parameter. After this call, `binder` will be either null or a
// valid pointer to an `AIBinder` owned by the caller.
@@ -554,25 +705,11 @@
impl Drop for Parcel {
fn drop(&mut self) {
// Run the C++ Parcel complete object destructor
- if let Self::Owned(ptr) = *self {
- unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. If we own the parcel, we can safely delete it
- // here.
- sys::AParcel_delete(ptr)
- }
- }
- }
-}
-
-impl Drop for OwnedParcel {
- fn drop(&mut self) {
- // Run the C++ Parcel complete object destructor
unsafe {
- // Safety: `OwnedParcel` always contains a valid pointer to an
+ // Safety: `Parcel` always contains a valid pointer to an
// `AParcel`. Since we own the parcel, we can safely delete it
// here.
- sys::AParcel_delete(self.ptr)
+ sys::AParcel_delete(self.ptr.as_ptr())
}
}
}
@@ -584,9 +721,9 @@
}
}
-impl fmt::Debug for OwnedParcel {
+impl<'a> fmt::Debug for BorrowedParcel<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("OwnedParcel")
+ f.debug_struct("BorrowedParcel")
.finish()
}
}
@@ -608,7 +745,7 @@
assert_eq!(parcel.read::<Option<String>>(), Ok(None));
assert_eq!(parcel.read::<String>(), Err(StatusCode::UNEXPECTED_NULL));
- assert_eq!(parcel.read_binder().err(), Some(StatusCode::BAD_TYPE));
+ assert_eq!(parcel.borrowed_ref().read_binder().err(), Some(StatusCode::BAD_TYPE));
parcel.write(&1i32).unwrap();
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 8bcc5d0..b0dea94 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -15,7 +15,7 @@
*/
use super::{
- Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray,
+ Deserialize, DeserializeArray, DeserializeOption, BorrowedParcel, Serialize, SerializeArray,
SerializeOption,
};
use crate::binder::AsNative;
@@ -61,7 +61,7 @@
}
impl Serialize for ParcelFileDescriptor {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
let fd = self.0.as_raw_fd();
let status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -78,7 +78,7 @@
impl SerializeArray for ParcelFileDescriptor {}
impl SerializeOption for ParcelFileDescriptor {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
if let Some(f) = this {
f.serialize(parcel)
} else {
@@ -95,7 +95,7 @@
}
impl DeserializeOption for ParcelFileDescriptor {
- fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
let mut fd = -1i32;
unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -125,7 +125,7 @@
}
impl Deserialize for ParcelFileDescriptor {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
Deserialize::deserialize(parcel)
.transpose()
.unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index db9d8b0..9007cba 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -16,14 +16,14 @@
use crate::binder::{AsNative, FromIBinder, Stability, Strong};
use crate::error::{status_result, status_t, Result, Status, StatusCode};
-use crate::parcel::Parcel;
+use crate::parcel::BorrowedParcel;
use crate::proxy::SpIBinder;
use crate::sys;
use std::convert::{TryFrom, TryInto};
use std::ffi::c_void;
use std::os::raw::{c_char, c_ulong};
-use std::mem::{self, MaybeUninit};
+use std::mem::{self, MaybeUninit, ManuallyDrop};
use std::ptr;
use std::slice;
@@ -39,7 +39,7 @@
/// `Serialize::serialize` and its variants are generally
/// preferred over this function, since the former also
/// prepend a header.
- fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()>;
+ fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>;
/// Internal deserialization function for parcelables.
///
@@ -47,26 +47,26 @@
/// `Deserialize::deserialize` and its variants are generally
/// preferred over this function, since the former also
/// parse the additional header.
- fn read_from_parcel(&mut self, parcel: &Parcel) -> Result<()>;
+ fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()>;
}
/// A struct whose instances can be written to a [`Parcel`].
// Might be able to hook this up as a serde backend in the future?
pub trait Serialize {
/// Serialize this instance into the given [`Parcel`].
- fn serialize(&self, parcel: &mut Parcel) -> Result<()>;
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>;
}
/// A struct whose instances can be restored from a [`Parcel`].
// Might be able to hook this up as a serde backend in the future?
pub trait Deserialize: Sized {
/// Deserialize an instance from the given [`Parcel`].
- fn deserialize(parcel: &Parcel) -> Result<Self>;
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self>;
/// Deserialize an instance from the given [`Parcel`] onto the
/// current object. This operation will overwrite the old value
/// partially or completely, depending on how much data is available.
- fn deserialize_from(&mut self, parcel: &Parcel) -> Result<()> {
+ fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
*self = Self::deserialize(parcel)?;
Ok(())
}
@@ -80,8 +80,8 @@
// We want the default implementation for most types, but an override for
// a few special ones like `readByteArray` for `u8`.
pub trait SerializeArray: Serialize + Sized {
- /// Serialize an array of this type into the given [`Parcel`].
- fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+ /// Serialize an array of this type into the given parcel.
+ fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
let res = unsafe {
// Safety: Safe FFI, slice will always be a safe pointer to pass.
sys::AParcel_writeParcelableArray(
@@ -111,7 +111,7 @@
let slice: &[T] = slice::from_raw_parts(array.cast(), index+1);
- let mut parcel = match Parcel::borrowed(parcel) {
+ let mut parcel = match BorrowedParcel::from_raw(parcel) {
None => return StatusCode::UNEXPECTED_NULL as status_t,
Some(p) => p,
};
@@ -126,8 +126,8 @@
/// Defaults to calling Deserialize::deserialize() manually for every element,
/// but can be overridden for custom implementations like `readByteArray`.
pub trait DeserializeArray: Deserialize {
- /// Deserialize an array of type from the given [`Parcel`].
- fn deserialize_array(parcel: &Parcel) -> Result<Option<Vec<Self>>> {
+ /// Deserialize an array of type from the given parcel.
+ fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
let res = unsafe {
// Safety: Safe FFI, vec is the correct opaque type expected by
@@ -173,7 +173,7 @@
None => return StatusCode::BAD_INDEX as status_t,
};
- let parcel = match Parcel::borrowed(parcel as *mut _) {
+ let parcel = match BorrowedParcel::from_raw(parcel as *mut _) {
None => return StatusCode::UNEXPECTED_NULL as status_t,
Some(p) => p,
};
@@ -205,8 +205,8 @@
// We also use it to provide a default implementation for AIDL-generated
// parcelables.
pub trait SerializeOption: Serialize {
- /// Serialize an Option of this type into the given [`Parcel`].
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ /// Serialize an Option of this type into the given parcel.
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
if let Some(inner) = this {
parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
parcel.write(inner)
@@ -218,8 +218,8 @@
/// Helper trait for types that can be nullable when deserialized.
pub trait DeserializeOption: Deserialize {
- /// Deserialize an Option of this type from the given [`Parcel`].
- fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+ /// Deserialize an Option of this type from the given parcel.
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
let null: i32 = parcel.read()?;
if null == NULL_PARCELABLE_FLAG {
Ok(None)
@@ -228,10 +228,10 @@
}
}
- /// Deserialize an Option of this type from the given [`Parcel`] onto the
+ /// Deserialize an Option of this type from the given parcel onto the
/// current object. This operation will overwrite the current value
/// partially or completely, depending on how much data is available.
- fn deserialize_option_from(this: &mut Option<Self>, parcel: &Parcel) -> Result<()> {
+ fn deserialize_option_from(this: &mut Option<Self>, parcel: &BorrowedParcel<'_>) -> Result<()> {
*this = Self::deserialize_option(parcel)?;
Ok(())
}
@@ -297,10 +297,23 @@
};
}
+/// Safety: All elements in the vector must be properly initialized.
+unsafe fn vec_assume_init<T>(vec: Vec<MaybeUninit<T>>) -> Vec<T> {
+ // We can convert from Vec<MaybeUninit<T>> to Vec<T> because MaybeUninit<T>
+ // has the same alignment and size as T, so the pointer to the vector
+ // allocation will be compatible.
+ let mut vec = ManuallyDrop::new(vec);
+ Vec::from_raw_parts(
+ vec.as_mut_ptr().cast(),
+ vec.len(),
+ vec.capacity(),
+ )
+}
+
macro_rules! impl_parcelable {
{Serialize, $ty:ty, $write_fn:path} => {
impl Serialize for $ty {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
unsafe {
// Safety: `Parcel` always contains a valid pointer to an
// `AParcel`, and any `$ty` literal value is safe to pass to
@@ -313,7 +326,7 @@
{Deserialize, $ty:ty, $read_fn:path} => {
impl Deserialize for $ty {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
let mut val = Self::default();
unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -329,7 +342,7 @@
{SerializeArray, $ty:ty, $write_array_fn:path} => {
impl SerializeArray for $ty {
- fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+ fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
let status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an
// `AParcel`. If the slice is > 0 length, `slice.as_ptr()`
@@ -353,7 +366,7 @@
{DeserializeArray, $ty:ty, $read_array_fn:path} => {
impl DeserializeArray for $ty {
- fn deserialize_array(parcel: &Parcel) -> Result<Option<Vec<Self>>> {
+ fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
let status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -371,11 +384,8 @@
// Safety: We are assuming that the NDK correctly
// initialized every element of the vector by now, so we
// know that all the MaybeUninits are now properly
- // initialized. We can transmute from Vec<MaybeUninit<T>> to
- // Vec<T> because MaybeUninit<T> has the same alignment and
- // size as T, so the pointer to the vector allocation will
- // be compatible.
- mem::transmute(vec)
+ // initialized.
+ vec.map(|vec| vec_assume_init(vec))
};
Ok(vec)
}
@@ -443,19 +453,19 @@
impl DeserializeArray for bool {}
impl Serialize for u8 {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
(*self as i8).serialize(parcel)
}
}
impl Deserialize for u8 {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
i8::deserialize(parcel).map(|v| v as u8)
}
}
impl SerializeArray for u8 {
- fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+ fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
let status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an
// `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
@@ -474,19 +484,19 @@
}
impl Serialize for i16 {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
(*self as u16).serialize(parcel)
}
}
impl Deserialize for i16 {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
u16::deserialize(parcel).map(|v| v as i16)
}
}
impl SerializeArray for i16 {
- fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+ fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
let status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an
// `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
@@ -505,7 +515,7 @@
}
impl SerializeOption for str {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
match this {
None => unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -541,7 +551,7 @@
}
impl Serialize for str {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
Some(self).serialize(parcel)
}
}
@@ -549,7 +559,7 @@
impl SerializeArray for &str {}
impl Serialize for String {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
Some(self.as_str()).serialize(parcel)
}
}
@@ -557,13 +567,13 @@
impl SerializeArray for String {}
impl SerializeOption for String {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeOption::serialize_option(this.map(String::as_str), parcel)
}
}
impl Deserialize for Option<String> {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
let mut vec: Option<Vec<u8>> = None;
let status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an `AParcel`.
@@ -591,7 +601,7 @@
impl DeserializeArray for Option<String> {}
impl Deserialize for String {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
Deserialize::deserialize(parcel)
.transpose()
.unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
@@ -601,19 +611,19 @@
impl DeserializeArray for String {}
impl<T: SerializeArray> Serialize for [T] {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeArray::serialize_array(self, parcel)
}
}
impl<T: SerializeArray> Serialize for Vec<T> {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeArray::serialize_array(&self[..], parcel)
}
}
impl<T: SerializeArray> SerializeOption for [T] {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
if let Some(v) = this {
SerializeArray::serialize_array(v, parcel)
} else {
@@ -623,13 +633,13 @@
}
impl<T: SerializeArray> SerializeOption for Vec<T> {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeOption::serialize_option(this.map(Vec::as_slice), parcel)
}
}
impl<T: DeserializeArray> Deserialize for Vec<T> {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
DeserializeArray::deserialize_array(parcel)
.transpose()
.unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
@@ -637,25 +647,25 @@
}
impl<T: DeserializeArray> DeserializeOption for Vec<T> {
- fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
DeserializeArray::deserialize_array(parcel)
}
}
impl Serialize for Stability {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
i32::from(*self).serialize(parcel)
}
}
impl Deserialize for Stability {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
i32::deserialize(parcel).and_then(Stability::try_from)
}
}
impl Serialize for Status {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
unsafe {
// Safety: `Parcel` always contains a valid pointer to an `AParcel`
// and `Status` always contains a valid pointer to an `AStatus`, so
@@ -670,7 +680,7 @@
}
impl Deserialize for Status {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
let mut status_ptr = ptr::null_mut();
let ret_status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -691,13 +701,13 @@
}
impl<T: Serialize + FromIBinder + ?Sized> Serialize for Strong<T> {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
Serialize::serialize(&**self, parcel)
}
}
impl<T: SerializeOption + FromIBinder + ?Sized> SerializeOption for Strong<T> {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeOption::serialize_option(this.map(|b| &**b), parcel)
}
}
@@ -705,14 +715,14 @@
impl<T: Serialize + FromIBinder + ?Sized> SerializeArray for Strong<T> {}
impl<T: FromIBinder + ?Sized> Deserialize for Strong<T> {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
let ibinder: SpIBinder = parcel.read()?;
FromIBinder::try_from(ibinder)
}
}
impl<T: FromIBinder + ?Sized> DeserializeOption for Strong<T> {
- fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
let ibinder: Option<SpIBinder> = parcel.read()?;
ibinder.map(FromIBinder::try_from).transpose()
}
@@ -722,29 +732,29 @@
// We need these to support Option<&T> for all T
impl<T: Serialize + ?Sized> Serialize for &T {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
Serialize::serialize(*self, parcel)
}
}
impl<T: SerializeOption + ?Sized> SerializeOption for &T {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeOption::serialize_option(this.copied(), parcel)
}
}
impl<T: SerializeOption> Serialize for Option<T> {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeOption::serialize_option(self.as_ref(), parcel)
}
}
impl<T: DeserializeOption> Deserialize for Option<T> {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
DeserializeOption::deserialize_option(parcel)
}
- fn deserialize_from(&mut self, parcel: &Parcel) -> Result<()> {
+ fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
DeserializeOption::deserialize_option_from(self, parcel)
}
}
@@ -762,7 +772,7 @@
impl $crate::parcel::Serialize for $parcelable {
fn serialize(
&self,
- parcel: &mut $crate::parcel::Parcel,
+ parcel: &mut $crate::parcel::BorrowedParcel<'_>,
) -> $crate::Result<()> {
<Self as $crate::parcel::SerializeOption>::serialize_option(
Some(self),
@@ -776,7 +786,7 @@
impl $crate::parcel::SerializeOption for $parcelable {
fn serialize_option(
this: Option<&Self>,
- parcel: &mut $crate::parcel::Parcel,
+ parcel: &mut $crate::parcel::BorrowedParcel<'_>,
) -> $crate::Result<()> {
if let Some(this) = this {
use $crate::parcel::Parcelable;
@@ -796,13 +806,12 @@
/// `Deserialize`, `DeserializeArray` and `DeserializeOption` for
/// structured parcelables. The target type must implement the
/// `Parcelable` trait.
-/// ```
#[macro_export]
macro_rules! impl_deserialize_for_parcelable {
($parcelable:ident) => {
impl $crate::parcel::Deserialize for $parcelable {
fn deserialize(
- parcel: &$crate::parcel::Parcel,
+ parcel: &$crate::parcel::BorrowedParcel<'_>,
) -> $crate::Result<Self> {
$crate::parcel::DeserializeOption::deserialize_option(parcel)
.transpose()
@@ -810,7 +819,7 @@
}
fn deserialize_from(
&mut self,
- parcel: &$crate::parcel::Parcel,
+ parcel: &$crate::parcel::BorrowedParcel<'_>,
) -> $crate::Result<()> {
let status: i32 = parcel.read()?;
if status == $crate::parcel::NULL_PARCELABLE_FLAG {
@@ -826,7 +835,7 @@
impl $crate::parcel::DeserializeOption for $parcelable {
fn deserialize_option(
- parcel: &$crate::parcel::Parcel,
+ parcel: &$crate::parcel::BorrowedParcel<'_>,
) -> $crate::Result<Option<Self>> {
let mut result = None;
Self::deserialize_option_from(&mut result, parcel)?;
@@ -834,7 +843,7 @@
}
fn deserialize_option_from(
this: &mut Option<Self>,
- parcel: &$crate::parcel::Parcel,
+ parcel: &$crate::parcel::BorrowedParcel<'_>,
) -> $crate::Result<()> {
let status: i32 = parcel.read()?;
if status == $crate::parcel::NULL_PARCELABLE_FLAG {
@@ -851,326 +860,332 @@
}
impl<T: Serialize> Serialize for Box<T> {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
Serialize::serialize(&**self, parcel)
}
}
impl<T: Deserialize> Deserialize for Box<T> {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
Deserialize::deserialize(parcel).map(Box::new)
}
}
impl<T: SerializeOption> SerializeOption for Box<T> {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeOption::serialize_option(this.map(|inner| &**inner), parcel)
}
}
impl<T: DeserializeOption> DeserializeOption for Box<T> {
- fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
DeserializeOption::deserialize_option(parcel).map(|t| t.map(Box::new))
}
}
-#[test]
-fn test_custom_parcelable() {
- struct Custom(u32, bool, String, Vec<String>);
+#[cfg(test)]
+mod tests {
+ use crate::Parcel;
+ use super::*;
- impl Serialize for Custom {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
- self.0.serialize(parcel)?;
- self.1.serialize(parcel)?;
- self.2.serialize(parcel)?;
- self.3.serialize(parcel)
+ #[test]
+ fn test_custom_parcelable() {
+ struct Custom(u32, bool, String, Vec<String>);
+
+ impl Serialize for Custom {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ self.0.serialize(parcel)?;
+ self.1.serialize(parcel)?;
+ self.2.serialize(parcel)?;
+ self.3.serialize(parcel)
+ }
}
- }
- impl Deserialize for Custom {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
- Ok(Custom(
- parcel.read()?,
- parcel.read()?,
- parcel.read()?,
- parcel.read::<Option<Vec<String>>>()?.unwrap(),
- ))
+ impl Deserialize for Custom {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
+ Ok(Custom(
+ parcel.read()?,
+ parcel.read()?,
+ parcel.read()?,
+ parcel.read::<Option<Vec<String>>>()?.unwrap(),
+ ))
+ }
}
+
+ let string8 = "Custom Parcelable".to_string();
+
+ let s1 = "str1".to_string();
+ let s2 = "str2".to_string();
+ let s3 = "str3".to_string();
+
+ let strs = vec![s1, s2, s3];
+
+ let custom = Custom(123_456_789, true, string8, strs);
+
+ let mut parcel = Parcel::new();
+ let start = parcel.get_data_position();
+
+ assert!(custom.serialize(&mut parcel.borrowed()).is_ok());
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let custom2 = Custom::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(custom2.0, 123_456_789);
+ assert!(custom2.1);
+ assert_eq!(custom2.2, custom.2);
+ assert_eq!(custom2.3, custom.3);
}
- let string8 = "Custom Parcelable".to_string();
+ #[test]
+ #[allow(clippy::excessive_precision)]
+ fn test_slice_parcelables() {
+ let bools = [true, false, false, true];
- let s1 = "str1".to_string();
- let s2 = "str2".to_string();
- let s3 = "str3".to_string();
+ let mut parcel = Parcel::new();
+ let start = parcel.get_data_position();
- let strs = vec![s1, s2, s3];
+ assert!(bools.serialize(&mut parcel.borrowed()).is_ok());
- let custom = Custom(123_456_789, true, string8, strs);
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
- let mut parcel = Parcel::new();
- let start = parcel.get_data_position();
+ assert_eq!(parcel.read::<u32>().unwrap(), 4);
+ assert_eq!(parcel.read::<u32>().unwrap(), 1);
+ assert_eq!(parcel.read::<u32>().unwrap(), 0);
+ assert_eq!(parcel.read::<u32>().unwrap(), 0);
+ assert_eq!(parcel.read::<u32>().unwrap(), 1);
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
- assert!(custom.serialize(&mut parcel).is_ok());
+ let vec = Vec::<bool>::deserialize(parcel.borrowed_ref()).unwrap();
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
+ assert_eq!(vec, [true, false, false, true]);
+
+ let u8s = [101u8, 255, 42, 117];
+
+ let mut parcel = Parcel::new();
+ let start = parcel.get_data_position();
+
+ assert!(parcel.write(&u8s[..]).is_ok());
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x752aff65); // bytes
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<u8>::deserialize(parcel.borrowed_ref()).unwrap();
+ assert_eq!(vec, [101, 255, 42, 117]);
+
+ let i8s = [-128i8, 127, 42, -117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert!(parcel.write(&i8s[..]).is_ok());
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x8b2a7f80); // bytes
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<u8>::deserialize(parcel.borrowed_ref()).unwrap();
+ assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]);
+
+ let u16s = [u16::max_value(), 12_345, 42, 117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(u16s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+ assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::max_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
+ assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+ assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<u16>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]);
+
+ let i16s = [i16::max_value(), i16::min_value(), 42, -117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(i16s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::max_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+ assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -117
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<i16>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]);
+
+ let u32s = [u32::max_value(), 12_345, 42, 117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(u32s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+ assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::max_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
+ assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+ assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<u32>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]);
+
+ let i32s = [i32::max_value(), i32::min_value(), 42, -117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(i32s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::max_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+ assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -117
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<i32>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]);
+
+ let u64s = [u64::max_value(), 12_345, 42, 117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(u64s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<u64>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]);
+
+ let i64s = [i64::max_value(), i64::min_value(), 42, -117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(i64s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<i64>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
+
+ let f32s = [
+ std::f32::NAN,
+ std::f32::INFINITY,
+ 1.23456789,
+ std::f32::EPSILON,
+ ];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(f32s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<f32>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ // NAN != NAN so we can't use it in the assert_eq:
+ assert!(vec[0].is_nan());
+ assert_eq!(vec[1..], f32s[1..]);
+
+ let f64s = [
+ std::f64::NAN,
+ std::f64::INFINITY,
+ 1.234567890123456789,
+ std::f64::EPSILON,
+ ];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(f64s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<f64>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ // NAN != NAN so we can't use it in the assert_eq:
+ assert!(vec[0].is_nan());
+ assert_eq!(vec[1..], f64s[1..]);
+
+ let s1 = "Hello, Binder!";
+ let s2 = "This is a utf8 string.";
+ let s3 = "Some more text here.";
+ let s4 = "Embedded nulls \0 \0";
+
+ let strs = [s1, s2, s3, s4];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(strs.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<String>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, strs);
}
-
- let custom2 = Custom::deserialize(&parcel).unwrap();
-
- assert_eq!(custom2.0, 123_456_789);
- assert!(custom2.1);
- assert_eq!(custom2.2, custom.2);
- assert_eq!(custom2.3, custom.3);
-}
-
-#[test]
-#[allow(clippy::excessive_precision)]
-fn test_slice_parcelables() {
- let bools = [true, false, false, true];
-
- let mut parcel = Parcel::new();
- let start = parcel.get_data_position();
-
- assert!(bools.serialize(&mut parcel).is_ok());
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4);
- assert_eq!(parcel.read::<u32>().unwrap(), 1);
- assert_eq!(parcel.read::<u32>().unwrap(), 0);
- assert_eq!(parcel.read::<u32>().unwrap(), 0);
- assert_eq!(parcel.read::<u32>().unwrap(), 1);
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<bool>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [true, false, false, true]);
-
- let u8s = [101u8, 255, 42, 117];
-
- let mut parcel = Parcel::new();
- let start = parcel.get_data_position();
-
- assert!(parcel.write(&u8s[..]).is_ok());
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0x752aff65); // bytes
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<u8>::deserialize(&parcel).unwrap();
- assert_eq!(vec, [101, 255, 42, 117]);
-
- let i8s = [-128i8, 127, 42, -117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert!(parcel.write(&i8s[..]).is_ok());
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0x8b2a7f80); // bytes
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<u8>::deserialize(&parcel).unwrap();
- assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]);
-
- let u16s = [u16::max_value(), 12_345, 42, 117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(u16s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::max_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
- assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
- assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<u16>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]);
-
- let i16s = [i16::max_value(), i16::min_value(), 42, -117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(i16s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::max_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
- assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -117
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<i16>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]);
-
- let u32s = [u32::max_value(), 12_345, 42, 117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(u32s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::max_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
- assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
- assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<u32>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]);
-
- let i32s = [i32::max_value(), i32::min_value(), 42, -117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(i32s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::max_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
- assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -117
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<i32>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]);
-
- let u64s = [u64::max_value(), 12_345, 42, 117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(u64s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<u64>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]);
-
- let i64s = [i64::max_value(), i64::min_value(), 42, -117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(i64s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<i64>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
-
- let f32s = [
- std::f32::NAN,
- std::f32::INFINITY,
- 1.23456789,
- std::f32::EPSILON,
- ];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(f32s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<f32>::deserialize(&parcel).unwrap();
-
- // NAN != NAN so we can't use it in the assert_eq:
- assert!(vec[0].is_nan());
- assert_eq!(vec[1..], f32s[1..]);
-
- let f64s = [
- std::f64::NAN,
- std::f64::INFINITY,
- 1.234567890123456789,
- std::f64::EPSILON,
- ];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(f64s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<f64>::deserialize(&parcel).unwrap();
-
- // NAN != NAN so we can't use it in the assert_eq:
- assert!(vec[0].is_nan());
- assert_eq!(vec[1..], f64s[1..]);
-
- let s1 = "Hello, Binder!";
- let s2 = "This is a utf8 string.";
- let s3 = "Some more text here.";
- let s4 = "Embedded nulls \0 \0";
-
- let strs = [s1, s2, s3, s4];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(strs.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<String>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, strs);
}
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index bccfd2d..b4282b2 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -16,7 +16,7 @@
use crate::binder::Stability;
use crate::error::{Result, StatusCode};
-use crate::parcel::{OwnedParcel, Parcel, Parcelable};
+use crate::parcel::{Parcel, BorrowedParcel, Parcelable};
use crate::{impl_deserialize_for_parcelable, impl_serialize_for_parcelable};
use downcast_rs::{impl_downcast, DowncastSync};
@@ -50,7 +50,7 @@
parcelable: Arc<dyn AnyParcelable>,
name: String,
},
- Parcel(OwnedParcel),
+ Parcel(Parcel),
}
impl Default for ParcelableHolderData {
@@ -148,7 +148,6 @@
}
}
ParcelableHolderData::Parcel(ref mut parcel) => {
- let parcel = parcel.borrowed();
unsafe {
// Safety: 0 should always be a valid position.
parcel.set_data_position(0)?;
@@ -160,7 +159,7 @@
}
let mut parcelable = T::default();
- parcelable.read_from_parcel(&parcel)?;
+ parcelable.read_from_parcel(parcel.borrowed_ref())?;
let parcelable = Arc::new(parcelable);
let result = Arc::clone(&parcelable);
@@ -181,7 +180,7 @@
impl_deserialize_for_parcelable!(ParcelableHolder);
impl Parcelable for ParcelableHolder {
- fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()> {
+ fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
parcel.write(&self.stability)?;
let mut data = self.data.lock().unwrap();
@@ -214,14 +213,13 @@
Ok(())
}
ParcelableHolderData::Parcel(ref mut p) => {
- let p = p.borrowed();
parcel.write(&p.get_data_size())?;
- parcel.append_all_from(&p)
+ parcel.append_all_from(&*p)
}
}
}
- fn read_from_parcel(&mut self, parcel: &Parcel) -> Result<()> {
+ fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
self.stability = parcel.read()?;
let data_size: i32 = parcel.read()?;
@@ -242,10 +240,8 @@
.checked_add(data_size)
.ok_or(StatusCode::BAD_VALUE)?;
- let mut new_parcel = OwnedParcel::new();
- new_parcel
- .borrowed()
- .append_from(parcel, data_start, data_size)?;
+ let mut new_parcel = Parcel::new();
+ new_parcel.append_from(parcel, data_start, data_size)?;
*self.data.get_mut().unwrap() = ParcelableHolderData::Parcel(new_parcel);
unsafe {
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index a8d0c33..83553d7 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -22,8 +22,7 @@
};
use crate::error::{status_result, Result, StatusCode};
use crate::parcel::{
- Deserialize, DeserializeArray, DeserializeOption, OwnedParcel, Parcel, Serialize, SerializeArray,
- SerializeOption,
+ Parcel, BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
};
use crate::sys;
@@ -235,7 +234,7 @@
}
impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
- fn prepare_transact(&self) -> Result<OwnedParcel> {
+ fn prepare_transact(&self) -> Result<Parcel> {
let mut input = ptr::null_mut();
let status = unsafe {
// Safety: `SpIBinder` guarantees that `self` always contains a
@@ -255,16 +254,16 @@
// Safety: At this point, `input` is either a valid, owned `AParcel`
// pointer, or null. `OwnedParcel::from_raw` safely handles both cases,
// taking ownership of the parcel.
- OwnedParcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL)
+ Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL)
}
}
fn submit_transact(
&self,
code: TransactionCode,
- data: OwnedParcel,
+ data: Parcel,
flags: TransactionFlags,
- ) -> Result<OwnedParcel> {
+ ) -> Result<Parcel> {
let mut reply = ptr::null_mut();
let status = unsafe {
// Safety: `SpIBinder` guarantees that `self` always contains a
@@ -299,7 +298,7 @@
// construct a `Parcel` out of it. `AIBinder_transact` passes
// ownership of the `reply` parcel to Rust, so we need to
// construct an owned variant.
- OwnedParcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL)
+ Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL)
}
}
@@ -415,13 +414,13 @@
}
impl Serialize for SpIBinder {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
parcel.write_binder(Some(self))
}
}
impl SerializeOption for SpIBinder {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
parcel.write_binder(this)
}
}
@@ -429,7 +428,7 @@
impl SerializeArray for SpIBinder {}
impl Deserialize for SpIBinder {
- fn deserialize(parcel: &Parcel) -> Result<SpIBinder> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<SpIBinder> {
parcel
.read_binder()
.transpose()
@@ -438,7 +437,7 @@
}
impl DeserializeOption for SpIBinder {
- fn deserialize_option(parcel: &Parcel) -> Result<Option<SpIBinder>> {
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<SpIBinder>> {
parcel.read_binder()
}
}
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index ebfe879..1fd2ead 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -17,7 +17,7 @@
//! Rust Binder crate integration tests
use binder::declare_binder_interface;
-use binder::parcel::{Parcel, OwnedParcel};
+use binder::parcel::BorrowedParcel;
use binder::{
Binder, BinderFeatures, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
FIRST_CALL_TRANSACTION,
@@ -179,8 +179,8 @@
fn on_transact(
service: &dyn ITest,
code: TransactionCode,
- _data: &Parcel,
- reply: &mut Parcel,
+ _data: &BorrowedParcel<'_>,
+ reply: &mut BorrowedParcel<'_>,
) -> binder::Result<()> {
match code.try_into()? {
TestTransactionCode::Test => reply.write(&service.test()?),
@@ -218,24 +218,24 @@
fn test(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
let binder = self.binder.clone();
P::spawn(
- move || binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(())).map(|p| OwnedParcel::try_from(p).unwrap()),
- |reply| async move { reply?.into_parcel().read() }
+ move || binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(())),
+ |reply| async move { reply?.read() }
)
}
fn get_dump_args(&self) -> binder::BoxFuture<'static, binder::Result<Vec<String>>> {
let binder = self.binder.clone();
P::spawn(
- move || binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(())).map(|p| OwnedParcel::try_from(p).unwrap()),
- |reply| async move { reply?.into_parcel().read() }
+ move || binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(())),
+ |reply| async move { reply?.read() }
)
}
fn get_selinux_context(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
let binder = self.binder.clone();
P::spawn(
- move || binder.transact(TestTransactionCode::GetSelinuxContext as TransactionCode, 0, |_| Ok(())).map(|p| OwnedParcel::try_from(p).unwrap()),
- |reply| async move { reply?.into_parcel().read() }
+ move || binder.transact(TestTransactionCode::GetSelinuxContext as TransactionCode, 0, |_| Ok(())),
+ |reply| async move { reply?.read() }
)
}
}
@@ -284,8 +284,8 @@
fn on_transact_same_descriptor(
_service: &dyn ITestSameDescriptor,
_code: TransactionCode,
- _data: &Parcel,
- _reply: &mut Parcel,
+ _data: &BorrowedParcel<'_>,
+ _reply: &mut BorrowedParcel<'_>,
) -> binder::Result<()> {
Ok(())
}
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index 66ba846..1fc761e 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -20,7 +20,7 @@
use binder::declare_binder_interface;
use binder::parcel::ParcelFileDescriptor;
use binder::{
- Binder, BinderFeatures, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status,
+ Binder, BinderFeatures, BorrowedParcel, ExceptionCode, Interface, Result, SpIBinder, Status,
StatusCode, TransactionCode,
};
@@ -111,8 +111,8 @@
fn on_transact(
_service: &dyn ReadParcelTest,
code: TransactionCode,
- parcel: &Parcel,
- reply: &mut Parcel,
+ parcel: &BorrowedParcel<'_>,
+ reply: &mut BorrowedParcel<'_>,
) -> Result<()> {
match code {
bindings::Transaction_TEST_BOOL => {
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 55ad3c6..5a96b78 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -22,6 +22,7 @@
#include <aidl/IBinderRpcTest.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android/binder_auto_utils.h>
#include <android/binder_libbinder.h>
#include <binder/Binder.h>
@@ -1514,7 +1515,17 @@
auto socket = rpcServer->releaseServer();
auto keepAlive = sp<BBinder>::make();
- ASSERT_EQ(OK, binder->setRpcClientDebug(std::move(socket), keepAlive));
+ auto setRpcClientDebugStatus = binder->setRpcClientDebug(std::move(socket), keepAlive);
+
+ if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+ ASSERT_EQ(INVALID_OPERATION, setRpcClientDebugStatus)
+ << "setRpcClientDebug should return INVALID_OPERATION on non-debuggable builds, "
+ "but get "
+ << statusToString(setRpcClientDebugStatus);
+ GTEST_SKIP();
+ }
+
+ ASSERT_EQ(OK, setRpcClientDebugStatus);
auto rpcSession = RpcSession::make();
ASSERT_EQ(OK, rpcSession->setupInetClient("127.0.0.1", port));
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index c986b82..8379675 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -33,10 +33,13 @@
// using just a few large reads.
static const size_t EVENT_BUFFER_SIZE = 100;
+static constexpr nsecs_t WAITING_FOR_VSYNC_TIMEOUT = ms2ns(300);
+
DisplayEventDispatcher::DisplayEventDispatcher(
const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::EventRegistrationFlags eventRegistration)
- : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false) {
+ : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false),
+ mLastVsyncCount(0), mLastScheduleVsyncTime(0) {
ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}
@@ -86,6 +89,7 @@
}
mWaitingForVsync = true;
+ mLastScheduleVsyncTime = systemTime(SYSTEM_TIME_MONOTONIC);
}
return OK;
}
@@ -124,9 +128,21 @@
this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
vsyncEventData.id);
mWaitingForVsync = false;
+ mLastVsyncCount = vsyncCount;
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
}
+ if (mWaitingForVsync) {
+ const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ const nsecs_t vsyncScheduleDelay = currentTime - mLastScheduleVsyncTime;
+ if (vsyncScheduleDelay > WAITING_FOR_VSYNC_TIMEOUT) {
+ ALOGW("Vsync time out! vsyncScheduleDelay=%" PRId64 "ms", ns2ms(vsyncScheduleDelay));
+ mWaitingForVsync = false;
+ dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */,
+ ++mLastVsyncCount, vsyncEventData /* empty data */);
+ }
+ }
+
return 1; // keep the callback
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 3881620..4a63544 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -88,10 +88,10 @@
void onFrameDequeued(const uint64_t) override;
void onFrameCancelled(const uint64_t) override;
- virtual void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
- const std::vector<SurfaceControlStats>& stats);
- void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
- const std::vector<SurfaceControlStats>& stats);
+ void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats);
+ virtual void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats);
void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount);
void setNextTransaction(SurfaceComposerClient::Transaction *t);
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 92c89b8..8a3a476 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -80,6 +80,8 @@
sp<Looper> mLooper;
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
+ uint32_t mLastVsyncCount;
+ nsecs_t mLastScheduleVsyncTime;
std::vector<FrameRateOverride> mFrameRateOverrides;
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index b2d5048..8607e1d 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -72,31 +72,30 @@
int height, int32_t format)
: BLASTBufferQueue(name, surface, width, height, format) {}
- void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
- const std::vector<SurfaceControlStats>& stats) override {
- BLASTBufferQueue::transactionCommittedCallback(latchTime, presentFence, stats);
-
+ void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats) override {
+ BLASTBufferQueue::transactionCallback(latchTime, presentFence, stats);
uint64_t frameNumber = stats[0].frameEventStats.frameNumber;
{
std::unique_lock lock{frameNumberMutex};
- mLastTransactionCommittedFrameNumber = frameNumber;
- mCommittedCV.notify_all();
+ mLastTransactionFrameNumber = frameNumber;
+ mWaitForCallbackCV.notify_all();
}
}
void waitForCallback(int64_t frameNumber) {
std::unique_lock lock{frameNumberMutex};
// Wait until all but one of the submitted buffers have been released.
- while (mLastTransactionCommittedFrameNumber < frameNumber) {
- mCommittedCV.wait(lock);
+ while (mLastTransactionFrameNumber < frameNumber) {
+ mWaitForCallbackCV.wait(lock);
}
}
private:
std::mutex frameNumberMutex;
- std::condition_variable mCommittedCV;
- int64_t mLastTransactionCommittedFrameNumber = -1;
+ std::condition_variable mWaitForCallbackCV;
+ int64_t mLastTransactionFrameNumber = -1;
};
class BLASTBufferQueueHelper {
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index a62d2b9..ecfaef8 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -40,6 +40,10 @@
"libui",
"libutils",
],
+
+ static_libs: [
+ "libtonemap",
+ ],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
}
@@ -97,7 +101,7 @@
"skia/filters/GaussianBlurFilter.cpp",
"skia/filters/KawaseBlurFilter.cpp",
"skia/filters/LinearEffect.cpp",
- "skia/filters/StretchShaderFactory.cpp"
+ "skia/filters/StretchShaderFactory.cpp",
],
}
diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp
index 5968399..baa5054 100644
--- a/libs/renderengine/benchmark/Android.bp
+++ b/libs/renderengine/benchmark/Android.bp
@@ -23,7 +23,10 @@
cc_benchmark {
name: "librenderengine_bench",
- defaults: ["skia_deps", "surfaceflinger_defaults"],
+ defaults: [
+ "skia_deps",
+ "surfaceflinger_defaults",
+ ],
srcs: [
"main.cpp",
"Codec.cpp",
@@ -32,6 +35,7 @@
],
static_libs: [
"librenderengine",
+ "libtonemap",
],
cflags: [
"-DLOG_TAG=\"RenderEngineBench\"",
@@ -50,5 +54,5 @@
"libutils",
],
- data: [ "resources/*"],
+ data: ["resources/*"],
}
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index 9ee7e4d..6c8f8e8 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -46,8 +46,8 @@
}
/**
- * Passed (indirectly - see RunSkiaGL) to Benchmark::Apply to create a Benchmark
- * which specifies which RenderEngineType it uses.
+ * Passed (indirectly - see RunSkiaGLThreaded) to Benchmark::Apply to create a
+ * Benchmark which specifies which RenderEngineType it uses.
*
* This simplifies calling ->Arg(type)->Arg(type) and provides strings to make
* it obvious which version is being run.
@@ -62,10 +62,10 @@
}
/**
- * Run a benchmark once using SKIA_GL.
+ * Run a benchmark once using SKIA_GL_THREADED.
*/
-static void RunSkiaGL(benchmark::internal::Benchmark* b) {
- AddRenderEngineType(b, RenderEngine::RenderEngineType::SKIA_GL);
+static void RunSkiaGLThreaded(benchmark::internal::Benchmark* b) {
+ AddRenderEngineType(b, RenderEngine::RenderEngineType::SKIA_GL_THREADED);
}
///////////////////////////////////////////////////////////////////////////////
@@ -256,4 +256,4 @@
benchDrawLayers(*re, layers, benchState, "blurred");
}
-BENCHMARK(BM_blur)->Apply(RunSkiaGL);
+BENCHMARK(BM_blur)->Apply(RunSkiaGLThreaded);
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index 73dadef..53136e4 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -19,6 +19,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <SkString.h>
+#include <tonemap/tonemap.h>
#include <utils/Trace.h>
#include <optional>
@@ -32,6 +33,11 @@
namespace renderengine {
namespace skia {
+static aidl::android::hardware::graphics::common::Dataspace toAidlDataspace(
+ ui::Dataspace dataspace) {
+ return static_cast<aidl::android::hardware::graphics::common::Dataspace>(dataspace);
+}
+
static void generateEOTF(ui::Dataspace dataspace, SkString& shader) {
switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
case HAL_DATASPACE_TRANSFER_ST2084:
@@ -127,159 +133,13 @@
default:
shader.append(R"(
float3 ScaleLuminance(float3 xyz) {
- return xyz * in_inputMaxLuminance;
+ return xyz * in_libtonemap_inputMaxLuminance;
}
)");
break;
}
}
-static void generateToneMapInterpolation(ui::Dataspace inputDataspace,
- ui::Dataspace outputDataspace, SkString& shader) {
- switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
- case HAL_DATASPACE_TRANSFER_ST2084:
- case HAL_DATASPACE_TRANSFER_HLG:
- switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
- case HAL_DATASPACE_TRANSFER_ST2084:
- shader.append(R"(
- float3 ToneMap(float3 xyz) {
- return xyz;
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_HLG:
- // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so
- // we'll clamp the luminance range in case we're mapping from PQ input to HLG
- // output.
- shader.append(R"(
- float3 ToneMap(float3 xyz) {
- return clamp(xyz, 0.0, 1000.0);
- }
- )");
- break;
- default:
- // Here we're mapping from HDR to SDR content, so interpolate using a Hermitian
- // polynomial onto the smaller luminance range.
- shader.append(R"(
- float3 ToneMap(float3 xyz) {
- float maxInLumi = in_inputMaxLuminance;
- float maxOutLumi = in_displayMaxLuminance;
-
- float nits = xyz.y;
-
- // if the max input luminance is less than what we can output then
- // no tone mapping is needed as all color values will be in range.
- if (maxInLumi <= maxOutLumi) {
- return xyz;
- } else {
-
- // three control points
- const float x0 = 10.0;
- const float y0 = 17.0;
- float x1 = maxOutLumi * 0.75;
- float y1 = x1;
- float x2 = x1 + (maxInLumi - x1) / 2.0;
- float y2 = y1 + (maxOutLumi - y1) * 0.75;
-
- // horizontal distances between the last three control points
- float h12 = x2 - x1;
- float h23 = maxInLumi - x2;
- // tangents at the last three control points
- float m1 = (y2 - y1) / h12;
- float m3 = (maxOutLumi - y2) / h23;
- float m2 = (m1 + m3) / 2.0;
-
- if (nits < x0) {
- // scale [0.0, x0] to [0.0, y0] linearly
- float slope = y0 / x0;
- return xyz * slope;
- } else if (nits < x1) {
- // scale [x0, x1] to [y0, y1] linearly
- float slope = (y1 - y0) / (x1 - x0);
- nits = y0 + (nits - x0) * slope;
- } else if (nits < x2) {
- // scale [x1, x2] to [y1, y2] using Hermite interp
- float t = (nits - x1) / h12;
- nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) +
- (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
- } else {
- // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp
- float t = (nits - x2) / h23;
- nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) +
- (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t;
- }
- }
-
- // color.y is greater than x0 and is thus non-zero
- return xyz * (nits / xyz.y);
- }
- )");
- break;
- }
- break;
- default:
- switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
- case HAL_DATASPACE_TRANSFER_ST2084:
- case HAL_DATASPACE_TRANSFER_HLG:
- // Map from SDR onto an HDR output buffer
- // Here we use a polynomial curve to map from [0, displayMaxLuminance] onto
- // [0, maxOutLumi] which is hard-coded to be 3000 nits.
- shader.append(R"(
- float3 ToneMap(float3 xyz) {
- const float maxOutLumi = 3000.0;
-
- const float x0 = 5.0;
- const float y0 = 2.5;
- float x1 = in_displayMaxLuminance * 0.7;
- float y1 = maxOutLumi * 0.15;
- float x2 = in_displayMaxLuminance * 0.9;
- float y2 = maxOutLumi * 0.45;
- float x3 = in_displayMaxLuminance;
- float y3 = maxOutLumi;
-
- float c1 = y1 / 3.0;
- float c2 = y2 / 2.0;
- float c3 = y3 / 1.5;
-
- float nits = xyz.y;
-
- if (nits <= x0) {
- // scale [0.0, x0] to [0.0, y0] linearly
- float slope = y0 / x0;
- return xyz * slope;
- } else if (nits <= x1) {
- // scale [x0, x1] to [y0, y1] using a curve
- float t = (nits - x0) / (x1 - x0);
- nits = (1.0 - t) * (1.0 - t) * y0 + 2.0 * (1.0 - t) * t * c1 + t * t * y1;
- } else if (nits <= x2) {
- // scale [x1, x2] to [y1, y2] using a curve
- float t = (nits - x1) / (x2 - x1);
- nits = (1.0 - t) * (1.0 - t) * y1 + 2.0 * (1.0 - t) * t * c2 + t * t * y2;
- } else {
- // scale [x2, x3] to [y2, y3] using a curve
- float t = (nits - x2) / (x3 - x2);
- nits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 + t * t * y3;
- }
-
- // xyz.y is greater than x0 and is thus non-zero
- return xyz * (nits / xyz.y);
- }
- )");
- break;
- default:
- // For completeness, this is tone-mapping from SDR to SDR, where this is just a
- // no-op.
- shader.append(R"(
- float3 ToneMap(float3 xyz) {
- return xyz;
- }
- )");
- break;
- }
- break;
- }
-}
-
// Normalizes from absolute light back to relative light (maps from [0, maxNits] back to [0, 1])
static void generateLuminanceNormalizationForOOTF(ui::Dataspace outputDataspace, SkString& shader) {
switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
@@ -300,7 +160,7 @@
default:
shader.append(R"(
float3 NormalizeLuminance(float3 xyz) {
- return xyz / in_displayMaxLuminance;
+ return xyz / in_libtonemap_displayMaxLuminance;
}
)");
break;
@@ -309,19 +169,22 @@
static void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace,
SkString& shader) {
- // Input uniforms
- shader.append(R"(
- uniform float in_displayMaxLuminance;
- uniform float in_inputMaxLuminance;
- )");
+ shader.append(tonemap::getToneMapper()
+ ->generateTonemapGainShaderSkSL(toAidlDataspace(inputDataspace),
+ toAidlDataspace(outputDataspace))
+ .c_str());
generateLuminanceScalesForOOTF(inputDataspace, shader);
- generateToneMapInterpolation(inputDataspace, outputDataspace, shader);
generateLuminanceNormalizationForOOTF(outputDataspace, shader);
shader.append(R"(
- float3 OOTF(float3 xyz) {
- return NormalizeLuminance(ToneMap(ScaleLuminance(xyz)));
+ float3 OOTF(float3 linearRGB, float3 xyz) {
+ float3 scaledLinearRGB = ScaleLuminance(linearRGB);
+ float3 scaledXYZ = ScaleLuminance(xyz);
+
+ float gain = libtonemap_LookupTonemapGain(scaledLinearRGB, scaledXYZ);
+
+ return NormalizeLuminance(scaledXYZ * gain);
}
)");
}
@@ -399,7 +262,9 @@
)");
}
shader.append(R"(
- c.rgb = OETF(ToRGB(OOTF(ToXYZ(EOTF(c.rgb)))));
+ float3 linearRGB = EOTF(c.rgb);
+ float3 xyz = ToXYZ(linearRGB);
+ c.rgb = OETF(ToRGB(OOTF(linearRGB, xyz)));
)");
if (undoPremultipliedAlpha) {
shader.append(R"(
@@ -465,11 +330,20 @@
colorTransform * mat4(outputColorSpace.getXYZtoRGB());
}
- effectBuilder.uniform("in_displayMaxLuminance") = maxDisplayLuminance;
- // If the input luminance is unknown, use display luminance (aka, no-op any luminance changes)
- // This will be the case for eg screenshots in addition to uncalibrated displays
- effectBuilder.uniform("in_inputMaxLuminance") =
- maxLuminance > 0 ? maxLuminance : maxDisplayLuminance;
+ tonemap::Metadata metadata{.displayMaxLuminance = maxDisplayLuminance,
+ // If the input luminance is unknown, use display luminance (aka,
+ // no-op any luminance changes)
+ // This will be the case for eg screenshots in addition to
+ // uncalibrated displays
+ .contentMaxLuminance =
+ maxLuminance > 0 ? maxLuminance : maxDisplayLuminance};
+
+ const auto uniforms = tonemap::getToneMapper()->generateShaderSkSLUniforms(metadata);
+
+ for (const auto& uniform : uniforms) {
+ effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size());
+ }
+
return effectBuilder.makeShader(nullptr, false);
}
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index d0e19dd..52b6c8f 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -23,7 +23,10 @@
cc_test {
name: "librenderengine_test",
- defaults: ["skia_deps", "surfaceflinger_defaults"],
+ defaults: [
+ "skia_deps",
+ "surfaceflinger_defaults",
+ ],
test_suites: ["device-tests"],
srcs: [
"RenderEngineTest.cpp",
@@ -36,6 +39,7 @@
"libgmock",
"librenderengine",
"librenderengine_mocks",
+ "libtonemap",
],
shared_libs: [
diff --git a/libs/tonemap/Android.bp b/libs/tonemap/Android.bp
new file mode 100644
index 0000000..231a342
--- /dev/null
+++ b/libs/tonemap/Android.bp
@@ -0,0 +1,37 @@
+// Copyright 2021 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_static {
+ name: "libtonemap",
+ vendor_available: true,
+
+ export_include_dirs: ["include"],
+ local_include_dirs: ["include"],
+
+ shared_libs: [
+ "android.hardware.graphics.common-V3-ndk",
+ ],
+ srcs: [
+ "tonemap.cpp",
+ ],
+}
diff --git a/libs/tonemap/OWNERS b/libs/tonemap/OWNERS
new file mode 100644
index 0000000..6d91da3
--- /dev/null
+++ b/libs/tonemap/OWNERS
@@ -0,0 +1,4 @@
+alecmouri@google.com
+jreck@google.com
+sallyqi@google.com
+scroggo@google.com
\ No newline at end of file
diff --git a/libs/tonemap/TEST_MAPPING b/libs/tonemap/TEST_MAPPING
new file mode 100644
index 0000000..00f83ba
--- /dev/null
+++ b/libs/tonemap/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "presubmit": [
+ {
+ "name": "librenderengine_test"
+ },
+ {
+ "name": "libtonemap_test"
+ }
+ ]
+}
diff --git a/libs/tonemap/include/tonemap/tonemap.h b/libs/tonemap/include/tonemap/tonemap.h
new file mode 100644
index 0000000..d350e16
--- /dev/null
+++ b/libs/tonemap/include/tonemap/tonemap.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
+
+#include <string>
+#include <vector>
+
+namespace android::tonemap {
+
+// Describes a shader uniform
+// The shader uniform is intended to be passed into a SkRuntimeShaderBuilder, i.e.:
+//
+// SkRuntimeShaderBuilder builder;
+// builder.uniform(<uniform name>).set(<uniform value>.data(), <uniform value>.size());
+struct ShaderUniform {
+ // The name of the uniform, used for binding into a shader.
+ // The shader must contain a uniform whose name matches this.
+ std::string name;
+
+ // The value for the uniform, which should be bound to the uniform identified by <name>
+ std::vector<uint8_t> value;
+};
+
+// Describes metadata which may be used for constructing the shader uniforms.
+// This metadata should not be used for manipulating the source code of the shader program directly,
+// as otherwise caching by other system of these shaders may break.
+struct Metadata {
+ float displayMaxLuminance = 0.0;
+ float contentMaxLuminance = 0.0;
+};
+
+class ToneMapper {
+public:
+ virtual ~ToneMapper() {}
+ // Constructs a tonemap shader whose shader language is SkSL
+ //
+ // The returned shader string *must* contain a function with the following signature:
+ // float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz);
+ //
+ // The arguments are:
+ // * linearRGB is the absolute nits of the RGB pixels in linear space
+ // * xyz is linearRGB converted into XYZ
+ //
+ // libtonemap_LookupTonemapGain() returns a float representing the amount by which to scale the
+ // absolute nits of the pixels. This function may be plugged into any existing SkSL shader, and
+ // is expected to look something like this:
+ //
+ // vec3 rgb = ...;
+ // // apply the EOTF based on the incoming dataspace to convert to linear nits.
+ // vec3 linearRGB = applyEOTF(rgb);
+ // // apply a RGB->XYZ matrix float3
+ // vec3 xyz = toXYZ(linearRGB);
+ // // Scale the luminance based on the content standard
+ // vec3 absoluteRGB = ScaleLuminance(linearRGB);
+ // vec3 absoluteXYZ = ScaleLuminance(xyz);
+ // float gain = libtonemap_LookupTonemapGain(absoluteRGB, absoluteXYZ);
+ // // Normalize the luminance back down to a [0, 1] range
+ // xyz = NormalizeLuminance(absoluteXYZ * gain);
+ // // apply a XYZ->RGB matrix and apply the output OETf.
+ // vec3 finalColor = applyOETF(ToRGB(xyz));
+ // ...
+ //
+ // Helper methods in this shader should be prefixed with "libtonemap_". Accordingly, libraries
+ // which consume this shader must *not* contain any methods prefixed with "libtonemap_" to
+ // guarantee that there are no conflicts in name resolution.
+ virtual std::string generateTonemapGainShaderSkSL(
+ aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
+ aidl::android::hardware::graphics::common::Dataspace destinationDataspace) = 0;
+
+ // Constructs uniform descriptions that correspond to those that are generated for the tonemap
+ // shader. Uniforms must be prefixed with "in_libtonemap_". Libraries which consume this shader
+ // must not bind any new uniforms that begin with this prefix.
+ //
+ // Downstream shaders may assume the existence of the uniform in_libtonemap_displayMaxLuminance
+ // and in_libtonemap_inputMaxLuminance, in order to assist with scaling and normalizing
+ // luminance as described in the documentation for generateTonemapGainShaderSkSL(). That is,
+ // shaders plugging in a tone-mapping shader returned by generateTonemapGainShaderSkSL() may
+ // assume that there are predefined floats in_libtonemap_displayMaxLuminance and
+ // in_libtonemap_inputMaxLuminance inside of the body of the tone-mapping shader.
+ virtual std::vector<ShaderUniform> generateShaderSkSLUniforms(const Metadata& metadata) = 0;
+};
+
+// Retrieves a tonemapper instance.
+// This instance is globally constructed.
+ToneMapper* getToneMapper();
+
+} // namespace android::tonemap
\ No newline at end of file
diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp
new file mode 100644
index 0000000..e58d519
--- /dev/null
+++ b/libs/tonemap/tests/Android.bp
@@ -0,0 +1,38 @@
+// Copyright 2021 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_test {
+ name: "libtonemap_test",
+ test_suites: ["device-tests"],
+ srcs: [
+ "tonemap_test.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.graphics.common-V3-ndk",
+ ],
+ static_libs: [
+ "libgmock",
+ "libgtest",
+ "libtonemap",
+ ],
+}
diff --git a/libs/tonemap/tests/tonemap_test.cpp b/libs/tonemap/tests/tonemap_test.cpp
new file mode 100644
index 0000000..7a7958f
--- /dev/null
+++ b/libs/tonemap/tests/tonemap_test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <tonemap/tonemap.h>
+#include <cmath>
+
+namespace android {
+
+using testing::HasSubstr;
+
+struct TonemapTest : public ::testing::Test {};
+
+TEST_F(TonemapTest, generateShaderSkSLUniforms_containsDefaultUniforms) {
+ static const constexpr float kDisplayMaxLuminance = 1.f;
+ static const constexpr float kContentMaxLuminance = 2.f;
+ tonemap::Metadata metadata{.displayMaxLuminance = kDisplayMaxLuminance,
+ .contentMaxLuminance = kContentMaxLuminance};
+ const auto uniforms = tonemap::getToneMapper()->generateShaderSkSLUniforms(metadata);
+
+ ASSERT_EQ(1, std::count_if(uniforms.cbegin(), uniforms.cend(), [](const auto& data) {
+ return data.name == "in_libtonemap_displayMaxLuminance";
+ }));
+ ASSERT_EQ(1, std::count_if(uniforms.cbegin(), uniforms.cend(), [](const auto& data) {
+ return data.name == "in_libtonemap_inputMaxLuminance";
+ }));
+
+ // Smoke check that metadata values are "real", specifically that they're non-zero and actually
+ // numbers. This is to help avoid shaders using these uniforms from dividing by zero or other
+ // catastrophic errors.
+ const auto& displayLum = std::find_if(uniforms.cbegin(), uniforms.cend(), [](const auto& data) {
+ return data.name == "in_libtonemap_displayMaxLuminance";
+ })->value;
+
+ float displayLumFloat = 0.f;
+ std::memcpy(&displayLumFloat, displayLum.data(), displayLum.size());
+ EXPECT_FALSE(std::isnan(displayLumFloat));
+ EXPECT_GT(displayLumFloat, 0);
+
+ const auto& contentLum = std::find_if(uniforms.cbegin(), uniforms.cend(), [](const auto& data) {
+ return data.name == "in_libtonemap_inputMaxLuminance";
+ })->value;
+
+ float contentLumFloat = 0.f;
+ std::memcpy(&contentLumFloat, contentLum.data(), contentLum.size());
+ EXPECT_FALSE(std::isnan(contentLumFloat));
+ EXPECT_GT(contentLumFloat, 0);
+}
+
+TEST_F(TonemapTest, generateTonemapGainShaderSkSL_containsEntryPoint) {
+ const auto shader =
+ tonemap::getToneMapper()
+ ->generateTonemapGainShaderSkSL(aidl::android::hardware::graphics::common::
+ Dataspace::BT2020_ITU_PQ,
+ aidl::android::hardware::graphics::common::
+ Dataspace::DISPLAY_P3);
+
+ // Other tests such as librenderengine_test will plug in the shader to check compilation.
+ EXPECT_THAT(shader, HasSubstr("float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)"));
+}
+
+} // namespace android
diff --git a/libs/tonemap/tonemap.cpp b/libs/tonemap/tonemap.cpp
new file mode 100644
index 0000000..350bca4
--- /dev/null
+++ b/libs/tonemap/tonemap.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#include <tonemap/tonemap.h>
+
+#include <cstdint>
+#include <mutex>
+#include <type_traits>
+
+namespace android::tonemap {
+
+namespace {
+
+// Flag containing the variant of tone map algorithm to use.
+enum class ToneMapAlgorithm {
+ AndroidO, // Default algorithm in place since Android O,
+};
+
+static const constexpr auto kToneMapAlgorithm = ToneMapAlgorithm::AndroidO;
+
+static const constexpr auto kTransferMask =
+ static_cast<int32_t>(aidl::android::hardware::graphics::common::Dataspace::TRANSFER_MASK);
+static const constexpr auto kTransferST2084 =
+ static_cast<int32_t>(aidl::android::hardware::graphics::common::Dataspace::TRANSFER_ST2084);
+static const constexpr auto kTransferHLG =
+ static_cast<int32_t>(aidl::android::hardware::graphics::common::Dataspace::TRANSFER_HLG);
+
+template <typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, bool> = true>
+std::vector<uint8_t> buildUniformValue(T value) {
+ std::vector<uint8_t> result;
+ result.resize(sizeof(value));
+ std::memcpy(result.data(), &value, sizeof(value));
+ return result;
+}
+
+class ToneMapperO : public ToneMapper {
+public:
+ std::string generateTonemapGainShaderSkSL(
+ aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
+ aidl::android::hardware::graphics::common::Dataspace destinationDataspace) override {
+ const int32_t sourceDataspaceInt = static_cast<int32_t>(sourceDataspace);
+ const int32_t destinationDataspaceInt = static_cast<int32_t>(destinationDataspace);
+
+ std::string program;
+ // Define required uniforms
+ program.append(R"(
+ uniform float in_libtonemap_displayMaxLuminance;
+ uniform float in_libtonemap_inputMaxLuminance;
+ )");
+ switch (sourceDataspaceInt & kTransferMask) {
+ case kTransferST2084:
+ case kTransferHLG:
+ switch (destinationDataspaceInt & kTransferMask) {
+ case kTransferST2084:
+ program.append(R"(
+ float libtonemap_ToneMapTargetNits(vec3 xyz) {
+ return xyz.y;
+ }
+ )");
+ break;
+ case kTransferHLG:
+ // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so
+ // we'll clamp the luminance range in case we're mapping from PQ input to
+ // HLG output.
+ program.append(R"(
+ float libtonemap_ToneMapTargetNits(vec3 xyz) {
+ return clamp(xyz.y, 0.0, 1000.0);
+ }
+ )");
+ break;
+ default:
+ // Here we're mapping from HDR to SDR content, so interpolate using a
+ // Hermitian polynomial onto the smaller luminance range.
+ program.append(R"(
+ float libtonemap_ToneMapTargetNits(vec3 xyz) {
+ float maxInLumi = in_libtonemap_inputMaxLuminance;
+ float maxOutLumi = in_libtonemap_displayMaxLuminance;
+
+ float nits = xyz.y;
+
+ // if the max input luminance is less than what we can
+ // output then no tone mapping is needed as all color
+ // values will be in range.
+ if (maxInLumi <= maxOutLumi) {
+ return xyz.y;
+ } else {
+
+ // three control points
+ const float x0 = 10.0;
+ const float y0 = 17.0;
+ float x1 = maxOutLumi * 0.75;
+ float y1 = x1;
+ float x2 = x1 + (maxInLumi - x1) / 2.0;
+ float y2 = y1 + (maxOutLumi - y1) * 0.75;
+
+ // horizontal distances between the last three
+ // control points
+ float h12 = x2 - x1;
+ float h23 = maxInLumi - x2;
+ // tangents at the last three control points
+ float m1 = (y2 - y1) / h12;
+ float m3 = (maxOutLumi - y2) / h23;
+ float m2 = (m1 + m3) / 2.0;
+
+ if (nits < x0) {
+ // scale [0.0, x0] to [0.0, y0] linearly
+ float slope = y0 / x0;
+ return nits * slope;
+ } else if (nits < x1) {
+ // scale [x0, x1] to [y0, y1] linearly
+ float slope = (y1 - y0) / (x1 - x0);
+ nits = y0 + (nits - x0) * slope;
+ } else if (nits < x2) {
+ // scale [x1, x2] to [y1, y2] using Hermite interp
+ float t = (nits - x1) / h12;
+ nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) *
+ (1.0 - t) * (1.0 - t) +
+ (y2 * (3.0 - 2.0 * t) +
+ h12 * m2 * (t - 1.0)) * t * t;
+ } else {
+ // scale [x2, maxInLumi] to [y2, maxOutLumi] using
+ // Hermite interp
+ float t = (nits - x2) / h23;
+ nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) *
+ (1.0 - t) * (1.0 - t) + (maxOutLumi *
+ (3.0 - 2.0 * t) + h23 * m3 *
+ (t - 1.0)) * t * t;
+ }
+ }
+
+ return nits;
+ }
+ )");
+ break;
+ }
+ break;
+ default:
+ switch (destinationDataspaceInt & kTransferMask) {
+ case kTransferST2084:
+ case kTransferHLG:
+ // Map from SDR onto an HDR output buffer
+ // Here we use a polynomial curve to map from [0, displayMaxLuminance] onto
+ // [0, maxOutLumi] which is hard-coded to be 3000 nits.
+ program.append(R"(
+ float libtonemap_ToneMapTargetNits(vec3 xyz) {
+ const float maxOutLumi = 3000.0;
+
+ const float x0 = 5.0;
+ const float y0 = 2.5;
+ float x1 = in_libtonemap_displayMaxLuminance * 0.7;
+ float y1 = maxOutLumi * 0.15;
+ float x2 = in_libtonemap_displayMaxLuminance * 0.9;
+ float y2 = maxOutLumi * 0.45;
+ float x3 = in_libtonemap_displayMaxLuminance;
+ float y3 = maxOutLumi;
+
+ float c1 = y1 / 3.0;
+ float c2 = y2 / 2.0;
+ float c3 = y3 / 1.5;
+
+ float nits = xyz.y;
+
+ if (nits <= x0) {
+ // scale [0.0, x0] to [0.0, y0] linearly
+ float slope = y0 / x0;
+ return nits * slope;
+ } else if (nits <= x1) {
+ // scale [x0, x1] to [y0, y1] using a curve
+ float t = (nits - x0) / (x1 - x0);
+ nits = (1.0 - t) * (1.0 - t) * y0 +
+ 2.0 * (1.0 - t) * t * c1 + t * t * y1;
+ } else if (nits <= x2) {
+ // scale [x1, x2] to [y1, y2] using a curve
+ float t = (nits - x1) / (x2 - x1);
+ nits = (1.0 - t) * (1.0 - t) * y1 +
+ 2.0 * (1.0 - t) * t * c2 + t * t * y2;
+ } else {
+ // scale [x2, x3] to [y2, y3] using a curve
+ float t = (nits - x2) / (x3 - x2);
+ nits = (1.0 - t) * (1.0 - t) * y2 +
+ 2.0 * (1.0 - t) * t * c3 + t * t * y3;
+ }
+
+ return nits;
+ }
+ )");
+ break;
+ default:
+ // For completeness, this is tone-mapping from SDR to SDR, where this is
+ // just a no-op.
+ program.append(R"(
+ float libtonemap_ToneMapTargetNits(vec3 xyz) {
+ return xyz.y;
+ }
+ )");
+ break;
+ }
+ break;
+ }
+
+ program.append(R"(
+ float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz) {
+ if (xyz.y <= 0.0) {
+ return 1.0;
+ }
+ return libtonemap_ToneMapTargetNits(xyz) / xyz.y;
+ }
+ )");
+ return program;
+ }
+
+ std::vector<ShaderUniform> generateShaderSkSLUniforms(const Metadata& metadata) override {
+ std::vector<ShaderUniform> uniforms;
+
+ uniforms.reserve(2);
+
+ uniforms.push_back({.name = "in_libtonemap_displayMaxLuminance",
+ .value = buildUniformValue<float>(metadata.displayMaxLuminance)});
+ uniforms.push_back({.name = "in_libtonemap_inputMaxLuminance",
+ .value = buildUniformValue<float>(metadata.contentMaxLuminance)});
+
+ return uniforms;
+ }
+};
+
+} // namespace
+
+ToneMapper* getToneMapper() {
+ static std::once_flag sOnce;
+ static std::unique_ptr<ToneMapper> sToneMapper;
+
+ std::call_once(sOnce, [&] {
+ switch (kToneMapAlgorithm) {
+ case ToneMapAlgorithm::AndroidO:
+ sToneMapper = std::unique_ptr<ToneMapper>(new ToneMapperO());
+ break;
+ }
+ });
+
+ return sToneMapper.get();
+}
+
+} // namespace android::tonemap
\ No newline at end of file
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 73e5749..8cdb706 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -73,7 +73,6 @@
"libui",
"lib-platform-compat-native-api",
"server_configurable_flags",
- "InputFlingerProperties",
],
static_libs: [
"libattestation",
@@ -125,7 +124,7 @@
"InputListener.cpp",
"InputReaderBase.cpp",
"InputThread.cpp",
- "VibrationElement.cpp"
+ "VibrationElement.cpp",
],
}
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index 171f2b5..4757d31 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -68,7 +68,6 @@
"libutils",
"lib-platform-compat-native-api",
"server_configurable_flags",
- "InputFlingerProperties",
],
static_libs: [
"libattestation",
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 1b19311..6952587 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -19,7 +19,6 @@
#define LOG_NDEBUG 1
-#include <InputFlingerProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -112,15 +111,6 @@
std::mutex& mMutex;
};
-// When per-window-input-rotation is enabled, InputFlinger works in the un-rotated display
-// coordinates and SurfaceFlinger includes the display rotation in the input window transforms.
-bool isPerWindowInputRotationEnabled() {
- static const bool PER_WINDOW_INPUT_ROTATION =
- sysprop::InputFlingerProperties::per_window_input_rotation().value_or(true);
-
- return PER_WINDOW_INPUT_ROTATION;
-}
-
// Default input dispatching timeout if there is no focused application or paused window
// from which to determine an appropriate dispatching timeout.
const std::chrono::duration DEFAULT_INPUT_DISPATCHING_TIMEOUT = std::chrono::milliseconds(
@@ -2519,8 +2509,7 @@
if (displayInfoIt != mDisplayInfos.end()) {
inputTarget.displayTransform = displayInfoIt->second.transform;
} else {
- ALOGI_IF(isPerWindowInputRotationEnabled(),
- "DisplayInfo not found for window on display: %d", windowInfo->displayId);
+ ALOGE("DisplayInfo not found for window on display: %d", windowInfo->displayId);
}
inputTargets.push_back(inputTarget);
it = inputTargets.end() - 1;
@@ -4725,21 +4714,19 @@
}
}
- if (isPerWindowInputRotationEnabled()) {
- // Determine if the orientation of any of the input windows have changed, and cancel all
- // pointer events if necessary.
- for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {
- const sp<WindowInfoHandle> newWindowHandle = getWindowHandleLocked(oldWindowHandle);
- if (newWindowHandle != nullptr &&
- newWindowHandle->getInfo()->transform.getOrientation() !=
- oldWindowOrientations[oldWindowHandle->getId()]) {
- std::shared_ptr<InputChannel> inputChannel =
- getInputChannelLocked(newWindowHandle->getToken());
- if (inputChannel != nullptr) {
- CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
- "touched window's orientation changed");
- synthesizeCancelationEventsForInputChannelLocked(inputChannel, options);
- }
+ // Determine if the orientation of any of the input windows have changed, and cancel all
+ // pointer events if necessary.
+ for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {
+ const sp<WindowInfoHandle> newWindowHandle = getWindowHandleLocked(oldWindowHandle);
+ if (newWindowHandle != nullptr &&
+ newWindowHandle->getInfo()->transform.getOrientation() !=
+ oldWindowOrientations[oldWindowHandle->getId()]) {
+ std::shared_ptr<InputChannel> inputChannel =
+ getInputChannelLocked(newWindowHandle->getToken());
+ if (inputChannel != nullptr) {
+ CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
+ "touched window's orientation changed");
+ synthesizeCancelationEventsForInputChannelLocked(inputChannel, options);
}
}
}
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index ee7b392..51546ce 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -71,7 +71,6 @@
"libstatslog",
"libui",
"libutils",
- "InputFlingerProperties",
],
static_libs: [
"libc++fs",
@@ -86,7 +85,7 @@
name: "libinputreader",
defaults: [
"inputflinger_defaults",
- "libinputreader_defaults"
+ "libinputreader_defaults",
],
srcs: [
"InputReaderFactory.cpp",
@@ -100,6 +99,6 @@
"libinputreader_headers",
],
static_libs: [
- "libc++fs"
+ "libc++fs",
],
}
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index f3d7cdc..15ba459 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -193,28 +193,18 @@
const bool isOrientedDevice =
(mParameters.orientationAware && mParameters.hasAssociatedDisplay);
- if (isPerWindowInputRotationEnabled()) {
- // When per-window input rotation is enabled, InputReader works in the un-rotated
- // coordinate space, so we don't need to do anything if the device is already
- // orientation-aware. If the device is not orientation-aware, then we need to apply the
- // inverse rotation of the display so that when the display rotation is applied later
- // as a part of the per-window transform, we get the expected screen coordinates.
- if (!isOrientedDevice) {
- std::optional<DisplayViewport> internalViewport =
- config->getDisplayViewportByType(ViewportType::INTERNAL);
- if (internalViewport) {
- mOrientation = getInverseRotation(internalViewport->orientation);
- mDisplayWidth = internalViewport->deviceWidth;
- mDisplayHeight = internalViewport->deviceHeight;
- }
- }
- } else {
- if (isOrientedDevice) {
- std::optional<DisplayViewport> internalViewport =
- config->getDisplayViewportByType(ViewportType::INTERNAL);
- if (internalViewport) {
- mOrientation = internalViewport->orientation;
- }
+ // InputReader works in the un-rotated display coordinate space, so we don't need to do
+ // anything if the device is already orientation-aware. If the device is not
+ // orientation-aware, then we need to apply the inverse rotation of the display so that
+ // when the display rotation is applied later as a part of the per-window transform, we
+ // get the expected screen coordinates.
+ if (!isOrientedDevice) {
+ std::optional<DisplayViewport> internalViewport =
+ config->getDisplayViewportByType(ViewportType::INTERNAL);
+ if (internalViewport) {
+ mOrientation = getInverseRotation(internalViewport->orientation);
+ mDisplayWidth = internalViewport->deviceWidth;
+ mDisplayHeight = internalViewport->deviceHeight;
}
}
@@ -347,12 +337,11 @@
if (moved) {
float dx = deltaX;
float dy = deltaY;
- if (isPerWindowInputRotationEnabled()) {
- // Rotate the delta from InputReader's un-rotated coordinate space to
- // PointerController's rotated coordinate space that is oriented with the
- // viewport.
- rotateDelta(getInverseRotation(mOrientation), &dx, &dy);
- }
+ // Rotate the delta from InputReader's un-rotated coordinate space to
+ // PointerController's rotated coordinate space that is oriented with the
+ // viewport.
+ rotateDelta(getInverseRotation(mOrientation), &dx, &dy);
+
mPointerController->move(dx, dy);
}
@@ -364,12 +353,11 @@
}
mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
- if (isPerWindowInputRotationEnabled()) {
- // Rotate the cursor position that is in PointerController's rotated coordinate space
- // to InputReader's un-rotated coordinate space.
- rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/,
- mDisplayWidth, mDisplayHeight);
- }
+ // Rotate the cursor position that is in PointerController's rotated coordinate space
+ // to InputReader's un-rotated coordinate space.
+ rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/,
+ mDisplayWidth, mDisplayHeight);
+
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index 197be98..8c30e38 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -17,7 +17,6 @@
#ifndef _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
#define _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
-#include <InputFlingerProperties.sysprop.h>
#include <input/DisplayViewport.h>
#include <stdint.h>
@@ -29,13 +28,6 @@
// --- Static Definitions ---
-// When per-window input rotation is enabled, display transformations such as rotation and
-// projection are part of the input window's transform. This means InputReader should work in the
-// un-rotated coordinate space.
-static bool isPerWindowInputRotationEnabled() {
- return sysprop::InputFlingerProperties::per_window_input_rotation().value_or(true);
-}
-
static int32_t getInverseRotation(int32_t orientation) {
switch (orientation) {
case DISPLAY_ORIENTATION_90:
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index fd33df9..3fe6fd1 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -168,17 +168,13 @@
: InputMapper(deviceContext),
mSource(0),
mDeviceMode(DeviceMode::DISABLED),
- mRawSurfaceWidth(-1),
- mRawSurfaceHeight(-1),
- mSurfaceLeft(0),
- mSurfaceTop(0),
- mSurfaceRight(0),
- mSurfaceBottom(0),
+ mDisplayWidth(-1),
+ mDisplayHeight(-1),
mPhysicalWidth(-1),
mPhysicalHeight(-1),
mPhysicalLeft(0),
mPhysicalTop(0),
- mSurfaceOrientation(DISPLAY_ORIENTATION_0) {}
+ mInputDeviceOrientation(DISPLAY_ORIENTATION_0) {}
TouchInputMapper::~TouchInputMapper() {}
@@ -266,11 +262,9 @@
dumpRawPointerAxes(dump);
dumpCalibration(dump);
dumpAffineTransformation(dump);
- dumpSurface(dump);
+ dumpDisplay(dump);
dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n");
- dump += StringPrintf(INDENT4 "XTranslate: %0.3f\n", mXTranslate);
- dump += StringPrintf(INDENT4 "YTranslate: %0.3f\n", mYTranslate);
dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale);
dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale);
dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
@@ -390,9 +384,9 @@
InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT |
InputReaderConfiguration::CHANGE_SHOW_TOUCHES |
InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
- // Configure device sources, surface dimensions, orientation and
+ // Configure device sources, display dimensions, orientation and
// scaling factors.
- configureSurface(when, &resetNeeded);
+ configureInputDevice(when, &resetNeeded);
}
if (changes && resetNeeded) {
@@ -615,7 +609,7 @@
return std::make_optional(newViewport);
}
-void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
+void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) {
DeviceMode oldDeviceMode = mDeviceMode;
resolveExternalStylusPresence();
@@ -673,31 +667,28 @@
}
// Raw width and height in the natural orientation.
- int32_t rawWidth = mRawPointerAxes.getRawWidth();
- int32_t rawHeight = mRawPointerAxes.getRawHeight();
+ const int32_t rawWidth = mRawPointerAxes.getRawWidth();
+ const int32_t rawHeight = mRawPointerAxes.getRawHeight();
- bool viewportChanged = mViewport != *newViewport;
+ const bool viewportChanged = mViewport != *newViewport;
bool skipViewportUpdate = false;
if (viewportChanged) {
- bool viewportOrientationChanged = mViewport.orientation != newViewport->orientation;
+ const bool viewportOrientationChanged = mViewport.orientation != newViewport->orientation;
mViewport = *newViewport;
if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) {
- // Convert rotated viewport to natural surface coordinates.
- int32_t naturalLogicalWidth, naturalLogicalHeight;
+ // Convert rotated viewport to the natural orientation.
int32_t naturalPhysicalWidth, naturalPhysicalHeight;
int32_t naturalPhysicalLeft, naturalPhysicalTop;
int32_t naturalDeviceWidth, naturalDeviceHeight;
- // Apply the inverse of the input device orientation so that the surface is configured
- // in the same orientation as the device. The input device orientation will be
- // re-applied to mSurfaceOrientation.
- const int32_t naturalSurfaceOrientation =
+ // Apply the inverse of the input device orientation so that the input device is
+ // configured in the same orientation as the viewport. The input device orientation will
+ // be re-applied by mInputDeviceOrientation.
+ const int32_t naturalDeviceOrientation =
(mViewport.orientation - static_cast<int32_t>(mParameters.orientation) + 4) % 4;
- switch (naturalSurfaceOrientation) {
+ switch (naturalDeviceOrientation) {
case DISPLAY_ORIENTATION_90:
- naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
- naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom;
@@ -706,8 +697,6 @@
naturalDeviceHeight = mViewport.deviceWidth;
break;
case DISPLAY_ORIENTATION_180:
- naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
- naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight;
@@ -716,8 +705,6 @@
naturalDeviceHeight = mViewport.deviceHeight;
break;
case DISPLAY_ORIENTATION_270:
- naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
- naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
naturalPhysicalLeft = mViewport.physicalTop;
@@ -727,8 +714,6 @@
break;
case DISPLAY_ORIENTATION_0:
default:
- naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
- naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
naturalPhysicalLeft = mViewport.physicalLeft;
@@ -749,58 +734,36 @@
mPhysicalLeft = naturalPhysicalLeft;
mPhysicalTop = naturalPhysicalTop;
- if (isPerWindowInputRotationEnabled()) {
- // When per-window input rotation is enabled, InputReader works in the display
- // space, so the surface bounds are the bounds of the display device.
- const int32_t oldSurfaceWidth = mRawSurfaceWidth;
- const int32_t oldSurfaceHeight = mRawSurfaceHeight;
- mRawSurfaceWidth = naturalDeviceWidth;
- mRawSurfaceHeight = naturalDeviceHeight;
- mSurfaceLeft = 0;
- mSurfaceTop = 0;
- mSurfaceRight = mRawSurfaceWidth;
- mSurfaceBottom = mRawSurfaceHeight;
- // When per-window input rotation is enabled, InputReader works in the un-rotated
- // coordinate space, so we don't need to do anything if the device is already
- // orientation-aware. If the device is not orientation-aware, then we need to apply
- // the inverse rotation of the display so that when the display rotation is applied
- // later as a part of the per-window transform, we get the expected screen
- // coordinates.
- mSurfaceOrientation = mParameters.orientationAware
- ? DISPLAY_ORIENTATION_0
- : getInverseRotation(mViewport.orientation);
- // For orientation-aware devices that work in the un-rotated coordinate space, the
- // viewport update should be skipped if it is only a change in the orientation.
- skipViewportUpdate = mParameters.orientationAware &&
- mRawSurfaceWidth == oldSurfaceWidth &&
- mRawSurfaceHeight == oldSurfaceHeight && viewportOrientationChanged;
- } else {
- mRawSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
- mRawSurfaceHeight =
- naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
- mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
- mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight;
- mSurfaceRight = mSurfaceLeft + naturalLogicalWidth;
- mSurfaceBottom = mSurfaceTop + naturalLogicalHeight;
+ const int32_t oldDisplayWidth = mDisplayWidth;
+ const int32_t oldDisplayHeight = mDisplayHeight;
+ mDisplayWidth = naturalDeviceWidth;
+ mDisplayHeight = naturalDeviceHeight;
- mSurfaceOrientation = mParameters.orientationAware ? mViewport.orientation
- : DISPLAY_ORIENTATION_0;
- }
+ // InputReader works in the un-rotated display coordinate space, so we don't need to do
+ // anything if the device is already orientation-aware. If the device is not
+ // orientation-aware, then we need to apply the inverse rotation of the display so that
+ // when the display rotation is applied later as a part of the per-window transform, we
+ // get the expected screen coordinates.
+ mInputDeviceOrientation = mParameters.orientationAware
+ ? DISPLAY_ORIENTATION_0
+ : getInverseRotation(mViewport.orientation);
+ // For orientation-aware devices that work in the un-rotated coordinate space, the
+ // viewport update should be skipped if it is only a change in the orientation.
+ skipViewportUpdate = mParameters.orientationAware && mDisplayWidth == oldDisplayWidth &&
+ mDisplayHeight == oldDisplayHeight && viewportOrientationChanged;
// Apply the input device orientation for the device.
- mSurfaceOrientation =
- (mSurfaceOrientation + static_cast<int32_t>(mParameters.orientation)) % 4;
+ mInputDeviceOrientation =
+ (mInputDeviceOrientation + static_cast<int32_t>(mParameters.orientation)) % 4;
} else {
mPhysicalWidth = rawWidth;
mPhysicalHeight = rawHeight;
mPhysicalLeft = 0;
mPhysicalTop = 0;
- mRawSurfaceWidth = rawWidth;
- mRawSurfaceHeight = rawHeight;
- mSurfaceLeft = 0;
- mSurfaceTop = 0;
- mSurfaceOrientation = DISPLAY_ORIENTATION_0;
+ mDisplayWidth = rawWidth;
+ mDisplayHeight = rawHeight;
+ mInputDeviceOrientation = DISPLAY_ORIENTATION_0;
}
}
@@ -829,14 +792,12 @@
if ((viewportChanged && !skipViewportUpdate) || deviceModeChanged) {
ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, "
"display id %d",
- getDeviceId(), getDeviceName().c_str(), mRawSurfaceWidth, mRawSurfaceHeight,
- mSurfaceOrientation, mDeviceMode, mViewport.displayId);
+ getDeviceId(), getDeviceName().c_str(), mDisplayWidth, mDisplayHeight,
+ mInputDeviceOrientation, mDeviceMode, mViewport.displayId);
// Configure X and Y factors.
- mXScale = float(mRawSurfaceWidth) / rawWidth;
- mYScale = float(mRawSurfaceHeight) / rawHeight;
- mXTranslate = -mSurfaceLeft;
- mYTranslate = -mSurfaceTop;
+ mXScale = float(mDisplayWidth) / rawWidth;
+ mYScale = float(mDisplayHeight) / rawHeight;
mXPrecision = 1.0f / mXScale;
mYPrecision = 1.0f / mYScale;
@@ -853,7 +814,7 @@
mGeometricScale = avg(mXScale, mYScale);
// Size of diagonal axis.
- float diagonalSize = hypotf(mRawSurfaceWidth, mRawSurfaceHeight);
+ float diagonalSize = hypotf(mDisplayWidth, mDisplayHeight);
// Size factors.
if (mCalibration.sizeCalibration != Calibration::SizeCalibration::NONE) {
@@ -1015,21 +976,21 @@
// Compute oriented precision, scales and ranges.
// Note that the maximum value reported is an inclusive maximum value so it is one
- // unit less than the total width or height of surface.
- switch (mSurfaceOrientation) {
+ // unit less than the total width or height of the display.
+ switch (mInputDeviceOrientation) {
case DISPLAY_ORIENTATION_90:
case DISPLAY_ORIENTATION_270:
mOrientedXPrecision = mYPrecision;
mOrientedYPrecision = mXPrecision;
- mOrientedRanges.x.min = mYTranslate;
- mOrientedRanges.x.max = mRawSurfaceHeight + mYTranslate - 1;
+ mOrientedRanges.x.min = 0;
+ mOrientedRanges.x.max = mDisplayHeight - 1;
mOrientedRanges.x.flat = 0;
mOrientedRanges.x.fuzz = 0;
mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;
- mOrientedRanges.y.min = mXTranslate;
- mOrientedRanges.y.max = mRawSurfaceWidth + mXTranslate - 1;
+ mOrientedRanges.y.min = 0;
+ mOrientedRanges.y.max = mDisplayWidth - 1;
mOrientedRanges.y.flat = 0;
mOrientedRanges.y.fuzz = 0;
mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
@@ -1039,14 +1000,14 @@
mOrientedXPrecision = mXPrecision;
mOrientedYPrecision = mYPrecision;
- mOrientedRanges.x.min = mXTranslate;
- mOrientedRanges.x.max = mRawSurfaceWidth + mXTranslate - 1;
+ mOrientedRanges.x.min = 0;
+ mOrientedRanges.x.max = mDisplayWidth - 1;
mOrientedRanges.x.flat = 0;
mOrientedRanges.x.fuzz = 0;
mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;
- mOrientedRanges.y.min = mYTranslate;
- mOrientedRanges.y.max = mRawSurfaceHeight + mYTranslate - 1;
+ mOrientedRanges.y.min = 0;
+ mOrientedRanges.y.max = mDisplayHeight - 1;
mOrientedRanges.y.flat = 0;
mOrientedRanges.y.fuzz = 0;
mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
@@ -1059,7 +1020,7 @@
if (mDeviceMode == DeviceMode::POINTER) {
// Compute pointer gesture detection parameters.
float rawDiagonal = hypotf(rawWidth, rawHeight);
- float displayDiagonal = hypotf(mRawSurfaceWidth, mRawSurfaceHeight);
+ float displayDiagonal = hypotf(mDisplayWidth, mDisplayHeight);
// Scale movements such that one whole swipe of the touch pad covers a
// given area relative to the diagonal size of the display when no acceleration
@@ -1093,19 +1054,15 @@
}
}
-void TouchInputMapper::dumpSurface(std::string& dump) {
+void TouchInputMapper::dumpDisplay(std::string& dump) {
dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str());
- dump += StringPrintf(INDENT3 "RawSurfaceWidth: %dpx\n", mRawSurfaceWidth);
- dump += StringPrintf(INDENT3 "RawSurfaceHeight: %dpx\n", mRawSurfaceHeight);
- dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
- dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
- dump += StringPrintf(INDENT3 "SurfaceRight: %d\n", mSurfaceRight);
- dump += StringPrintf(INDENT3 "SurfaceBottom: %d\n", mSurfaceBottom);
+ dump += StringPrintf(INDENT3 "DisplayWidth: %dpx\n", mDisplayWidth);
+ dump += StringPrintf(INDENT3 "DisplayHeight: %dpx\n", mDisplayHeight);
dump += StringPrintf(INDENT3 "PhysicalWidth: %dpx\n", mPhysicalWidth);
dump += StringPrintf(INDENT3 "PhysicalHeight: %dpx\n", mPhysicalHeight);
dump += StringPrintf(INDENT3 "PhysicalLeft: %d\n", mPhysicalLeft);
dump += StringPrintf(INDENT3 "PhysicalTop: %d\n", mPhysicalTop);
- dump += StringPrintf(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation);
+ dump += StringPrintf(INDENT3 "InputDeviceOrientation: %d\n", mInputDeviceOrientation);
}
void TouchInputMapper::configureVirtualKeys() {
@@ -1144,16 +1101,16 @@
int32_t halfHeight = virtualKeyDefinition.height / 2;
virtualKey.hitLeft =
- (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mRawSurfaceWidth +
+ (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mDisplayWidth +
touchScreenLeft;
virtualKey.hitRight =
- (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mRawSurfaceWidth +
+ (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mDisplayWidth +
touchScreenLeft;
- virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight /
- mRawSurfaceHeight +
+ virtualKey.hitTop =
+ (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / mDisplayHeight +
touchScreenTop;
- virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight /
- mRawSurfaceHeight +
+ virtualKey.hitBottom =
+ (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mDisplayHeight +
touchScreenTop;
mVirtualKeys.push_back(virtualKey);
}
@@ -1419,7 +1376,7 @@
void TouchInputMapper::updateAffineTransformation() {
mAffineTransform = getPolicy()->getTouchAffineTransformation(getDeviceContext().getDescriptor(),
- mSurfaceOrientation);
+ mInputDeviceOrientation);
}
void TouchInputMapper::reset(nsecs_t when) {
@@ -1867,8 +1824,10 @@
// Pointer just went down. Check for virtual key press or off-screen touches.
uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id);
- // Exclude unscaled device for inside surface checking.
- if (!isPointInsideSurface(pointer.x, pointer.y) && mDeviceMode != DeviceMode::UNSCALED) {
+ // Skip checking whether the pointer is inside the physical frame if the device is in
+ // unscaled mode.
+ if (!isPointInsidePhysicalFrame(pointer.x, pointer.y) &&
+ mDeviceMode != DeviceMode::UNSCALED) {
// If exactly one pointer went down, check for virtual key hit.
// Otherwise we will drop the entire stroke.
if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
@@ -2137,7 +2096,7 @@
}
// Walk through the the active pointers and map device coordinates onto
- // surface coordinates and adjust for display orientation.
+ // display coordinates and adjust for display orientation.
for (uint32_t i = 0; i < currentPointerCount; i++) {
const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];
@@ -2297,15 +2256,15 @@
mAffineTransform.applyTo(xTransformed, yTransformed);
rotateAndScale(xTransformed, yTransformed);
- // Adjust X, Y, and coverage coords for surface orientation.
+ // Adjust X, Y, and coverage coords for input device orientation.
float left, top, right, bottom;
- switch (mSurfaceOrientation) {
+ switch (mInputDeviceOrientation) {
case DISPLAY_ORIENTATION_90:
- left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
- right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
- bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
- top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
+ left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale;
+ right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale;
+ bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
+ top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
orientation -= M_PI_2;
if (mOrientedRanges.haveOrientation &&
orientation < mOrientedRanges.orientation.min) {
@@ -2316,8 +2275,8 @@
case DISPLAY_ORIENTATION_180:
left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
- bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
- top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
+ bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
+ top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
orientation -= M_PI;
if (mOrientedRanges.haveOrientation &&
orientation < mOrientedRanges.orientation.min) {
@@ -2328,8 +2287,8 @@
case DISPLAY_ORIENTATION_270:
left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
- bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
- top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
+ bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale;
+ top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale;
orientation += M_PI_2;
if (mOrientedRanges.haveOrientation &&
orientation > mOrientedRanges.orientation.max) {
@@ -2338,10 +2297,10 @@
}
break;
default:
- left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
- right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
- bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
- top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
+ left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale;
+ right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale;
+ bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale;
+ top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale;
break;
}
@@ -2854,7 +2813,7 @@
deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
- rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
+ rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
mPointerVelocityControl.move(when, &deltaX, &deltaY);
// Move the pointer using a relative motion.
@@ -2988,7 +2947,7 @@
deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
- rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
+ rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
mPointerVelocityControl.move(when, &deltaX, &deltaY);
// Move the pointer using a relative motion.
@@ -3246,7 +3205,7 @@
commonDeltaX *= mPointerXMovementScale;
commonDeltaY *= mPointerYMovementScale;
- rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY);
+ rotateDelta(mInputDeviceOrientation, &commonDeltaX, &commonDeltaY);
mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
mPointerGesture.referenceGestureX += commonDeltaX;
@@ -3356,7 +3315,7 @@
mCurrentRawState.rawPointerData.pointerForId(touchId);
float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale;
float deltaY = (pointer.y - mPointerGesture.referenceTouchY) * mPointerYZoomScale;
- rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
+ rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
mPointerGesture.currentGestureProperties[i].clear();
mPointerGesture.currentGestureProperties[i].id = gestureId;
@@ -3472,7 +3431,7 @@
mLastRawState.rawPointerData.pointers[lastIndex].y) *
mPointerYMovementScale;
- rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
+ rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
mPointerVelocityControl.move(when, &deltaX, &deltaY);
moveMouseCursor(deltaX, deltaY);
@@ -3697,7 +3656,7 @@
const int32_t deviceId = getDeviceId();
std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
std::for_each(frames.begin(), frames.end(),
- [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
+ [this](TouchVideoFrame& frame) { frame.rotate(this->mInputDeviceOrientation); });
NotifyMotionArgs args(getContext()->getNextId(), when, readTime, deviceId, source, displayId,
policyFlags, action, actionButton, flags, metaState, buttonState,
MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
@@ -3741,56 +3700,49 @@
abortTouches(when, readTime, 0 /* policyFlags*/);
}
-// Transform raw coordinate to surface coordinate
-void TouchInputMapper::rotateAndScale(float& x, float& y) {
- // Scale to surface coordinate.
+// Transform input device coordinates to display panel coordinates.
+void TouchInputMapper::rotateAndScale(float& x, float& y) const {
const float xScaled = float(x - mRawPointerAxes.x.minValue) * mXScale;
const float yScaled = float(y - mRawPointerAxes.y.minValue) * mYScale;
const float xScaledMax = float(mRawPointerAxes.x.maxValue - x) * mXScale;
const float yScaledMax = float(mRawPointerAxes.y.maxValue - y) * mYScale;
- // Rotate to surface coordinate.
+ // Rotate to display coordinate.
// 0 - no swap and reverse.
// 90 - swap x/y and reverse y.
// 180 - reverse x, y.
// 270 - swap x/y and reverse x.
- switch (mSurfaceOrientation) {
+ switch (mInputDeviceOrientation) {
case DISPLAY_ORIENTATION_0:
- x = xScaled + mXTranslate;
- y = yScaled + mYTranslate;
+ x = xScaled;
+ y = yScaled;
break;
case DISPLAY_ORIENTATION_90:
- y = xScaledMax - (mRawSurfaceWidth - mSurfaceRight);
- x = yScaled + mYTranslate;
+ y = xScaledMax;
+ x = yScaled;
break;
case DISPLAY_ORIENTATION_180:
- x = xScaledMax - (mRawSurfaceWidth - mSurfaceRight);
- y = yScaledMax - (mRawSurfaceHeight - mSurfaceBottom);
+ x = xScaledMax;
+ y = yScaledMax;
break;
case DISPLAY_ORIENTATION_270:
- y = xScaled + mXTranslate;
- x = yScaledMax - (mRawSurfaceHeight - mSurfaceBottom);
+ y = xScaled;
+ x = yScaledMax;
break;
default:
assert(false);
}
}
-bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
+bool TouchInputMapper::isPointInsidePhysicalFrame(int32_t x, int32_t y) const {
const float xScaled = (x - mRawPointerAxes.x.minValue) * mXScale;
const float yScaled = (y - mRawPointerAxes.y.minValue) * mYScale;
- if (isPerWindowInputRotationEnabled()) {
- return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
- xScaled >= mPhysicalLeft && xScaled <= (mPhysicalLeft + mPhysicalWidth) &&
- y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
- yScaled >= mPhysicalTop && yScaled <= (mPhysicalTop + mPhysicalHeight);
- }
return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
- xScaled >= mSurfaceLeft && xScaled <= mSurfaceRight &&
+ xScaled >= mPhysicalLeft && xScaled <= (mPhysicalLeft + mPhysicalWidth) &&
y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
- yScaled >= mSurfaceTop && yScaled <= mSurfaceBottom;
+ yScaled >= mPhysicalTop && yScaled <= (mPhysicalTop + mPhysicalHeight);
}
const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) {
@@ -4048,11 +4000,9 @@
}
void TouchInputMapper::moveMouseCursor(float dx, float dy) const {
- if (isPerWindowInputRotationEnabled()) {
- // Convert from InputReader's un-rotated coordinate space to PointerController's coordinate
- // space that is oriented with the viewport.
- rotateDelta(mViewport.orientation, &dx, &dy);
- }
+ // Convert from InputReader's un-rotated coordinate space to PointerController's coordinate
+ // space that is oriented with the viewport.
+ rotateDelta(mViewport.orientation, &dx, &dy);
mPointerController->move(dx, dy);
}
@@ -4062,7 +4012,6 @@
float y = 0;
mPointerController->getPosition(&x, &y);
- if (!isPerWindowInputRotationEnabled()) return {x, y};
if (!mViewport.isValid()) return {x, y};
// Convert from PointerController's rotated coordinate space that is oriented with the viewport
@@ -4073,11 +4022,9 @@
}
void TouchInputMapper::setMouseCursorPosition(float x, float y) const {
- if (isPerWindowInputRotationEnabled() && mViewport.isValid()) {
- // Convert from InputReader's un-rotated coordinate space to PointerController's rotated
- // coordinate space that is oriented with the viewport.
- rotatePoint(mViewport.orientation, x, y, mRawSurfaceWidth, mRawSurfaceHeight);
- }
+ // Convert from InputReader's un-rotated coordinate space to PointerController's rotated
+ // coordinate space that is oriented with the viewport.
+ rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight);
mPointerController->setPosition(x, y);
}
@@ -4092,11 +4039,9 @@
float y = spotCoords[index].getY();
float pressure = spotCoords[index].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
- if (isPerWindowInputRotationEnabled()) {
- // Convert from InputReader's un-rotated coordinate space to PointerController's rotated
- // coordinate space.
- rotatePoint(mViewport.orientation, x, y, mRawSurfaceWidth, mRawSurfaceHeight);
- }
+ // Convert from InputReader's un-rotated coordinate space to PointerController's rotated
+ // coordinate space.
+ rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight);
outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_X, x);
outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 3340672..496491b 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -406,8 +406,8 @@
virtual void dumpParameters(std::string& dump);
virtual void configureRawPointerAxes();
virtual void dumpRawPointerAxes(std::string& dump);
- virtual void configureSurface(nsecs_t when, bool* outResetNeeded);
- virtual void dumpSurface(std::string& dump);
+ virtual void configureInputDevice(nsecs_t when, bool* outResetNeeded);
+ virtual void dumpDisplay(std::string& dump);
virtual void configureVirtualKeys();
virtual void dumpVirtualKeys(std::string& dump);
virtual void parseCalibration();
@@ -426,39 +426,27 @@
// The components of the viewport are specified in the display's rotated orientation.
DisplayViewport mViewport;
- // The surface orientation, width and height set by configureSurface().
- // The width and height are derived from the viewport but are specified
+ // The width and height are obtained from the viewport and are specified
// in the natural orientation.
- // They could be used for calculating diagonal, scaling factors, and virtual keys.
- int32_t mRawSurfaceWidth;
- int32_t mRawSurfaceHeight;
+ int32_t mDisplayWidth;
+ int32_t mDisplayHeight;
- // The surface origin specifies how the surface coordinates should be translated
- // to align with the logical display coordinate space.
- // TODO(b/188939842): Remove surface coordinates when Per-Window Input Rotation is enabled.
- int32_t mSurfaceLeft;
- int32_t mSurfaceTop;
- int32_t mSurfaceRight;
- int32_t mSurfaceBottom;
-
- // Similar to the surface coordinates, but in the raw display coordinate space rather than in
- // the logical coordinate space.
+ // The physical frame is the rectangle in the display's coordinate space that maps to the
+ // the logical display frame.
int32_t mPhysicalWidth;
int32_t mPhysicalHeight;
int32_t mPhysicalLeft;
int32_t mPhysicalTop;
- // The orientation may be different from the viewport orientation as it specifies
- // the rotation of the surface coordinates required to produce the viewport's
- // requested orientation, so it will depend on whether the device is orientation aware.
- int32_t mSurfaceOrientation;
+ // The orientation of the input device relative to that of the display panel. It specifies
+ // the rotation of the input device coordinates required to produce the display panel
+ // orientation, so it will depend on whether the device is orientation aware.
+ int32_t mInputDeviceOrientation;
// Translation and scaling factors, orientation-independent.
- float mXTranslate;
float mXScale;
float mXPrecision;
- float mYTranslate;
float mYScale;
float mYPrecision;
@@ -808,13 +796,13 @@
// touchscreen.
void updateTouchSpots();
- bool isPointInsideSurface(int32_t x, int32_t y);
+ bool isPointInsidePhysicalFrame(int32_t x, int32_t y) const;
const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y);
static void assignPointerIds(const RawState& last, RawState& current);
const char* modeToString(DeviceMode deviceMode);
- void rotateAndScale(float& x, float& y);
+ void rotateAndScale(float& x, float& y) const;
// Wrapper methods for interfacing with PointerController. These are used to convert points
// between the coordinate spaces used by InputReader and PointerController, if they differ.
diff --git a/services/inputflinger/sysprop/Android.bp b/services/inputflinger/sysprop/Android.bp
deleted file mode 100644
index b9d65ee..0000000
--- a/services/inputflinger/sysprop/Android.bp
+++ /dev/null
@@ -1,15 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-sysprop_library {
- name: "InputFlingerProperties",
- srcs: ["*.sysprop"],
- api_packages: ["android.sysprop"],
- property_owner: "Platform",
-}
diff --git a/services/inputflinger/sysprop/InputFlingerProperties.sysprop b/services/inputflinger/sysprop/InputFlingerProperties.sysprop
deleted file mode 100644
index 1c7e724..0000000
--- a/services/inputflinger/sysprop/InputFlingerProperties.sysprop
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2021 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.
-
-module: "android.sysprop.InputFlingerProperties"
-owner: Platform
-
-# When per-window-input-rotation is enabled, InputReader works in the un-rotated
-# display coordinate space, and the display rotation is encoded as part of the
-# input window transform that is sent from SurfaceFlinger to InputDispatcher.
-prop {
- api_name: "per_window_input_rotation"
- type: Boolean
- scope: Internal
- access: ReadWrite
- prop_name: "persist.debug.per_window_input_rotation"
-}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 53b03ad..336afc6 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -16,7 +16,6 @@
#include <CursorInputMapper.h>
#include <InputDevice.h>
-#include <InputFlingerProperties.sysprop.h>
#include <InputMapper.h>
#include <InputReader.h>
#include <InputReaderBase.h>
@@ -2695,7 +2694,6 @@
static const int32_t DEVICE_CONTROLLER_NUMBER;
static const Flags<InputDeviceClass> DEVICE_CLASSES;
static const int32_t EVENTHUB_ID;
- static const std::optional<bool> INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE;
std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
@@ -2713,18 +2711,12 @@
}
void SetUp() override {
- // Ensure per_window_input_rotation is enabled.
- sysprop::InputFlingerProperties::per_window_input_rotation(true);
-
SetUp(DEVICE_CLASSES);
}
void TearDown() override {
mFakeListener.reset();
mFakePolicy.clear();
-
- sysprop::InputFlingerProperties::per_window_input_rotation(
- INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE);
}
void addConfigurationProperty(const char* key, const char* value) {
@@ -2836,8 +2828,6 @@
const Flags<InputDeviceClass> InputMapperTest::DEVICE_CLASSES =
Flags<InputDeviceClass>(0); // not needed for current tests
const int32_t InputMapperTest::EVENTHUB_ID = 1;
-const std::optional<bool> InputMapperTest::INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE =
- sysprop::InputFlingerProperties::per_window_input_rotation();
// --- SwitchInputMapperTest ---
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 4e29172..fb42cc0 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -79,6 +79,7 @@
"libperfetto_client_experimental",
"librenderengine",
"libserviceutils",
+ "libtonemap",
"libtrace_proto",
"libaidlcommonsupport",
],
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 88e3fb6..b4ccb80 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -549,19 +549,13 @@
}
bool BufferStateLayer::setTransactionCompletedListeners(
- const std::vector<ListenerCallbacks>& listenerCallbacks, const sp<IBinder>& layerHandle) {
+ const std::vector<sp<CallbackHandle>>& handles) {
// If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return
- if (listenerCallbacks.empty()) {
+ if (handles.empty()) {
mReleasePreviousBuffer = false;
return false;
}
- std::vector<sp<CallbackHandle>> handles;
- handles.reserve(listenerCallbacks.size());
- for (auto& [listener, callbackIds] : listenerCallbacks) {
- handles.emplace_back(new CallbackHandle(listener, callbackIds, layerHandle));
- }
-
const bool willPresent = willPresentCurrentTransaction();
for (const auto& handle : handles) {
@@ -577,10 +571,9 @@
// Store so latched time and release fence can be set
mDrawingState.callbackHandles.push_back(handle);
- } else {
- // If this layer will NOT need to be relatched and presented this frame
+ } else { // If this layer will NOT need to be relatched and presented this frame
// Notify the transaction completed thread this handle is done
- mFlinger->getTransactionCallbackInvoker().addUnpresentedCallbackHandle(handle);
+ mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle);
}
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index ceed188..eea700c 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -65,8 +65,7 @@
bool setSurfaceDamageRegion(const Region& surfaceDamage) override;
bool setApi(int32_t api) override;
bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
- bool setTransactionCompletedListeners(const std::vector<ListenerCallbacks>& handles,
- const sp<IBinder>& layerHandle) override;
+ bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
bool addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
nsecs_t requestedPresentTime) override;
bool setPosition(float /*x*/, float /*y*/) override;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 83b4a25..aefc014 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -38,6 +38,7 @@
static_libs: [
"libmath",
"librenderengine",
+ "libtonemap",
"libtrace_proto",
"libaidlcommonsupport",
],
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f5c5b4a..968a49d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2628,17 +2628,6 @@
return true;
}
-bool Layer::setTransactionCompletedListeners(
- const std::vector<ListenerCallbacks>& listenerCallbacks, const sp<IBinder>&) {
- if (listenerCallbacks.empty()) {
- return false;
- }
- for (auto& listener : listenerCallbacks) {
- mFlinger->getTransactionCallbackInvoker().addEmptyCallback(listener);
- }
- return false;
-}
-
// ---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 5af8dda..bda1c28 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -426,8 +426,10 @@
virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; };
virtual bool setApi(int32_t /*api*/) { return false; };
virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
- virtual bool setTransactionCompletedListeners(const std::vector<ListenerCallbacks>& /*handles*/,
- const sp<IBinder>& /* layerHandle */);
+ virtual bool setTransactionCompletedListeners(
+ const std::vector<sp<CallbackHandle>>& /*handles*/) {
+ return false;
+ };
virtual bool addFrameEvent(const sp<Fence>& /*acquireFence*/, nsecs_t /*postedTime*/,
nsecs_t /*requestedPresentTime*/) {
return false;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a990e6b..9ee4885 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1964,9 +1964,34 @@
{
mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod));
- mustComposite |= flushAndCommitTransactions();
+ bool needsTraversal = false;
+ if (clearTransactionFlags(eTransactionFlushNeeded)) {
+ needsTraversal = flushTransactionQueues();
+ }
+
+ const bool shouldCommit =
+ (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal;
+ if (shouldCommit) {
+ commitTransactions();
+ }
+
+ if (transactionFlushNeeded()) {
+ setTransactionFlags(eTransactionFlushNeeded);
+ }
+
+ mustComposite |= shouldCommit;
mustComposite |= latchBuffers();
+ // This has to be called after latchBuffers because we want to include the layers that have
+ // been latched in the commit callback
+ if (!needsTraversal) {
+ // Invoke empty transaction callbacks early.
+ mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */);
+ } else {
+ // Invoke OnCommit callbacks.
+ mTransactionCallbackInvoker.sendCallbacks(true /* onCommitOnly */);
+ }
+
updateLayerGeometry();
}
@@ -1987,34 +2012,6 @@
return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}
-bool SurfaceFlinger::flushAndCommitTransactions() {
- ATRACE_CALL();
-
- bool needsTraversal = false;
- if (clearTransactionFlags(eTransactionFlushNeeded)) {
- needsTraversal = flushTransactionQueues();
- }
-
- const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal;
- if (shouldCommit) {
- commitTransactions();
- }
-
- if (!needsTraversal) {
- // Invoke empty transaction callbacks early.
- mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */);
- } else {
- // Invoke OnCommit callbacks.
- mTransactionCallbackInvoker.sendCallbacks(true /* onCommitOnly */);
- }
-
- if (transactionFlushNeeded()) {
- setTransactionFlags(eTransactionFlushNeeded);
- }
-
- return shouldCommit;
-}
-
void SurfaceFlinger::composite(nsecs_t frameTime) {
ATRACE_CALL();
@@ -3028,32 +3025,24 @@
mInputWindowCommands.clear();
}
-bool enablePerWindowInputRotation() {
- static bool value =
- android::base::GetBoolProperty("persist.debug.per_window_input_rotation", true);
- return value;
-}
-
void SurfaceFlinger::notifyWindowInfos() {
std::vector<WindowInfo> windowInfos;
std::vector<DisplayInfo> displayInfos;
std::unordered_map<uint32_t /*layerStackId*/, const ui::Transform> displayTransforms;
- if (enablePerWindowInputRotation()) {
- for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
- if (!display->receivesInput()) {
- continue;
- }
- const uint32_t layerStackId = display->getLayerStack().id;
- const auto& [info, transform] = display->getInputInfo();
- const auto& [it, emplaced] = displayTransforms.try_emplace(layerStackId, transform);
- if (!emplaced) {
- ALOGE("Multiple displays claim to accept input for the same layer stack: %u",
- layerStackId);
- continue;
- }
- displayInfos.emplace_back(info);
+ for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ if (!display->receivesInput()) {
+ continue;
}
+ const uint32_t layerStackId = display->getLayerStack().id;
+ const auto& [info, transform] = display->getInputInfo();
+ const auto& [it, emplaced] = displayTransforms.try_emplace(layerStackId, transform);
+ if (!emplaced) {
+ ALOGE("Multiple displays claim to accept input for the same layer stack: %u",
+ layerStackId);
+ continue;
+ }
+ displayInfos.emplace_back(info);
}
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
@@ -3062,7 +3051,7 @@
const DisplayDevice* display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get();
ui::Transform displayTransform = ui::Transform();
- if (enablePerWindowInputRotation() && display != nullptr) {
+ if (display != nullptr) {
// When calculating the screen bounds we ignore the transparent region since it may
// result in an unwanted offset.
const auto it = displayTransforms.find(display->getLayerStack().id);
@@ -3780,10 +3769,11 @@
transactionFlags |= setDisplayStateLocked(display);
}
- // Add listeners w/ surfaces so they can get their callback. Note that listeners with
- // SurfaceControls will start registration during setClientStateLocked below.
+ // start and end registration for listeners w/ no surface so they can get their callback. Note
+ // that listeners with SurfaceControls will start registration during setClientStateLocked
+ // below.
for (const auto& listener : listenerCallbacks) {
- mTransactionCallbackInvoker.addEmptyCallback(listener);
+ mTransactionCallbackInvoker.addEmptyTransaction(listener);
}
uint32_t clientStateFlags = 0;
@@ -3955,7 +3945,7 @@
}
if (layer == nullptr) {
for (auto& [listener, callbackIds] : s.listeners) {
- mTransactionCallbackInvoker.addUnpresentedCallbackHandle(
+ mTransactionCallbackInvoker.registerUnpresentedCallbackHandle(
new CallbackHandle(listener, callbackIds, s.surface));
}
return 0;
@@ -4226,6 +4216,12 @@
flags |= eTransactionNeeded | eTraversalNeeded;
}
}
+ std::vector<sp<CallbackHandle>> callbackHandles;
+ if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) {
+ for (auto& [listener, callbackIds] : filteredListeners) {
+ callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
+ }
+ }
if (what & layer_state_t::eBufferChanged &&
layer->setBuffer(s.bufferData, postTime, desiredPresentTime, isAutoTimestamp,
@@ -4235,11 +4231,7 @@
layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime);
}
- if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) {
- if (layer->setTransactionCompletedListeners(filteredListeners, s.surface)) {
- flags |= eTraversalNeeded;
- }
- }
+ if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
// Do not put anything that updates layer state or modifies flags after
// setTransactionCompletedListener
return flags;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e3bcde2..8897858 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -684,9 +684,6 @@
const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
EXCLUDES(mStateLock);
- // Returns whether transactions were committed.
- bool flushAndCommitTransactions() EXCLUDES(mStateLock);
-
void commitTransactions() EXCLUDES(mStateLock);
void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
void doCommitTransactions() REQUIRES(mStateLock);
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index 418fbc5..f3d46ea 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -74,10 +74,10 @@
}
}
-void TransactionCallbackInvoker::addEmptyCallback(const ListenerCallbacks& listenerCallbacks) {
+void TransactionCallbackInvoker::addEmptyTransaction(const ListenerCallbacks& listenerCallbacks) {
auto& [listener, callbackIds] = listenerCallbacks;
- TransactionStats* transactionStats;
- findOrCreateTransactionStats(listener, callbackIds, &transactionStats);
+ auto& transactionStatsDeque = mCompletedTransactions[listener];
+ transactionStatsDeque.emplace_back(callbackIds);
}
status_t TransactionCallbackInvoker::addOnCommitCallbackHandles(
@@ -116,7 +116,7 @@
return NO_ERROR;
}
-status_t TransactionCallbackInvoker::addUnpresentedCallbackHandle(
+status_t TransactionCallbackInvoker::registerUnpresentedCallbackHandle(
const sp<CallbackHandle>& handle) {
return addCallbackHandle(handle, std::vector<JankData>());
}
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 6f67947..e203d41 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -71,10 +71,8 @@
// Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
// presented this frame.
- status_t addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
- // Adds the callback handles for empty transactions or for non-buffer layer updates which do not
- // include layer stats.
- void addEmptyCallback(const ListenerCallbacks& listenerCallbacks);
+ status_t registerUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
+ void addEmptyTransaction(const ListenerCallbacks& listenerCallbacks);
void addPresentFence(const sp<Fence>& presentFence);
@@ -83,12 +81,14 @@
mCompletedTransactions.clear();
}
+ status_t addCallbackHandle(const sp<CallbackHandle>& handle,
+ const std::vector<JankData>& jankData);
+
+
private:
status_t findOrCreateTransactionStats(const sp<IBinder>& listener,
const std::vector<CallbackId>& callbackIds,
TransactionStats** outTransactionStats);
- status_t addCallbackHandle(const sp<CallbackHandle>& handle,
- const std::vector<JankData>& jankData);
std::unordered_map<sp<IBinder>, std::deque<TransactionStats>, IListenerHash>
mCompletedTransactions;
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 7beba15..5c16fee 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -26,6 +26,7 @@
namespace android {
using android::hardware::graphics::common::V1_1::BufferUsage;
+using SCHash = SurfaceComposerClient::SCHash;
::testing::Environment* const binderEnv =
::testing::AddGlobalTestEnvironment(new BinderEnvironment());
@@ -102,6 +103,24 @@
}
}
+ static void waitForCommitCallback(
+ CallbackHelper& helper,
+ const std::unordered_set<sp<SurfaceControl>, SCHash>& committedSc) {
+ CallbackData callbackData;
+ ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData));
+
+ const auto& surfaceControlStats = callbackData.surfaceControlStats;
+
+ ASSERT_EQ(surfaceControlStats.size(), committedSc.size()) << "wrong number of surfaces";
+
+ for (const auto& stats : surfaceControlStats) {
+ ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control";
+
+ const auto& expectedSc = committedSc.find(stats.surfaceControl);
+ ASSERT_NE(expectedSc, committedSc.end()) << "unexpected surface control";
+ }
+ }
+
DisplayEventReceiver mDisplayEventReceiver;
int mEpollFd;
@@ -1067,7 +1086,7 @@
}
// b202394221
-TEST_F(LayerCallbackTest, NonBufferLayerStateChanges) {
+TEST_F(LayerCallbackTest, DISABLED_NonBufferLayerStateChanges) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createColorLayer("ColorLayer", Color::RED));
@@ -1085,47 +1104,29 @@
EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
}
-class TimedCallbackHelper {
-public:
- static void function(void* callbackContext, nsecs_t, const sp<Fence>&,
- const std::vector<SurfaceControlStats>&) {
- if (!callbackContext) {
- ALOGE("failed to get callback context");
- }
- TimedCallbackHelper* helper = static_cast<TimedCallbackHelper*>(callbackContext);
- std::lock_guard lock(helper->mMutex);
- helper->mInvokedTime = systemTime();
- helper->mCv.notify_all();
+TEST_F(LayerCallbackTest, CommitCallbackOffscreenLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+ sp<SurfaceControl> offscreenLayer =
+ createSurface(mClient, "Offscreen Layer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState, layer.get());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, true);
+ err |= fillTransaction(transaction, &callback, offscreenLayer, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
}
- void waitForCallback() {
- std::unique_lock lock(mMutex);
- ASSERT_TRUE(mCv.wait_for(lock, std::chrono::seconds(3), [&] { return mInvokedTime != -1; }))
- << "did not receive callback";
- }
- void* getContext() { return static_cast<void*>(this); }
+ transaction.reparent(offscreenLayer, nullptr)
+ .addTransactionCommittedCallback(callback.function, callback.getContext());
+ transaction.apply();
- std::mutex mMutex;
- std::condition_variable mCv;
- nsecs_t mInvokedTime = -1;
-};
-
-TEST_F(LayerCallbackTest, EmptyTransactionCallbackOrder) {
- TimedCallbackHelper onCommitCallback;
- TimedCallbackHelper onCompleteCallback;
-
- // Add transaction callback before on commit callback
- Transaction()
- .addTransactionCompletedCallback(onCompleteCallback.function,
- onCompleteCallback.getContext())
- .addTransactionCommittedCallback(onCommitCallback.function,
- onCommitCallback.getContext())
- .apply();
-
- EXPECT_NO_FATAL_FAILURE(onCompleteCallback.waitForCallback());
- EXPECT_NO_FATAL_FAILURE(onCommitCallback.waitForCallback());
- // verify we get the oncomplete at the same time or after the oncommit callback.
- EXPECT_GE(onCompleteCallback.mInvokedTime, onCommitCallback.mInvokedTime);
+ std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+ committedSc.insert(layer);
+ committedSc.insert(offscreenLayer);
+ EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
}
-
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index f152ced..1ac5680 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -142,6 +142,7 @@
"libtimestats",
"libtimestats_atoms_proto",
"libtimestats_proto",
+ "libtonemap",
"libtrace_proto",
"perfetto_trace_protos",
],