Merge "Add prebuilt_etc for android.hardware.fingerprint"
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/include/binder/Enum.h b/include/binder/Enum.h
deleted file mode 100644
index 4c25654..0000000
--- a/include/binder/Enum.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2020 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
-
-#error Do not rely on global include files. All Android cc_* programs are given access to \
- include_dirs for frameworks/native/include via global configuration, but this is legacy \
- configuration. Instead, you should have a direct dependency on libbinder OR one of your \
- dependencies should re-export libbinder headers with export_shared_lib_headers.
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 8fb4a37..9670d7b 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -207,6 +207,23 @@
status_t writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeStrongBinderVector(const std::vector<sp<IBinder>>& val);
+ // Write an IInterface or a vector of IInterface's
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t writeStrongBinder(const sp<T>& val) {
+ return writeStrongBinder(T::asBinder(val));
+ }
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t writeStrongBinderVector(const std::vector<sp<T>>& val) {
+ return writeData(val);
+ }
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t writeStrongBinderVector(const std::optional<std::vector<sp<T>>>& val) {
+ return writeData(val);
+ }
+
// Write an Enum vector with underlying type int8_t.
// Does not use padding; each byte is contiguous.
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
@@ -421,6 +438,16 @@
status_t readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const;
status_t readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readStrongBinderVector(std::vector<sp<IBinder>>* val) const;
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t readStrongBinderVector(std::vector<sp<T>>* val) const {
+ return readData(val);
+ }
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t readStrongBinderVector(std::optional<std::vector<sp<T>>>* val) const {
+ return readData(val);
+ }
status_t readByteVector(std::optional<std::vector<int8_t>>* val) const;
status_t readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
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/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 8ffa735..6949c2c 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -104,6 +104,17 @@
return {};
}
+// b/175635923 libcxx causes "implicit-conversion" with a string with invalid char
+static std::string SanitizeString(const String16& str) {
+ std::string sanitized{String8(str)};
+ for (auto& c : sanitized) {
+ if (!isprint(c)) {
+ c = '?';
+ }
+ }
+ return sanitized;
+}
+
bool AIBinder::associateClass(const AIBinder_Class* clazz) {
if (clazz == nullptr) return false;
@@ -118,7 +129,7 @@
if (descriptor != newDescriptor) {
if (getBinder()->isBinderAlive()) {
LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor
- << "' but descriptor is actually '" << descriptor << "'.";
+ << "' but descriptor is actually '" << SanitizeString(descriptor) << "'.";
} else {
// b/155793159
LOG(ERROR) << __func__ << ": Cannot associate class '" << newDescriptor
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index 2b18a0a..67623a6 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -27,15 +27,67 @@
#pragma once
#include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
#include <android/binder_internal_logging.h>
#include <android/binder_parcel.h>
#include <optional>
#include <string>
+#include <type_traits>
#include <vector>
namespace ndk {
+namespace {
+template <typename Test, template <typename...> class Ref>
+struct is_specialization : std::false_type {};
+
+template <template <typename...> class Ref, typename... Args>
+struct is_specialization<Ref<Args...>, Ref> : std::true_type {};
+
+template <typename Test, template <typename...> class Ref>
+static inline constexpr bool is_specialization_v = is_specialization<Test, Ref>::value;
+
+// Get the first template type from a container, the T from MyClass<T, ...>.
+template <typename T>
+struct first_template_type {
+ using type = void;
+};
+
+template <template <typename...> class V, typename T, typename... Args>
+struct first_template_type<V<T, Args...>> {
+ using type = T;
+};
+
+template <typename T>
+using first_template_type_t = typename first_template_type<T>::type;
+
+// Tells if T represents NDK interface (shared_ptr<ICInterface-derived>)
+template <typename T>
+static inline constexpr bool is_interface_v = is_specialization_v<T, std::shared_ptr>&&
+ std::is_base_of_v<::ndk::ICInterface, first_template_type_t<T>>;
+
+// Tells if T represents NDK parcelable with readFromParcel/writeToParcel methods defined
+template <typename T, typename = void>
+struct is_parcelable : std::false_type {};
+
+template <typename T>
+struct is_parcelable<
+ T, std::void_t<decltype(std::declval<T>().readFromParcel(std::declval<const AParcel*>())),
+ decltype(std::declval<T>().writeToParcel(std::declval<AParcel*>()))>>
+ : std::true_type {};
+
+template <typename T>
+static inline constexpr bool is_parcelable_v = is_parcelable<T>::value;
+
+// Tells if T represents nullable NDK parcelable (optional<parcelable> or unique_ptr<parcelable>)
+template <typename T>
+static inline constexpr bool is_nullable_parcelable_v = is_parcelable_v<first_template_type_t<T>> &&
+ (is_specialization_v<T, std::optional> ||
+ is_specialization_v<T, std::unique_ptr>);
+
+} // namespace
+
/**
* This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
*/
@@ -429,11 +481,19 @@
*/
template <typename P>
static inline binder_status_t AParcel_writeParcelable(AParcel* parcel, const P& p) {
- binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
- if (status != STATUS_OK) {
- return status;
+ if constexpr (is_interface_v<P>) {
+ if (!p) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+ return first_template_type_t<P>::writeToParcel(parcel, p);
+ } else {
+ static_assert(is_parcelable_v<P>);
+ binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
+ if (status != STATUS_OK) {
+ return status;
+ }
+ return p.writeToParcel(parcel);
}
- return p.writeToParcel(parcel);
}
/**
@@ -441,85 +501,81 @@
*/
template <typename P>
static inline binder_status_t AParcel_readParcelable(const AParcel* parcel, P* p) {
- int32_t null;
- binder_status_t status = AParcel_readInt32(parcel, &null);
- if (status != STATUS_OK) {
+ if constexpr (is_interface_v<P>) {
+ binder_status_t status = first_template_type_t<P>::readFromParcel(parcel, p);
+ if (status == STATUS_OK) {
+ if (!*p) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+ }
return status;
+ } else {
+ static_assert(is_parcelable_v<P>);
+ int32_t null;
+ binder_status_t status = AParcel_readInt32(parcel, &null);
+ if (status != STATUS_OK) {
+ return status;
+ }
+ if (null == 0) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+ return p->readFromParcel(parcel);
}
- if (null == 0) {
- return STATUS_UNEXPECTED_NULL;
- }
- return p->readFromParcel(parcel);
}
/**
* Convenience API for writing a nullable parcelable.
*/
template <typename P>
-static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel,
- const std::optional<P>& p) {
- if (p == std::nullopt) {
- return AParcel_writeInt32(parcel, 0); // null
+static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel, const P& p) {
+ if constexpr (is_interface_v<P>) {
+ return first_template_type_t<P>::writeToParcel(parcel, p);
+ } else {
+ static_assert(is_nullable_parcelable_v<P>);
+ if (!p) {
+ return AParcel_writeInt32(parcel, 0); // null
+ }
+ binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
+ if (status != STATUS_OK) {
+ return status;
+ }
+ return p->writeToParcel(parcel);
}
- binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
- if (status != STATUS_OK) {
- return status;
- }
- return p->writeToParcel(parcel);
-}
-
-/**
- * Convenience API for writing a nullable parcelable.
- */
-template <typename P>
-static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel,
- const std::unique_ptr<P>& p) {
- if (!p) {
- return AParcel_writeInt32(parcel, 0); // null
- }
- binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
- if (status != STATUS_OK) {
- return status;
- }
- return p->writeToParcel(parcel);
}
/**
* Convenience API for reading a nullable parcelable.
*/
template <typename P>
-static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel,
- std::optional<P>* p) {
- int32_t null;
- binder_status_t status = AParcel_readInt32(parcel, &null);
- if (status != STATUS_OK) {
- return status;
+static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel, P* p) {
+ if constexpr (is_interface_v<P>) {
+ return first_template_type_t<P>::readFromParcel(parcel, p);
+ } else if constexpr (is_specialization_v<P, std::optional>) {
+ int32_t null;
+ binder_status_t status = AParcel_readInt32(parcel, &null);
+ if (status != STATUS_OK) {
+ return status;
+ }
+ if (null == 0) {
+ *p = std::nullopt;
+ return STATUS_OK;
+ }
+ *p = std::optional<first_template_type_t<P>>(first_template_type_t<P>{});
+ return (*p)->readFromParcel(parcel);
+ } else {
+ static_assert(is_specialization_v<P, std::unique_ptr>);
+ int32_t null;
+ binder_status_t status = AParcel_readInt32(parcel, &null);
+ if (status != STATUS_OK) {
+ return status;
+ }
+ if (null == 0) {
+ p->reset();
+ return STATUS_OK;
+ }
+ *p = std::make_unique<first_template_type_t<P>>();
+ return (*p)->readFromParcel(parcel);
}
- if (null == 0) {
- *p = std::nullopt;
- return STATUS_OK;
- }
- *p = std::optional<P>(P{});
- return (*p)->readFromParcel(parcel);
-}
-
-/**
- * Convenience API for reading a nullable parcelable.
- */
-template <typename P>
-static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel,
- std::unique_ptr<P>* p) {
- int32_t null;
- binder_status_t status = AParcel_readInt32(parcel, &null);
- if (status != STATUS_OK) {
- return status;
- }
- if (null == 0) {
- p->reset();
- return STATUS_OK;
- }
- *p = std::make_unique<P>();
- return (*p)->readFromParcel(parcel);
}
/**
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index d63a8d0..197c0a1 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -119,11 +119,11 @@
AIBinder_setRequestingSid; # apex
AParcel_markSensitive; # systemapi llndk
AServiceManager_forEachDeclaredInstance; # apex llndk
- AServiceManager_forceLazyServicesPersist; # llndk
+ AServiceManager_forceLazyServicesPersist; # apex llndk
AServiceManager_isDeclared; # apex llndk
AServiceManager_isUpdatableViaApex; # apex
AServiceManager_reRegister; # llndk
- AServiceManager_registerLazyService; # llndk
+ AServiceManager_registerLazyService; # apex llndk
AServiceManager_setActiveServicesCallback; # llndk
AServiceManager_tryUnregister; # llndk
AServiceManager_waitForService; # apex llndk
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 ec00e1d..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,56 +701,60 @@
}
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)
}
}
+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()
}
}
+impl<T: FromIBinder + ?Sized> DeserializeArray for Strong<T> {}
+
// 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)
}
}
@@ -758,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),
@@ -772,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;
@@ -792,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()
@@ -806,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 {
@@ -822,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)?;
@@ -830,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 {
@@ -847,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/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 155a25b..32406e5 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -192,6 +192,8 @@
// only reading one binder type for now
PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readStrongBinder),
PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readNullableStrongBinder),
+ PARCEL_READ_WITH_STATUS(std::vector<android::sp<android::os::IServiceManager>>, readStrongBinderVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<android::sp<android::os::IServiceManager>>>, readStrongBinderVector),
PARCEL_READ_WITH_STATUS(::std::unique_ptr<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
PARCEL_READ_WITH_STATUS(::std::optional<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index c0a762d..752fcbb 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -25,6 +25,7 @@
// TODO(b/142061461): parent class
class SomeParcelable {
public:
+ binder_status_t writeToParcel(AParcel* /*parcel*/) { return STATUS_OK; }
binder_status_t readFromParcel(const AParcel* parcel) {
return AParcel_readInt32(parcel, &mValue);
}
@@ -33,6 +34,41 @@
int32_t mValue = 0;
};
+class ISomeInterface : public ::ndk::ICInterface {
+public:
+ ISomeInterface() = default;
+ virtual ~ISomeInterface() = default;
+ static binder_status_t readFromParcel(const AParcel* parcel,
+ std::shared_ptr<ISomeInterface>* instance);
+};
+
+static binder_status_t onTransact(AIBinder*, transaction_code_t, const AParcel*, AParcel*) {
+ return STATUS_UNKNOWN_TRANSACTION;
+}
+
+static AIBinder_Class* g_class = ::ndk::ICInterface::defineClass("ISomeInterface", onTransact);
+
+class BpSomeInterface : public ::ndk::BpCInterface<ISomeInterface> {
+public:
+ explicit BpSomeInterface(const ::ndk::SpAIBinder& binder) : BpCInterface(binder) {}
+ virtual ~BpSomeInterface() = default;
+};
+
+binder_status_t ISomeInterface::readFromParcel(const AParcel* parcel,
+ std::shared_ptr<ISomeInterface>* instance) {
+ ::ndk::SpAIBinder binder;
+ binder_status_t status = AParcel_readStrongBinder(parcel, binder.getR());
+ if (status == STATUS_OK) {
+ if (AIBinder_associateClass(binder.get(), g_class)) {
+ *instance = std::static_pointer_cast<ISomeInterface>(
+ ::ndk::ICInterface::asInterface(binder.get()));
+ } else {
+ *instance = ::ndk::SharedRefBase::make<BpSomeInterface>(binder);
+ }
+ }
+ return status;
+}
+
#define PARCEL_READ(T, FUN) \
[](const NdkParcelAdapter& p, uint8_t /*data*/) { \
FUZZ_LOG() << "about to read " #T " using " #FUN " with status"; \
@@ -100,6 +136,8 @@
PARCEL_READ(std::optional<std::vector<ndk::SpAIBinder>>, ndk::AParcel_readVector),
PARCEL_READ(std::vector<ndk::ScopedFileDescriptor>, ndk::AParcel_readVector),
PARCEL_READ(std::optional<std::vector<ndk::ScopedFileDescriptor>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<std::shared_ptr<ISomeInterface>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<std::shared_ptr<ISomeInterface>>>, ndk::AParcel_readVector),
PARCEL_READ(std::vector<int32_t>, ndk::AParcel_readVector),
PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_readVector),
PARCEL_READ(std::vector<uint32_t>, ndk::AParcel_readVector),
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index e1b1efc..46800f2 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/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 4ade240..08f3597 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -56,6 +56,8 @@
sp<Looper> mLooper;
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
+ uint32_t mLastVsyncCount;
+ nsecs_t mLastScheduleVsyncTime;
std::vector<FrameRateOverride> mFrameRateOverrides;
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 30c42a3..fcbc16f 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -89,8 +89,15 @@
// Treblized input device config files will be located /product/usr, /system_ext/usr,
// /odm/usr or /vendor/usr.
- const char* rootsForPartition[]{"/product", "/system_ext", "/odm", "/vendor",
- getenv("ANDROID_ROOT")};
+ // These files may also be in the com.android.input.config APEX.
+ const char* rootsForPartition[]{
+ "/product",
+ "/system_ext",
+ "/odm",
+ "/vendor",
+ "/apex/com.android.input.config/etc",
+ getenv("ANDROID_ROOT"),
+ };
for (size_t i = 0; i < size(rootsForPartition); i++) {
if (rootsForPartition[i] == nullptr) {
continue;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index a519786..c2a2794 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3899,6 +3899,13 @@
args->downTime, args->pointerCount,
args->pointerProperties, args->pointerCoords, 0, 0);
+ if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
+ IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER &&
+ !mInputFilterEnabled) {
+ const bool isDown = args->action == AMOTION_EVENT_ACTION_DOWN;
+ mLatencyTracker.trackListener(args->id, isDown, args->eventTime, args->readTime);
+ }
+
needWake = enqueueInboundEventLocked(std::move(newEntry));
mLock.unlock();
} // release lock
diff --git a/services/inputflinger/dispatcher/LatencyTracker.cpp b/services/inputflinger/dispatcher/LatencyTracker.cpp
index d634dcd..52f189c 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.cpp
+++ b/services/inputflinger/dispatcher/LatencyTracker.cpp
@@ -50,13 +50,12 @@
* key-value pair. Equivalent to the imaginary std api std::multimap::erase(key, value).
*/
template <typename K, typename V>
-static void eraseByKeyAndValue(std::multimap<K, V>& map, K key, V value) {
- auto iterpair = map.equal_range(key);
-
- for (auto it = iterpair.first; it != iterpair.second; ++it) {
+static void eraseByValue(std::multimap<K, V>& map, const V& value) {
+ for (auto it = map.begin(); it != map.end();) {
if (it->second == value) {
- map.erase(it);
- break;
+ it = map.erase(it);
+ } else {
+ it++;
}
}
}
@@ -76,9 +75,7 @@
// confuse us by reporting the rest of the timeline for one of them. This should happen
// rarely, so we won't lose much data
mTimelines.erase(it);
- // In case we have another input event with a different id and at the same eventTime,
- // only erase this specific inputEventId.
- eraseByKeyAndValue(mEventTimes, eventTime, inputEventId);
+ eraseByValue(mEventTimes, inputEventId);
return;
}
mTimelines.emplace(inputEventId, InputEventTimeline(isDown, eventTime, readTime));
@@ -90,7 +87,8 @@
nsecs_t finishTime) {
const auto it = mTimelines.find(inputEventId);
if (it == mTimelines.end()) {
- // It's possible that an app sends a bad (or late)'Finish' signal, since it's free to do
+ // This could happen if we erased this event when duplicate events were detected. It's
+ // also possible that an app sent a bad (or late) 'Finish' signal, since it's free to do
// anything in its process. Just drop the report and move on.
return;
}
@@ -120,7 +118,8 @@
std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline) {
const auto it = mTimelines.find(inputEventId);
if (it == mTimelines.end()) {
- // It's possible that an app sends a bad (or late) 'Timeline' signal, since it's free to do
+ // This could happen if we erased this event when duplicate events were detected. It's
+ // also possible that an app sent a bad (or late) 'Timeline' signal, since it's free to do
// anything in its process. Just drop the report and move on.
return;
}
@@ -166,14 +165,6 @@
}
}
-void LatencyTracker::reportNow() {
- for (const auto& [inputEventId, timeline] : mTimelines) {
- mTimelineProcessor->processTimeline(timeline);
- }
- mTimelines.clear();
- mEventTimes.clear();
-}
-
std::string LatencyTracker::dump(const char* prefix) {
return StringPrintf("%sLatencyTracker:\n", prefix) +
StringPrintf("%s mTimelines.size() = %zu\n", prefix, mTimelines.size()) +
diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h
index 289b8ed..4b0c618 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.h
+++ b/services/inputflinger/dispatcher/LatencyTracker.h
@@ -43,6 +43,12 @@
LatencyTracker(InputEventTimelineProcessor* processor);
/**
* Start keeping track of an event identified by inputEventId. This must be called first.
+ * If duplicate events are encountered (events that have the same eventId), none of them will be
+ * tracked. This is because there is not enough information to correctly track them. The api's
+ * 'trackFinishedEvent' and 'trackGraphicsLatency' only contain the inputEventId, and not the
+ * eventTime. Even if eventTime was provided, there would still be a possibility of having
+ * duplicate events that happen to have the same eventTime and inputEventId. Therefore, we
+ * must drop all duplicate data.
*/
void trackListener(int32_t inputEventId, bool isDown, nsecs_t eventTime, nsecs_t readTime);
void trackFinishedEvent(int32_t inputEventId, const sp<IBinder>& connectionToken,
@@ -50,14 +56,6 @@
void trackGraphicsLatency(int32_t inputEventId, const sp<IBinder>& connectionToken,
std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);
- /**
- * Report all collected events immediately, even if some of them are currently incomplete
- * and may receive 'trackFinishedEvent' or 'trackGraphicsLatency' calls in the future.
- * This is useful for tests. Otherwise, tests would have to inject additional "future" events,
- * which is not convenient.
- */
- void reportNow();
-
std::string dump(const char* prefix);
private:
diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp
index e7e1937..89c0741 100644
--- a/services/inputflinger/tests/LatencyTracker_test.cpp
+++ b/services/inputflinger/tests/LatencyTracker_test.cpp
@@ -16,6 +16,7 @@
#include "../dispatcher/LatencyTracker.h"
+#include <android-base/properties.h>
#include <binder/Binder.h>
#include <gtest/gtest.h>
#include <inttypes.h>
@@ -23,11 +24,16 @@
#define TAG "LatencyTracker_test"
+using android::base::HwTimeoutMultiplier;
using android::inputdispatcher::InputEventTimeline;
using android::inputdispatcher::LatencyTracker;
namespace android::inputdispatcher {
+const std::chrono::duration ANR_TIMEOUT = std::chrono::milliseconds(
+ android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
+ HwTimeoutMultiplier());
+
InputEventTimeline getTestTimeline() {
InputEventTimeline t(
/*isDown*/ true,
@@ -57,6 +63,8 @@
}
void TearDown() override {}
+ void triggerEventReporting(nsecs_t lastEventTime);
+
void assertReceivedTimeline(const InputEventTimeline& timeline);
/**
* Timelines can be received in any order (order is not guaranteed). So if we are expecting more
@@ -72,8 +80,17 @@
std::deque<InputEventTimeline> mReceivedTimelines;
};
+/**
+ * Send an event that would trigger the reporting of all of the events that are at least as old as
+ * the provided 'lastEventTime'.
+ */
+void LatencyTrackerTest::triggerEventReporting(nsecs_t lastEventTime) {
+ const nsecs_t triggerEventTime =
+ lastEventTime + std::chrono::nanoseconds(ANR_TIMEOUT).count() + 1;
+ mTracker->trackListener(1 /*inputEventId*/, true /*isDown*/, triggerEventTime, 3 /*readTime*/);
+}
+
void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& timeline) {
- mTracker->reportNow();
ASSERT_FALSE(mReceivedTimelines.empty());
const InputEventTimeline& t = mReceivedTimelines.front();
ASSERT_EQ(timeline, t);
@@ -88,7 +105,6 @@
* equal element in B, and for every element in B there is an equal element in A.
*/
void LatencyTrackerTest::assertReceivedTimelines(const std::vector<InputEventTimeline>& timelines) {
- mTracker->reportNow();
ASSERT_EQ(timelines.size(), mReceivedTimelines.size());
for (const InputEventTimeline& expectedTimeline : timelines) {
bool found = false;
@@ -121,6 +137,7 @@
*/
TEST_F(LatencyTrackerTest, TrackListener_DoesNotTriggerReporting) {
mTracker->trackListener(1 /*inputEventId*/, false /*isDown*/, 2 /*eventTime*/, 3 /*readTime*/);
+ triggerEventReporting(2 /*eventTime*/);
assertReceivedTimeline(InputEventTimeline{false, 2, 3});
}
@@ -130,6 +147,7 @@
TEST_F(LatencyTrackerTest, TrackFinishedEvent_DoesNotTriggerReporting) {
mTracker->trackFinishedEvent(1 /*inputEventId*/, connection1, 2 /*deliveryTime*/,
3 /*consumeTime*/, 4 /*finishTime*/);
+ triggerEventReporting(4 /*eventTime*/);
assertReceivedTimelines({});
}
@@ -141,6 +159,7 @@
graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
mTracker->trackGraphicsLatency(1 /*inputEventId*/, connection2, graphicsTimeline);
+ triggerEventReporting(3 /*eventTime*/);
assertReceivedTimelines({});
}
@@ -155,9 +174,30 @@
expectedCT.consumeTime, expectedCT.finishTime);
mTracker->trackGraphicsLatency(inputEventId, connectionToken, expectedCT.graphicsTimeline);
+ triggerEventReporting(expected.eventTime);
assertReceivedTimeline(expected);
}
+/**
+ * Send 2 events with the same inputEventId, but different eventTime's. Ensure that no crash occurs,
+ * and that the tracker drops such events completely.
+ */
+TEST_F(LatencyTrackerTest, WhenDuplicateEventsAreReported_DoesNotCrash) {
+ constexpr nsecs_t inputEventId = 1;
+ constexpr nsecs_t readTime = 3; // does not matter for this test
+ constexpr bool isDown = true; // does not matter for this test
+
+ // In the following 2 calls to trackListener, the inputEventId's are the same, but event times
+ // are different.
+ mTracker->trackListener(inputEventId, isDown, 1 /*eventTime*/, readTime);
+ mTracker->trackListener(inputEventId, isDown, 2 /*eventTime*/, readTime);
+
+ triggerEventReporting(2 /*eventTime*/);
+ // Since we sent duplicate input events, the tracker should just delete all of them, because it
+ // does not have enough information to properly track them.
+ assertReceivedTimelines({});
+}
+
TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) {
constexpr int32_t inputEventId1 = 1;
InputEventTimeline timeline1(
@@ -204,6 +244,7 @@
mTracker->trackGraphicsLatency(inputEventId2, connection2,
connectionTimeline2.graphicsTimeline);
// Now both events should be completed
+ triggerEventReporting(timeline2.eventTime);
assertReceivedTimelines({timeline1, timeline2});
}
@@ -228,6 +269,7 @@
mTracker->trackGraphicsLatency(1 /*inputEventId*/, token, expectedCT.graphicsTimeline);
expectedTimelines[0].connectionTimelines.emplace(token, std::move(expectedCT));
+ triggerEventReporting(timeline.eventTime);
assertReceivedTimelines(expectedTimelines);
}
@@ -246,6 +288,7 @@
mTracker->trackGraphicsLatency(inputEventId, connection1, expectedCT.graphicsTimeline);
mTracker->trackListener(inputEventId, expected.isDown, expected.eventTime, expected.readTime);
+ triggerEventReporting(expected.eventTime);
assertReceivedTimeline(
InputEventTimeline{expected.isDown, expected.eventTime, expected.readTime});
}
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
new file mode 100644
index 0000000..df4db19
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -0,0 +1,45 @@
+// 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.
+
+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_fuzz {
+ name: "inputflinger_latencytracker_fuzzer",
+ defaults: [
+ "inputflinger_defaults",
+ ],
+ include_dirs: [
+ "frameworks/native/services/inputflinger",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libui",
+ "libutils",
+ "libinput",
+ "libinputflinger",
+ ],
+ srcs: [
+ "LatencyTrackerFuzzer.cpp",
+ ],
+}
diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
new file mode 100644
index 0000000..4f066ad
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 <fuzzer/FuzzedDataProvider.h>
+#include "dispatcher/LatencyTracker.h"
+
+namespace android {
+
+namespace inputdispatcher {
+
+/**
+ * A processor of InputEventTimelines that does nothing with the provided data.
+ */
+class EmptyProcessor : public InputEventTimelineProcessor {
+public:
+ /**
+ * Just ignore the provided timeline
+ */
+ void processTimeline(const InputEventTimeline& timeline) override {
+ for (const auto& [token, connectionTimeline] : timeline.connectionTimelines) {
+ connectionTimeline.isComplete();
+ }
+ };
+};
+
+static sp<IBinder> getConnectionToken(FuzzedDataProvider& fdp,
+ std::array<sp<IBinder>, 10>& tokens) {
+ const bool useExistingToken = fdp.ConsumeBool();
+ if (useExistingToken) {
+ return tokens[fdp.ConsumeIntegralInRange<size_t>(0ul, tokens.size() - 1)];
+ }
+ return new BBinder();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+
+ EmptyProcessor emptyProcessor;
+ LatencyTracker tracker(&emptyProcessor);
+
+ // Make some pre-defined tokens to ensure that some timelines are complete.
+ std::array<sp<IBinder> /*token*/, 10> predefinedTokens;
+ for (size_t i = 0; i < predefinedTokens.size(); i++) {
+ predefinedTokens[i] = new BBinder();
+ }
+
+ // Randomly invoke LatencyTracker api's until randomness is exhausted.
+ while (fdp.remaining_bytes() > 0) {
+ fdp.PickValueInArray<std::function<void()>>({
+ [&]() -> void {
+ int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+ int32_t isDown = fdp.ConsumeBool();
+ nsecs_t eventTime = fdp.ConsumeIntegral<nsecs_t>();
+ nsecs_t readTime = fdp.ConsumeIntegral<nsecs_t>();
+ tracker.trackListener(inputEventId, isDown, eventTime, readTime);
+ },
+ [&]() -> void {
+ int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+ sp<IBinder> connectionToken = getConnectionToken(fdp, predefinedTokens);
+ nsecs_t deliveryTime = fdp.ConsumeIntegral<nsecs_t>();
+ nsecs_t consumeTime = fdp.ConsumeIntegral<nsecs_t>();
+ nsecs_t finishTime = fdp.ConsumeIntegral<nsecs_t>();
+ tracker.trackFinishedEvent(inputEventId, connectionToken, deliveryTime,
+ consumeTime, finishTime);
+ },
+ [&]() -> void {
+ int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+ sp<IBinder> connectionToken = getConnectionToken(fdp, predefinedTokens);
+ std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
+ for (size_t i = 0; i < graphicsTimeline.size(); i++) {
+ graphicsTimeline[i] = fdp.ConsumeIntegral<nsecs_t>();
+ }
+ tracker.trackGraphicsLatency(inputEventId, connectionToken, graphicsTimeline);
+ },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace inputdispatcher
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 673239d..caeff4a 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -63,18 +63,17 @@
return OK;
}
-static status_t startDisplayService() {
+static void startDisplayService() {
using android::frameworks::displayservice::V1_0::implementation::DisplayService;
using android::frameworks::displayservice::V1_0::IDisplayService;
sp<IDisplayService> displayservice = new DisplayService();
status_t err = displayservice->registerAsService();
+ // b/141930622
if (err != OK) {
- ALOGE("Could not register IDisplayService service.");
+ ALOGE("Did not register (deprecated) IDisplayService service.");
}
-
- return err;
}
int main(int, char**) {