summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-14 00:17:53 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-14 00:17:53 +0000
commit8ed6f5a3fb701d3d78b20233827c8727fb5b1f7e (patch)
tree34727bfd2cb9cf626e5777f185296cfd84501a88
parent0687ad03d7c9dd39d7d6cbd4daa30ee388b5254b (diff)
parentf2f5f26192e10045d780e03b4e199503b4ba98c2 (diff)
downloadnative-8ed6f5a3fb701d3d78b20233827c8727fb5b1f7e.tar.gz
Snap for 11216811 from f2f5f26192e10045d780e03b4e199503b4ba98c2 to 24Q1-release
Change-Id: Ib0a1981e1c53a850d3d9143b010d945e42e41aee
-rw-r--r--include/ftl/details/function.h135
-rw-r--r--include/ftl/function.h297
-rw-r--r--libs/binder/libbinder_rpc_unstable.cpp12
-rw-r--r--libs/binder/liblog_stub/include/log/log.h14
-rw-r--r--libs/binder/rust/rpcbinder/src/lib.rs2
-rw-r--r--libs/binder/rust/rpcbinder/src/session.rs34
-rw-r--r--libs/binder/trusty/binder_rpc_unstable/rules.mk32
-rw-r--r--libs/binder/trusty/rust/binder_rpc_unstable_bindgen/BinderBindings.hpp17
-rw-r--r--libs/binder/trusty/rust/binder_rpc_unstable_bindgen/lib.rs24
-rw-r--r--libs/binder/trusty/rust/binder_rpc_unstable_bindgen/rules.mk40
-rw-r--r--libs/binder/trusty/rust/rpcbinder/rules.mk35
-rw-r--r--libs/binder/trusty/rust/rules.mk1
-rw-r--r--libs/ftl/Android.bp1
-rw-r--r--libs/ftl/function_test.cpp379
-rw-r--r--services/inputflinger/tests/PointerChoreographer_test.cpp4
-rw-r--r--services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp42
-rw-r--r--services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp73
-rw-r--r--services/surfaceflinger/DisplayHardware/AidlComposerHal.h6
-rw-r--r--services/surfaceflinger/DisplayHardware/ComposerHal.h2
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp2
-rw-r--r--services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp4
-rw-r--r--services/surfaceflinger/DisplayHardware/HidlComposerHal.h2
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp21
-rw-r--r--services/surfaceflinger/common/FlagManager.cpp3
-rw-r--r--services/surfaceflinger/common/include/common/FlagManager.h1
-rw-r--r--services/surfaceflinger/surfaceflinger_flags.aconfig8
-rw-r--r--services/surfaceflinger/tests/unittests/HWComposerTest.cpp6
-rw-r--r--services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h2
-rw-r--r--vulkan/include/vulkan/vk_android_native_buffer.h7
-rw-r--r--vulkan/libvulkan/swapchain.cpp12
-rw-r--r--vulkan/nulldrv/Android.bp5
-rw-r--r--vulkan/nulldrv/null_driver.cpp1
-rw-r--r--vulkan/nulldrv/null_driver_gen.cpp2
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"