diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-14 00:17:53 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-14 00:17:53 +0000 |
commit | 8ed6f5a3fb701d3d78b20233827c8727fb5b1f7e (patch) | |
tree | 34727bfd2cb9cf626e5777f185296cfd84501a88 | |
parent | 0687ad03d7c9dd39d7d6cbd4daa30ee388b5254b (diff) | |
parent | f2f5f26192e10045d780e03b4e199503b4ba98c2 (diff) | |
download | native-8ed6f5a3fb701d3d78b20233827c8727fb5b1f7e.tar.gz |
Snap for 11216811 from f2f5f26192e10045d780e03b4e199503b4ba98c2 to 24Q1-release
Change-Id: Ib0a1981e1c53a850d3d9143b010d945e42e41aee
33 files changed, 1159 insertions, 67 deletions
diff --git a/include/ftl/details/function.h b/include/ftl/details/function.h new file mode 100644 index 0000000000..35c5a8b302 --- /dev/null +++ b/include/ftl/details/function.h @@ -0,0 +1,135 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <array> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <type_traits> + +namespace android::ftl::details { + +// The maximum allowed value for the template argument `N` in +// `ftl::Function<F, N>`. +constexpr size_t kFunctionMaximumN = 14; + +// Converts a member function pointer type `Ret(Class::*)(Args...)` to an equivalent non-member +// function type `Ret(Args...)`. + +template <typename> +struct remove_member_function_pointer; + +template <typename Class, typename Ret, typename... Args> +struct remove_member_function_pointer<Ret (Class::*)(Args...)> { + using type = Ret(Args...); +}; + +template <typename Class, typename Ret, typename... Args> +struct remove_member_function_pointer<Ret (Class::*)(Args...) const> { + using type = Ret(Args...); +}; + +template <auto MemberFunction> +using remove_member_function_pointer_t = + typename remove_member_function_pointer<decltype(MemberFunction)>::type; + +// Helper functions for binding to the supported targets. + +template <typename Ret, typename... Args> +auto bind_opaque_no_op() -> Ret (*)(void*, Args...) { + return [](void*, Args...) -> Ret { + if constexpr (!std::is_void_v<Ret>) { + return Ret{}; + } + }; +} + +template <typename F, typename Ret, typename... Args> +auto bind_opaque_function_object(const F&) -> Ret (*)(void*, Args...) { + return [](void* opaque, Args... args) -> Ret { + return std::invoke(*static_cast<F*>(opaque), std::forward<Args>(args)...); + }; +} + +template <auto MemberFunction, typename Class, typename Ret, typename... Args> +auto bind_member_function(Class* instance, Ret (*)(Args...) = nullptr) { + return [instance](Args... args) -> Ret { + return std::invoke(MemberFunction, instance, std::forward<Args>(args)...); + }; +} + +template <auto FreeFunction, typename Ret, typename... Args> +auto bind_free_function(Ret (*)(Args...) = nullptr) { + return [](Args... args) -> Ret { return std::invoke(FreeFunction, std::forward<Args>(args)...); }; +} + +// Traits class for the opaque storage used by Function. + +template <std::size_t N> +struct function_opaque_storage { + // The actual type used for the opaque storage. An `N` of zero specifies the minimum useful size, + // which allows a lambda with zero or one capture args. + using type = std::array<std::intptr_t, N + 1>; + + template <typename S> + static constexpr bool require_trivially_copyable = std::is_trivially_copyable_v<S>; + + template <typename S> + static constexpr bool require_trivially_destructible = std::is_trivially_destructible_v<S>; + + template <typename S> + static constexpr bool require_will_fit_in_opaque_storage = sizeof(S) <= sizeof(type); + + template <typename S> + static constexpr bool require_alignment_compatible = + std::alignment_of_v<S> <= std::alignment_of_v<type>; + + // Copies `src` into the opaque storage, and returns that storage. + template <typename S> + static type opaque_copy(const S& src) { + // TODO: Replace with C++20 concepts/constraints which can give more details. + static_assert(require_trivially_copyable<S>, + "ftl::Function can only store lambdas that capture trivially copyable data."); + static_assert( + require_trivially_destructible<S>, + "ftl::Function can only store lambdas that capture trivially destructible data."); + static_assert(require_will_fit_in_opaque_storage<S>, + "ftl::Function has limited storage for lambda captured state. Maybe you need to " + "increase N?"); + static_assert(require_alignment_compatible<S>); + + type opaque; + std::memcpy(opaque.data(), &src, sizeof(S)); + return opaque; + } +}; + +// Traits class to help determine the template parameters to use for a ftl::Function, given a +// function object. + +template <typename F, typename = decltype(&F::operator())> +struct function_traits { + // The function type `F` with which to instantiate the `Function<F, N>` template. + using type = remove_member_function_pointer_t<&F::operator()>; + + // The (minimum) size `N` with which to instantiate the `Function<F, N>` template. + static constexpr std::size_t size = + (std::max(sizeof(std::intptr_t), sizeof(F)) - 1) / sizeof(std::intptr_t); +}; + +} // namespace android::ftl::details diff --git a/include/ftl/function.h b/include/ftl/function.h new file mode 100644 index 0000000000..3538ca4eae --- /dev/null +++ b/include/ftl/function.h @@ -0,0 +1,297 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstddef> +#include <functional> +#include <type_traits> +#include <utility> + +#include <ftl/details/function.h> + +namespace android::ftl { + +// ftl::Function<F, N> is a container for function object, and can mostly be used in place of +// std::function<F>. +// +// Unlike std::function<F>, a ftl::Function<F, N>: +// +// * Uses a static amount of memory (controlled by N), and never any dynamic allocation. +// * Satisfies the std::is_trivially_copyable<> trait. +// * Satisfies the std::is_trivially_destructible<> trait. +// +// However those same limits are also required from the contained function object in turn. +// +// The size of a ftl::Function<F, N> is guaranteed to be: +// +// sizeof(std::intptr_t) * (N + 2) +// +// A ftl::Function<F, N> can always be implicitly converted to a larger size ftl::Function<F, M>. +// Trying to convert the other way leads to a compilation error. +// +// A default-constructed ftl::Function is in an empty state. The operator bool() overload returns +// false in this state. It is undefined behavior to attempt to invoke the function in this state. +// +// The ftl::Function<F, N> can also be constructed or assigned from ftl::no_op. This sets up the +// ftl::Function to be non-empty, with a function that when called does nothing except +// default-constructs a return value. +// +// The ftl::make_function() helpers construct a ftl::Function<F, N>, including deducing the +// values of F and N from the arguments it is given. +// +// The static ftl::Function<F, N>::make() helpers construct a ftl::Function<F, N> without that +// deduction, and also allow for implicit argument conversion if the target being called needs them. +// +// The construction helpers allow any of the following types of functions to be stored: +// +// * Any SMALL function object (as defined by the C++ Standard), such as a lambda with a small +// capture, or other "functor". The requirements are: +// +// 1) The function object must be trivial to destroy (in fact, the destructor will never +// actually be called once copied to the internal storage). +// 2) The function object must be trivial to copy (the raw bytes will be copied as the +// ftl::Function<F, N> is copied/moved). +// 3) The size of the function object cannot be larger than sizeof(std::intptr_t) * (N + 1), +// and it cannot require stricter alignment than alignof(std::intptr_t). +// +// With the default of N=0, a lambda can only capture a single pointer-sized argument. This is +// enough to capture `this`, which is why N=0 is the default. +// +// * A member function, with the address passed as the template value argument to the construction +// helper function, along with the instance pointer needed to invoke it passed as an ordinary +// argument. +// +// ftl::make_function<&Class::member_function>(this); +// +// Note that the indicated member function will be invoked non-virtually. If you need it to be +// invoked virtually, you should invoke it yourself with a small lambda like so: +// +// ftl::function([this] { virtual_member_function(); }); +// +// * An ordinary function ("free function"), with the address of the function passed as a template +// value argument. +// +// ftl::make_function<&std::atoi>(); +// +// As with the member function helper, as the function is known at compile time, it will be called +// directly. +// +// Example usage: +// +// class MyClass { +// public: +// void on_event() const {} +// int on_string(int*, std::string_view) { return 1; } +// +// auto get_function() { +// return ftl::function([this] { on_event(); }); +// } +// } cls; +// +// // A function container with no arguments, and returning no value. +// ftl::Function<void()> f; +// +// // Construct a ftl::Function containing a small lambda. +// f = cls.get_function(); +// +// // Construct a ftl::Function that calls `cls.on_event()`. +// f = ftl::function<&MyClass::on_event>(&cls); +// +// // Create a do-nothing function. +// f = ftl::no_op; +// +// // Invoke the contained function. +// f(); +// +// // Also invokes it. +// std::invoke(f); +// +// // Create a typedef to give a more meaningful name and bound the size. +// using MyFunction = ftl::Function<int(std::string_view), 2>; +// int* ptr = nullptr; +// auto f1 = MyFunction::make_function( +// [cls = &cls, ptr](std::string_view sv) { +// return cls->on_string(ptr, sv); +// }); +// int r = f1("abc"sv); +// +// // Returns a default-constructed int (0). +// f1 = ftl::no_op; +// r = f1("abc"sv); +// assert(r == 0); + +template <typename F, std::size_t N = 0> +class Function; + +// Used to construct a Function that does nothing. +struct NoOpTag {}; + +constexpr NoOpTag no_op; + +// Detects that a type is a `ftl::Function<F, N>` regardless of what `F` and `N` are. +template <typename> +struct is_function : public std::false_type {}; + +template <typename F, std::size_t N> +struct is_function<Function<F, N>> : public std::true_type {}; + +template <typename T> +constexpr bool is_function_v = is_function<T>::value; + +template <typename Ret, typename... Args, std::size_t N> +class Function<Ret(Args...), N> final { + // Enforce a valid size, with an arbitrary maximum allowed size for the container of + // sizeof(std::intptr_t) * 16, though that maximum can be relaxed. + static_assert(N <= details::kFunctionMaximumN); + + using OpaqueStorageTraits = details::function_opaque_storage<N>; + + public: + // Defining result_type allows ftl::Function to be substituted for std::function. + using result_type = Ret; + + // Constructs an empty ftl::Function. + Function() = default; + + // Constructing or assigning from nullptr_t also creates an empty ftl::Function. + Function(std::nullptr_t) {} + Function& operator=(std::nullptr_t) { return *this = Function(nullptr); } + + // Constructing from NoOpTag sets up a a special no-op function which is valid to call, and which + // returns a default constructed return value. + Function(NoOpTag) : function_(details::bind_opaque_no_op<Ret, Args...>()) {} + Function& operator=(NoOpTag) { return *this = Function(no_op); } + + // Constructing/assigning from a function object stores a copy of that function object, however: + // * It must be trivially copyable, as the implementation makes a copy with memcpy(). + // * It must be trivially destructible, as the implementation doesn't destroy the copy! + // * It must fit in the limited internal storage, which enforces size/alignment restrictions. + + template <typename F, typename = std::enable_if_t<std::is_invocable_r_v<Ret, F, Args...>>> + Function(const F& f) + : opaque_(OpaqueStorageTraits::opaque_copy(f)), + function_(details::bind_opaque_function_object<F, Ret, Args...>(f)) {} + + template <typename F, typename = std::enable_if_t<std::is_invocable_r_v<Ret, F, Args...>>> + Function& operator=(const F& f) noexcept { + return *this = Function{OpaqueStorageTraits::opaque_copy(f), + details::bind_opaque_function_object<F, Ret, Args...>(f)}; + } + + // Constructing/assigning from a smaller ftl::Function is allowed, but not anything else. + + template <std::size_t M> + Function(const Function<Ret(Args...), M>& other) + : opaque_{OpaqueStorageTraits::opaque_copy(other.opaque_)}, function_(other.function_) {} + + template <std::size_t M> + auto& operator=(const Function<Ret(Args...), M>& other) { + return *this = Function{OpaqueStorageTraits::opaque_copy(other.opaque_), other.function_}; + } + + // Returns true if a function is set. + explicit operator bool() const { return function_ != nullptr; } + + // Checks if the other function has the same contents as this one. + bool operator==(const Function& other) const { + return other.opaque_ == opaque_ && other.function_ == function_; + } + bool operator!=(const Function& other) const { return !operator==(other); } + + // Alternative way of testing for a function being set. + bool operator==(std::nullptr_t) const { return function_ == nullptr; } + bool operator!=(std::nullptr_t) const { return function_ != nullptr; } + + // Invokes the function. + Ret operator()(Args... args) const { + return std::invoke(function_, opaque_.data(), std::forward<Args>(args)...); + } + + // Creation helper for function objects, such as lambdas. + template <typename F> + static auto make(const F& f) -> decltype(Function{f}) { + return Function{f}; + } + + // Creation helper for a class pointer and a compile-time chosen member function to call. + template <auto MemberFunction, typename Class> + static auto make(Class* instance) -> decltype(Function{ + details::bind_member_function<MemberFunction>(instance, + static_cast<Ret (*)(Args...)>(nullptr))}) { + return Function{details::bind_member_function<MemberFunction>( + instance, static_cast<Ret (*)(Args...)>(nullptr))}; + } + + // Creation helper for a compile-time chosen free function to call. + template <auto FreeFunction> + static auto make() -> decltype(Function{ + details::bind_free_function<FreeFunction>(static_cast<Ret (*)(Args...)>(nullptr))}) { + return Function{ + details::bind_free_function<FreeFunction>(static_cast<Ret (*)(Args...)>(nullptr))}; + } + + private: + // Needed so a Function<F, M> can be converted to a Function<F, N>. + template <typename, std::size_t> + friend class Function; + + // The function pointer type of function stored in `function_`. The first argument is always + // `&opaque_`. + using StoredFunction = Ret(void*, Args...); + + // The type of the opaque storage, used to hold an appropriate function object. + // The type stored here is ONLY known to the StoredFunction. + // We always use at least one std::intptr_t worth of storage, and always a multiple of that size. + using OpaqueStorage = typename OpaqueStorageTraits::type; + + // Internal constructor for creating from a raw opaque blob + function pointer. + Function(const OpaqueStorage& opaque, StoredFunction* function) + : opaque_(opaque), function_(function) {} + + // Note: `mutable` so that `operator() const` can use it. + mutable OpaqueStorage opaque_{}; + StoredFunction* function_{nullptr}; +}; + +// Makes a ftl::Function given a function object `F`. +template <typename F, typename T = details::function_traits<F>> +Function(const F&) -> Function<typename T::type, T::size>; + +template <typename F> +auto make_function(const F& f) -> decltype(Function{f}) { + return Function{f}; +} + +// Makes a ftl::Function given a `MemberFunction` and a instance pointer to the associated `Class`. +template <auto MemberFunction, typename Class> +auto make_function(Class* instance) + -> decltype(Function{details::bind_member_function<MemberFunction>( + instance, + static_cast<details::remove_member_function_pointer_t<MemberFunction>*>(nullptr))}) { + return Function{details::bind_member_function<MemberFunction>( + instance, static_cast<details::remove_member_function_pointer_t<MemberFunction>*>(nullptr))}; +} + +// Makes a ftl::Function given an ordinary free function. +template <auto FreeFunction> +auto make_function() -> decltype(Function{ + details::bind_free_function<FreeFunction>(static_cast<decltype(FreeFunction)>(nullptr))}) { + return Function{ + details::bind_free_function<FreeFunction>(static_cast<decltype(FreeFunction)>(nullptr))}; +} + +} // namespace android::ftl diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp index ddd82e8ef7..cb44c58c2c 100644 --- a/libs/binder/libbinder_rpc_unstable.cpp +++ b/libs/binder/libbinder_rpc_unstable.cpp @@ -20,8 +20,14 @@ #include <binder/RpcServer.h> #include <binder/RpcSession.h> #include <binder/unique_fd.h> + +#ifndef __TRUSTY__ #include <cutils/sockets.h> +#endif + +#ifdef __linux__ #include <linux/vm_sockets.h> +#endif // __linux__ using android::OK; using android::RpcServer; @@ -74,6 +80,7 @@ RpcSession::FileDescriptorTransportMode toTransportMode( extern "C" { +#ifndef __TRUSTY__ ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid, unsigned int port) { auto server = RpcServer::make(); @@ -147,6 +154,7 @@ ARpcServer* ARpcServer_newInet(AIBinder* service, const char* address, unsigned server->setRootObject(AIBinder_toPlatformBinder(service)); return createObjectHandle<ARpcServer>(server); } +#endif // __TRUSTY__ void ARpcServer_setSupportedFileDescriptorTransportModes( ARpcServer* handle, const ARpcSession_FileDescriptorTransportMode modes[], @@ -187,6 +195,7 @@ void ARpcSession_free(ARpcSession* handle) { freeObjectHandle<RpcSession>(handle); } +#ifndef __TRUSTY__ AIBinder* ARpcSession_setupVsockClient(ARpcSession* handle, unsigned int cid, unsigned int port) { auto session = handleToStrongPointer<RpcSession>(handle); if (status_t status = session->setupVsockClient(cid, port); status != OK) { @@ -234,13 +243,14 @@ AIBinder* ARpcSession_setupInet(ARpcSession* handle, const char* address, unsign } return AIBinder_fromPlatformBinder(session->getRootObject()); } +#endif // __TRUSTY__ AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* handle, int (*requestFd)(void* param), void* param) { auto session = handleToStrongPointer<RpcSession>(handle); auto request = [=] { return unique_fd{requestFd(param)}; }; if (status_t status = session->setupPreconnectedClient(unique_fd{}, request); status != OK) { - ALOGE("Failed to set up vsock client. error: %s", statusToString(status).c_str()); + ALOGE("Failed to set up preconnected client. error: %s", statusToString(status).c_str()); return nullptr; } return AIBinder_fromPlatformBinder(session->getRootObject()); diff --git a/libs/binder/liblog_stub/include/log/log.h b/libs/binder/liblog_stub/include/log/log.h index 3b656076b3..91c9632c1b 100644 --- a/libs/binder/liblog_stub/include/log/log.h +++ b/libs/binder/liblog_stub/include/log/log.h @@ -35,15 +35,19 @@ constexpr bool __android_log_stub_is_loggable(android_LogPriority priority) { return ANDROID_LOG_STUB_MIN_PRIORITY <= priority; } -int __android_log_print(int prio, const char* tag, const char* fmt, ...) - __attribute__((format(printf, 3, 4))) #ifdef ANDROID_LOG_STUB_WEAK_PRINT - __attribute__((weak)) +#define __ANDROID_LOG_STUB_IS_PRINT_PRESENT __android_log_print +#define __ANDROID_LOG_STUB_PRINT_ATTR __attribute__((weak)) +#else +#define __ANDROID_LOG_STUB_IS_PRINT_PRESENT true +#define __ANDROID_LOG_STUB_PRINT_ATTR #endif - ; + +int __android_log_print(int prio, const char* tag, const char* fmt, ...) + __attribute__((format(printf, 3, 4))) __ANDROID_LOG_STUB_PRINT_ATTR; #define IF_ALOG(priority, tag) \ - if (__android_log_stub_is_loggable(ANDROID_##priority) && __android_log_print) + if (__android_log_stub_is_loggable(ANDROID_##priority) && __ANDROID_LOG_STUB_IS_PRINT_PRESENT) #define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG) #define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG) #define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG) diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs index a9573850f1..163f000ac8 100644 --- a/libs/binder/rust/rpcbinder/src/lib.rs +++ b/libs/binder/rust/rpcbinder/src/lib.rs @@ -16,8 +16,10 @@ //! API for RPC Binder services. +#[cfg(not(target_os = "trusty"))] mod server; mod session; +#[cfg(not(target_os = "trusty"))] pub use server::{RpcServer, RpcServerRef}; pub use session::{FileDescriptorTransportMode, RpcSession, RpcSessionRef}; diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs index 79a951073e..09688a21a7 100644 --- a/libs/binder/rust/rpcbinder/src/session.rs +++ b/libs/binder/rust/rpcbinder/src/session.rs @@ -17,11 +17,8 @@ use binder::unstable_api::new_spibinder; use binder::{FromIBinder, SpIBinder, StatusCode, Strong}; use foreign_types::{foreign_type, ForeignType, ForeignTypeRef}; -use std::ffi::CString; -use std::os::{ - raw::{c_int, c_void}, - unix::io::{AsRawFd, BorrowedFd, RawFd}, -}; +use std::os::fd::RawFd; +use std::os::raw::{c_int, c_void}; pub use binder_rpc_unstable_bindgen::ARpcSession_FileDescriptorTransportMode as FileDescriptorTransportMode; @@ -87,6 +84,7 @@ impl RpcSessionRef { } /// Connects to an RPC Binder server over vsock for a particular interface. + #[cfg(not(target_os = "trusty"))] pub fn setup_vsock_client<T: FromIBinder + ?Sized>( &self, cid: u32, @@ -106,11 +104,12 @@ impl RpcSessionRef { /// Connects to an RPC Binder server over a names Unix Domain Socket for /// a particular interface. + #[cfg(not(target_os = "trusty"))] pub fn setup_unix_domain_client<T: FromIBinder + ?Sized>( &self, socket_name: &str, ) -> Result<Strong<T>, StatusCode> { - let socket_name = match CString::new(socket_name) { + let socket_name = match std::ffi::CString::new(socket_name) { Ok(s) => s, Err(e) => { log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e); @@ -131,10 +130,12 @@ impl RpcSessionRef { /// Connects to an RPC Binder server over a bootstrap Unix Domain Socket /// for a particular interface. + #[cfg(not(target_os = "trusty"))] pub fn setup_unix_domain_bootstrap_client<T: FromIBinder + ?Sized>( &self, - bootstrap_fd: BorrowedFd, + bootstrap_fd: std::os::fd::BorrowedFd, ) -> Result<Strong<T>, StatusCode> { + use std::os::fd::AsRawFd; // SAFETY: ARpcSession_setupUnixDomainBootstrapClient does not take // ownership of bootstrap_fd. The returned AIBinder has correct // reference count, and the ownership can safely be taken by new_spibinder. @@ -148,12 +149,13 @@ impl RpcSessionRef { } /// Connects to an RPC Binder server over inet socket at the given address and port. + #[cfg(not(target_os = "trusty"))] pub fn setup_inet_client<T: FromIBinder + ?Sized>( &self, address: &str, port: u32, ) -> Result<Strong<T>, StatusCode> { - let address = match CString::new(address) { + let address = match std::ffi::CString::new(address) { Ok(s) => s, Err(e) => { log::error!("Cannot convert {} to CString. Error: {:?}", address, e); @@ -173,6 +175,22 @@ impl RpcSessionRef { Self::get_interface(service) } + #[cfg(target_os = "trusty")] + pub fn setup_trusty_client<T: FromIBinder + ?Sized>( + &self, + port: &std::ffi::CStr, + ) -> Result<Strong<T>, StatusCode> { + self.setup_preconnected_client(|| { + let h = tipc::Handle::connect(port) + .expect("Failed to connect to service port {SERVICE_PORT}"); + + // Do not close the handle at the end of the scope + let fd = h.as_raw_fd(); + core::mem::forget(h); + Some(fd) + }) + } + /// Connects to an RPC Binder server, using the given callback to get (and /// take ownership of) file descriptors already connected to it. pub fn setup_preconnected_client<T: FromIBinder + ?Sized>( diff --git a/libs/binder/trusty/binder_rpc_unstable/rules.mk b/libs/binder/trusty/binder_rpc_unstable/rules.mk new file mode 100644 index 0000000000..d8dbce54e8 --- /dev/null +++ b/libs/binder/trusty/binder_rpc_unstable/rules.mk @@ -0,0 +1,32 @@ +# Copyright (C) 2023 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. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) +LIBBINDER_DIR := $(LOCAL_DIR)/../.. + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := \ + $(LIBBINDER_DIR)/libbinder_rpc_unstable.cpp \ + +MODULE_EXPORT_INCLUDES += \ + $(LIBBINDER_DIR)/include_rpc_unstable \ + +MODULE_LIBRARY_DEPS += \ + $(LIBBINDER_DIR)/trusty \ + $(LIBBINDER_DIR)/trusty/ndk \ + trusty/user/base/lib/libstdc++-trusty \ + +include make/library.mk diff --git a/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/BinderBindings.hpp b/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/BinderBindings.hpp new file mode 100644 index 0000000000..6f96566618 --- /dev/null +++ b/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/BinderBindings.hpp @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2023 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 <binder_rpc_unstable.hpp> diff --git a/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/lib.rs b/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/lib.rs new file mode 100644 index 0000000000..c7036f45f7 --- /dev/null +++ b/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/lib.rs @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2023 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. + */ + +//! Generated Rust bindings to binder_rpc_unstable + +#[allow(bad_style)] +mod sys { + include!(env!("BINDGEN_INC_FILE")); +} + +pub use sys::*; diff --git a/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/rules.mk b/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/rules.mk new file mode 100644 index 0000000000..ef1b7c3cf8 --- /dev/null +++ b/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/rules.mk @@ -0,0 +1,40 @@ +# Copyright (C) 2023 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. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) +LIBBINDER_DIR := $(LOCAL_DIR)/../../.. + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := $(LOCAL_DIR)/lib.rs + +MODULE_CRATE_NAME := binder_rpc_unstable_bindgen + +MODULE_LIBRARY_DEPS += \ + $(LIBBINDER_DIR)/trusty \ + $(LIBBINDER_DIR)/trusty/binder_rpc_unstable \ + $(LIBBINDER_DIR)/trusty/ndk \ + $(LIBBINDER_DIR)/trusty/rust/binder_ndk_sys \ + trusty/user/base/lib/libstdc++-trusty \ + trusty/user/base/lib/trusty-sys \ + +MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/BinderBindings.hpp + +MODULE_BINDGEN_FLAGS += \ + --blocklist-type="AIBinder" \ + --raw-line="use binder_ndk_sys::AIBinder;" \ + --rustified-enum="ARpcSession_FileDescriptorTransportMode" \ + +include make/library.mk diff --git a/libs/binder/trusty/rust/rpcbinder/rules.mk b/libs/binder/trusty/rust/rpcbinder/rules.mk new file mode 100644 index 0000000000..76f3b9401f --- /dev/null +++ b/libs/binder/trusty/rust/rpcbinder/rules.mk @@ -0,0 +1,35 @@ +# Copyright (C) 2023 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. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) +LIBBINDER_DIR := $(LOCAL_DIR)/../../.. + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := $(LIBBINDER_DIR)/rust/rpcbinder/src/lib.rs + +MODULE_CRATE_NAME := rpcbinder + +MODULE_LIBRARY_DEPS += \ + $(LIBBINDER_DIR)/trusty \ + $(LIBBINDER_DIR)/trusty/ndk \ + $(LIBBINDER_DIR)/trusty/rust \ + $(LIBBINDER_DIR)/trusty/rust/binder_ndk_sys \ + $(LIBBINDER_DIR)/trusty/rust/binder_rpc_unstable_bindgen \ + external/rust/crates/foreign-types \ + trusty/user/base/lib/tipc/rust \ + trusty/user/base/lib/trusty-sys \ + +include make/library.mk diff --git a/libs/binder/trusty/rust/rules.mk b/libs/binder/trusty/rust/rules.mk index be90df3147..6de7eb5b3c 100644 --- a/libs/binder/trusty/rust/rules.mk +++ b/libs/binder/trusty/rust/rules.mk @@ -26,6 +26,7 @@ MODULE_LIBRARY_DEPS += \ $(LIBBINDER_DIR)/trusty \ $(LIBBINDER_DIR)/trusty/ndk \ $(LIBBINDER_DIR)/trusty/rust/binder_ndk_sys \ + $(LIBBINDER_DIR)/trusty/rust/binder_rpc_unstable_bindgen \ external/rust/crates/downcast-rs \ trusty/user/base/lib/trusty-sys \ diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index ea1b5e4998..918680d6a7 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -17,6 +17,7 @@ cc_test { "enum_test.cpp", "fake_guard_test.cpp", "flags_test.cpp", + "function_test.cpp", "future_test.cpp", "match_test.cpp", "mixins_test.cpp", diff --git a/libs/ftl/function_test.cpp b/libs/ftl/function_test.cpp new file mode 100644 index 0000000000..91b5e08041 --- /dev/null +++ b/libs/ftl/function_test.cpp @@ -0,0 +1,379 @@ +/* + * Copyright 2022 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 <ftl/function.h> +#include <gtest/gtest.h> + +#include <array> +#include <cstddef> +#include <cstdint> +#include <string_view> +#include <type_traits> + +namespace android::test { +namespace { + +// Create an alias to composite requirements defined by the trait class `T` for easier testing. +template <typename T, typename S> +inline constexpr bool is_opaquely_storable = (T::template require_trivially_copyable<S> && + T::template require_trivially_destructible<S> && + T::template require_will_fit_in_opaque_storage<S> && + T::template require_alignment_compatible<S>); + +// `I` gives a count of sizeof(std::intptr_t) bytes , and `J` gives a raw count of bytes +template <size_t I, size_t J = 0> +struct KnownSizeFunctionObject { + using Data = std::array<std::byte, sizeof(std::intptr_t) * I + J>; + void operator()() const {}; + Data data{}; +}; + +} // namespace + +// static_assert the expected type traits +static_assert(std::is_invocable_r_v<void, ftl::Function<void()>>); +static_assert(std::is_trivially_copyable_v<ftl::Function<void()>>); +static_assert(std::is_trivially_destructible_v<ftl::Function<void()>>); +static_assert(std::is_trivially_copy_constructible_v<ftl::Function<void()>>); +static_assert(std::is_trivially_move_constructible_v<ftl::Function<void()>>); +static_assert(std::is_trivially_copy_assignable_v<ftl::Function<void()>>); +static_assert(std::is_trivially_move_assignable_v<ftl::Function<void()>>); + +template <typename T> +using function_traits = ftl::details::function_traits<T>; + +// static_assert that the expected value of N is used for known function object sizes. +static_assert(function_traits<KnownSizeFunctionObject<0, 0>>::size == 0); +static_assert(function_traits<KnownSizeFunctionObject<0, 1>>::size == 0); +static_assert(function_traits<KnownSizeFunctionObject<1, 0>>::size == 0); +static_assert(function_traits<KnownSizeFunctionObject<1, 1>>::size == 1); +static_assert(function_traits<KnownSizeFunctionObject<2, 0>>::size == 1); +static_assert(function_traits<KnownSizeFunctionObject<2, 1>>::size == 2); + +// Check that is_function_v works +static_assert(!ftl::is_function_v<KnownSizeFunctionObject<0>>); +static_assert(!ftl::is_function_v<std::function<void()>>); +static_assert(ftl::is_function_v<ftl::Function<void()>>); + +// static_assert what can and cannot be stored inside the opaque storage + +template <size_t N> +using function_opaque_storage = ftl::details::function_opaque_storage<N>; + +// Function objects can be stored if they fit. +static_assert(is_opaquely_storable<function_opaque_storage<0>, KnownSizeFunctionObject<0>>); +static_assert(is_opaquely_storable<function_opaque_storage<0>, KnownSizeFunctionObject<1>>); +static_assert(!is_opaquely_storable<function_opaque_storage<0>, KnownSizeFunctionObject<2>>); + +static_assert(is_opaquely_storable<function_opaque_storage<1>, KnownSizeFunctionObject<2>>); +static_assert(!is_opaquely_storable<function_opaque_storage<1>, KnownSizeFunctionObject<3>>); + +static_assert(is_opaquely_storable<function_opaque_storage<2>, KnownSizeFunctionObject<3>>); +static_assert(!is_opaquely_storable<function_opaque_storage<2>, KnownSizeFunctionObject<4>>); + +// Another opaque storage can be stored if it fits. This property is used to copy smaller +// ftl::Functions into larger ones. +static_assert(is_opaquely_storable<function_opaque_storage<2>, function_opaque_storage<0>::type>); +static_assert(is_opaquely_storable<function_opaque_storage<2>, function_opaque_storage<1>::type>); +static_assert(is_opaquely_storable<function_opaque_storage<2>, function_opaque_storage<2>::type>); +static_assert(!is_opaquely_storable<function_opaque_storage<2>, function_opaque_storage<3>::type>); + +// Function objects that aren't trivially copyable or destroyable cannot be stored. +auto lambda_capturing_unique_ptr = [ptr = std::unique_ptr<void*>()] { static_cast<void>(ptr); }; +static_assert( + !is_opaquely_storable<function_opaque_storage<2>, decltype(lambda_capturing_unique_ptr)>); + +// Keep in sync with "Example usage" in header file. +TEST(Function, Example) { + using namespace std::string_view_literals; + + class MyClass { + public: + void on_event() const {} + int on_string(int*, std::string_view) { return 1; } + + auto get_function() { + return ftl::make_function([this] { on_event(); }); + } + } cls; + + // A function container with no arguments, and returning no value. + ftl::Function<void()> f; + + // Construct a ftl::Function containing a small lambda. + f = cls.get_function(); + + // Construct a ftl::Function that calls `cls.on_event()`. + f = ftl::make_function<&MyClass::on_event>(&cls); + + // Create a do-nothing function. + f = ftl::no_op; + + // Invoke the contained function. + f(); + + // Also invokes it. + std::invoke(f); + + // Create a typedef to give a more meaningful name and bound the size. + using MyFunction = ftl::Function<int(std::string_view), 2>; + int* ptr = nullptr; + auto f1 = + MyFunction::make([cls = &cls, ptr](std::string_view sv) { return cls->on_string(ptr, sv); }); + int r = f1("abc"sv); + + // Returns a default-constructed int (0). + f1 = ftl::no_op; + r = f1("abc"sv); + EXPECT_EQ(r, 0); +} + +TEST(Function, BasicOperations) { + // Default constructible. + ftl::Function<int()> f; + + // Compares as empty + EXPECT_FALSE(f); + EXPECT_TRUE(f == nullptr); + EXPECT_FALSE(f != nullptr); + EXPECT_TRUE(ftl::Function<int()>() == f); + EXPECT_FALSE(ftl::Function<int()>() != f); + + // Assigning no_op sets it to not empty. + f = ftl::no_op; + + // Verify it can be called, and that it returns a default constructed value. + EXPECT_EQ(f(), 0); + + // Comparable when non-empty. + EXPECT_TRUE(f); + EXPECT_FALSE(f == nullptr); + EXPECT_TRUE(f != nullptr); + EXPECT_FALSE(ftl::Function<int()>() == f); + EXPECT_TRUE(ftl::Function<int()>() != f); + + // Constructing from nullptr means empty. + f = ftl::Function<int()>{nullptr}; + EXPECT_FALSE(f); + + // Assigning nullptr means it is empty. + f = nullptr; + EXPECT_FALSE(f); + + // Move construction + f = ftl::no_op; + ftl::Function<int()> g{std::move(f)}; + EXPECT_TRUE(g != nullptr); + + // Move assignment + f = nullptr; + f = std::move(g); + EXPECT_TRUE(f != nullptr); + + // Copy construction + ftl::Function<int()> h{f}; + EXPECT_TRUE(h != nullptr); + + // Copy assignment + g = h; + EXPECT_TRUE(g != nullptr); +} + +TEST(Function, CanMoveConstructFromLambda) { + auto lambda = [] {}; + ftl::Function<void()> f{std::move(lambda)}; +} + +TEST(Function, TerseDeducedConstructAndAssignFromLambda) { + auto f = ftl::Function([] { return 1; }); + EXPECT_EQ(f(), 1); + + f = [] { return 2; }; + EXPECT_EQ(f(), 2); +} + +namespace { + +struct ImplicitConversionsHelper { + auto exact(int) -> int { return 0; } + auto inexact(long) -> short { return 0; } + // TODO: Switch to `auto templated(auto x)` with C++20 + template <typename T> + T templated(T x) { + return x; + } + + static auto static_exact(int) -> int { return 0; } + static auto static_inexact(long) -> short { return 0; } + // TODO: Switch to `static auto static_templated(auto x)` with C++20 + template <typename T> + static T static_templated(T x) { + return x; + } +}; + +} // namespace + +TEST(Function, ImplicitConversions) { + using Function = ftl::Function<int(int)>; + auto check = [](Function f) { return f(0); }; + auto exact = [](int) -> int { return 0; }; + auto inexact = [](long) -> short { return 0; }; + auto templated = [](auto x) { return x; }; + + ImplicitConversionsHelper helper; + + // Note, `check(nullptr)` would crash, so we can only check if it would be invocable. + static_assert(std::is_invocable_v<decltype(check), decltype(nullptr)>); + + // Note: We invoke each of these to fully expand all the templates involved. + EXPECT_EQ(check(ftl::no_op), 0); + + EXPECT_EQ(check(exact), 0); + EXPECT_EQ(check(inexact), 0); + EXPECT_EQ(check(templated), 0); + + EXPECT_EQ(check(Function::make<&ImplicitConversionsHelper::exact>(&helper)), 0); + EXPECT_EQ(check(Function::make<&ImplicitConversionsHelper::inexact>(&helper)), 0); + EXPECT_EQ(check(Function::make<&ImplicitConversionsHelper::templated<int>>(&helper)), 0); + + EXPECT_EQ(check(Function::make<&ImplicitConversionsHelper::static_exact>()), 0); + EXPECT_EQ(check(Function::make<&ImplicitConversionsHelper::static_inexact>()), 0); + EXPECT_EQ(check(Function::make<&ImplicitConversionsHelper::static_templated<int>>()), 0); +} + +TEST(Function, MakeWithNonConstMemberFunction) { + struct Observer { + bool called = false; + void setCalled() { called = true; } + } observer; + + auto f = ftl::make_function<&Observer::setCalled>(&observer); + + f(); + + EXPECT_TRUE(observer.called); + + EXPECT_TRUE(f == ftl::Function<void()>::make<&Observer::setCalled>(&observer)); +} + +TEST(Function, MakeWithConstMemberFunction) { + struct Observer { + mutable bool called = false; + void setCalled() const { called = true; } + } observer; + + const auto f = ftl::make_function<&Observer::setCalled>(&observer); + + f(); + + EXPECT_TRUE(observer.called); + + EXPECT_TRUE(f == ftl::Function<void()>::make<&Observer::setCalled>(&observer)); +} + +TEST(Function, MakeWithConstClassPointer) { + const struct Observer { + mutable bool called = false; + void setCalled() const { called = true; } + } observer; + + const auto f = ftl::make_function<&Observer::setCalled>(&observer); + + f(); + + EXPECT_TRUE(observer.called); + + EXPECT_TRUE(f == ftl::Function<void()>::make<&Observer::setCalled>(&observer)); +} + +TEST(Function, MakeWithNonCapturingLambda) { + auto f = ftl::make_function([](int a, int b) { return a + b; }); + EXPECT_EQ(f(1, 2), 3); +} + +TEST(Function, MakeWithCapturingLambda) { + bool called = false; + auto f = ftl::make_function([&called](int a, int b) { + called = true; + return a + b; + }); + EXPECT_EQ(f(1, 2), 3); + EXPECT_TRUE(called); +} + +TEST(Function, MakeWithCapturingMutableLambda) { + bool called = false; + auto f = ftl::make_function([&called](int a, int b) mutable { + called = true; + return a + b; + }); + EXPECT_EQ(f(1, 2), 3); + EXPECT_TRUE(called); +} + +TEST(Function, MakeWithThreePointerCapturingLambda) { + bool my_bool = false; + int my_int = 0; + float my_float = 0.f; + + auto f = ftl::make_function( + [ptr_bool = &my_bool, ptr_int = &my_int, ptr_float = &my_float](int a, int b) mutable { + *ptr_bool = true; + *ptr_int = 1; + *ptr_float = 1.f; + + return a + b; + }); + + EXPECT_EQ(f(1, 2), 3); + + EXPECT_TRUE(my_bool); + EXPECT_EQ(my_int, 1); + EXPECT_EQ(my_float, 1.f); +} + +TEST(Function, MakeWithFreeFunction) { + auto f = ftl::make_function<&std::make_unique<int, int>>(); + std::unique_ptr<int> unique_int = f(1); + ASSERT_TRUE(unique_int); + EXPECT_EQ(*unique_int, 1); +} + +TEST(Function, CopyToLarger) { + int counter = 0; + ftl::Function<void()> a{[ptr_counter = &counter] { (*ptr_counter)++; }}; + ftl::Function<void(), 1> b = a; + ftl::Function<void(), 2> c = a; + + EXPECT_EQ(counter, 0); + a(); + EXPECT_EQ(counter, 1); + b(); + EXPECT_EQ(counter, 2); + c(); + EXPECT_EQ(counter, 3); + + b = [ptr_counter = &counter] { (*ptr_counter) += 2; }; + c = [ptr_counter = &counter] { (*ptr_counter) += 3; }; + + b(); + EXPECT_EQ(counter, 5); + c(); + EXPECT_EQ(counter, 8); +} + +} // namespace android::test diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp index 490cf2f55a..193b84d313 100644 --- a/services/inputflinger/tests/PointerChoreographer_test.cpp +++ b/services/inputflinger/tests/PointerChoreographer_test.cpp @@ -34,7 +34,9 @@ namespace { // Helpers to std::visit with lambdas. template <typename... V> -struct Visitor : V... {}; +struct Visitor : V... { + using V::operator()...; +}; template <typename... V> Visitor(V...) -> Visitor<V...>; diff --git a/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp index 0bd8fb3de3..dc5a2130e7 100644 --- a/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp @@ -65,6 +65,27 @@ private: std::map<int32_t /*displayId*/, InputVerifier> mVerifiers; }; +void scrambleWindow(FuzzedDataProvider& fdp, FakeWindowHandle& window) { + const int32_t left = fdp.ConsumeIntegralInRange<int32_t>(0, 100); + const int32_t top = fdp.ConsumeIntegralInRange<int32_t>(0, 100); + const int32_t width = fdp.ConsumeIntegralInRange<int32_t>(0, 100); + const int32_t height = fdp.ConsumeIntegralInRange<int32_t>(0, 100); + + window.setFrame(Rect(left, top, left + width, top + height)); + window.setSlippery(fdp.ConsumeBool()); + window.setDupTouchToWallpaper(fdp.ConsumeBool()); + window.setIsWallpaper(fdp.ConsumeBool()); + window.setVisible(fdp.ConsumeBool()); + window.setPreventSplitting(fdp.ConsumeBool()); + const bool isTrustedOverlay = fdp.ConsumeBool(); + window.setTrustedOverlay(isTrustedOverlay); + if (isTrustedOverlay) { + window.setSpy(fdp.ConsumeBool()); + } else { + window.setSpy(false); + } +} + } // namespace sp<FakeWindowHandle> generateFuzzedWindow(FuzzedDataProvider& fdp, InputDispatcher& dispatcher, @@ -73,17 +94,9 @@ sp<FakeWindowHandle> generateFuzzedWindow(FuzzedDataProvider& fdp, InputDispatch std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); std::string windowName = android::base::StringPrintf("Win") + std::to_string(windowNumber++); sp<FakeWindowHandle> window = - sp<FakeWindowHandle>::make(application, dispatcher, "Fake", displayId); + sp<FakeWindowHandle>::make(application, dispatcher, windowName, displayId); - const int32_t left = fdp.ConsumeIntegralInRange<int32_t>(0, 100); - const int32_t top = fdp.ConsumeIntegralInRange<int32_t>(0, 100); - const int32_t width = fdp.ConsumeIntegralInRange<int32_t>(0, 100); - const int32_t height = fdp.ConsumeIntegralInRange<int32_t>(0, 100); - - window->setFrame(Rect(left, top, left + width, top + height)); - window->setSlippery(fdp.ConsumeBool()); - window->setDupTouchToWallpaper(fdp.ConsumeBool()); - window->setTrustedOverlay(fdp.ConsumeBool()); + scrambleWindow(fdp, *window); return window; } @@ -113,7 +126,14 @@ void randomizeWindows( windowsPerDisplay.erase(displayId); } }, - // Could also clone a window, change flags, reposition, etc... + // Change flags or move some of the existing windows + [&]() -> void { + for (auto& window : windows) { + if (fdp.ConsumeBool()) { + scrambleWindow(fdp, *window); + } + } + }, })(); } diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index c25f9ddd12..64a8ae7fcd 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -271,7 +271,10 @@ AidlComposer::AidlComposer(const std::string& serviceName) { } } } - + if (getLayerLifecycleBatchCommand()) { + mEnableLayerCommandBatchingFlag = + FlagManager::getInstance().enable_layer_command_batching(); + } ALOGI("Loaded AIDL composer3 HAL service"); } @@ -288,7 +291,7 @@ bool AidlComposer::isSupported(OptionalFeature feature) const { } } -bool AidlComposer::getDisplayConfigurationsSupported() const { +bool AidlComposer::isVrrSupported() const { return mComposerInterfaceVersion >= 3 && FlagManager::getInstance().vrr_config(); } @@ -407,25 +410,58 @@ Error AidlComposer::acceptDisplayChanges(Display display) { Error AidlComposer::createLayer(Display display, Layer* outLayer) { int64_t layer; - const auto status = mAidlComposerClient->createLayer(translate<int64_t>(display), - kMaxLayerBufferCount, &layer); - if (!status.isOk()) { - ALOGE("createLayer failed %s", status.getDescription().c_str()); - return static_cast<Error>(status.getServiceSpecificError()); + Error error = Error::NONE; + if (!mEnableLayerCommandBatchingFlag) { + const auto status = mAidlComposerClient->createLayer(translate<int64_t>(display), + kMaxLayerBufferCount, &layer); + if (!status.isOk()) { + ALOGE("createLayer failed %s", status.getDescription().c_str()); + return static_cast<Error>(status.getServiceSpecificError()); + } + } else { + // generate a unique layerID. map in AidlComposer with <SF_layerID, HWC_layerID> + // Add this as a new displayCommand in execute command. + // return the SF generated layerID instead of calling HWC + layer = mLayerID++; + mMutex.lock_shared(); + if (auto writer = getWriter(display)) { + writer->get().setLayerLifecycleBatchCommandType(translate<int64_t>(display), + translate<int64_t>(layer), + LayerLifecycleBatchCommandType::CREATE); + writer->get().setNewBufferSlotCount(translate<int64_t>(display), + translate<int64_t>(layer), kMaxLayerBufferCount); + } else { + error = Error::BAD_DISPLAY; + } + mMutex.unlock_shared(); } - *outLayer = translate<Layer>(layer); - return Error::NONE; + return error; } Error AidlComposer::destroyLayer(Display display, Layer layer) { - const auto status = mAidlComposerClient->destroyLayer(translate<int64_t>(display), - translate<int64_t>(layer)); - if (!status.isOk()) { - ALOGE("destroyLayer failed %s", status.getDescription().c_str()); - return static_cast<Error>(status.getServiceSpecificError()); + Error error = Error::NONE; + if (!mEnableLayerCommandBatchingFlag) { + const auto status = mAidlComposerClient->destroyLayer(translate<int64_t>(display), + translate<int64_t>(layer)); + if (!status.isOk()) { + ALOGE("destroyLayer failed %s", status.getDescription().c_str()); + return static_cast<Error>(status.getServiceSpecificError()); + } + } else { + mMutex.lock_shared(); + if (auto writer = getWriter(display)) { + writer->get() + .setLayerLifecycleBatchCommandType(translate<int64_t>(display), + translate<int64_t>(layer), + LayerLifecycleBatchCommandType::DESTROY); + } else { + error = Error::BAD_DISPLAY; + } + mMutex.unlock_shared(); } - return Error::NONE; + + return error; } Error AidlComposer::getActiveConfig(Display display, Config* outConfig) { @@ -591,6 +627,13 @@ Error AidlComposer::getHdrCapabilities(Display display, std::vector<Hdr>* outTyp return Error::NONE; } +bool AidlComposer::getLayerLifecycleBatchCommand() { + std::vector<Capability> capabilities = getCapabilities(); + bool hasCapability = std::find(capabilities.begin(), capabilities.end(), + Capability::LAYER_LIFECYCLE_BATCH_COMMAND) != capabilities.end(); + return hasCapability; +} + Error AidlComposer::getOverlaySupport(AidlOverlayProperties* outProperties) { const auto status = mAidlComposerClient->getOverlaySupport(outProperties); if (!status.isOk()) { diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index 51ac1f5e6a..ea0e53a202 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -66,7 +66,7 @@ public: ~AidlComposer() override; bool isSupported(OptionalFeature) const; - bool getDisplayConfigurationsSupported() const; + bool isVrrSupported() const; std::vector<aidl::android::hardware::graphics::composer3::Capability> getCapabilities() override; @@ -262,7 +262,7 @@ private: void removeDisplay(Display) EXCLUDES(mMutex); void addReader(Display) REQUIRES(mMutex); void removeReader(Display) REQUIRES(mMutex); - + bool getLayerLifecycleBatchCommand(); bool hasMultiThreadedPresentSupport(Display); // 64KiB minus a small space for metadata such as read/write pointers @@ -293,6 +293,8 @@ private: ftl::SharedMutex mMutex; int32_t mComposerInterfaceVersion = 1; + bool mEnableLayerCommandBatchingFlag = false; + std::atomic<int64_t> mLayerID = 1; // Buffer slots for layers are cleared by setting the slot buffer to this buffer. sp<GraphicBuffer> mClearSlotBuffer; diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 1a24222af3..bc067a0e5d 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -105,7 +105,7 @@ public: }; virtual bool isSupported(OptionalFeature) const = 0; - virtual bool getDisplayConfigurationsSupported() const = 0; + virtual bool isVrrSupported() const = 0; virtual std::vector<aidl::android::hardware::graphics::composer3::Capability> getCapabilities() = 0; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 6b67865bdb..2e8ecba8be 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -321,7 +321,7 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModes(PhysicalDisplayId d const auto hwcDisplayId = mDisplayData.at(displayId).hwcDisplay->getId(); - if (mComposer->getDisplayConfigurationsSupported()) { + if (mComposer->isVrrSupported()) { return getModesFromDisplayConfigurations(hwcDisplayId, maxFrameIntervalNs); } diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 5f1d5f8164..c4ff9cc6be 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -276,8 +276,8 @@ bool HidlComposer::isSupported(OptionalFeature feature) const { } } -bool HidlComposer::getDisplayConfigurationsSupported() const { - // getDisplayConfigurations is not supported on the HIDL composer. +bool HidlComposer::isVrrSupported() const { + // VRR is not supported on the HIDL composer. return false; }; diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index c768d2758d..d78bfb7c6b 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -167,7 +167,7 @@ public: ~HidlComposer() override; bool isSupported(OptionalFeature) const; - bool getDisplayConfigurationsSupported() const; + bool isVrrSupported() const; std::vector<aidl::android::hardware::graphics::composer3::Capability> getCapabilities() override; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9b417c6c96..1f8f2d6c94 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2160,19 +2160,16 @@ void SurfaceFlinger::onComposerHalVsyncIdle(hal::HWDisplayId) { void SurfaceFlinger::onRefreshRateChangedDebug(const RefreshRateChangedDebugData& data) { ATRACE_CALL(); if (const auto displayId = getHwComposer().toPhysicalDisplayId(data.display); displayId) { - const Fps fps = Fps::fromPeriodNsecs(data.vsyncPeriodNanos); - ATRACE_FORMAT("%s Fps %d", __func__, fps.getIntValue()); + const char* const whence = __func__; static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { - { - { - const auto display = getDisplayDeviceLocked(*displayId); - FTL_FAKE_GUARD(kMainThreadContext, - display->updateRefreshRateOverlayRate(fps, - display->getActiveMode() - .fps, - /* setByHwc */ true)); - } - } + const Fps fps = Fps::fromPeriodNsecs(getHwComposer().getComposer()->isVrrSupported() + ? data.refreshPeriodNanos + : data.vsyncPeriodNanos); + ATRACE_FORMAT("%s Fps %d", whence, fps.getIntValue()); + const auto display = getDisplayDeviceLocked(*displayId); + FTL_FAKE_GUARD(kMainThreadContext, + display->updateRefreshRateOverlayRate(fps, display->getActiveMode().fps, + /* setByHwc */ true)); })); } } diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp index 9b77751d1c..cb1faee6b9 100644 --- a/services/surfaceflinger/common/FlagManager.cpp +++ b/services/surfaceflinger/common/FlagManager.cpp @@ -127,7 +127,7 @@ void FlagManager::dump(std::string& result) const { DUMP_READ_ONLY_FLAG(display_protected); DUMP_READ_ONLY_FLAG(fp16_client_target); DUMP_READ_ONLY_FLAG(game_default_frame_rate); - + DUMP_READ_ONLY_FLAG(enable_layer_command_batching); #undef DUMP_READ_ONLY_FLAG #undef DUMP_SERVER_FLAG #undef DUMP_FLAG_INTERVAL @@ -201,6 +201,7 @@ FLAG_MANAGER_READ_ONLY_FLAG(enable_fro_dependent_features, "") FLAG_MANAGER_READ_ONLY_FLAG(display_protected, "") FLAG_MANAGER_READ_ONLY_FLAG(fp16_client_target, "debug.sf.fp16_client_target") FLAG_MANAGER_READ_ONLY_FLAG(game_default_frame_rate, "") +FLAG_MANAGER_READ_ONLY_FLAG(enable_layer_command_batching, "") /// Trunk stable server flags /// FLAG_MANAGER_SERVER_FLAG(late_boot_misc2, "") diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h index 3a509f6352..2e1d6aee4d 100644 --- a/services/surfaceflinger/common/include/common/FlagManager.h +++ b/services/surfaceflinger/common/include/common/FlagManager.h @@ -66,6 +66,7 @@ public: bool display_protected() const; bool fp16_client_target() const; bool game_default_frame_rate() const; + bool enable_layer_command_batching() const; protected: // overridden for unit tests diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig index 3f26448a54..1a28b81483 100644 --- a/services/surfaceflinger/surfaceflinger_flags.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags.aconfig @@ -32,6 +32,14 @@ flag { } flag { + name: "enable_layer_command_batching" + namespace: "core_graphics" + description: "This flag controls batching on createLayer/destroyLayer command with executeCommand." + bug: "290685621" + is_fixed_read_only: true +} + +flag { name: "dont_skip_on_early" namespace: "core_graphics" description: "This flag is guarding the behaviour where SurfaceFlinger is trying to opportunistically present a frame when the configuration change from late to early" diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index d3ce4f2b90..c5e179fb4c 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -143,7 +143,7 @@ TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); ASSERT_TRUE(info); - EXPECT_CALL(*mHal, getDisplayConfigurationsSupported()).WillRepeatedly(Return(false)); + EXPECT_CALL(*mHal, isVrrSupported()).WillRepeatedly(Return(false)); { EXPECT_CALL(*mHal, getDisplayConfigs(kHwcDisplayId, _)) @@ -235,7 +235,7 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_OFF) { const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); ASSERT_TRUE(info); - EXPECT_CALL(*mHal, getDisplayConfigurationsSupported()).WillRepeatedly(Return(false)); + EXPECT_CALL(*mHal, isVrrSupported()).WillRepeatedly(Return(false)); { EXPECT_CALL(*mHal, getDisplayConfigs(kHwcDisplayId, _)) @@ -324,7 +324,7 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); ASSERT_TRUE(info); - EXPECT_CALL(*mHal, getDisplayConfigurationsSupported()).WillRepeatedly(Return(true)); + EXPECT_CALL(*mHal, isVrrSupported()).WillRepeatedly(Return(true)); { EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _, _)) diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index d649679ac8..184dada32e 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -51,7 +51,7 @@ public: ~Composer() override; MOCK_METHOD(bool, isSupported, (OptionalFeature), (const, override)); - MOCK_METHOD(bool, getDisplayConfigurationsSupported, (), (const, override)); + MOCK_METHOD(bool, isVrrSupported, (), (const, override)); MOCK_METHOD0(getCapabilities, std::vector<aidl::android::hardware::graphics::composer3::Capability>()); MOCK_METHOD0(dumpDebugInfo, std::string()); diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h index 7c8e695d67..3e3f962ded 100644 --- a/vulkan/include/vulkan/vk_android_native_buffer.h +++ b/vulkan/include/vulkan/vk_android_native_buffer.h @@ -63,7 +63,8 @@ extern "C" { /* * NOTE ON VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 11 * - * This version of the extension deprecates the last of grallocusage + * This version of the extension deprecates the last of grallocusage and + * extends VkNativeBufferANDROID to support passing AHardwareBuffer* */ #define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 11 #define VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME "VK_ANDROID_native_buffer" @@ -111,6 +112,9 @@ typedef struct { * usage: gralloc usage requested when the buffer was allocated * usage2: gralloc usage requested when the buffer was allocated * usage3: gralloc usage requested when the buffer was allocated + * ahb: The AHardwareBuffer* from the actual ANativeWindowBuffer. Caller + * maintains ownership of resource. AHardwareBuffer pointer is only valid + * for the duration of the function call */ typedef struct { VkStructureType sType; @@ -121,6 +125,7 @@ typedef struct { int usage; /* DEPRECATED in SPEC_VERSION 6 */ VkNativeBufferUsage2ANDROID usage2; /* DEPRECATED in SPEC_VERSION 9 */ uint64_t usage3; /* ADDED in SPEC_VERSION 9 */ + AHardwareBuffer* ahb; /* ADDED in SPEC_VERSION 11 */ } VkNativeBufferANDROID; /* diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 4f7b0f4c57..0df5e77181 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -1970,6 +1970,8 @@ VkResult CreateSwapchainKHR(VkDevice device, &image_native_buffer.usage2.producer, &image_native_buffer.usage2.consumer); image_native_buffer.usage3 = img.buffer->usage; + image_native_buffer.ahb = + ANativeWindowBuffer_getHardwareBuffer(img.buffer.get()); image_create.pNext = &image_native_buffer; ATRACE_BEGIN("CreateImage"); @@ -2146,7 +2148,12 @@ VkResult AcquireNextImageKHR(VkDevice device, .stride = buffer->stride, .format = buffer->format, .usage = int(buffer->usage), + .usage3 = buffer->usage, + .ahb = ANativeWindowBuffer_getHardwareBuffer(buffer), }; + android_convertGralloc0To1Usage(int(buffer->usage), + &nb.usage2.producer, + &nb.usage2.consumer); VkBindImageMemoryInfo bimi = { .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, .pNext = &nb, @@ -2692,7 +2699,12 @@ static void InterceptBindImageMemory2( .stride = buffer->stride, .format = buffer->format, .usage = int(buffer->usage), + .usage3 = buffer->usage, + .ahb = ANativeWindowBuffer_getHardwareBuffer(buffer), }; + android_convertGralloc0To1Usage(int(buffer->usage), + &native_buffer.usage2.producer, + &native_buffer.usage2.consumer); // Reserve enough space to avoid letting re-allocation invalidate the // addresses of the elements inside. out_native_buffers->reserve(bind_info_count); diff --git a/vulkan/nulldrv/Android.bp b/vulkan/nulldrv/Android.bp index a6d540bb93..5112e14dc8 100644 --- a/vulkan/nulldrv/Android.bp +++ b/vulkan/nulldrv/Android.bp @@ -46,5 +46,8 @@ cc_library_shared { "hwvulkan_headers", "vulkan_headers", ], - shared_libs: ["liblog"], + shared_libs: [ + "liblog", + "libnativewindow", + ], } diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp index 2e87f1718b..973e71c892 100644 --- a/vulkan/nulldrv/null_driver.cpp +++ b/vulkan/nulldrv/null_driver.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <android/hardware_buffer.h> #include <hardware/hwvulkan.h> #include <errno.h> diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp index 935535f5bf..d34851e536 100644 --- a/vulkan/nulldrv/null_driver_gen.cpp +++ b/vulkan/nulldrv/null_driver_gen.cpp @@ -16,6 +16,8 @@ // WARNING: This file is generated. See ../README.md for instructions. +#include <android/hardware_buffer.h> + #include <algorithm> #include "null_driver_gen.h" |