Merge "SF: Fix use after move bug in screen capture refactor"
diff --git a/include/android/surface_control_jni.h b/include/android/surface_control_jni.h
index a0a1fdb..840f6e7 100644
--- a/include/android/surface_control_jni.h
+++ b/include/android/surface_control_jni.h
@@ -44,7 +44,7 @@
*
* Available since API level 34.
*/
-ASurfaceControl* _Nonnull ASurfaceControl_fromSurfaceControl(JNIEnv* _Nonnull env,
+ASurfaceControl* _Nonnull ASurfaceControl_fromJava(JNIEnv* _Nonnull env,
jobject _Nonnull surfaceControlObj) __INTRODUCED_IN(__ANDROID_API_U__);
/**
@@ -59,7 +59,7 @@
*
* Available since API level 34.
*/
-ASurfaceTransaction* _Nonnull ASurfaceTransaction_fromTransaction(JNIEnv* _Nonnull env,
+ASurfaceTransaction* _Nonnull ASurfaceTransaction_fromJava(JNIEnv* _Nonnull env,
jobject _Nonnull transactionObj) __INTRODUCED_IN(__ANDROID_API_U__);
__END_DECLS
diff --git a/include/ftl/flags.h b/include/ftl/flags.h
index 70aaa0e..cdb4e84 100644
--- a/include/ftl/flags.h
+++ b/include/ftl/flags.h
@@ -125,7 +125,7 @@
/* Tests whether all of the given flags are set */
bool all(Flags<F> f) const { return (mFlags & f.mFlags) == f.mFlags; }
- Flags<F> operator|(Flags<F> rhs) const { return static_cast<F>(mFlags | rhs.mFlags); }
+ constexpr Flags<F> operator|(Flags<F> rhs) const { return static_cast<F>(mFlags | rhs.mFlags); }
Flags<F>& operator|=(Flags<F> rhs) {
mFlags = mFlags | rhs.mFlags;
return *this;
@@ -217,7 +217,7 @@
}
template <typename F, typename = std::enable_if_t<is_scoped_enum_v<F>>>
-Flags<F> operator|(F lhs, F rhs) {
+constexpr Flags<F> operator|(F lhs, F rhs) {
return static_cast<F>(to_underlying(lhs) | to_underlying(rhs));
}
diff --git a/include/ftl/shared_mutex.h b/include/ftl/shared_mutex.h
new file mode 100644
index 0000000..146f5ba
--- /dev/null
+++ b/include/ftl/shared_mutex.h
@@ -0,0 +1,47 @@
+/*
+ * 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 <shared_mutex>
+
+namespace android::ftl {
+
+// Wrapper around std::shared_mutex to provide capabilities for thread-safety
+// annotations.
+// TODO(b/257958323): This class is no longer needed once b/135688034 is fixed (currently blocked on
+// b/175635923).
+class [[clang::capability("shared_mutex")]] SharedMutex final {
+ public:
+ [[clang::acquire_capability()]] void lock() {
+ mutex_.lock();
+ }
+ [[clang::release_capability()]] void unlock() {
+ mutex_.unlock();
+ }
+
+ [[clang::acquire_shared_capability()]] void lock_shared() {
+ mutex_.lock_shared();
+ }
+ [[clang::release_shared_capability()]] void unlock_shared() {
+ mutex_.unlock_shared();
+ }
+
+ private:
+ std::shared_mutex mutex_;
+};
+
+} // namespace android::ftl
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index fdf4167..f17bb7d 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -495,6 +495,7 @@
"libbase",
"libbinder",
"libbinder_ndk",
+ "libcutils_sockets",
"liblog",
"libutils",
],
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 83d0de7..399667d 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -564,6 +564,29 @@
return OK;
}
+status_t RpcServer::setupRawSocketServer(base::unique_fd socket_fd) {
+ RpcTransportFd transportFd(std::move(socket_fd));
+ if (!transportFd.fd.ok()) {
+ int savedErrno = errno;
+ ALOGE("Could not get initialized Unix socket: %s", strerror(savedErrno));
+ return -savedErrno;
+ }
+ // Right now, we create all threads at once, making accept4 slow. To avoid hanging the client,
+ // the backlog is increased to a large number.
+ // TODO(b/189955605): Once we create threads dynamically & lazily, the backlog can be reduced
+ // to 1.
+ if (0 != TEMP_FAILURE_RETRY(listen(transportFd.fd.get(), 50 /*backlog*/))) {
+ int savedErrno = errno;
+ ALOGE("Could not listen initialized Unix socket: %s", strerror(savedErrno));
+ return -savedErrno;
+ }
+ if (status_t status = setupExternalServer(std::move(transportFd.fd)); status != OK) {
+ ALOGE("Another thread has set up server while calling setupSocketServer. Race?");
+ return status;
+ }
+ return OK;
+}
+
void RpcServer::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) {
const std::vector<uint8_t>& id = session->mId;
LOG_ALWAYS_FATAL_IF(id.empty(), "Server sessions must be initialized with ID");
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 81ae26a3..4ad0a47 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -71,6 +71,16 @@
[[nodiscard]] status_t setupUnixDomainServer(const char* path);
/**
+ * Sets up an RPC server with a raw socket file descriptor.
+ * The socket should be created and bound to a socket address already, e.g.
+ * the socket can be created in init.rc.
+ *
+ * This method is used in the libbinder_rpc_unstable API
+ * RunInitUnixDomainRpcServer().
+ */
+ [[nodiscard]] status_t setupRawSocketServer(base::unique_fd socket_fd);
+
+ /**
* Creates an RPC server at the current port.
*/
[[nodiscard]] status_t setupVsockServer(unsigned int port);
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index e4a9f99..dd177af 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -42,6 +42,20 @@
AIBinder* VsockRpcClient(unsigned int cid, unsigned int port);
+// Starts a Unix domain RPC server with a given init-managed Unix domain `name` and
+// a given root IBinder object.
+// The socket should be created in init.rc with the same `name`.
+//
+// This function sets up the server, calls readyCallback with a given param, and
+// then joins before returning.
+bool RunInitUnixDomainRpcServer(AIBinder* service, const char* name,
+ void (*readyCallback)(void* param), void* param);
+
+// Gets the service via the RPC binder with Unix domain socket with the given
+// Unix socket `name`.
+// The final Unix domain socket path name is /dev/socket/`name`.
+AIBinder* UnixDomainRpcClient(const char* name);
+
// Connect to an RPC server with preconnected file descriptors.
//
// requestFd should connect to the server and return a valid file descriptor, or
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index 1f38bb9..ae07aee 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -19,6 +19,7 @@
#include <android/binder_libbinder.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+#include <cutils/sockets.h>
#include <linux/vm_sockets.h>
using android::OK;
@@ -30,6 +31,17 @@
extern "C" {
+void RunRpcServer(android::sp<RpcServer>& server, AIBinder* service,
+ void (*readyCallback)(void* param), void* param) {
+ server->setRootObject(AIBinder_toPlatformBinder(service));
+
+ if (readyCallback) readyCallback(param);
+ server->join();
+
+ // Shutdown any open sessions since server failed.
+ (void)server->shutdown();
+}
+
bool RunVsockRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
void* factoryContext, unsigned int port) {
auto server = RpcServer::make();
@@ -60,13 +72,7 @@
<< " error: " << statusToString(status).c_str();
return false;
}
- server->setRootObject(AIBinder_toPlatformBinder(service));
-
- if (readyCallback) readyCallback(param);
- server->join();
-
- // Shutdown any open sessions since server failed.
- (void)server->shutdown();
+ RunRpcServer(server, service, readyCallback, param);
return true;
}
@@ -84,6 +90,31 @@
return AIBinder_fromPlatformBinder(session->getRootObject());
}
+bool RunInitUnixDomainRpcServer(AIBinder* service, const char* name,
+ void (*readyCallback)(void* param), void* param) {
+ auto server = RpcServer::make();
+ auto fd = unique_fd(android_get_control_socket(name));
+ if (status_t status = server->setupRawSocketServer(std::move(fd)); status != OK) {
+ LOG(ERROR) << "Failed to set up Unix Domain RPC server with name " << name
+ << " error: " << statusToString(status).c_str();
+ return false;
+ }
+ RunRpcServer(server, service, readyCallback, param);
+ return true;
+}
+
+AIBinder* UnixDomainRpcClient(const char* name) {
+ std::string pathname(name);
+ pathname = ANDROID_SOCKET_DIR "/" + pathname;
+ auto session = RpcSession::make();
+ if (status_t status = session->setupUnixDomainClient(pathname.c_str()); status != OK) {
+ LOG(ERROR) << "Failed to set up Unix Domain RPC client with path: " << pathname
+ << " error: " << statusToString(status).c_str();
+ return nullptr;
+ }
+ return AIBinder_fromPlatformBinder(session->getRootObject());
+}
+
AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param) {
auto session = RpcSession::make();
auto request = [=] { return unique_fd{requestFd(param)}; };
diff --git a/libs/binder/libbinder_rpc_unstable.map.txt b/libs/binder/libbinder_rpc_unstable.map.txt
index 347831a..f9c7bcf 100644
--- a/libs/binder/libbinder_rpc_unstable.map.txt
+++ b/libs/binder/libbinder_rpc_unstable.map.txt
@@ -3,6 +3,8 @@
RunVsockRpcServer;
RunVsockRpcServerCallback;
VsockRpcClient;
+ RunInitUnixDomainRpcServer;
+ UnixDomainRpcClient;
RpcPreconnectedClient;
local:
*;
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 5ebc27f..9771cc9 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -20,6 +20,7 @@
"libbinder_rs",
"libdowncast_rs",
"liblibc",
+ "liblog_rust",
],
apex_available: [
"com.android.compos",
diff --git a/libs/binder/rust/rpcbinder/src/client.rs b/libs/binder/rust/rpcbinder/src/client.rs
index 4343ff4..48c787b 100644
--- a/libs/binder/rust/rpcbinder/src/client.rs
+++ b/libs/binder/rust/rpcbinder/src/client.rs
@@ -15,6 +15,7 @@
*/
use binder::{unstable_api::new_spibinder, FromIBinder, SpIBinder, StatusCode, Strong};
+use std::ffi::CString;
use std::os::{
raw::{c_int, c_void},
unix::io::RawFd,
@@ -35,6 +36,27 @@
interface_cast(get_vsock_rpc_service(cid, port))
}
+/// Connects to an RPC Binder server over Unix domain socket.
+pub fn get_unix_domain_rpc_service(socket_name: &str) -> Option<SpIBinder> {
+ let socket_name = match CString::new(socket_name) {
+ Ok(s) => s,
+ Err(e) => {
+ log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
+ return None;
+ }
+ };
+ // SAFETY: AIBinder returned by UnixDomainRpcClient has correct reference count,
+ // and the ownership can safely be taken by new_spibinder.
+ unsafe { new_spibinder(binder_rpc_unstable_bindgen::UnixDomainRpcClient(socket_name.as_ptr())) }
+}
+
+/// Connects to an RPC Binder server for a particular interface over Unix domain socket.
+pub fn get_unix_domain_rpc_interface<T: FromIBinder + ?Sized>(
+ socket_name: &str,
+) -> Result<Strong<T>, StatusCode> {
+ interface_cast(get_unix_domain_rpc_service(socket_name))
+}
+
/// Connects to an RPC Binder server, using the given callback to get (and take ownership of)
/// file descriptors already connected to it.
pub fn get_preconnected_rpc_service(
diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs
index fb6b90c..89a49a4 100644
--- a/libs/binder/rust/rpcbinder/src/lib.rs
+++ b/libs/binder/rust/rpcbinder/src/lib.rs
@@ -20,7 +20,9 @@
mod server;
pub use client::{
- get_preconnected_rpc_interface, get_preconnected_rpc_service, get_vsock_rpc_interface,
- get_vsock_rpc_service,
+ get_preconnected_rpc_interface, get_preconnected_rpc_service, get_unix_domain_rpc_interface,
+ get_unix_domain_rpc_service, get_vsock_rpc_interface, get_vsock_rpc_service,
};
-pub use server::{run_vsock_rpc_server, run_vsock_rpc_server_with_factory};
+pub use server::{
+ run_init_unix_domain_rpc_server, run_vsock_rpc_server, run_vsock_rpc_server_with_factory,
+};
diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs
index 8009297..b350a13 100644
--- a/libs/binder/rust/rpcbinder/src/server.rs
+++ b/libs/binder/rust/rpcbinder/src/server.rs
@@ -18,7 +18,7 @@
unstable_api::{AIBinder, AsNative},
SpIBinder,
};
-use std::{os::raw, ptr::null_mut};
+use std::{ffi::CString, os::raw, ptr::null_mut};
/// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
/// port.
@@ -35,7 +35,28 @@
F: FnOnce(),
{
let mut ready_notifier = ReadyNotifier(Some(on_ready));
- ready_notifier.run_server(service, port)
+ ready_notifier.run_vsock_server(service, port)
+}
+
+/// Runs a binder RPC server, serving the supplied binder service implementation on the given
+/// socket file name. The socket should be initialized in init.rc with the same name.
+///
+/// If and when the server is ready for connections, `on_ready` is called to allow appropriate
+/// action to be taken - e.g. to notify clients that they may now attempt to connect.
+///
+/// The current thread is joined to the binder thread pool to handle incoming messages.
+///
+/// Returns true if the server has shutdown normally, false if it failed in some way.
+pub fn run_init_unix_domain_rpc_server<F>(
+ service: SpIBinder,
+ socket_name: &str,
+ on_ready: F,
+) -> bool
+where
+ F: FnOnce(),
+{
+ let mut ready_notifier = ReadyNotifier(Some(on_ready));
+ ready_notifier.run_init_unix_domain_server(service, socket_name)
}
struct ReadyNotifier<F>(Option<F>)
@@ -46,7 +67,7 @@
where
F: FnOnce(),
{
- fn run_server(&mut self, mut service: SpIBinder, port: u32) -> bool {
+ fn run_vsock_server(&mut self, mut service: SpIBinder, port: u32) -> bool {
let service = service.as_native_mut();
let param = self.as_void_ptr();
@@ -64,6 +85,31 @@
}
}
+ fn run_init_unix_domain_server(&mut self, mut service: SpIBinder, socket_name: &str) -> bool {
+ let socket_name = match CString::new(socket_name) {
+ Ok(s) => s,
+ Err(e) => {
+ log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
+ return false;
+ }
+ };
+ let service = service.as_native_mut();
+ let param = self.as_void_ptr();
+
+ // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+ // Plus the binder objects are threadsafe.
+ // RunInitUnixDomainRpcServer does not retain a reference to `ready_callback` or `param`;
+ // it only uses them before it returns, which is during the lifetime of `self`.
+ unsafe {
+ binder_rpc_unstable_bindgen::RunInitUnixDomainRpcServer(
+ service,
+ socket_name.as_ptr(),
+ Some(Self::ready_callback),
+ param,
+ )
+ }
+ }
+
fn as_void_ptr(&mut self) -> *mut raw::c_void {
self as *mut _ as *mut raw::c_void
}
diff --git a/libs/binder/tests/BinderRpcTestServerConfig.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl
index 4cdeac4..aac4b04 100644
--- a/libs/binder/tests/BinderRpcTestServerConfig.aidl
+++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl
@@ -22,5 +22,6 @@
int serverVersion;
int vsockPort;
int unixBootstrapFd; // Inherited from parent
+ int socketFd;
@utf8InCpp String addr;
}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 004dea3..79bd9d4 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -129,6 +129,15 @@
return vsockPort++;
}
+static base::unique_fd initUnixSocket(std::string addr) {
+ auto socket_addr = UnixSocketAddress(addr.c_str());
+ base::unique_fd fd(
+ TEMP_FAILURE_RETRY(socket(socket_addr.addr()->sa_family, SOCK_STREAM, AF_UNIX)));
+ CHECK(fd.ok());
+ CHECK_EQ(0, TEMP_FAILURE_RETRY(bind(fd.get(), socket_addr.addr(), socket_addr.addrSize())));
+ return fd;
+}
+
// Destructors need to be defined, even if pure virtual
ProcessSession::~ProcessSession() {}
@@ -243,13 +252,18 @@
singleThreaded ? "_single_threaded" : "",
noKernel ? "_no_kernel" : "");
- base::unique_fd bootstrapClientFd, bootstrapServerFd;
+ base::unique_fd bootstrapClientFd, bootstrapServerFd, socketFd;
// Do not set O_CLOEXEC, bootstrapServerFd needs to survive fork/exec.
// This is because we cannot pass ParcelFileDescriptor over a pipe.
if (!base::Socketpair(SOCK_STREAM, &bootstrapClientFd, &bootstrapServerFd)) {
int savedErrno = errno;
LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno);
}
+ auto addr = allocateSocketAddress();
+ // Initializes the socket before the fork/exec.
+ if (socketType == SocketType::UNIX_RAW) {
+ socketFd = initUnixSocket(addr);
+ }
auto ret = std::make_unique<LinuxProcessSession>(
Process([=](android::base::borrowed_fd writeEnd, android::base::borrowed_fd readEnd) {
@@ -265,8 +279,9 @@
serverConfig.rpcSecurity = static_cast<int32_t>(rpcSecurity);
serverConfig.serverVersion = serverVersion;
serverConfig.vsockPort = allocateVsockPort();
- serverConfig.addr = allocateSocketAddress();
+ serverConfig.addr = addr;
serverConfig.unixBootstrapFd = bootstrapServerFd.get();
+ serverConfig.socketFd = socketFd.get();
for (auto mode : options.serverSupportedFileDescriptorTransportModes) {
serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
static_cast<int32_t>(mode));
@@ -312,6 +327,7 @@
return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
});
break;
+ case SocketType::UNIX_RAW:
case SocketType::UNIX:
status = session->setupUnixDomainClient(serverConfig.addr.c_str());
break;
@@ -1042,7 +1058,8 @@
}
static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
- std::vector<SocketType> ret = {SocketType::UNIX, SocketType::UNIX_BOOTSTRAP, SocketType::INET};
+ std::vector<SocketType> ret = {SocketType::UNIX, SocketType::UNIX_BOOTSTRAP, SocketType::INET,
+ SocketType::UNIX_RAW};
if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED);
@@ -1284,6 +1301,17 @@
mAcceptConnection = &Server::recvmsgServerConnection;
mConnectToServer = [this] { return connectToUnixBootstrap(mBootstrapSocket); };
} break;
+ case SocketType::UNIX_RAW: {
+ auto addr = allocateSocketAddress();
+ auto status = rpcServer->setupRawSocketServer(initUnixSocket(addr));
+ if (status != OK) {
+ return AssertionFailure()
+ << "setupRawSocketServer: " << statusToString(status);
+ }
+ mConnectToServer = [addr] {
+ return connectTo(UnixSocketAddress(addr.c_str()));
+ };
+ } break;
case SocketType::VSOCK: {
auto port = allocateVsockPort();
auto status = rpcServer->setupVsockServer(port);
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
index dc7d264..654e16c 100644
--- a/libs/binder/tests/binderRpcTestCommon.h
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -69,6 +69,7 @@
PRECONNECTED,
UNIX,
UNIX_BOOTSTRAP,
+ UNIX_RAW,
VSOCK,
INET,
};
@@ -81,6 +82,8 @@
return "unix_domain_socket";
case SocketType::UNIX_BOOTSTRAP:
return "unix_domain_socket_bootstrap";
+ case SocketType::UNIX_RAW:
+ return "raw_uds";
case SocketType::VSOCK:
return "vm_socket";
case SocketType::INET:
diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h
index 721fbfe..5a78782 100644
--- a/libs/binder/tests/binderRpcTestFixture.h
+++ b/libs/binder/tests/binderRpcTestFixture.h
@@ -108,7 +108,8 @@
bool supportsFdTransport() const {
return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS &&
(socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX ||
- socketType() == SocketType::UNIX_BOOTSTRAP);
+ socketType() == SocketType::UNIX_BOOTSTRAP ||
+ socketType() == SocketType::UNIX_RAW);
}
void SetUp() override {
diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp
index a922b21..cc40995 100644
--- a/libs/binder/tests/binderRpcTestService.cpp
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -54,6 +54,9 @@
case SocketType::UNIX_BOOTSTRAP:
CHECK_EQ(OK, server->setupUnixDomainSocketBootstrapServer(std::move(unixBootstrapFd)));
break;
+ case SocketType::UNIX_RAW:
+ CHECK_EQ(OK, server->setupRawSocketServer(base::unique_fd(serverConfig.socketFd)));
+ break;
case SocketType::VSOCK:
CHECK_EQ(OK, server->setupVsockServer(serverConfig.vsockPort));
break;
diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp
index 1e8d93d..f960442 100644
--- a/libs/binder/tests/binderRpcUniversalTests.cpp
+++ b/libs/binder/tests/binderRpcUniversalTests.cpp
@@ -86,7 +86,7 @@
SocketType type = std::get<0>(GetParam());
if (type == SocketType::PRECONNECTED || type == SocketType::UNIX ||
- type == SocketType::UNIX_BOOTSTRAP) {
+ type == SocketType::UNIX_BOOTSTRAP || type == SocketType::UNIX_RAW) {
// we can't get port numbers for unix sockets
return;
}
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index 81113bc..df0b271 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -24,6 +24,7 @@
"match_test.cpp",
"non_null_test.cpp",
"optional_test.cpp",
+ "shared_mutex_test.cpp",
"small_map_test.cpp",
"small_vector_test.cpp",
"static_vector_test.cpp",
diff --git a/libs/ftl/shared_mutex_test.cpp b/libs/ftl/shared_mutex_test.cpp
new file mode 100644
index 0000000..6da7061
--- /dev/null
+++ b/libs/ftl/shared_mutex_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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/shared_mutex.h>
+#include <gtest/gtest.h>
+#include <ftl/fake_guard.h>
+
+namespace android::test {
+
+TEST(SharedMutex, SharedLock) {
+ ftl::SharedMutex mutex;
+ std::shared_lock shared_lock(mutex);
+
+ { std::shared_lock shared_lock2(mutex); }
+}
+
+TEST(SharedMutex, ExclusiveLock) {
+ ftl::SharedMutex mutex;
+ std::unique_lock unique_lock(mutex);
+}
+
+TEST(SharedMutex, Annotations) {
+ struct {
+ void foo() FTL_ATTRIBUTE(requires_shared_capability(mutex)) { num++; }
+ void bar() FTL_ATTRIBUTE(requires_capability(mutex)) { num++; }
+ void baz() {
+ std::shared_lock shared_lock(mutex);
+ num++;
+ }
+ ftl::SharedMutex mutex;
+ int num = 0;
+
+ } s;
+
+ {
+ // TODO(b/257958323): Use an RAII class instead of locking manually.
+ s.mutex.lock_shared();
+ s.foo();
+ s.baz();
+ s.mutex.unlock_shared();
+ }
+ s.mutex.lock();
+ s.bar();
+ s.mutex.unlock();
+}
+
+} // namespace android::test
diff --git a/libs/gui/DisplayInfo.cpp b/libs/gui/DisplayInfo.cpp
index 52d9540..bd640df 100644
--- a/libs/gui/DisplayInfo.cpp
+++ b/libs/gui/DisplayInfo.cpp
@@ -20,8 +20,13 @@
#include <gui/DisplayInfo.h>
#include <private/gui/ParcelUtils.h>
+#include <android-base/stringprintf.h>
#include <log/log.h>
+#include <inttypes.h>
+
+#define INDENT " "
+
namespace android::gui {
// --- DisplayInfo ---
@@ -67,4 +72,17 @@
return OK;
}
+void DisplayInfo::dump(std::string& out, const char* prefix) const {
+ using android::base::StringAppendF;
+
+ out += prefix;
+ StringAppendF(&out, "DisplayViewport[id=%" PRId32 "]\n", displayId);
+ out += prefix;
+ StringAppendF(&out, INDENT "Width=%" PRId32 ", Height=%" PRId32 "\n", logicalWidth,
+ logicalHeight);
+ std::string transformPrefix(prefix);
+ transformPrefix.append(INDENT);
+ transform.dump(out, "Transform", transformPrefix.c_str());
+}
+
} // namespace android::gui
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 4c887ec..a77ca04 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -60,11 +60,11 @@
virtual ~BpSurfaceComposer();
status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
- const Vector<ComposerState>& state,
- const Vector<DisplayState>& displays, uint32_t flags,
- const sp<IBinder>& applyToken, const InputWindowCommands& commands,
- int64_t desiredPresentTime, bool isAutoTimestamp,
- const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
+ Vector<ComposerState>& state, const Vector<DisplayState>& displays,
+ uint32_t flags, const sp<IBinder>& applyToken,
+ const InputWindowCommands& commands, int64_t desiredPresentTime,
+ bool isAutoTimestamp, const client_cache_t& uncacheBuffer,
+ bool hasListenerCallbacks,
const std::vector<ListenerCallbacks>& listenerCallbacks,
uint64_t transactionId) override {
Parcel data, reply;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 9e175ec..d18d22d 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -912,11 +912,11 @@
client_cache_t uncacheBuffer;
uncacheBuffer.token = BufferCache::getInstance().getToken();
uncacheBuffer.id = cacheId;
-
+ Vector<ComposerState> composerStates;
status_t status =
- sf->setTransactionState(FrameTimelineInfo{}, {}, {}, ISurfaceComposer::eOneWay,
- Transaction::getDefaultApplyToken(), {}, systemTime(), true,
- uncacheBuffer, false, {}, generateId());
+ sf->setTransactionState(FrameTimelineInfo{}, composerStates, {},
+ ISurfaceComposer::eOneWay, Transaction::getDefaultApplyToken(),
+ {}, systemTime(), true, uncacheBuffer, false, {}, generateId());
if (status != NO_ERROR) {
ALOGE_AND_TRACE("SurfaceComposerClient::doUncacheBufferTransaction - %s",
strerror(-status));
diff --git a/libs/gui/include/gui/DisplayInfo.h b/libs/gui/include/gui/DisplayInfo.h
index 74f33a2..42b62c7 100644
--- a/libs/gui/include/gui/DisplayInfo.h
+++ b/libs/gui/include/gui/DisplayInfo.h
@@ -41,6 +41,8 @@
status_t writeToParcel(android::Parcel*) const override;
status_t readFromParcel(const android::Parcel*) override;
+
+ void dump(std::string& result, const char* prefix = "") const;
};
} // namespace android::gui
\ No newline at end of file
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e91d754..d517e99 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -55,7 +55,7 @@
namespace android {
struct client_cache_t;
-struct ComposerState;
+class ComposerState;
struct DisplayStatInfo;
struct DisplayState;
struct InputWindowCommands;
@@ -110,7 +110,7 @@
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
virtual status_t setTransactionState(
- const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state,
+ const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 45272e7..09f171d 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -311,7 +311,8 @@
bool dimmingEnabled;
};
-struct ComposerState {
+class ComposerState {
+public:
layer_state_t state;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 67c669d..6d3b425 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -696,7 +696,7 @@
}
status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/,
- const Vector<ComposerState>& /*state*/,
+ Vector<ComposerState>& /*state*/,
const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
const sp<IBinder>& /*applyToken*/,
const InputWindowCommands& /*inputWindowCommands*/,
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index 25fe9f2..8d7c13c 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -23,17 +23,24 @@
#include <math/mat4.h>
#include <renderengine/PrintMatrix.h>
#include <renderengine/BorderRenderInfo.h>
+#include <ui/DisplayId.h>
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Transform.h>
+#include <optional>
+
namespace android {
namespace renderengine {
// DisplaySettings contains the settings that are applicable when drawing all
// layers for a given display.
struct DisplaySettings {
+ // A string containing the name of the display, along with its id, if it has
+ // one.
+ std::string namePlusId;
+
// Rectangle describing the physical display. We will project from the
// logical clip onto this rectangle.
Rect physicalDisplay = Rect::INVALID_RECT;
@@ -85,8 +92,8 @@
};
static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
- return lhs.physicalDisplay == rhs.physicalDisplay && lhs.clip == rhs.clip &&
- lhs.maxLuminance == rhs.maxLuminance &&
+ return lhs.namePlusId == rhs.namePlusId && lhs.physicalDisplay == rhs.physicalDisplay &&
+ lhs.clip == rhs.clip && lhs.maxLuminance == rhs.maxLuminance &&
lhs.currentLuminanceNits == rhs.currentLuminanceNits &&
lhs.outputDataspace == rhs.outputDataspace &&
lhs.colorTransform == rhs.colorTransform &&
@@ -121,6 +128,7 @@
static inline void PrintTo(const DisplaySettings& settings, ::std::ostream* os) {
*os << "DisplaySettings {";
+ *os << "\n .display = " << settings.namePlusId;
*os << "\n .physicalDisplay = ";
PrintTo(settings.physicalDisplay, os);
*os << "\n .clip = ";
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index b9aa5ac..fca6c0e 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -636,7 +636,7 @@
const DisplaySettings& display, const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/,
base::unique_fd&& bufferFence) {
- ATRACE_NAME("SkiaGL::drawLayersInternal");
+ ATRACE_FORMAT("%s for %s", __func__, display.namePlusId.c_str());
std::lock_guard<std::mutex> lock(mRenderingMutex);
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index 99c4936..ab5c5ef 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -46,6 +46,7 @@
"LatencyAggregator.cpp",
"LatencyTracker.cpp",
"Monitor.cpp",
+ "TouchedWindow.cpp",
"TouchState.cpp",
],
}
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 33e7e17..ec9701a 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -308,7 +308,8 @@
volatile int32_t DispatchEntry::sNextSeqAtomic;
-DispatchEntry::DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
+DispatchEntry::DispatchEntry(std::shared_ptr<EventEntry> eventEntry,
+ ftl::Flags<InputTarget::Flags> targetFlags,
const ui::Transform& transform, const ui::Transform& rawTransform,
float globalScaleFactor)
: seq(nextSeq()),
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 60f319a..f801912 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -223,7 +223,7 @@
const uint32_t seq; // unique sequence number, never 0
std::shared_ptr<EventEntry> eventEntry; // the event to dispatch
- int32_t targetFlags;
+ ftl::Flags<InputTarget::Flags> targetFlags;
ui::Transform transform;
ui::Transform rawTransform;
float globalScaleFactor;
@@ -238,13 +238,15 @@
int32_t resolvedAction;
int32_t resolvedFlags;
- DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
- const ui::Transform& transform, const ui::Transform& rawTransform,
- float globalScaleFactor);
+ DispatchEntry(std::shared_ptr<EventEntry> eventEntry,
+ ftl::Flags<InputTarget::Flags> targetFlags, const ui::Transform& transform,
+ const ui::Transform& rawTransform, float globalScaleFactor);
- inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; }
+ inline bool hasForegroundTarget() const {
+ return targetFlags.test(InputTarget::Flags::FOREGROUND);
+ }
- inline bool isSplit() const { return targetFlags & InputTarget::FLAG_SPLIT; }
+ inline bool isSplit() const { return targetFlags.test(InputTarget::Flags::SPLIT); }
private:
static volatile int32_t sNextSeqAtomic;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index f698217..7b7c42a 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -29,6 +29,7 @@
#include <gui/SurfaceComposerClient.h>
#endif
#include <input/InputDevice.h>
+#include <input/PrintTools.h>
#include <powermanager/PowerManager.h>
#include <unistd.h>
#include <utils/Trace.h>
@@ -50,6 +51,7 @@
#define INDENT3 " "
#define INDENT4 " "
+using namespace android::ftl::flag_operators;
using android::base::HwTimeoutMultiplier;
using android::base::Result;
using android::base::StringPrintf;
@@ -241,9 +243,9 @@
}
dump.append(INDENT4);
dump += entry.eventEntry->getDescription();
- dump += StringPrintf(", seq=%" PRIu32
- ", targetFlags=0x%08x, resolvedAction=%d, age=%" PRId64 "ms",
- entry.seq, entry.targetFlags, entry.resolvedAction,
+ dump += StringPrintf(", seq=%" PRIu32 ", targetFlags=%s, resolvedAction=%d, age=%" PRId64
+ "ms",
+ entry.seq, entry.targetFlags.string().c_str(), entry.resolvedAction,
ns2ms(currentTime - entry.eventEntry->eventTime));
if (entry.deliveryTime != 0) {
// This entry was delivered, so add information on how long we've been waiting
@@ -288,9 +290,9 @@
first->applicationInfo.token == second->applicationInfo.token;
}
-std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
- std::shared_ptr<EventEntry> eventEntry,
- int32_t inputTargetFlags) {
+std::unique_ptr<DispatchEntry> createDispatchEntry(
+ const InputTarget& inputTarget, std::shared_ptr<EventEntry> eventEntry,
+ ftl::Flags<InputTarget::Flags> inputTargetFlags) {
if (inputTarget.useDefaultPointerTransform()) {
const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
@@ -483,11 +485,11 @@
entry.pointerProperties[pointerIndex].toolType == AMOTION_EVENT_TOOL_TYPE_ERASER);
}
-// Determines if the given window can be targeted as InputTarget::FLAG_FOREGROUND.
+// Determines if the given window can be targeted as InputTarget::Flags::FOREGROUND.
// Foreground events are only sent to "foreground targetable" windows, but not all gestures sent to
// such window are necessarily targeted with the flag. For example, an event with ACTION_OUTSIDE can
// be sent to such a window, but it is not a foreground event and doesn't use
-// InputTarget::FLAG_FOREGROUND.
+// InputTarget::Flags::FOREGROUND.
bool canReceiveForegroundTouches(const WindowInfo& info) {
// A non-touchable window can still receive touch events (e.g. in the case of
// STYLUS_INTERCEPTOR), so prevent such windows from receiving foreground events for touches.
@@ -1100,7 +1102,7 @@
if (addOutsideTargets &&
info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) {
- touchState->addOrUpdateWindow(windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE,
+ touchState->addOrUpdateWindow(windowHandle, InputTarget::Flags::DISPATCH_AS_OUTSIDE,
BitSet32(0));
}
}
@@ -1371,7 +1373,7 @@
}
InputTarget target;
target.inputChannel = channel;
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ target.flags = InputTarget::Flags::DISPATCH_AS_IS;
entry->dispatchInProgress = true;
std::string message = std::string("Focus ") + (entry->hasFocus ? "entering " : "leaving ") +
channel->getName();
@@ -1445,7 +1447,7 @@
}
InputTarget target;
target.inputChannel = channel;
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ target.flags = InputTarget::Flags::DISPATCH_AS_IS;
entry->dispatchInProgress = true;
dispatchEventLocked(currentTime, entry, {target});
@@ -1482,7 +1484,7 @@
}
InputTarget target;
target.inputChannel = channel;
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ target.flags = InputTarget::Flags::DISPATCH_AS_IS;
inputTargets.push_back(target);
}
return inputTargets;
@@ -1595,7 +1597,7 @@
std::vector<InputTarget> inputTargets;
addWindowTargetLocked(focusedWindow,
- InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,
+ InputTarget::Flags::FOREGROUND | InputTarget::Flags::DISPATCH_AS_IS,
BitSet32(0), getDownTime(*entry), inputTargets);
// Add monitor channels from event's or focused display.
@@ -1708,7 +1710,8 @@
if (injectionResult == InputEventInjectionResult::SUCCEEDED) {
LOG_ALWAYS_FATAL_IF(focusedWindow == nullptr);
addWindowTargetLocked(focusedWindow,
- InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,
+ InputTarget::Flags::FOREGROUND |
+ InputTarget::Flags::DISPATCH_AS_IS,
BitSet32(0), getDownTime(*entry), inputTargets);
}
}
@@ -1760,7 +1763,7 @@
}
InputTarget target;
target.inputChannel = channel;
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ target.flags = InputTarget::Flags::DISPATCH_AS_IS;
entry->dispatchInProgress = true;
dispatchEventLocked(currentTime, entry, {target});
}
@@ -2195,20 +2198,20 @@
}
// Set target flags.
- int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_IS;
+ ftl::Flags<InputTarget::Flags> targetFlags = InputTarget::Flags::DISPATCH_AS_IS;
if (canReceiveForegroundTouches(*windowHandle->getInfo())) {
// There should only be one touched window that can be "foreground" for the pointer.
- targetFlags |= InputTarget::FLAG_FOREGROUND;
+ targetFlags |= InputTarget::Flags::FOREGROUND;
}
if (isSplit) {
- targetFlags |= InputTarget::FLAG_SPLIT;
+ targetFlags |= InputTarget::Flags::SPLIT;
}
if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
- targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+ targetFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED;
} else if (isWindowObscuredLocked(windowHandle)) {
- targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+ targetFlags |= InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED;
}
// Update the temporary touch state.
@@ -2232,11 +2235,10 @@
// If the pointer is not currently down, then ignore the event.
if (!tempTouchState.isDown()) {
- if (DEBUG_FOCUS) {
- ALOGD("Dropping event because the pointer is not down or we previously "
- "dropped the pointer down event in display %" PRId32,
- displayId);
- }
+ ALOGD_IF(DEBUG_FOCUS,
+ "Dropping event because the pointer is not down or we previously "
+ "dropped the pointer down event in display %" PRId32 ": %s",
+ displayId, entry.getDescription().c_str());
outInjectionResult = InputEventInjectionResult::FAILED;
goto Failed;
}
@@ -2276,7 +2278,7 @@
}
// Make a slippery exit from the old window.
tempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
- InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT,
+ InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT,
BitSet32(0));
// Make a slippery entrance into the new window.
@@ -2284,17 +2286,18 @@
isSplit = !isFromMouse;
}
- int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER;
+ ftl::Flags<InputTarget::Flags> targetFlags =
+ InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER;
if (canReceiveForegroundTouches(*newTouchedWindowHandle->getInfo())) {
- targetFlags |= InputTarget::FLAG_FOREGROUND;
+ targetFlags |= InputTarget::Flags::FOREGROUND;
}
if (isSplit) {
- targetFlags |= InputTarget::FLAG_SPLIT;
+ targetFlags |= InputTarget::Flags::SPLIT;
}
if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
- targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+ targetFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED;
} else if (isWindowObscuredLocked(newTouchedWindowHandle)) {
- targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+ targetFlags |= InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED;
}
BitSet32 pointerIds;
@@ -2317,7 +2320,8 @@
mLastHoverWindowHandle->getName().c_str());
}
tempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,
- InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
+ InputTarget::Flags::DISPATCH_AS_HOVER_EXIT,
+ BitSet32(0));
}
// Let the new window know that the hover sequence is starting, unless we already did it
@@ -2330,7 +2334,7 @@
newHoverWindowHandle->getName().c_str());
}
tempTouchState.addOrUpdateWindow(newHoverWindowHandle,
- InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER,
+ InputTarget::Flags::DISPATCH_AS_HOVER_ENTER,
BitSet32(0));
}
}
@@ -2343,7 +2347,7 @@
[](const TouchedWindow& touchedWindow) {
return !canReceiveForegroundTouches(
*touchedWindow.windowHandle->getInfo()) ||
- (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0;
+ touchedWindow.targetFlags.test(InputTarget::Flags::FOREGROUND);
})) {
ALOGI("Dropping event because there is no touched window on display %d to receive it: %s",
displayId, entry.getDescription().c_str());
@@ -2355,7 +2359,7 @@
if (entry.injectionState != nullptr) {
std::string errs;
for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
- if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
+ if (touchedWindow.targetFlags.test(InputTarget::Flags::DISPATCH_AS_OUTSIDE)) {
// Allow ACTION_OUTSIDE events generated by targeted injection to be
// dispatched to any uid, since the coords will be zeroed out later.
continue;
@@ -2380,11 +2384,11 @@
if (foregroundWindowHandle) {
const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
- if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
+ if (touchedWindow.targetFlags.test(InputTarget::Flags::DISPATCH_AS_OUTSIDE)) {
sp<WindowInfoHandle> windowInfoHandle = touchedWindow.windowHandle;
if (windowInfoHandle->getInfo()->ownerUid != foregroundWindowUid) {
tempTouchState.addOrUpdateWindow(windowInfoHandle,
- InputTarget::FLAG_ZERO_COORDS,
+ InputTarget::Flags::ZERO_COORDS,
BitSet32(0));
}
}
@@ -2411,13 +2415,12 @@
if (info->displayId == displayId &&
windowHandle->getInfo()->inputConfig.test(
WindowInfo::InputConfig::IS_WALLPAPER)) {
- tempTouchState
- .addOrUpdateWindow(windowHandle,
- InputTarget::FLAG_WINDOW_IS_OBSCURED |
- InputTarget::
- FLAG_WINDOW_IS_PARTIALLY_OBSCURED |
- InputTarget::FLAG_DISPATCH_AS_IS,
- BitSet32(0), entry.eventTime);
+ tempTouchState.addOrUpdateWindow(windowHandle,
+ InputTarget::Flags::WINDOW_IS_OBSCURED |
+ InputTarget::Flags::
+ WINDOW_IS_PARTIALLY_OBSCURED |
+ InputTarget::Flags::DISPATCH_AS_IS,
+ BitSet32(0), entry.eventTime);
}
}
}
@@ -2443,10 +2446,8 @@
if (isHoverAction) {
// Started hovering, therefore no longer down.
if (oldState && oldState->isDown()) {
- if (DEBUG_FOCUS) {
- ALOGD("Conflicting pointer actions: Hover received while pointer was "
- "down.");
- }
+ ALOGD_IF(DEBUG_FOCUS,
+ "Conflicting pointer actions: Hover received while pointer was down.");
*outConflictingPointerActions = true;
}
tempTouchState.reset();
@@ -2462,9 +2463,7 @@
} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
// First pointer went down.
if (oldState && oldState->isDown()) {
- if (DEBUG_FOCUS) {
- ALOGD("Conflicting pointer actions: Down received while already down.");
- }
+ ALOGD("Conflicting pointer actions: Down received while already down.");
*outConflictingPointerActions = true;
}
} else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
@@ -2612,7 +2611,8 @@
}
void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHandle,
- int32_t targetFlags, BitSet32 pointerIds,
+ ftl::Flags<InputTarget::Flags> targetFlags,
+ BitSet32 pointerIds,
std::optional<nsecs_t> firstDownTimeInTarget,
std::vector<InputTarget>& inputTargets) const {
std::vector<InputTarget>::iterator it =
@@ -2660,7 +2660,7 @@
for (const Monitor& monitor : selectResponsiveMonitorsLocked(monitorsIt->second)) {
InputTarget target;
target.inputChannel = monitor.inputChannel;
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ target.flags = InputTarget::Flags::DISPATCH_AS_IS;
// target.firstDownTimeInTarget is not set for global monitors. It is only required in split
// touch and global monitoring works as intended even without setting firstDownTimeInTarget
if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
@@ -2692,7 +2692,7 @@
// We do want to potentially flag touchable windows even if they have 0
// opacity, since they can consume touches and alter the effects of the
// user interaction (eg. apps that rely on
- // FLAG_WINDOW_IS_PARTIALLY_OBSCURED should still be told about those
+ // Flags::WINDOW_IS_PARTIALLY_OBSCURED should still be told about those
// windows), hence we also check for FLAG_NOT_TOUCHABLE.
return false;
} else if (info->ownerUid == otherInfo->ownerUid) {
@@ -2921,9 +2921,9 @@
ATRACE_NAME(message.c_str());
}
if (DEBUG_DISPATCH_CYCLE) {
- ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
+ ALOGD("channel '%s' ~ prepareDispatchCycle - flags=%s, "
"globalScaleFactor=%f, pointerIds=0x%x %s",
- connection->getInputChannelName().c_str(), inputTarget.flags,
+ connection->getInputChannelName().c_str(), inputTarget.flags.string().c_str(),
inputTarget.globalScaleFactor, inputTarget.pointerIds.value,
inputTarget.getPointerInfoString().c_str());
}
@@ -2940,9 +2940,9 @@
}
// Split a motion event if needed.
- if (inputTarget.flags & InputTarget::FLAG_SPLIT) {
+ if (inputTarget.flags.test(InputTarget::Flags::SPLIT)) {
LOG_ALWAYS_FATAL_IF(eventEntry->type != EventEntry::Type::MOTION,
- "Entry type %s should not have FLAG_SPLIT",
+ "Entry type %s should not have Flags::SPLIT",
ftl::enum_string(eventEntry->type).c_str());
const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
@@ -2991,17 +2991,17 @@
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
+ InputTarget::Flags::DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
+ InputTarget::Flags::DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
+ InputTarget::Flags::DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::FLAG_DISPATCH_AS_IS);
+ InputTarget::Flags::DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
+ InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
+ InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.empty()) {
@@ -3012,18 +3012,20 @@
void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
std::shared_ptr<EventEntry> eventEntry,
const InputTarget& inputTarget,
- int32_t dispatchMode) {
+ ftl::Flags<InputTarget::Flags> dispatchMode) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf("enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)",
connection->getInputChannelName().c_str(),
- dispatchModeToString(dispatchMode).c_str());
+ dispatchMode.string().c_str());
ATRACE_NAME(message.c_str());
}
- int32_t inputTargetFlags = inputTarget.flags;
- if (!(inputTargetFlags & dispatchMode)) {
+ ftl::Flags<InputTarget::Flags> inputTargetFlags = inputTarget.flags;
+ if (!inputTargetFlags.any(dispatchMode)) {
return;
}
- inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;
+
+ inputTargetFlags.clear(InputTarget::DISPATCH_MASK);
+ inputTargetFlags |= dispatchMode;
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
@@ -3060,15 +3062,15 @@
constexpr int32_t DEFAULT_RESOLVED_EVENT_ID =
static_cast<int32_t>(IdGenerator::Source::OTHER);
dispatchEntry->resolvedEventId = DEFAULT_RESOLVED_EVENT_ID;
- if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
+ if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_OUTSIDE)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
- } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
+ } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_HOVER_EXIT)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
- } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {
+ } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_HOVER_ENTER)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
- } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
+ } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
- } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {
+ } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
} else {
dispatchEntry->resolvedAction = motionEntry.action;
@@ -3088,10 +3090,10 @@
}
dispatchEntry->resolvedFlags = motionEntry.flags;
- if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
+ if (dispatchEntry->targetFlags.test(InputTarget::Flags::WINDOW_IS_OBSCURED)) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
}
- if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) {
+ if (dispatchEntry->targetFlags.test(InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED)) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
}
@@ -3191,8 +3193,7 @@
std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> newConnectionTokens;
std::vector<sp<Connection>> newConnections;
for (const InputTarget& target : targets) {
- if ((target.flags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) ==
- InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
+ if (target.flags.test(InputTarget::Flags::DISPATCH_AS_OUTSIDE)) {
continue; // Skip windows that receive ACTION_OUTSIDE
}
@@ -3251,7 +3252,7 @@
// Set the X and Y offset and X and Y scale depending on the input source.
if ((motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) &&
- !(dispatchEntry.targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
+ !(dispatchEntry.targetFlags.test(InputTarget::Flags::ZERO_COORDS))) {
float globalScaleFactor = dispatchEntry.globalScaleFactor;
if (globalScaleFactor != 1.0f) {
for (uint32_t i = 0; i < motionEntry.pointerCount; i++) {
@@ -3264,7 +3265,7 @@
}
usingCoords = scaledCoords;
}
- } else if (dispatchEntry.targetFlags & InputTarget::FLAG_ZERO_COORDS) {
+ } else if (dispatchEntry.targetFlags.test(InputTarget::Flags::ZERO_COORDS)) {
// We don't want the dispatch target to know the coordinates
for (uint32_t i = 0; i < motionEntry.pointerCount; i++) {
scaledCoords[i].clear();
@@ -3666,7 +3667,7 @@
target.globalScaleFactor = windowInfo->globalScaleFactor;
}
target.inputChannel = connection->inputChannel;
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ target.flags = InputTarget::Flags::DISPATCH_AS_IS;
const bool wasEmpty = connection->outboundQueue.empty();
@@ -3701,7 +3702,7 @@
}
enqueueDispatchEntryLocked(connection, std::move(cancelationEventEntry), target,
- InputTarget::FLAG_DISPATCH_AS_IS);
+ InputTarget::Flags::DISPATCH_AS_IS);
}
// If the outbound queue was previously empty, start the dispatch cycle going.
@@ -3737,7 +3738,7 @@
target.globalScaleFactor = windowInfo->globalScaleFactor;
}
target.inputChannel = connection->inputChannel;
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ target.flags = InputTarget::Flags::DISPATCH_AS_IS;
const bool wasEmpty = connection->outboundQueue.empty();
for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) {
@@ -3763,7 +3764,7 @@
}
enqueueDispatchEntryLocked(connection, std::move(downEventEntry), target,
- InputTarget::FLAG_DISPATCH_AS_IS);
+ InputTarget::Flags::DISPATCH_AS_IS);
}
// If the outbound queue was previously empty, start the dispatch cycle going.
@@ -4826,7 +4827,7 @@
synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, options);
// Since we are about to drop the touch, cancel the events for the wallpaper as
// well.
- if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND &&
+ if (touchedWindow.targetFlags.test(InputTarget::Flags::FOREGROUND) &&
touchedWindow.windowHandle->getInfo()->inputConfig.test(
gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
sp<WindowInfoHandle> wallpaper = state.getWallpaperWindow();
@@ -5144,16 +5145,16 @@
}
// Erase old window.
- int32_t oldTargetFlags = touchedWindow->targetFlags;
+ ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow->targetFlags;
BitSet32 pointerIds = touchedWindow->pointerIds;
state->removeWindowByToken(fromToken);
// Add new window.
nsecs_t downTimeInTarget = now();
- int32_t newTargetFlags =
- oldTargetFlags & (InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
+ ftl::Flags<InputTarget::Flags> newTargetFlags =
+ oldTargetFlags & (InputTarget::Flags::SPLIT | InputTarget::Flags::DISPATCH_AS_IS);
if (canReceiveForegroundTouches(*toWindowHandle->getInfo())) {
- newTargetFlags |= InputTarget::FLAG_FOREGROUND;
+ newTargetFlags |= InputTarget::Flags::FOREGROUND;
}
state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds, downTimeInTarget);
@@ -5207,7 +5208,7 @@
sp<WindowInfoHandle> touchedForegroundWindow;
// If multiple foreground windows are touched, return nullptr
for (const TouchedWindow& window : state.windows) {
- if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
+ if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
if (touchedForegroundWindow != nullptr) {
ALOGI("Two or more foreground windows: %s and %s",
touchedForegroundWindow->getName().c_str(),
@@ -5320,22 +5321,8 @@
if (!mTouchStatesByDisplay.empty()) {
dump += StringPrintf(INDENT "TouchStatesByDisplay:\n");
for (const auto& [displayId, state] : mTouchStatesByDisplay) {
- dump += StringPrintf(INDENT2 "%d: deviceId=%d, source=0x%08x\n", displayId,
- state.deviceId, state.source);
- if (!state.windows.empty()) {
- dump += INDENT3 "Windows:\n";
- for (size_t i = 0; i < state.windows.size(); i++) {
- const TouchedWindow& touchedWindow = state.windows[i];
- dump += StringPrintf(INDENT4 "%zu: name='%s', pointerIds=0x%0x, "
- "targetFlags=0x%x, firstDownTimeInTarget=%" PRId64
- "ms\n",
- i, touchedWindow.windowHandle->getName().c_str(),
- touchedWindow.pointerIds.value, touchedWindow.targetFlags,
- ns2ms(touchedWindow.firstDownTimeInTarget.value_or(0)));
- }
- } else {
- dump += INDENT3 "Windows: <none>\n";
- }
+ std::string touchStateDump = addLinePrefix(state.dump(), INDENT2);
+ dump += INDENT2 + std::to_string(displayId) + " : " + touchStateDump;
}
} else {
dump += INDENT "TouchStates: <no displays touched>\n";
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 0ddbbeb..5efb39e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -553,7 +553,7 @@
const std::vector<Monitor>& gestureMonitors) const REQUIRES(mLock);
void addWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle,
- int32_t targetFlags, BitSet32 pointerIds,
+ ftl::Flags<InputTarget::Flags> targetFlags, BitSet32 pointerIds,
std::optional<nsecs_t> firstDownTimeInTarget,
std::vector<InputTarget>& inputTargets) const REQUIRES(mLock);
void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId)
@@ -600,8 +600,8 @@
std::shared_ptr<EventEntry>, const InputTarget& inputTarget)
REQUIRES(mLock);
void enqueueDispatchEntryLocked(const sp<Connection>& connection, std::shared_ptr<EventEntry>,
- const InputTarget& inputTarget, int32_t dispatchMode)
- REQUIRES(mLock);
+ const InputTarget& inputTarget,
+ ftl::Flags<InputTarget::Flags> dispatchMode) REQUIRES(mLock);
status_t publishMotionEvent(Connection& connection, DispatchEntry& dispatchEntry) const;
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
index 2df97d9..2f39480 100644
--- a/services/inputflinger/dispatcher/InputTarget.cpp
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -24,24 +24,6 @@
namespace android::inputdispatcher {
-std::string dispatchModeToString(int32_t dispatchMode) {
- switch (dispatchMode) {
- case InputTarget::FLAG_DISPATCH_AS_IS:
- return "DISPATCH_AS_IS";
- case InputTarget::FLAG_DISPATCH_AS_OUTSIDE:
- return "DISPATCH_AS_OUTSIDE";
- case InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER:
- return "DISPATCH_AS_HOVER_ENTER";
- case InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT:
- return "DISPATCH_AS_HOVER_EXIT";
- case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT:
- return "DISPATCH_AS_SLIPPERY_EXIT";
- case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER:
- return "DISPATCH_AS_SLIPPERY_ENTER";
- }
- return StringPrintf("%" PRId32, dispatchMode);
-}
-
void InputTarget::addPointers(BitSet32 newPointerIds, const ui::Transform& transform) {
// The pointerIds can be empty, but still a valid InputTarget. This can happen when there is no
// valid pointer property from the input event.
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index b2966f6..61b07fe 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -16,6 +16,7 @@
#pragma once
+#include <ftl/flags.h>
#include <gui/constants.h>
#include <input/InputTransport.h>
#include <ui/Transform.h>
@@ -30,70 +31,70 @@
* window area.
*/
struct InputTarget {
- enum {
+ enum class Flags : uint32_t {
/* This flag indicates that the event is being delivered to a foreground application. */
- FLAG_FOREGROUND = 1 << 0,
+ FOREGROUND = 1 << 0,
/* This flag indicates that the MotionEvent falls within the area of the target
* obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
- FLAG_WINDOW_IS_OBSCURED = 1 << 1,
+ WINDOW_IS_OBSCURED = 1 << 1,
/* This flag indicates that a motion event is being split across multiple windows. */
- FLAG_SPLIT = 1 << 2,
+ SPLIT = 1 << 2,
/* This flag indicates that the pointer coordinates dispatched to the application
* will be zeroed out to avoid revealing information to an application. This is
* used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing
* the same UID from watching all touches. */
- FLAG_ZERO_COORDS = 1 << 3,
+ ZERO_COORDS = 1 << 3,
/* This flag indicates that the event should be sent as is.
* Should always be set unless the event is to be transmuted. */
- FLAG_DISPATCH_AS_IS = 1 << 8,
+ DISPATCH_AS_IS = 1 << 8,
/* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
* of the area of this target and so should instead be delivered as an
* AMOTION_EVENT_ACTION_OUTSIDE to this target. */
- FLAG_DISPATCH_AS_OUTSIDE = 1 << 9,
+ DISPATCH_AS_OUTSIDE = 1 << 9,
/* This flag indicates that a hover sequence is starting in the given window.
* The event is transmuted into ACTION_HOVER_ENTER. */
- FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10,
+ DISPATCH_AS_HOVER_ENTER = 1 << 10,
/* This flag indicates that a hover event happened outside of a window which handled
* previous hover events, signifying the end of the current hover sequence for that
* window.
* The event is transmuted into ACTION_HOVER_ENTER. */
- FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11,
+ DISPATCH_AS_HOVER_EXIT = 1 << 11,
/* This flag indicates that the event should be canceled.
* It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips
* outside of a window. */
- FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12,
+ DISPATCH_AS_SLIPPERY_EXIT = 1 << 12,
/* This flag indicates that the event should be dispatched as an initial down.
* It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips
* into a new window. */
- FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13,
-
- /* Mask for all dispatch modes. */
- FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS | FLAG_DISPATCH_AS_OUTSIDE |
- FLAG_DISPATCH_AS_HOVER_ENTER | FLAG_DISPATCH_AS_HOVER_EXIT |
- FLAG_DISPATCH_AS_SLIPPERY_EXIT | FLAG_DISPATCH_AS_SLIPPERY_ENTER,
+ DISPATCH_AS_SLIPPERY_ENTER = 1 << 13,
/* This flag indicates that the target of a MotionEvent is partly or wholly
* obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */
- FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
-
+ WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
};
+ /* Mask for all dispatch modes. */
+ static constexpr const ftl::Flags<InputTarget::Flags> DISPATCH_MASK =
+ ftl::Flags<InputTarget::Flags>() | Flags::DISPATCH_AS_IS | Flags::DISPATCH_AS_OUTSIDE |
+ Flags::DISPATCH_AS_HOVER_ENTER | Flags::DISPATCH_AS_HOVER_EXIT |
+ Flags::DISPATCH_AS_SLIPPERY_EXIT | Flags::DISPATCH_AS_SLIPPERY_ENTER;
+
// The input channel to be targeted.
std::shared_ptr<InputChannel> inputChannel;
// Flags for the input target.
- int32_t flags = 0;
+ ftl::Flags<Flags> flags;
// Scaling factor to apply to MotionEvent as it is delivered.
// (ignored for KeyEvents)
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index f5b7cb8..ee7da93 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -14,12 +14,14 @@
* limitations under the License.
*/
+#include <android-base/stringprintf.h>
#include <gui/WindowInfo.h>
#include "InputTarget.h"
-
#include "TouchState.h"
+using namespace android::ftl::flag_operators;
+using android::base::StringPrintf;
using android::gui::WindowInfo;
using android::gui::WindowInfoHandle;
@@ -29,14 +31,15 @@
*this = TouchState();
}
-void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags,
- BitSet32 pointerIds, std::optional<nsecs_t> eventTime) {
+void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle,
+ ftl::Flags<InputTarget::Flags> targetFlags, BitSet32 pointerIds,
+ std::optional<nsecs_t> eventTime) {
for (size_t i = 0; i < windows.size(); i++) {
TouchedWindow& touchedWindow = windows[i];
if (touchedWindow.windowHandle == windowHandle) {
touchedWindow.targetFlags |= targetFlags;
- if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
- touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;
+ if (targetFlags.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT)) {
+ touchedWindow.targetFlags.clear(InputTarget::Flags::DISPATCH_AS_IS);
}
// For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have
// downTime set initially. Need to update existing window when an pointer is down for
@@ -69,10 +72,10 @@
void TouchState::filterNonAsIsTouchWindows() {
for (size_t i = 0; i < windows.size();) {
TouchedWindow& window = windows[i];
- if (window.targetFlags &
- (InputTarget::FLAG_DISPATCH_AS_IS | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) {
- window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK;
- window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS;
+ if (window.targetFlags.any(InputTarget::Flags::DISPATCH_AS_IS |
+ InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
+ window.targetFlags.clear(InputTarget::DISPATCH_MASK);
+ window.targetFlags |= InputTarget::Flags::DISPATCH_AS_IS;
i += 1;
} else {
windows.erase(windows.begin() + i);
@@ -104,7 +107,7 @@
sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const {
for (size_t i = 0; i < windows.size(); i++) {
const TouchedWindow& window = windows[i];
- if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
+ if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
return window.windowHandle;
}
}
@@ -115,7 +118,7 @@
// Must have exactly one foreground window.
bool haveSlipperyForegroundWindow = false;
for (const TouchedWindow& window : windows) {
- if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
+ if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
if (haveSlipperyForegroundWindow ||
!window.windowHandle->getInfo()->inputConfig.test(
WindowInfo::InputConfig::SLIPPERY)) {
@@ -143,4 +146,19 @@
[](const TouchedWindow& window) { return !window.pointerIds.isEmpty(); });
}
+std::string TouchState::dump() const {
+ std::string out;
+ out += StringPrintf("deviceId=%d, source=0x%08x\n", deviceId, source);
+ if (!windows.empty()) {
+ out += " Windows:\n";
+ for (size_t i = 0; i < windows.size(); i++) {
+ const TouchedWindow& touchedWindow = windows[i];
+ out += StringPrintf(" %zu : ", i) + touchedWindow.dump();
+ }
+ } else {
+ out += " Windows: <none>\n";
+ }
+ return out;
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index d1d3e9a..77c1cdf 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -16,7 +16,6 @@
#pragma once
-#include "Monitor.h"
#include "TouchedWindow.h"
namespace android {
@@ -41,7 +40,7 @@
void reset();
void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
- int32_t targetFlags, BitSet32 pointerIds,
+ ftl::Flags<InputTarget::Flags> targetFlags, BitSet32 pointerIds,
std::optional<nsecs_t> eventTime = std::nullopt);
void removeWindowByToken(const sp<IBinder>& token);
void filterNonAsIsTouchWindows();
@@ -57,6 +56,7 @@
sp<android::gui::WindowInfoHandle> getWallpaperWindow() const;
// Whether any of the windows are currently being touched
bool isDown() const;
+ std::string dump() const;
};
} // namespace inputdispatcher
diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp
new file mode 100644
index 0000000..af74598
--- /dev/null
+++ b/services/inputflinger/dispatcher/TouchedWindow.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 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 "TouchedWindow.h"
+
+#include <android-base/stringprintf.h>
+#include <input/PrintTools.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+
+namespace inputdispatcher {
+
+std::string TouchedWindow::dump() const {
+ return StringPrintf("name='%s', pointerIds=0x%0x, "
+ "targetFlags=%s, firstDownTimeInTarget=%s\n",
+ windowHandle->getName().c_str(), pointerIds.value,
+ targetFlags.string().c_str(), toString(firstDownTimeInTarget).c_str());
+}
+
+} // namespace inputdispatcher
+} // namespace android
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index a6c505b..dd08323 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -16,23 +16,24 @@
#pragma once
-namespace android {
+#include <gui/WindowInfo.h>
+#include <utils/BitSet.h>
+#include "InputTarget.h"
-namespace gui {
-class WindowInfoHandle;
-}
+namespace android {
namespace inputdispatcher {
// Focus tracking for touch.
struct TouchedWindow {
sp<gui::WindowInfoHandle> windowHandle;
- int32_t targetFlags;
+ ftl::Flags<InputTarget::Flags> targetFlags;
BitSet32 pointerIds;
bool isPilferingPointers = false;
// Time at which the first action down occurred on this window.
// NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE scenario.
std::optional<nsecs_t> firstDownTimeInTarget;
+ std::string dump() const;
};
} // namespace inputdispatcher
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index 647e10c..7e0c1c7 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -79,6 +79,8 @@
POINTER,
// Show spots and a spot anchor in place of the mouse pointer.
SPOT,
+
+ ftl_last = SPOT,
};
/* Sets the mode of the pointer controller. */
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index c691ca9..a4f257c 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -67,7 +67,7 @@
// --- CursorInputMapper ---
CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext)
- : InputMapper(deviceContext) {}
+ : InputMapper(deviceContext), mLastEventTime(std::numeric_limits<nsecs_t>::min()) {}
CursorInputMapper::~CursorInputMapper() {
if (mPointerController != nullptr) {
@@ -276,6 +276,7 @@
std::list<NotifyArgs> CursorInputMapper::reset(nsecs_t when) {
mButtonState = 0;
mDownTime = 0;
+ mLastEventTime = std::numeric_limits<nsecs_t>::min();
mPointerVelocityControl.reset();
mWheelXVelocityControl.reset();
@@ -295,7 +296,11 @@
mCursorScrollAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
- out += sync(rawEvent->when, rawEvent->readTime);
+ const nsecs_t eventTime =
+ applyBluetoothTimestampSmoothening(getDeviceContext().getDeviceIdentifier(),
+ rawEvent->when, mLastEventTime);
+ out += sync(eventTime, rawEvent->readTime);
+ mLastEventTime = eventTime;
}
return out;
}
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index 6a4275e..20746e5 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -121,6 +121,7 @@
int32_t mButtonState;
nsecs_t mDownTime;
+ nsecs_t mLastEventTime;
void configureParameters();
void dumpParameters(std::string& dump);
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index 5a7ba9a..0b7ff84 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -101,4 +101,30 @@
return out;
}
+// For devices connected over Bluetooth, although they may produce events at a consistent rate,
+// the events might end up reaching Android in a "batched" manner through the Bluetooth
+// stack, where a few events may be clumped together and processed around the same time.
+// In this case, if the input device or its driver does not send or process the actual event
+// generation timestamps, the event time will set to whenever the kernel received the event.
+// When the timestamp deltas are minuscule for these batched events, any changes in x or y
+// coordinates result in extremely large instantaneous velocities, which can negatively impact
+// user experience. To avoid this, we augment the timestamps so that subsequent event timestamps
+// differ by at least a minimum delta value.
+static nsecs_t applyBluetoothTimestampSmoothening(const InputDeviceIdentifier& identifier,
+ nsecs_t currentEventTime, nsecs_t lastEventTime) {
+ if (identifier.bus != BUS_BLUETOOTH) {
+ return currentEventTime;
+ }
+
+ // Assume the fastest rate at which a Bluetooth touch device can report input events is one
+ // every 4 milliseconds, or 250 Hz. Timestamps for successive events from a Bluetooth device
+ // will be separated by at least this amount.
+ constexpr static nsecs_t MIN_BLUETOOTH_TIMESTAMP_DELTA = ms2ns(4);
+ // We define a maximum smoothing time delta so that we don't generate events too far into the
+ // future.
+ constexpr static nsecs_t MAX_BLUETOOTH_SMOOTHING_DELTA = ms2ns(32);
+ return std::min(std::max(currentEventTime, lastEventTime + MIN_BLUETOOTH_TIMESTAMP_DELTA),
+ currentEventTime + MAX_BLUETOOTH_SMOOTHING_DELTA);
+}
+
} // namespace android
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 3947cf7..bf73ce5 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -1469,6 +1469,9 @@
const RawState& last =
mRawStatesPending.size() == 1 ? mCurrentRawState : mRawStatesPending.rbegin()[1];
+ next.when = applyBluetoothTimestampSmoothening(getDeviceContext().getDeviceIdentifier(), when,
+ last.when);
+
// Assign pointer ids.
if (!mHavePointerIds) {
assignPointerIds(last, next);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index d5e4d5a..c20f28b 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -318,7 +318,7 @@
RawPointerAxes mRawPointerAxes;
struct RawState {
- nsecs_t when{};
+ nsecs_t when{std::numeric_limits<nsecs_t>::min()};
nsecs_t readTime{};
// Raw pointer sample data.
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index e4e22df..879d36e 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -99,6 +99,11 @@
// Error tolerance for floating point assertions.
static const float EPSILON = 0.001f;
+// Minimum timestamp separation between subsequent input events from a Bluetooth device.
+static constexpr nsecs_t MIN_BLUETOOTH_TIMESTAMP_DELTA = ms2ns(4);
+// Maximum smoothing time delta so that we don't generate events too far into the future.
+constexpr static nsecs_t MAX_BLUETOOTH_SMOOTHING_DELTA = ms2ns(32);
+
template<typename T>
static inline T min(T a, T b) {
return a < b ? a : b;
@@ -530,10 +535,11 @@
FakeEventHub() { }
- void addDevice(int32_t deviceId, const std::string& name,
- ftl::Flags<InputDeviceClass> classes) {
+ void addDevice(int32_t deviceId, const std::string& name, ftl::Flags<InputDeviceClass> classes,
+ int bus = 0) {
Device* device = new Device(classes);
device->identifier.name = name;
+ device->identifier.bus = bus;
mDevices.add(deviceId, device);
enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0);
@@ -3255,13 +3261,13 @@
std::unique_ptr<InstrumentedInputReader> mReader;
std::shared_ptr<InputDevice> mDevice;
- virtual void SetUp(ftl::Flags<InputDeviceClass> classes) {
+ virtual void SetUp(ftl::Flags<InputDeviceClass> classes, int bus = 0) {
mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = sp<FakeInputReaderPolicy>::make();
mFakeListener = std::make_unique<TestInputListener>();
mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
*mFakeListener);
- mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes);
+ mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes, bus);
// Consume the device reset notification generated when adding a new device.
mFakeListener->assertNotifyDeviceResetWasCalled();
}
@@ -3299,15 +3305,16 @@
std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
const std::string& location, int32_t eventHubId,
- ftl::Flags<InputDeviceClass> classes) {
+ ftl::Flags<InputDeviceClass> classes, int bus = 0) {
InputDeviceIdentifier identifier;
identifier.name = name;
identifier.location = location;
+ identifier.bus = bus;
std::shared_ptr<InputDevice> device =
std::make_shared<InputDevice>(mReader->getContext(), deviceId, DEVICE_GENERATION,
identifier);
mReader->pushNextDevice(device);
- mFakeEventHub->addDevice(eventHubId, name, classes);
+ mFakeEventHub->addDevice(eventHubId, name, classes, bus);
mReader->loopOnce();
return device;
}
@@ -5486,6 +5493,106 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
}
+// --- BluetoothCursorInputMapperTest ---
+
+class BluetoothCursorInputMapperTest : public CursorInputMapperTest {
+protected:
+ void SetUp() override {
+ InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::EXTERNAL, BUS_BLUETOOTH);
+
+ mFakePointerController = std::make_shared<FakePointerController>();
+ mFakePolicy->setPointerController(mFakePointerController);
+ }
+};
+
+TEST_F(BluetoothCursorInputMapperTest, TimestampSmoothening) {
+ addConfigurationProperty("cursor.mode", "pointer");
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+ nsecs_t kernelEventTime = ARBITRARY_TIME;
+ nsecs_t expectedEventTime = ARBITRARY_TIME;
+ process(mapper, kernelEventTime, READ_TIME, EV_REL, REL_X, 1);
+ process(mapper, kernelEventTime, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithEventTime(expectedEventTime))));
+
+ // Process several events that come in quick succession, according to their timestamps.
+ for (int i = 0; i < 3; i++) {
+ constexpr static nsecs_t delta = ms2ns(1);
+ static_assert(delta < MIN_BLUETOOTH_TIMESTAMP_DELTA);
+ kernelEventTime += delta;
+ expectedEventTime += MIN_BLUETOOTH_TIMESTAMP_DELTA;
+
+ process(mapper, kernelEventTime, READ_TIME, EV_REL, REL_X, 1);
+ process(mapper, kernelEventTime, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithEventTime(expectedEventTime))));
+ }
+}
+
+TEST_F(BluetoothCursorInputMapperTest, TimestampSmootheningIsCapped) {
+ addConfigurationProperty("cursor.mode", "pointer");
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+ nsecs_t expectedEventTime = ARBITRARY_TIME;
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 1);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithEventTime(expectedEventTime))));
+
+ // Process several events with the same timestamp from the kernel.
+ // Ensure that we do not generate events too far into the future.
+ constexpr static int32_t numEvents =
+ MAX_BLUETOOTH_SMOOTHING_DELTA / MIN_BLUETOOTH_TIMESTAMP_DELTA;
+ for (int i = 0; i < numEvents; i++) {
+ expectedEventTime += MIN_BLUETOOTH_TIMESTAMP_DELTA;
+
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 1);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithEventTime(expectedEventTime))));
+ }
+
+ // By processing more events with the same timestamp, we should not generate events with a
+ // timestamp that is more than the specified max time delta from the timestamp at its injection.
+ const nsecs_t cappedEventTime = ARBITRARY_TIME + MAX_BLUETOOTH_SMOOTHING_DELTA;
+ for (int i = 0; i < 3; i++) {
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 1);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithEventTime(cappedEventTime))));
+ }
+}
+
+TEST_F(BluetoothCursorInputMapperTest, TimestampSmootheningNotUsed) {
+ addConfigurationProperty("cursor.mode", "pointer");
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+ nsecs_t kernelEventTime = ARBITRARY_TIME;
+ nsecs_t expectedEventTime = ARBITRARY_TIME;
+ process(mapper, kernelEventTime, READ_TIME, EV_REL, REL_X, 1);
+ process(mapper, kernelEventTime, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithEventTime(expectedEventTime))));
+
+ // If the next event has a timestamp that is sufficiently spaced out so that Bluetooth timestamp
+ // smoothening is not needed, its timestamp is not affected.
+ kernelEventTime += MAX_BLUETOOTH_SMOOTHING_DELTA + ms2ns(1);
+ expectedEventTime = kernelEventTime;
+
+ process(mapper, kernelEventTime, READ_TIME, EV_REL, REL_X, 1);
+ process(mapper, kernelEventTime, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithEventTime(expectedEventTime))));
+}
+
// --- TouchInputMapperTest ---
class TouchInputMapperTest : public InputMapperTest {
@@ -7479,7 +7586,8 @@
void processKey(MultiTouchInputMapper& mapper, int32_t code, int32_t value);
void processHidUsage(MultiTouchInputMapper& mapper, int32_t usageCode, int32_t value);
void processMTSync(MultiTouchInputMapper& mapper);
- void processSync(MultiTouchInputMapper& mapper);
+ void processSync(MultiTouchInputMapper& mapper, nsecs_t eventTime = ARBITRARY_TIME,
+ nsecs_t readTime = READ_TIME);
};
void MultiTouchInputMapperTest::prepareAxes(int axes) {
@@ -7592,8 +7700,9 @@
process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_MT_REPORT, 0);
}
-void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper& mapper) {
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper& mapper, nsecs_t eventTime,
+ nsecs_t readTime) {
+ process(mapper, eventTime, readTime, EV_SYN, SYN_REPORT, 0);
}
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) {
@@ -10228,6 +10337,56 @@
ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
}
+// --- BluetoothMultiTouchInputMapperTest ---
+
+class BluetoothMultiTouchInputMapperTest : public MultiTouchInputMapperTest {
+protected:
+ void SetUp() override {
+ InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::EXTERNAL, BUS_BLUETOOTH);
+ }
+};
+
+TEST_F(BluetoothMultiTouchInputMapperTest, TimestampSmoothening) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT | PRESSURE);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ nsecs_t kernelEventTime = ARBITRARY_TIME;
+ nsecs_t expectedEventTime = ARBITRARY_TIME;
+ // Touch down.
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, 100, 200);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper, ARBITRARY_TIME);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithEventTime(ARBITRARY_TIME))));
+
+ // Process several events that come in quick succession, according to their timestamps.
+ for (int i = 0; i < 3; i++) {
+ constexpr static nsecs_t delta = ms2ns(1);
+ static_assert(delta < MIN_BLUETOOTH_TIMESTAMP_DELTA);
+ kernelEventTime += delta;
+ expectedEventTime += MIN_BLUETOOTH_TIMESTAMP_DELTA;
+
+ processPosition(mapper, 101 + i, 201 + i);
+ processSync(mapper, kernelEventTime);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
+ WithEventTime(expectedEventTime))));
+ }
+
+ // Release the touch.
+ processId(mapper, INVALID_TRACKING_ID);
+ processPressure(mapper, RAW_PRESSURE_MIN);
+ processSync(mapper, ARBITRARY_TIME + ms2ns(50));
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
+ WithEventTime(ARBITRARY_TIME + ms2ns(50)))));
+}
+
+// --- MultiTouchPointerModeTest ---
+
class MultiTouchPointerModeTest : public MultiTouchInputMapperTest {
protected:
float mPointerMovementScale;
diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h
index 5107af7..9a47e3e 100644
--- a/services/inputflinger/tests/TestInputListenerMatchers.h
+++ b/services/inputflinger/tests/TestInputListenerMatchers.h
@@ -91,4 +91,9 @@
return arg.buttonState == buttons;
}
+MATCHER_P(WithEventTime, eventTime, "InputEvent with specified eventTime") {
+ *result_listener << "expected event time " << eventTime << ", but got " << arg.eventTime;
+ return arg.eventTime == eventTime;
+}
+
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index e06da33..9ca5da9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -155,6 +155,8 @@
bool mustRecompose() const;
+ const std::string& getNamePlusId() const { return mNamePlusId; }
+
private:
void dirtyEntireOutput();
void updateCompositionStateForBorder(const compositionengine::CompositionRefreshArgs&);
@@ -165,6 +167,7 @@
const compositionengine::CompositionRefreshArgs&) const;
std::string mName;
+ std::string mNamePlusId;
std::unique_ptr<compositionengine::DisplayColorProfile> mDisplayColorProfile;
std::unique_ptr<compositionengine::RenderSurface> mRenderSurface;
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 1c5cbed..24669c2 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -25,6 +25,7 @@
#include <compositionengine/impl/DumpHelpers.h>
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/RenderSurface.h>
+#include <gui/TraceUtils.h>
#include <utils/Trace.h>
@@ -235,7 +236,7 @@
bool Display::chooseCompositionStrategy(
std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
- ATRACE_CALL();
+ ATRACE_FORMAT("%s for %s", __func__, getNamePlusId().c_str());
ALOGV(__FUNCTION__);
if (mIsDisconnected) {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index d1daca6..3ee8017 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -29,6 +29,7 @@
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/impl/planner/Planner.h>
#include <ftl/future.h>
+#include <gui/TraceUtils.h>
#include <thread>
@@ -116,6 +117,9 @@
void Output::setName(const std::string& name) {
mName = name;
+ auto displayIdOpt = getDisplayId();
+ mNamePlusId = base::StringPrintf("%s (%s)", mName.c_str(),
+ displayIdOpt ? to_string(*displayIdOpt).c_str() : "NA");
}
void Output::setCompositionEnabled(bool enabled) {
@@ -427,7 +431,7 @@
}
void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
- ATRACE_CALL();
+ ATRACE_FORMAT("%s for %s", __func__, mNamePlusId.c_str());
ALOGV(__FUNCTION__);
updateColorProfile(refreshArgs);
@@ -1322,6 +1326,7 @@
const auto& outputState = getState();
renderengine::DisplaySettings clientCompositionDisplay;
+ clientCompositionDisplay.namePlusId = mNamePlusId;
clientCompositionDisplay.physicalDisplay = outputState.framebufferSpace.getContent();
clientCompositionDisplay.clip = outputState.layerStackSpace.getContent();
clientCompositionDisplay.orientation =
@@ -1488,7 +1493,7 @@
}
void Output::postFramebuffer() {
- ATRACE_CALL();
+ ATRACE_FORMAT("%s for %s", __func__, mNamePlusId.c_str());
ALOGV(__FUNCTION__);
if (!getState().isEnabled) {
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 0e41962..eff5130 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -230,6 +230,8 @@
return;
}
+ addReader(translate<Display>(kSingleReaderKey));
+
ALOGI("Loaded AIDL composer3 HAL service");
}
@@ -298,12 +300,19 @@
}
}
-void AidlComposer::resetCommands() {
- mWriter.reset();
+void AidlComposer::resetCommands(Display display) {
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().reset();
+ }
+ mMutex.unlock_shared();
}
-Error AidlComposer::executeCommands() {
- return execute();
+Error AidlComposer::executeCommands(Display display) {
+ mMutex.lock_shared();
+ auto error = execute(display);
+ mMutex.unlock_shared();
+ return error;
}
uint32_t AidlComposer::getMaxVirtualDisplayCount() {
@@ -334,6 +343,7 @@
*outDisplay = translate<Display>(virtualDisplay.display);
*format = static_cast<PixelFormat>(virtualDisplay.format);
+ addDisplay(translate<Display>(virtualDisplay.display));
return Error::NONE;
}
@@ -343,12 +353,20 @@
ALOGE("destroyVirtualDisplay failed %s", status.getDescription().c_str());
return static_cast<Error>(status.getServiceSpecificError());
}
+ removeDisplay(display);
return Error::NONE;
}
Error AidlComposer::acceptDisplayChanges(Display display) {
- mWriter.acceptDisplayChanges(translate<int64_t>(display));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().acceptDisplayChanges(translate<int64_t>(display));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::createLayer(Display display, Layer* outLayer) {
@@ -388,7 +406,17 @@
Error AidlComposer::getChangedCompositionTypes(
Display display, std::vector<Layer>* outLayers,
std::vector<aidl::android::hardware::graphics::composer3::Composition>* outTypes) {
- const auto changedLayers = mReader.takeChangedCompositionTypes(translate<int64_t>(display));
+ std::vector<ChangedCompositionLayer> changedLayers;
+ Error error = Error::NONE;
+ {
+ mMutex.lock_shared();
+ if (auto reader = getReader(display)) {
+ changedLayers = reader->get().takeChangedCompositionTypes(translate<int64_t>(display));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ }
outLayers->reserve(changedLayers.size());
outTypes->reserve(changedLayers.size());
@@ -396,7 +424,7 @@
outLayers->emplace_back(translate<Layer>(layer.layer));
outTypes->emplace_back(layer.composition);
}
- return Error::NONE;
+ return error;
}
Error AidlComposer::getColorModes(Display display, std::vector<ColorMode>* outModes) {
@@ -448,7 +476,17 @@
Error AidlComposer::getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
std::vector<Layer>* outLayers,
std::vector<uint32_t>* outLayerRequestMasks) {
- const auto displayRequests = mReader.takeDisplayRequests(translate<int64_t>(display));
+ Error error = Error::NONE;
+ DisplayRequest displayRequests;
+ {
+ mMutex.lock_shared();
+ if (auto reader = getReader(display)) {
+ displayRequests = reader->get().takeDisplayRequests(translate<int64_t>(display));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ }
*outDisplayRequestMask = translate<uint32_t>(displayRequests.mask);
outLayers->reserve(displayRequests.layerRequests.size());
outLayerRequestMasks->reserve(displayRequests.layerRequests.size());
@@ -457,7 +495,7 @@
outLayers->emplace_back(translate<Layer>(layer.layer));
outLayerRequestMasks->emplace_back(translate<uint32_t>(layer.mask));
}
- return Error::NONE;
+ return error;
}
Error AidlComposer::getDozeSupport(Display display, bool* outSupport) {
@@ -511,7 +549,17 @@
Error AidlComposer::getReleaseFences(Display display, std::vector<Layer>* outLayers,
std::vector<int>* outReleaseFences) {
- auto fences = mReader.takeReleaseFences(translate<int64_t>(display));
+ Error error = Error::NONE;
+ std::vector<ReleaseFences::Layer> fences;
+ {
+ mMutex.lock_shared();
+ if (auto reader = getReader(display)) {
+ fences = reader->get().takeReleaseFences(translate<int64_t>(display));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ }
outLayers->reserve(fences.size());
outReleaseFences->reserve(fences.size());
@@ -522,19 +570,29 @@
*fence.fence.getR() = -1;
outReleaseFences->emplace_back(fenceOwner);
}
- return Error::NONE;
+ return error;
}
Error AidlComposer::presentDisplay(Display display, int* outPresentFence) {
ATRACE_NAME("HwcPresentDisplay");
- mWriter.presentDisplay(translate<int64_t>(display));
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ auto writer = getWriter(display);
+ auto reader = getReader(display);
+ if (writer && reader) {
+ writer->get().presentDisplay(translate<int64_t>(display));
+ error = execute(display);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
- Error error = execute();
if (error != Error::NONE) {
+ mMutex.unlock_shared();
return error;
}
- auto fence = mReader.takePresentFence(translate<int64_t>(display));
+ auto fence = reader->get().takePresentFence(translate<int64_t>(display));
+ mMutex.unlock_shared();
// take ownership
*outPresentFence = fence.get();
*fence.getR() = -1;
@@ -559,11 +617,19 @@
handle = target->getNativeBuffer()->handle;
}
- mWriter.setClientTarget(translate<int64_t>(display), slot, handle, acquireFence,
- translate<aidl::android::hardware::graphics::common::Dataspace>(
- dataspace),
- translate<AidlRect>(damage));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get()
+ .setClientTarget(translate<int64_t>(display), slot, handle, acquireFence,
+ translate<aidl::android::hardware::graphics::common::Dataspace>(
+ dataspace),
+ translate<AidlRect>(damage));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) {
@@ -579,14 +645,28 @@
}
Error AidlComposer::setColorTransform(Display display, const float* matrix) {
- mWriter.setColorTransform(translate<int64_t>(display), matrix);
- return Error::NONE;
+ auto error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setColorTransform(translate<int64_t>(display), matrix);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setOutputBuffer(Display display, const native_handle_t* buffer,
int releaseFence) {
- mWriter.setOutputBuffer(translate<int64_t>(display), 0, buffer, dup(releaseFence));
- return Error::NONE;
+ auto error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setOutputBuffer(translate<int64_t>(display), 0, buffer, dup(releaseFence));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setPowerMode(Display display, IComposerClient::PowerMode mode) {
@@ -624,16 +704,26 @@
Error AidlComposer::validateDisplay(Display display, nsecs_t expectedPresentTime,
uint32_t* outNumTypes, uint32_t* outNumRequests) {
ATRACE_NAME("HwcValidateDisplay");
- mWriter.validateDisplay(translate<int64_t>(display),
- ClockMonotonicTimestamp{expectedPresentTime});
+ const auto displayId = translate<int64_t>(display);
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ auto writer = getWriter(display);
+ auto reader = getReader(display);
+ if (writer && reader) {
+ writer->get().validateDisplay(displayId, ClockMonotonicTimestamp{expectedPresentTime});
+ error = execute(display);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
- Error error = execute();
if (error != Error::NONE) {
+ mMutex.unlock_shared();
return error;
}
- mReader.hasChanges(translate<int64_t>(display), outNumTypes, outNumRequests);
+ reader->get().hasChanges(displayId, outNumTypes, outNumRequests);
+ mMutex.unlock_shared();
return Error::NONE;
}
@@ -641,39 +731,59 @@
uint32_t* outNumTypes, uint32_t* outNumRequests,
int* outPresentFence, uint32_t* state) {
ATRACE_NAME("HwcPresentOrValidateDisplay");
- mWriter.presentOrvalidateDisplay(translate<int64_t>(display),
- ClockMonotonicTimestamp{expectedPresentTime});
+ const auto displayId = translate<int64_t>(display);
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ auto writer = getWriter(display);
+ auto reader = getReader(display);
+ if (writer && reader) {
+ writer->get().presentOrvalidateDisplay(displayId,
+ ClockMonotonicTimestamp{expectedPresentTime});
+ error = execute(display);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
- Error error = execute();
if (error != Error::NONE) {
+ mMutex.unlock_shared();
return error;
}
- const auto result = mReader.takePresentOrValidateStage(translate<int64_t>(display));
+ const auto result = reader->get().takePresentOrValidateStage(displayId);
if (!result.has_value()) {
*state = translate<uint32_t>(-1);
+ mMutex.unlock_shared();
return Error::NO_RESOURCES;
}
*state = translate<uint32_t>(*result);
if (*result == PresentOrValidate::Result::Presented) {
- auto fence = mReader.takePresentFence(translate<int64_t>(display));
+ auto fence = reader->get().takePresentFence(displayId);
// take ownership
*outPresentFence = fence.get();
*fence.getR() = -1;
}
if (*result == PresentOrValidate::Result::Validated) {
- mReader.hasChanges(translate<int64_t>(display), outNumTypes, outNumRequests);
+ reader->get().hasChanges(displayId, outNumTypes, outNumRequests);
}
+ mMutex.unlock_shared();
return Error::NONE;
}
Error AidlComposer::setCursorPosition(Display display, Layer layer, int32_t x, int32_t y) {
- mWriter.setLayerCursorPosition(translate<int64_t>(display), translate<int64_t>(layer), x, y);
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerCursorPosition(translate<int64_t>(display), translate<int64_t>(layer),
+ x, y);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerBuffer(Display display, Layer layer, uint32_t slot,
@@ -683,90 +793,190 @@
handle = buffer->getNativeBuffer()->handle;
}
- mWriter.setLayerBuffer(translate<int64_t>(display), translate<int64_t>(layer), slot, handle,
- acquireFence);
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerBuffer(translate<int64_t>(display), translate<int64_t>(layer), slot,
+ handle, acquireFence);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerSurfaceDamage(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& damage) {
- mWriter.setLayerSurfaceDamage(translate<int64_t>(display), translate<int64_t>(layer),
- translate<AidlRect>(damage));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerSurfaceDamage(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlRect>(damage));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerBlendMode(Display display, Layer layer,
IComposerClient::BlendMode mode) {
- mWriter.setLayerBlendMode(translate<int64_t>(display), translate<int64_t>(layer),
- translate<BlendMode>(mode));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerBlendMode(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<BlendMode>(mode));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerColor(Display display, Layer layer, const Color& color) {
- mWriter.setLayerColor(translate<int64_t>(display), translate<int64_t>(layer), color);
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerColor(translate<int64_t>(display), translate<int64_t>(layer), color);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerCompositionType(
Display display, Layer layer,
aidl::android::hardware::graphics::composer3::Composition type) {
- mWriter.setLayerCompositionType(translate<int64_t>(display), translate<int64_t>(layer), type);
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerCompositionType(translate<int64_t>(display),
+ translate<int64_t>(layer), type);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerDataspace(Display display, Layer layer, Dataspace dataspace) {
- mWriter.setLayerDataspace(translate<int64_t>(display), translate<int64_t>(layer),
- translate<AidlDataspace>(dataspace));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerDataspace(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlDataspace>(dataspace));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerDisplayFrame(Display display, Layer layer,
const IComposerClient::Rect& frame) {
- mWriter.setLayerDisplayFrame(translate<int64_t>(display), translate<int64_t>(layer),
- translate<AidlRect>(frame));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerDisplayFrame(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlRect>(frame));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerPlaneAlpha(Display display, Layer layer, float alpha) {
- mWriter.setLayerPlaneAlpha(translate<int64_t>(display), translate<int64_t>(layer), alpha);
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerPlaneAlpha(translate<int64_t>(display), translate<int64_t>(layer),
+ alpha);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerSidebandStream(Display display, Layer layer,
const native_handle_t* stream) {
- mWriter.setLayerSidebandStream(translate<int64_t>(display), translate<int64_t>(layer), stream);
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerSidebandStream(translate<int64_t>(display), translate<int64_t>(layer),
+ stream);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerSourceCrop(Display display, Layer layer,
const IComposerClient::FRect& crop) {
- mWriter.setLayerSourceCrop(translate<int64_t>(display), translate<int64_t>(layer),
- translate<AidlFRect>(crop));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerSourceCrop(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlFRect>(crop));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerTransform(Display display, Layer layer, Transform transform) {
- mWriter.setLayerTransform(translate<int64_t>(display), translate<int64_t>(layer),
- translate<AidlTransform>(transform));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerTransform(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlTransform>(transform));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerVisibleRegion(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& visible) {
- mWriter.setLayerVisibleRegion(translate<int64_t>(display), translate<int64_t>(layer),
- translate<AidlRect>(visible));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerVisibleRegion(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlRect>(visible));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerZOrder(Display display, Layer layer, uint32_t z) {
- mWriter.setLayerZOrder(translate<int64_t>(display), translate<int64_t>(layer), z);
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerZOrder(translate<int64_t>(display), translate<int64_t>(layer), z);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
-Error AidlComposer::execute() {
- const auto& commands = mWriter.getPendingCommands();
+Error AidlComposer::execute(Display display) {
+ auto writer = getWriter(display);
+ auto reader = getReader(display);
+ if (!writer || !reader) {
+ return Error::BAD_DISPLAY;
+ }
+
+ const auto& commands = writer->get().getPendingCommands();
if (commands.empty()) {
- mWriter.reset();
+ writer->get().reset();
return Error::NONE;
}
@@ -778,9 +988,9 @@
return static_cast<Error>(status.getServiceSpecificError());
}
- mReader.parse(std::move(results));
+ reader->get().parse(std::move(results));
}
- const auto commandErrors = mReader.takeErrors();
+ const auto commandErrors = reader->get().takeErrors();
Error error = Error::NONE;
for (const auto& cmdErr : commandErrors) {
const auto index = static_cast<size_t>(cmdErr.commandIndex);
@@ -798,7 +1008,7 @@
}
}
- mWriter.reset();
+ writer->get().reset();
return error;
}
@@ -806,9 +1016,17 @@
Error AidlComposer::setLayerPerFrameMetadata(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) {
- mWriter.setLayerPerFrameMetadata(translate<int64_t>(display), translate<int64_t>(layer),
- translate<AidlPerFrameMetadata>(perFrameMetadatas));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerPerFrameMetadata(translate<int64_t>(display),
+ translate<int64_t>(layer),
+ translate<AidlPerFrameMetadata>(perFrameMetadatas));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
std::vector<IComposerClient::PerFrameMetadataKey> AidlComposer::getPerFrameMetadataKeys(
@@ -868,8 +1086,16 @@
}
Error AidlComposer::setLayerColorTransform(Display display, Layer layer, const float* matrix) {
- mWriter.setLayerColorTransform(translate<int64_t>(display), translate<int64_t>(layer), matrix);
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerColorTransform(translate<int64_t>(display), translate<int64_t>(layer),
+ matrix);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat,
@@ -932,20 +1158,36 @@
Error AidlComposer::setLayerPerFrameMetadataBlobs(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) {
- mWriter.setLayerPerFrameMetadataBlobs(translate<int64_t>(display), translate<int64_t>(layer),
- translate<AidlPerFrameMetadataBlob>(metadata));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerPerFrameMetadataBlobs(translate<int64_t>(display),
+ translate<int64_t>(layer),
+ translate<AidlPerFrameMetadataBlob>(metadata));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setDisplayBrightness(Display display, float brightness, float brightnessNits,
const DisplayBrightnessOptions& options) {
- mWriter.setDisplayBrightness(translate<int64_t>(display), brightness, brightnessNits);
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setDisplayBrightness(translate<int64_t>(display), brightness, brightnessNits);
- if (options.applyImmediately) {
- return execute();
+ if (options.applyImmediately) {
+ error = execute(display);
+ mMutex.unlock_shared();
+ return error;
+ }
+ } else {
+ error = Error::BAD_DISPLAY;
}
-
- return Error::NONE;
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::getDisplayCapabilities(Display display,
@@ -1085,20 +1327,43 @@
Error AidlComposer::getClientTargetProperty(
Display display, ClientTargetPropertyWithBrightness* outClientTargetProperty) {
- *outClientTargetProperty = mReader.takeClientTargetProperty(translate<int64_t>(display));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto reader = getReader(display)) {
+ *outClientTargetProperty =
+ reader->get().takeClientTargetProperty(translate<int64_t>(display));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerBrightness(Display display, Layer layer, float brightness) {
- mWriter.setLayerBrightness(translate<int64_t>(display), translate<int64_t>(layer), brightness);
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerBrightness(translate<int64_t>(display), translate<int64_t>(layer),
+ brightness);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::setLayerBlockingRegion(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& blocking) {
- mWriter.setLayerBlockingRegion(translate<int64_t>(display), translate<int64_t>(layer),
- translate<AidlRect>(blocking));
- return Error::NONE;
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerBlockingRegion(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlRect>(blocking));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
}
Error AidlComposer::getDisplayDecorationSupport(Display display,
@@ -1136,5 +1401,88 @@
return Error::NONE;
}
+ftl::Optional<std::reference_wrapper<ComposerClientWriter>> AidlComposer::getWriter(Display display)
+ REQUIRES_SHARED(mMutex) {
+ return mWriters.get(display);
+}
+
+ftl::Optional<std::reference_wrapper<ComposerClientReader>> AidlComposer::getReader(Display display)
+ REQUIRES_SHARED(mMutex) {
+ if (mSingleReader) {
+ display = translate<Display>(kSingleReaderKey);
+ }
+ return mReaders.get(display);
+}
+
+void AidlComposer::removeDisplay(Display display) {
+ mMutex.lock();
+ bool wasErased = mWriters.erase(display);
+ ALOGW_IF(!wasErased,
+ "Attempting to remove writer for display %" PRId64 " which is not connected",
+ translate<int64_t>(display));
+ if (!mSingleReader) {
+ removeReader(display);
+ }
+ mMutex.unlock();
+}
+
+void AidlComposer::onHotplugDisconnect(Display display) {
+ removeDisplay(display);
+}
+
+bool AidlComposer::hasMultiThreadedPresentSupport(Display display) {
+ const auto displayId = translate<int64_t>(display);
+ std::vector<AidlDisplayCapability> capabilities;
+ const auto status = mAidlComposerClient->getDisplayCapabilities(displayId, &capabilities);
+ if (!status.isOk()) {
+ ALOGE("getDisplayCapabilities failed %s", status.getDescription().c_str());
+ return false;
+ }
+ return std::find(capabilities.begin(), capabilities.end(),
+ AidlDisplayCapability::MULTI_THREADED_PRESENT) != capabilities.end();
+}
+
+void AidlComposer::addReader(Display display) {
+ const auto displayId = translate<int64_t>(display);
+ std::optional<int64_t> displayOpt;
+ if (displayId != kSingleReaderKey) {
+ displayOpt.emplace(displayId);
+ }
+ auto [it, added] = mReaders.try_emplace(display, std::move(displayOpt));
+ ALOGW_IF(!added, "Attempting to add writer for display %" PRId64 " which is already connected",
+ displayId);
+}
+
+void AidlComposer::removeReader(Display display) {
+ bool wasErased = mReaders.erase(display);
+ ALOGW_IF(!wasErased,
+ "Attempting to remove reader for display %" PRId64 " which is not connected",
+ translate<int64_t>(display));
+}
+
+void AidlComposer::addDisplay(Display display) {
+ const auto displayId = translate<int64_t>(display);
+ mMutex.lock();
+ auto [it, added] = mWriters.try_emplace(display, displayId);
+ ALOGW_IF(!added, "Attempting to add writer for display %" PRId64 " which is already connected",
+ displayId);
+ if (mSingleReader) {
+ if (hasMultiThreadedPresentSupport(display)) {
+ mSingleReader = false;
+ removeReader(translate<Display>(kSingleReaderKey));
+ // Note that this includes the new display.
+ for (const auto& [existingDisplay, _] : mWriters) {
+ addReader(existingDisplay);
+ }
+ }
+ } else {
+ addReader(display);
+ }
+ mMutex.unlock();
+}
+
+void AidlComposer::onHotplugConnect(Display display) {
+ addDisplay(display);
+}
} // namespace Hwc2
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index f2a59a5..d84efe7 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -17,10 +17,12 @@
#pragma once
#include "ComposerHal.h"
+#include <ftl/shared_mutex.h>
+#include <ftl/small_map.h>
+#include <functional>
#include <optional>
#include <string>
-#include <unordered_map>
#include <utility>
#include <vector>
@@ -70,10 +72,10 @@
// Reset all pending commands in the command buffer. Useful if you want to
// skip a frame but have already queued some commands.
- void resetCommands() override;
+ void resetCommands(Display) override;
// Explicitly flush all pending commands in the command buffer.
- Error executeCommands() override;
+ Error executeCommands(Display) override;
uint32_t getMaxVirtualDisplayCount() override;
Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
@@ -228,16 +230,29 @@
Error getPhysicalDisplayOrientation(Display displayId,
AidlTransform* outDisplayOrientation) override;
+ void onHotplugConnect(Display) override;
+ void onHotplugDisconnect(Display) override;
private:
// Many public functions above simply write a command into the command
// queue to batch the calls. validateDisplay and presentDisplay will call
// this function to execute the command queue.
- Error execute();
+ Error execute(Display) REQUIRES_SHARED(mMutex);
// returns the default instance name for the given service
static std::string instance(const std::string& serviceName);
+ ftl::Optional<std::reference_wrapper<ComposerClientWriter>> getWriter(Display)
+ REQUIRES_SHARED(mMutex);
+ ftl::Optional<std::reference_wrapper<ComposerClientReader>> getReader(Display)
+ REQUIRES_SHARED(mMutex);
+ void addDisplay(Display) EXCLUDES(mMutex);
+ void removeDisplay(Display) EXCLUDES(mMutex);
+ void addReader(Display) REQUIRES(mMutex);
+ void removeReader(Display) REQUIRES(mMutex);
+
+ bool hasMultiThreadedPresentSupport(Display);
+
// 64KiB minus a small space for metadata such as read/write pointers
static constexpr size_t kWriterInitialSize = 64 * 1024 / sizeof(uint32_t) - 16;
// Max number of buffers that may be cached for a given layer
@@ -245,8 +260,25 @@
// 1. Tightly coupling this cache to the max size of BufferQueue
// 2. Adding an additional slot for the layer caching feature in SurfaceFlinger (see: Planner.h)
static const constexpr uint32_t kMaxLayerBufferCount = BufferQueue::NUM_BUFFER_SLOTS + 1;
- ComposerClientWriter mWriter;
- ComposerClientReader mReader;
+
+ // Without DisplayCapability::MULTI_THREADED_PRESENT, we use a single reader
+ // for all displays. With the capability, we use a separate reader for each
+ // display.
+ bool mSingleReader = true;
+ // Invalid displayId used as a key to mReaders when mSingleReader is true.
+ static constexpr int64_t kSingleReaderKey = 0;
+
+ // TODO (b/256881188): Use display::PhysicalDisplayMap instead of hard-coded `3`
+ ftl::SmallMap<Display, ComposerClientWriter, 3> mWriters GUARDED_BY(mMutex);
+ ftl::SmallMap<Display, ComposerClientReader, 3> mReaders GUARDED_BY(mMutex);
+ // Protect access to mWriters and mReaders with a shared_mutex. Adding and
+ // removing a display require exclusive access, since the iterator or the
+ // writer/reader may be invalidated. Other calls need shared access while
+ // using the writer/reader, so they can use their display's writer/reader
+ // without it being deleted or the iterator being invalidated.
+ // TODO (b/257958323): Use std::shared_mutex and RAII once they support
+ // threading annotations.
+ ftl::SharedMutex mMutex;
// Aidl interface
using AidlIComposer = aidl::android::hardware::graphics::composer3::IComposer;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index b02f867..a9bf282 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -110,10 +110,10 @@
// Reset all pending commands in the command buffer. Useful if you want to
// skip a frame but have already queued some commands.
- virtual void resetCommands() = 0;
+ virtual void resetCommands(Display) = 0;
// Explicitly flush all pending commands in the command buffer.
- virtual Error executeCommands() = 0;
+ virtual Error executeCommands(Display) = 0;
virtual uint32_t getMaxVirtualDisplayCount() = 0;
virtual Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat*,
@@ -283,6 +283,8 @@
virtual Error getPhysicalDisplayOrientation(Display displayId,
AidlTransform* outDisplayOrientation) = 0;
virtual Error getOverlaySupport(V3_0::OverlayProperties* outProperties) = 0;
+ virtual void onHotplugConnect(Display) = 0;
+ virtual void onHotplugDisconnect(Display) = 0;
};
} // namespace Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 168e2dd..5f11cb8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -513,7 +513,7 @@
if (displayData.validateWasSkipped) {
// explicitly flush all pending commands
- auto error = static_cast<hal::Error>(mComposer->executeCommands());
+ auto error = static_cast<hal::Error>(mComposer->executeCommands(hwcDisplay->getId()));
RETURN_IF_HWC_ERROR_FOR("executeCommands", error, displayId, UNKNOWN_ERROR);
RETURN_IF_HWC_ERROR_FOR("present", displayData.presentError, displayId, UNKNOWN_ERROR);
return NO_ERROR;
@@ -933,6 +933,8 @@
: "Secondary display",
.deviceProductInfo = std::nullopt};
}();
+
+ mComposer->onHotplugConnect(hwcDisplayId);
}
if (!isConnected(info->id)) {
@@ -960,6 +962,7 @@
// The display will later be destroyed by a call to HWComposer::disconnectDisplay. For now, mark
// it as disconnected.
mDisplayData.at(*displayId).hwcDisplay->setConnected(false);
+ mComposer->onHotplugDisconnect(hwcDisplayId);
return DisplayIdentificationInfo{.id = *displayId};
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index a664d2c..f8522e2 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -273,11 +273,11 @@
}
}
-void HidlComposer::resetCommands() {
+void HidlComposer::resetCommands(Display) {
mWriter.reset();
}
-Error HidlComposer::executeCommands() {
+Error HidlComposer::executeCommands(Display) {
return execute();
}
@@ -1357,6 +1357,9 @@
registerCallback(sp<ComposerCallbackBridge>::make(callback, vsyncSwitchingSupported));
}
+void HidlComposer::onHotplugConnect(Display) {}
+void HidlComposer::onHotplugDisconnect(Display) {}
+
CommandReader::~CommandReader() {
resetData();
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index b436408..48b720c 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -177,10 +177,10 @@
// Reset all pending commands in the command buffer. Useful if you want to
// skip a frame but have already queued some commands.
- void resetCommands() override;
+ void resetCommands(Display) override;
// Explicitly flush all pending commands in the command buffer.
- Error executeCommands() override;
+ Error executeCommands(Display) override;
uint32_t getMaxVirtualDisplayCount() override;
Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
@@ -339,6 +339,8 @@
Error getPhysicalDisplayOrientation(Display displayId,
AidlTransform* outDisplayOrientation) override;
+ void onHotplugConnect(Display) override;
+ void onHotplugDisconnect(Display) override;
private:
class CommandWriter : public CommandWriterBase {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2a18521..e3fe7a7 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2841,7 +2841,7 @@
bool Layer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer,
const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime,
bool isAutoTimestamp, std::optional<nsecs_t> dequeueTime,
- const FrameTimelineInfo& info) {
+ const FrameTimelineInfo& info, int hwcBufferSlot) {
ATRACE_FORMAT("setBuffer %s - hasBuffer=%s", getDebugName(), (buffer ? "true" : "false"));
if (!buffer) {
return false;
@@ -2887,7 +2887,7 @@
mDrawingState.releaseBufferListener = bufferData.releaseBufferListener;
mDrawingState.buffer = std::move(buffer);
mDrawingState.clientCacheId = bufferData.cachedBuffer;
-
+ mDrawingState.hwcBufferSlot = hwcBufferSlot;
mDrawingState.acquireFence = bufferData.flags.test(BufferData::BufferDataChange::fenceChanged)
? bufferData.acquireFence
: Fence::NO_FENCE;
@@ -3186,7 +3186,7 @@
mBufferInfo.mHdrMetadata = mDrawingState.hdrMetadata;
mBufferInfo.mApi = mDrawingState.api;
mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse;
- mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(mDrawingState.clientCacheId);
+ mBufferInfo.mBufferSlot = mDrawingState.hwcBufferSlot;
}
Rect Layer::computeBufferCrop(const State& s) {
@@ -3205,7 +3205,6 @@
LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata());
args.textureName = mTextureName;
sp<Layer> layer = mFlinger->getFactory().createBufferStateLayer(args);
- layer->mHwcSlotGenerator = mHwcSlotGenerator;
layer->setInitialValuesForClone(sp<Layer>::fromExisting(this));
return layer;
}
@@ -3970,6 +3969,10 @@
}
}
+int Layer::getHwcCacheSlot(const client_cache_t& clientCacheId) {
+ return mHwcSlotGenerator->getHwcCacheSlot(clientCacheId);
+}
+
LayerSnapshotGuard::LayerSnapshotGuard(Layer* layer) : mLayer(layer) {
LOG_ALWAYS_FATAL_IF(!mLayer, "LayerSnapshotGuard received a null layer.");
mLayer->mLayerFE->mSnapshot = std::move(mLayer->mSnapshot);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 9585fa9..7669bab 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -146,6 +146,7 @@
bool transformToDisplayInverse;
Region transparentRegionHint;
std::shared_ptr<renderengine::ExternalTexture> buffer;
+ int hwcBufferSlot;
client_cache_t clientCacheId;
sp<Fence> acquireFence;
std::shared_ptr<FenceTime> acquireFenceTime;
@@ -297,7 +298,8 @@
bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */,
const BufferData& /* bufferData */, nsecs_t /* postTime */,
nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/,
- std::optional<nsecs_t> /* dequeueTime */, const FrameTimelineInfo& /*info*/);
+ std::optional<nsecs_t> /* dequeueTime */, const FrameTimelineInfo& /*info*/,
+ int /* hwcBufferSlot */);
bool setDataspace(ui::Dataspace /*dataspace*/);
bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/);
bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/);
@@ -811,6 +813,7 @@
void updateMetadataSnapshot(const LayerMetadata& parentMetadata);
void updateRelativeMetadataSnapshot(const LayerMetadata& relativeLayerMetadata,
std::unordered_set<Layer*>& visited);
+ int getHwcCacheSlot(const client_cache_t& clientCacheId);
protected:
// For unit tests
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d68b00a..13bfd62 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -107,6 +107,7 @@
#include <optional>
#include <type_traits>
#include <unordered_map>
+#include <vector>
#include <ui/DisplayIdentification.h>
#include "BackgroundExecutor.h"
@@ -313,8 +314,9 @@
mCompositionEngine(mFactory.createCompositionEngine()),
mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
mTunnelModeEnabledReporter(sp<TunnelModeEnabledReporter>::make()),
- mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
+ mInternalDisplayDensity(
+ getDensityFromProperty("ro.sf.lcd_density", !mEmulatedDisplayDensity)),
mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)),
mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make()) {
ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
@@ -372,7 +374,7 @@
int debugDdms = atoi(value);
ALOGI_IF(debugDdms, "DDMS debugging not supported");
- property_get("debug.sf.enable_gl_backpressure", value, "0");
+ property_get("debug.sf.enable_gl_backpressure", value, "1");
mPropagateBackpressureClientComposition = atoi(value);
ALOGI_IF(mPropagateBackpressureClientComposition,
"Enabling backpressure propagation for Client Composition");
@@ -3899,7 +3901,7 @@
}
status_t SurfaceFlinger::setTransactionState(
- const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,
+ const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
@@ -3931,7 +3933,29 @@
IPCThreadState* ipc = IPCThreadState::self();
const int originPid = ipc->getCallingPid();
const int originUid = ipc->getCallingUid();
- TransactionState state{frameTimelineInfo, states,
+
+ std::vector<ResolvedComposerState> resolvedStates;
+ resolvedStates.reserve(states.size());
+ for (auto& state : states) {
+ resolvedStates.emplace_back(std::move(state));
+ auto& resolvedState = resolvedStates.back();
+ if (resolvedState.state.hasBufferChanges() && resolvedState.state.hasValidBuffer() &&
+ resolvedState.state.surface) {
+ sp<Layer> layer = LayerHandle::getLayer(resolvedState.state.surface);
+ std::string layerName = (layer) ?
+ layer->getDebugName() : std::to_string(resolvedState.state.layerId);
+ resolvedState.externalTexture =
+ getExternalTextureFromBufferData(*resolvedState.state.bufferData,
+ layerName.c_str(), transactionId);
+ mBufferCountTracker.increment(resolvedState.state.surface->localBinder());
+ if (layer) {
+ resolvedState.hwcBufferSlot =
+ layer->getHwcCacheSlot(resolvedState.state.bufferData->cachedBuffer);
+ }
+ }
+ }
+
+ TransactionState state{frameTimelineInfo, resolvedStates,
displays, flags,
applyToken, inputWindowCommands,
desiredPresentTime, isAutoTimestamp,
@@ -3940,11 +3964,6 @@
listenerCallbacks, originPid,
originUid, transactionId};
- // Check for incoming buffer updates and increment the pending buffer count.
- state.traverseStatesWithBuffers([&](const layer_state_t& state) {
- mBufferCountTracker.increment(state.surface->localBinder());
- });
-
if (mTransactionTracing) {
mTransactionTracing->addQueuedTransaction(state);
}
@@ -3963,7 +3982,7 @@
}
bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo,
- Vector<ComposerState>& states,
+ std::vector<ResolvedComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
const int64_t desiredPresentTime, bool isAutoTimestamp,
@@ -3985,13 +4004,12 @@
}
uint32_t clientStateFlags = 0;
- for (int i = 0; i < states.size(); i++) {
- ComposerState& state = states.editItemAt(i);
+ for (auto& resolvedState : states) {
clientStateFlags |=
- setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp,
- postTime, permissions, transactionId);
- if ((flags & eAnimation) && state.state.surface) {
- if (const auto layer = LayerHandle::getLayer(state.state.surface)) {
+ setClientStateLocked(frameTimelineInfo, resolvedState, desiredPresentTime,
+ isAutoTimestamp, postTime, permissions, transactionId);
+ if ((flags & eAnimation) && resolvedState.state.surface) {
+ if (const auto layer = LayerHandle::getLayer(resolvedState.state.surface)) {
using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType;
mScheduler->recordLayerHistory(layer.get(),
isAutoTimestamp ? 0 : desiredPresentTime,
@@ -4103,7 +4121,7 @@
}
uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTimelineInfo,
- ComposerState& composerState,
+ ResolvedComposerState& composerState,
int64_t desiredPresentTime, bool isAutoTimestamp,
int64_t postTime, uint32_t permissions,
uint64_t transactionId) {
@@ -4398,11 +4416,9 @@
}
if (what & layer_state_t::eBufferChanged) {
- std::shared_ptr<renderengine::ExternalTexture> buffer =
- getExternalTextureFromBufferData(*s.bufferData, layer->getDebugName(),
- transactionId);
- if (layer->setBuffer(buffer, *s.bufferData, postTime, desiredPresentTime, isAutoTimestamp,
- dequeueBufferTimestamp, frameTimelineInfo)) {
+ if (layer->setBuffer(composerState.externalTexture, *s.bufferData, postTime,
+ desiredPresentTime, isAutoTimestamp, dequeueBufferTimestamp,
+ frameTimelineInfo, composerState.hwcBufferSlot)) {
flags |= eTraversalNeeded;
}
} else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
@@ -4610,7 +4626,7 @@
LOG_ALWAYS_FATAL_IF(token == nullptr);
// reset screen orientation and use primary layer stack
- Vector<ComposerState> state;
+ std::vector<ResolvedComposerState> state;
Vector<DisplayState> displays;
DisplayState d;
d.what = DisplayState::eDisplayProjectionChanged |
@@ -7021,9 +7037,12 @@
}
if (result.error() == ClientCache::AddError::CacheFull) {
- mTransactionHandler
- .onTransactionQueueStalled(transactionId, bufferData.releaseBufferListener,
- "Buffer processing hung due to full buffer cache");
+ ALOGE("Attempted to create an ExternalTexture for layer %s but CacheFull", layerName);
+
+ if (bufferData.releaseBufferListener) {
+ bufferData.releaseBufferListener->onTransactionQueueStalled(
+ String8("Buffer processing hung due to full buffer cache"));
+ }
}
return nullptr;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index fd96fbb..0706598 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -490,9 +490,8 @@
sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const;
status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
- const Vector<ComposerState>& state,
- const Vector<DisplayState>& displays, uint32_t flags,
- const sp<IBinder>& applyToken,
+ Vector<ComposerState>& state, const Vector<DisplayState>& displays,
+ uint32_t flags, const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands,
int64_t desiredPresentTime, bool isAutoTimestamp,
const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
@@ -693,7 +692,8 @@
/*
* Transactions
*/
- bool applyTransactionState(const FrameTimelineInfo& info, Vector<ComposerState>& state,
+ bool applyTransactionState(const FrameTimelineInfo& info,
+ std::vector<ResolvedComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
const int64_t desiredPresentTime, bool isAutoTimestamp,
@@ -714,7 +714,7 @@
const TransactionHandler::TransactionFlushState& flushState)
REQUIRES(kMainThreadContext);
- uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&,
+ uint32_t setClientStateLocked(const FrameTimelineInfo&, ResolvedComposerState&,
int64_t desiredPresentTime, bool isAutoTimestamp,
int64_t postTime, uint32_t permissions, uint64_t transactionId)
REQUIRES(mStateLock);
@@ -1285,8 +1285,8 @@
sp<TunnelModeEnabledReporter> mTunnelModeEnabledReporter;
ui::DisplayPrimaries mInternalDisplayPrimaries;
- const float mInternalDisplayDensity;
const float mEmulatedDisplayDensity;
+ const float mInternalDisplayDensity;
// Should only be accessed by the main thread.
sp<os::IInputFlinger> mInputFlinger;
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 3418c82..2f46487 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -310,10 +310,10 @@
int32_t layerCount = proto.layer_changes_size();
t.states.reserve(static_cast<size_t>(layerCount));
for (int i = 0; i < layerCount; i++) {
- ComposerState s;
+ ResolvedComposerState s;
s.state.what = 0;
fromProto(proto.layer_changes(i), s.state);
- t.states.add(s);
+ t.states.emplace_back(s);
}
int32_t displayCount = proto.display_changes_size();
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index 25fdd26..f1a6c0e 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -240,13 +240,7 @@
for (int j = 0; j < entry.transactions_size(); j++) {
// apply transactions
TransactionState transaction = parser.fromProto(entry.transactions(j));
- mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
- transaction.displays, transaction.flags,
- transaction.applyToken, transaction.inputWindowCommands,
- transaction.desiredPresentTime,
- transaction.isAutoTimestamp, {},
- transaction.hasListenerCallbacks,
- transaction.listenerCallbacks, transaction.id);
+ mFlinger.setTransactionStateInternal(transaction);
}
const auto frameTime = TimePoint::fromNs(entry.elapsed_realtime_nanos());
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index 3cbfe81..7bde2c1 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -20,17 +20,27 @@
#include <memory>
#include <mutex>
#include <vector>
+#include "renderengine/ExternalTexture.h"
#include <gui/LayerState.h>
#include <system/window.h>
namespace android {
+// Extends the client side composer state by resolving buffer cache ids.
+class ResolvedComposerState : public ComposerState {
+public:
+ ResolvedComposerState() = default;
+ ResolvedComposerState(ComposerState&& source) { state = std::move(source.state); }
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture;
+ int hwcBufferSlot = 0;
+};
+
struct TransactionState {
TransactionState() = default;
TransactionState(const FrameTimelineInfo& frameTimelineInfo,
- const Vector<ComposerState>& composerStates,
+ std::vector<ResolvedComposerState>& composerStates,
const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
const sp<IBinder>& applyToken, const InputWindowCommands& inputWindowCommands,
int64_t desiredPresentTime, bool isAutoTimestamp,
@@ -38,7 +48,7 @@
bool hasListenerCallbacks, std::vector<ListenerCallbacks> listenerCallbacks,
int originPid, int originUid, uint64_t transactionId)
: frameTimelineInfo(frameTimelineInfo),
- states(composerStates),
+ states(std::move(composerStates)),
displays(displayStates),
flags(transactionFlags),
applyToken(applyToken),
@@ -57,18 +67,20 @@
// Invokes `void(const layer_state_t&)` visitor for matching layers.
template <typename Visitor>
void traverseStatesWithBuffers(Visitor&& visitor) const {
- for (const auto& [state] : states) {
- if (state.hasBufferChanges() && state.hasValidBuffer() && state.surface) {
- visitor(state);
+ for (const auto& state : states) {
+ if (state.state.hasBufferChanges() && state.state.hasValidBuffer() &&
+ state.state.surface) {
+ visitor(state.state);
}
}
}
template <typename Visitor>
void traverseStatesWithBuffersWhileTrue(Visitor&& visitor) const {
- for (const auto& [state] : states) {
- if (state.hasBufferChanges() && state.hasValidBuffer() && state.surface) {
- if (!visitor(state)) return;
+ for (const auto& state : states) {
+ if (state.state.hasBufferChanges() && state.state.hasValidBuffer() &&
+ state.state.surface) {
+ if (!visitor(state.state)) return;
}
}
}
@@ -79,8 +91,8 @@
bool isFrameActive() const {
if (!displays.empty()) return true;
- for (const auto& [state] : states) {
- if (state.frameRateCompatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE) {
+ for (const auto& state : states) {
+ if (state.state.frameRateCompatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE) {
return true;
}
}
@@ -89,7 +101,7 @@
}
FrameTimelineInfo frameTimelineInfo;
- Vector<ComposerState> states;
+ std::vector<ResolvedComposerState> states;
Vector<DisplayState> displays;
uint32_t flags;
sp<IBinder> applyToken;
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index f8fc6f5..8a6af10 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -326,8 +326,8 @@
invokeComposerHal2_3(&composer, display, outLayer);
invokeComposerHal2_4(&composer, display, outLayer);
- composer.executeCommands();
- composer.resetCommands();
+ composer.executeCommands(display);
+ composer.resetCommands(display);
composer.destroyLayer(display, outLayer);
composer.destroyVirtualDisplay(display);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 9ba9b90..ee5392e 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -730,12 +730,14 @@
return mFlinger->mTransactionHandler.mPendingTransactionQueues;
}
- auto setTransactionState(
- const FrameTimelineInfo &frameTimelineInfo, const Vector<ComposerState> &states,
- const Vector<DisplayState> &displays, uint32_t flags, const sp<IBinder> &applyToken,
- const InputWindowCommands &inputWindowCommands, int64_t desiredPresentTime,
- bool isAutoTimestamp, const client_cache_t &uncacheBuffer, bool hasListenerCallbacks,
- std::vector<ListenerCallbacks> &listenerCallbacks, uint64_t transactionId) {
+ auto setTransactionState(const FrameTimelineInfo &frameTimelineInfo,
+ Vector<ComposerState> &states, const Vector<DisplayState> &displays,
+ uint32_t flags, const sp<IBinder> &applyToken,
+ const InputWindowCommands &inputWindowCommands,
+ int64_t desiredPresentTime, bool isAutoTimestamp,
+ const client_cache_t &uncacheBuffer, bool hasListenerCallbacks,
+ std::vector<ListenerCallbacks> &listenerCallbacks,
+ uint64_t transactionId) {
return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken,
inputWindowCommands, desiredPresentTime,
isAutoTimestamp, uncacheBuffer, hasListenerCallbacks,
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index acfc1d4..c5b3fa6 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -160,7 +160,7 @@
layer->setBuffer(texture, {} /*bufferData*/, mFdp.ConsumeIntegral<nsecs_t>() /*postTime*/,
mFdp.ConsumeIntegral<nsecs_t>() /*desiredTime*/,
mFdp.ConsumeBool() /*isAutoTimestamp*/,
- {mFdp.ConsumeIntegral<nsecs_t>()} /*dequeue*/, {} /*info*/);
+ {mFdp.ConsumeIntegral<nsecs_t>()} /*dequeue*/, {} /*info*/, 0 /* hwcslot */);
LayerRenderArea layerArea(*(flinger.flinger()), layer, getFuzzedRect(),
{mFdp.ConsumeIntegral<int32_t>(),
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 9d8e0a2..342c646 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -73,6 +73,7 @@
EXPECT_CALL(*mHal, setClientTargetSlotCount(_));
EXPECT_CALL(*mHal, setVsyncEnabled(hwcDisplayId, Hwc2::IComposerClient::Vsync::DISABLE));
+ EXPECT_CALL(*mHal, onHotplugConnect(hwcDisplayId));
}
};
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index df53f15..dbb8bd8 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -429,18 +429,24 @@
return mFlinger->mTransactionHandler.mPendingTransactionCount.load();
}
- auto setTransactionState(
- const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,
- const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
- const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
- bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
- std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) {
+ auto setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
+ Vector<ComposerState>& states, const Vector<DisplayState>& displays,
+ uint32_t flags, const sp<IBinder>& applyToken,
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime, bool isAutoTimestamp,
+ const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
+ std::vector<ListenerCallbacks>& listenerCallbacks,
+ uint64_t transactionId) {
return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken,
inputWindowCommands, desiredPresentTime,
isAutoTimestamp, uncacheBuffer, hasListenerCallbacks,
listenerCallbacks, transactionId);
}
+ auto setTransactionStateInternal(TransactionState& transaction) {
+ return mFlinger->mTransactionHandler.queueTransaction(std::move(transaction));
+ }
+
auto flushTransactionQueues() {
return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues(kVsyncId));
}
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 9888f00..488d4a9 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -32,6 +32,7 @@
#include "FrontEnd/TransactionHandler.h"
#include "TestableSurfaceFlinger.h"
+#include "TransactionState.h"
#include "mock/MockEventThread.h"
#include "mock/MockVsyncController.h"
@@ -359,13 +360,23 @@
EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
- for (const auto& transaction : transactions) {
- mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
- transaction.displays, transaction.flags,
- transaction.applyToken, transaction.inputWindowCommands,
- transaction.desiredPresentTime,
- transaction.isAutoTimestamp, transaction.uncacheBuffer,
- mHasListenerCallbacks, mCallbacks, transaction.id);
+ for (auto transaction : transactions) {
+ std::vector<ResolvedComposerState> resolvedStates;
+ resolvedStates.reserve(transaction.states.size());
+ for (auto& state : transaction.states) {
+ resolvedStates.emplace_back(std::move(state));
+ }
+
+ TransactionState transactionState(transaction.frameTimelineInfo, resolvedStates,
+ transaction.displays, transaction.flags,
+ transaction.applyToken,
+ transaction.inputWindowCommands,
+ transaction.desiredPresentTime,
+ transaction.isAutoTimestamp,
+ transaction.uncacheBuffer, systemTime(), 0,
+ mHasListenerCallbacks, mCallbacks, getpid(),
+ static_cast<int>(getuid()), transaction.id);
+ mFlinger.setTransactionStateInternal(transactionState);
}
mFlinger.flushTransactionQueues();
EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index 1173d1c..09d002f 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -126,7 +126,7 @@
HAL_PIXEL_FORMAT_RGBA_8888,
0ULL /*usage*/);
layer->setBuffer(externalTexture, bufferData, postTime, /*desiredPresentTime*/ 30, false,
- dequeueTime, FrameTimelineInfo{});
+ dequeueTime, FrameTimelineInfo{}, 0);
commitTransaction(layer.get());
nsecs_t latchTime = 25;
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index 14e1aac..b6427c0 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -46,14 +46,14 @@
size_t layerCount = 2;
t1.states.reserve(layerCount);
for (uint32_t i = 0; i < layerCount; i++) {
- ComposerState s;
+ ResolvedComposerState s;
if (i == 1) {
layer.parentSurfaceControlForChild =
sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), layerHandle, 42,
"#42");
}
s.state = layer;
- t1.states.add(s);
+ t1.states.emplace_back(s);
}
size_t displayCount = 2;
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index ae03db4..7dfbcc0 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -131,7 +131,7 @@
FrameTimelineInfo ftInfo;
ftInfo.vsyncId = 1;
ftInfo.inputEventId = 0;
- layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo);
+ layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo, 0);
acquireFence->signalForTest(12);
commitTransaction(layer.get());
@@ -166,7 +166,7 @@
FrameTimelineInfo ftInfo;
ftInfo.vsyncId = 1;
ftInfo.inputEventId = 0;
- layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo);
+ layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo, 0);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -183,7 +183,7 @@
2ULL /* bufferId */,
HAL_PIXEL_FORMAT_RGBA_8888,
0ULL /*usage*/);
- layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfo);
+ layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfo, 0);
nsecs_t end = systemTime();
acquireFence2->signalForTest(12);
@@ -229,7 +229,7 @@
1ULL /* bufferId */,
HAL_PIXEL_FORMAT_RGBA_8888,
0ULL /*usage*/);
- layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo);
+ layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo, 0);
acquireFence->signalForTest(12);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
@@ -264,7 +264,7 @@
FrameTimelineInfo ftInfo;
ftInfo.vsyncId = 1;
ftInfo.inputEventId = 0;
- layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo);
+ layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo, 0);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -307,7 +307,7 @@
FrameTimelineInfo ftInfo3;
ftInfo3.vsyncId = 3;
ftInfo3.inputEventId = 0;
- layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo3);
+ layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo3, 0);
EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto bufferSurfaceFrameTX = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -352,7 +352,7 @@
FrameTimelineInfo ftInfo;
ftInfo.vsyncId = 1;
ftInfo.inputEventId = 0;
- layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo);
+ layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo, 0);
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -367,7 +367,7 @@
1ULL /* bufferId */,
HAL_PIXEL_FORMAT_RGBA_8888,
0ULL /*usage*/);
- layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfo);
+ layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfo, 0);
acquireFence2->signalForTest(12);
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -404,7 +404,7 @@
FrameTimelineInfo ftInfo;
ftInfo.vsyncId = 1;
ftInfo.inputEventId = 0;
- layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo);
+ layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo, 0);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame1 = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -424,7 +424,7 @@
FrameTimelineInfo ftInfoInv;
ftInfoInv.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID;
ftInfoInv.inputEventId = 0;
- layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfoInv);
+ layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfoInv, 0);
auto dropEndTime1 = systemTime();
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -445,7 +445,7 @@
FrameTimelineInfo ftInfo2;
ftInfo2.vsyncId = 2;
ftInfo2.inputEventId = 0;
- layer->setBuffer(externalTexture3, bufferData, 10, 20, false, std::nullopt, ftInfo2);
+ layer->setBuffer(externalTexture3, bufferData, 10, 20, false, std::nullopt, ftInfo2, 0);
auto dropEndTime2 = systemTime();
acquireFence3->signalForTest(12);
@@ -494,7 +494,7 @@
FrameTimelineInfo ftInfo;
ftInfo.vsyncId = 1;
ftInfo.inputEventId = 0;
- layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo);
+ layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo, 0);
FrameTimelineInfo ftInfo2;
ftInfo2.vsyncId = 2;
ftInfo2.inputEventId = 0;
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 2dbcfbd..482c3a8 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -112,16 +112,16 @@
{
TransactionState transaction;
transaction.id = 50;
- ComposerState layerState;
+ ResolvedComposerState layerState;
layerState.state.surface = fakeLayerHandle;
layerState.state.what = layer_state_t::eLayerChanged;
layerState.state.z = 42;
- transaction.states.add(layerState);
- ComposerState childState;
+ transaction.states.emplace_back(layerState);
+ ResolvedComposerState childState;
childState.state.surface = fakeChildLayerHandle;
childState.state.what = layer_state_t::eLayerChanged;
childState.state.z = 43;
- transaction.states.add(childState);
+ transaction.states.emplace_back(childState);
mTracing.addQueuedTransaction(transaction);
std::vector<TransactionState> transactions;
@@ -138,12 +138,12 @@
{
TransactionState transaction;
transaction.id = 51;
- ComposerState layerState;
+ ResolvedComposerState layerState;
layerState.state.surface = fakeLayerHandle;
layerState.state.what = layer_state_t::eLayerChanged | layer_state_t::ePositionChanged;
layerState.state.z = 41;
layerState.state.x = 22;
- transaction.states.add(layerState);
+ transaction.states.emplace_back(layerState);
mTracing.addQueuedTransaction(transaction);
std::vector<TransactionState> transactions;
@@ -247,16 +247,16 @@
{
TransactionState transaction;
transaction.id = 50;
- ComposerState layerState;
+ ResolvedComposerState layerState;
layerState.state.surface = fakeLayerHandle;
layerState.state.what = layer_state_t::eLayerChanged;
layerState.state.z = 42;
- transaction.states.add(layerState);
- ComposerState mirrorState;
+ transaction.states.emplace_back(layerState);
+ ResolvedComposerState mirrorState;
mirrorState.state.surface = fakeMirrorLayerHandle;
mirrorState.state.what = layer_state_t::eLayerChanged;
mirrorState.state.z = 43;
- transaction.states.add(mirrorState);
+ transaction.states.emplace_back(mirrorState);
mTracing.addQueuedTransaction(transaction);
std::vector<TransactionState> transactions;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 3808487..5ee38ec 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -56,8 +56,8 @@
std::vector<aidl::android::hardware::graphics::composer3::Capability>());
MOCK_METHOD0(dumpDebugInfo, std::string());
MOCK_METHOD1(registerCallback, void(HWC2::ComposerCallback&));
- MOCK_METHOD0(resetCommands, void());
- MOCK_METHOD0(executeCommands, Error());
+ MOCK_METHOD1(resetCommands, void(Display));
+ MOCK_METHOD1(executeCommands, Error(Display));
MOCK_METHOD0(getMaxVirtualDisplayCount, uint32_t());
MOCK_METHOD4(createVirtualDisplay, Error(uint32_t, uint32_t, PixelFormat*, Display*));
MOCK_METHOD1(destroyVirtualDisplay, Error(Display));
@@ -166,6 +166,8 @@
MOCK_METHOD2(getPhysicalDisplayOrientation, Error(Display, AidlTransform*));
MOCK_METHOD1(getOverlaySupport,
Error(aidl::android::hardware::graphics::composer3::OverlayProperties*));
+ MOCK_METHOD1(onHotplugConnect, void(Display));
+ MOCK_METHOD1(onHotplugDisconnect, void(Display));
};
} // namespace Hwc2::mock
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index abcac3c..87b3a89 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -787,13 +787,14 @@
std::vector<VkSurfaceFormatKHR> all_formats = {
{VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
- // Also allow to use PASS_THROUGH + HAL_DATASPACE_ARBITRARY
- {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT},
- {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_PASS_THROUGH_EXT},
};
if (colorspace_ext) {
all_formats.emplace_back(VkSurfaceFormatKHR{
+ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ all_formats.emplace_back(VkSurfaceFormatKHR{
+ VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ all_formats.emplace_back(VkSurfaceFormatKHR{
VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT});
}
@@ -812,16 +813,22 @@
if (AHardwareBuffer_isSupported(&desc)) {
all_formats.emplace_back(VkSurfaceFormatKHR{
VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
- all_formats.emplace_back(VkSurfaceFormatKHR{
- VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ if (colorspace_ext) {
+ all_formats.emplace_back(
+ VkSurfaceFormatKHR{VK_FORMAT_R5G6B5_UNORM_PACK16,
+ VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ }
}
desc.format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
if (AHardwareBuffer_isSupported(&desc)) {
all_formats.emplace_back(VkSurfaceFormatKHR{
VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
- all_formats.emplace_back(VkSurfaceFormatKHR{
- VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ if (colorspace_ext) {
+ all_formats.emplace_back(
+ VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
+ VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ }
if (wide_color_support) {
all_formats.emplace_back(
VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
@@ -837,9 +844,11 @@
all_formats.emplace_back(
VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
- all_formats.emplace_back(
- VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
- VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ if (colorspace_ext) {
+ all_formats.emplace_back(
+ VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+ VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ }
if (wide_color_support) {
all_formats.emplace_back(
VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
@@ -849,9 +858,10 @@
desc.format = AHARDWAREBUFFER_FORMAT_R8_UNORM;
if (AHardwareBuffer_isSupported(&desc)) {
- all_formats.emplace_back(
- VkSurfaceFormatKHR{VK_FORMAT_R8_UNORM,
- VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ if (colorspace_ext) {
+ all_formats.emplace_back(VkSurfaceFormatKHR{
+ VK_FORMAT_R8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ }
}
// NOTE: Any new formats that are added must be coordinated across different