Merge "Dynamically add STYLUS source for multi-touch devices"
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index ebb7891..34ea759 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1956,7 +1956,7 @@
join_fds(context_input_fds), swap_fd.get(), instruction_set, compiler_filter,
debuggable, boot_complete, for_restore, target_sdk_version,
enable_hidden_api_checks, generate_compact_dex, use_jitzygote_image,
- compilation_reason);
+ background_job_compile, compilation_reason);
bool cancelled = false;
pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled);
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index 51c4589..4221a3a 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -81,6 +81,7 @@
bool enable_hidden_api_checks,
bool generate_compact_dex,
bool use_jitzygote,
+ bool background_job_compile,
const char* compilation_reason) {
PrepareBootImageFlags(use_jitzygote);
@@ -92,7 +93,8 @@
debuggable, target_sdk_version, enable_hidden_api_checks,
generate_compact_dex, compilation_reason);
- PrepareCompilerRuntimeAndPerfConfigFlags(post_bootcomplete, for_restore);
+ PrepareCompilerRuntimeAndPerfConfigFlags(post_bootcomplete, for_restore,
+ background_job_compile);
const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
@@ -296,7 +298,8 @@
}
void RunDex2Oat::PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete,
- bool for_restore) {
+ bool for_restore,
+ bool background_job_compile) {
// CPU set
{
std::string cpu_set_format = "--cpu-set=%s";
@@ -306,7 +309,12 @@
"dalvik.vm.restore-dex2oat-cpu-set",
"dalvik.vm.dex2oat-cpu-set",
cpu_set_format)
- : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format))
+ : (background_job_compile
+ ? MapPropertyToArgWithBackup(
+ "dalvik.vm.background-dex2oat-cpu-set",
+ "dalvik.vm.dex2oat-cpu-set",
+ cpu_set_format)
+ : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format)))
: MapPropertyToArg("dalvik.vm.boot-dex2oat-cpu-set", cpu_set_format);
AddArg(dex2oat_cpu_set_arg);
}
@@ -320,7 +328,12 @@
"dalvik.vm.restore-dex2oat-threads",
"dalvik.vm.dex2oat-threads",
threads_format)
- : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format))
+ : (background_job_compile
+ ? MapPropertyToArgWithBackup(
+ "dalvik.vm.background-dex2oat-threads",
+ "dalvik.vm.dex2oat-threads",
+ threads_format)
+ : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format)))
: MapPropertyToArg("dalvik.vm.boot-dex2oat-threads", threads_format);
AddArg(dex2oat_threads_arg);
}
diff --git a/cmds/installd/run_dex2oat.h b/cmds/installd/run_dex2oat.h
index 559244f..c13e1f1 100644
--- a/cmds/installd/run_dex2oat.h
+++ b/cmds/installd/run_dex2oat.h
@@ -51,6 +51,7 @@
bool enable_hidden_api_checks,
bool generate_compact_dex,
bool use_jitzygote,
+ bool background_job_compile,
const char* compilation_reason);
void Exec(int exit_code);
@@ -76,7 +77,9 @@
bool enable_hidden_api_checks,
bool generate_compact_dex,
const char* compilation_reason);
- void PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete, bool for_restore);
+ void PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete,
+ bool for_restore,
+ bool background_job_compile);
virtual std::string GetProperty(const std::string& key, const std::string& default_value);
virtual bool GetBoolProperty(const std::string& key, bool default_value);
diff --git a/cmds/installd/run_dex2oat_test.cpp b/cmds/installd/run_dex2oat_test.cpp
index 2a8135a..304ba7b 100644
--- a/cmds/installd/run_dex2oat_test.cpp
+++ b/cmds/installd/run_dex2oat_test.cpp
@@ -115,6 +115,7 @@
bool enable_hidden_api_checks = false;
bool generate_compact_dex = true;
bool use_jitzygote = false;
+ bool background_job_compile = false;
const char* compilation_reason = nullptr;
};
@@ -259,6 +260,7 @@
args->enable_hidden_api_checks,
args->generate_compact_dex,
args->use_jitzygote,
+ args->background_job_compile,
args->compilation_reason);
runner.Exec(/*exit_code=*/ 0);
}
@@ -375,6 +377,30 @@
VerifyExpectedFlags();
}
+TEST_F(RunDex2OatTest, CpuSetPostBootCompleteBackground) {
+ setSystemProperty("dalvik.vm.background-dex2oat-cpu-set", "1,3");
+ setSystemProperty("dalvik.vm.dex2oat-cpu-set", "1,2");
+ auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+ args->post_bootcomplete = true;
+ args->background_job_compile = true;
+ CallRunDex2Oat(std::move(args));
+
+ SetExpectedFlagUsed("--cpu-set", "=1,3");
+ VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, CpuSetPostBootCompleteBackground_Backup) {
+ setSystemProperty("dalvik.vm.background-dex2oat-cpu-set", "");
+ setSystemProperty("dalvik.vm.dex2oat-cpu-set", "1,2");
+ auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+ args->post_bootcomplete = true;
+ args->background_job_compile = true;
+ CallRunDex2Oat(std::move(args));
+
+ SetExpectedFlagUsed("--cpu-set", "=1,2");
+ VerifyExpectedFlags();
+}
+
TEST_F(RunDex2OatTest, CpuSetPostBootCompleteForRestore) {
setSystemProperty("dalvik.vm.restore-dex2oat-cpu-set", "1,2");
setSystemProperty("dalvik.vm.dex2oat-cpu-set", "2,3");
@@ -481,6 +507,30 @@
VerifyExpectedFlags();
}
+TEST_F(RunDex2OatTest, ThreadsPostBootCompleteBackground) {
+ setSystemProperty("dalvik.vm.background-dex2oat-threads", "2");
+ setSystemProperty("dalvik.vm.dex2oat-threads", "3");
+ auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+ args->post_bootcomplete = true;
+ args->background_job_compile = true;
+ CallRunDex2Oat(std::move(args));
+
+ SetExpectedFlagUsed("-j", "2");
+ VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, ThreadsPostBootCompleteBackground_Backup) {
+ setSystemProperty("dalvik.vm.background-dex2oat-threads", "");
+ setSystemProperty("dalvik.vm.dex2oat-threads", "3");
+ auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+ args->post_bootcomplete = true;
+ args->background_job_compile = true;
+ CallRunDex2Oat(std::move(args));
+
+ SetExpectedFlagUsed("-j", "3");
+ VerifyExpectedFlags();
+}
+
TEST_F(RunDex2OatTest, ThreadsPostBootCompleteForRestore) {
setSystemProperty("dalvik.vm.restore-dex2oat-threads", "4");
setSystemProperty("dalvik.vm.dex2oat-threads", "5");
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index fd879c6..61f931e 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -53,6 +53,9 @@
init_rc: ["servicemanager.microdroid.rc"],
srcs: ["main.cpp"],
bootstrap: true,
+ // Prevent this from being installed when running tests in this directory.
+ // This is okay because microdorid build rule can bundle this anyway.
+ installable: false,
}
cc_binary {
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 2ae61b9..cc038ae 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -136,6 +136,7 @@
updatableViaApex = manifestInstance.updatableViaApex();
return false; // break (libvintf uses opposite convention)
});
+ if (updatableViaApex.has_value()) return true; // break (found match)
return false; // continue
});
@@ -154,7 +155,7 @@
manifestInstance.interface() + "/" + manifestInstance.instance();
instances.push_back(aname);
}
- return false; // continue
+ return true; // continue (libvintf uses opposite convention)
});
return false; // continue
});
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index 5d5a75e..0fd8d8e 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -14,13 +14,15 @@
* limitations under the License.
*/
+#include <android-base/properties.h>
+#include <android-base/strings.h>
#include <android/os/BnServiceCallback.h>
#include <binder/Binder.h>
-#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <cutils/android_filesystem_config.h>
-#include <gtest/gtest.h>
#include <gmock/gmock.h>
+#include <gtest/gtest.h>
#include "Access.h"
#include "ServiceManager.h"
@@ -75,6 +77,11 @@
return sm;
}
+static bool isCuttlefish() {
+ return android::base::StartsWith(android::base::GetProperty("ro.product.vendor.device", ""),
+ "vsoc_");
+}
+
TEST(AddService, HappyHappy) {
auto sm = getPermissiveServiceManager();
EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
@@ -306,6 +313,49 @@
EXPECT_THAT(out, ElementsAre("sa"));
}
+TEST(Vintf, UpdatableViaApex) {
+ if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+
+ auto sm = getPermissiveServiceManager();
+ std::optional<std::string> updatableViaApex;
+ EXPECT_TRUE(sm->updatableViaApex("android.hardware.camera.provider.ICameraProvider/internal/0",
+ &updatableViaApex)
+ .isOk());
+ EXPECT_EQ(std::make_optional<std::string>("com.google.emulated.camera.provider.hal"),
+ updatableViaApex);
+}
+
+TEST(Vintf, UpdatableViaApex_InvalidNameReturnsNullOpt) {
+ if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+
+ auto sm = getPermissiveServiceManager();
+ std::optional<std::string> updatableViaApex;
+ EXPECT_TRUE(sm->updatableViaApex("android.hardware.camera.provider.ICameraProvider",
+ &updatableViaApex)
+ .isOk()); // missing instance name
+ EXPECT_EQ(std::nullopt, updatableViaApex);
+}
+
+TEST(Vintf, GetUpdatableNames) {
+ if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+
+ auto sm = getPermissiveServiceManager();
+ std::vector<std::string> names;
+ EXPECT_TRUE(sm->getUpdatableNames("com.google.emulated.camera.provider.hal", &names).isOk());
+ EXPECT_EQ(std::vector<
+ std::string>{"android.hardware.camera.provider.ICameraProvider/internal/0"},
+ names);
+}
+
+TEST(Vintf, GetUpdatableNames_InvalidApexNameReturnsEmpty) {
+ if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+
+ auto sm = getPermissiveServiceManager();
+ std::vector<std::string> names;
+ EXPECT_TRUE(sm->getUpdatableNames("non.existing.apex.name", &names).isOk());
+ EXPECT_EQ(std::vector<std::string>{}, names);
+}
+
class CallbackHistorian : public BnServiceCallback {
Status onRegistration(const std::string& name, const sp<IBinder>& binder) override {
registrations.push_back(name);
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h
index 5fa47f6..eed6b33 100644
--- a/include/android/performance_hint.h
+++ b/include/android/performance_hint.h
@@ -88,6 +88,36 @@
typedef struct APerformanceHintSession APerformanceHintSession;
/**
+ * Hints for the session used by {@link APerformanceHint_sendHint} to signal upcoming changes
+ * in the mode or workload.
+ */
+enum SessionHint {
+ /**
+ * This hint indicates a sudden increase in CPU workload intensity. It means
+ * that this hint session needs extra CPU resources immediately to meet the
+ * target duration for the current work cycle.
+ */
+ CPU_LOAD_UP = 0,
+ /**
+ * This hint indicates a decrease in CPU workload intensity. It means that
+ * this hint session can reduce CPU resources and still meet the target duration.
+ */
+ CPU_LOAD_DOWN = 1,
+ /*
+ * This hint indicates an upcoming CPU workload that is completely changed and
+ * unknown. It means that the hint session should reset CPU resources to a known
+ * baseline to prepare for an arbitrary load, and must wake up if inactive.
+ */
+ CPU_LOAD_RESET = 2,
+ /*
+ * This hint indicates that the most recent CPU workload is resuming after a
+ * period of inactivity. It means that the hint session should allocate similar
+ * CPU resources to what was used previously, and must wake up if inactive.
+ */
+ CPU_LOAD_RESUME = 3,
+};
+
+/**
* Acquire an instance of the performance hint manager.
*
* @return manager instance on success, nullptr on failure.
@@ -159,6 +189,17 @@
void APerformanceHint_closeSession(
APerformanceHintSession* session) __INTRODUCED_IN(__ANDROID_API_T__);
+/**
+ * Sends performance hints to inform the hint session of changes in the workload.
+ *
+ * @param session The performance hint session instance to update.
+ * @param hint The hint to send to the session.
+ * @return 0 on success
+ * EPIPE if communication with the system service has failed.
+ */
+int APerformanceHint_sendHint(
+ APerformanceHintSession* session, int hint) __INTRODUCED_IN(__ANDROID_API_U__);
+
__END_DECLS
#endif // ANDROID_NATIVE_PERFORMANCE_HINT_H
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/include/input/VelocityControl.h b/include/input/VelocityControl.h
index f72a1bd..f3c201e 100644
--- a/include/input/VelocityControl.h
+++ b/include/input/VelocityControl.h
@@ -16,10 +16,13 @@
#pragma once
+#include <android-base/stringprintf.h>
#include <input/Input.h>
#include <input/VelocityTracker.h>
#include <utils/Timers.h>
+using android::base::StringPrintf;
+
namespace android {
/*
@@ -69,6 +72,12 @@
scale(scale), lowThreshold(lowThreshold),
highThreshold(highThreshold), acceleration(acceleration) {
}
+
+ std::string dump() const {
+ return StringPrintf("scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, "
+ "acceleration=%0.3f\n",
+ scale, lowThreshold, highThreshold, acceleration);
+ }
};
/*
@@ -78,6 +87,9 @@
public:
VelocityControl();
+ /* Gets the various parameters. */
+ VelocityControlParameters& getParameters();
+
/* Sets the various parameters. */
void setParameters(const VelocityControlParameters& parameters);
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..bd72a53 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -564,6 +564,26 @@
return OK;
}
+status_t RpcServer::setupRawSocketServer(base::unique_fd socket_fd) {
+ LOG_ALWAYS_FATAL_IF(!socket_fd.ok(), "Socket must be setup to listen.");
+ RpcTransportFd transportFd(std::move(socket_fd));
+
+ // 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..9edb3b6 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,35 @@
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 (!fd.ok()) {
+ LOG(ERROR) << "Failed to get fd for the socket:" << name;
+ return false;
+ }
+ 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/Android.bp b/libs/binder/tests/Android.bp
index 92d132f..03e4a23 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -232,6 +232,7 @@
srcs: [
"binderRpcTest.cpp",
"binderRpcTestCommon.cpp",
+ "binderRpcUniversalTests.cpp",
],
test_suites: ["general-tests"],
diff --git a/libs/binder/tests/BinderRpcTestServerConfig.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl
index 4cdeac4..b2e0ef2 100644
--- a/libs/binder/tests/BinderRpcTestServerConfig.aidl
+++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl
@@ -21,6 +21,6 @@
int rpcSecurity;
int serverVersion;
int vsockPort;
- int unixBootstrapFd; // Inherited from parent
+ int socketFd; // Inherited from the parent process.
@utf8InCpp String addr;
}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 5d5b530..68a827b 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -15,7 +15,6 @@
*/
#include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
#include <chrono>
#include <cstdlib>
@@ -45,29 +44,6 @@
constexpr bool kEnableSharedLibs = true;
#endif
-static_assert(RPC_WIRE_PROTOCOL_VERSION + 1 == RPC_WIRE_PROTOCOL_VERSION_NEXT ||
- RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
-
-TEST(BinderRpcParcel, EntireParcelFormatted) {
- Parcel p;
- p.writeInt32(3);
-
- EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "format must be set before data is written");
-}
-
-TEST(BinderRpc, CannotUseNextWireVersion) {
- auto session = RpcSession::make();
- EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT));
- EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 1));
- EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 2));
- EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 15));
-}
-
-TEST(BinderRpc, CanUseExperimentalWireVersion) {
- auto session = RpcSession::make();
- EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL));
-}
-
static std::string WaitStatusToString(int wstatus) {
if (WIFEXITED(wstatus)) {
return base::StringPrintf("exit status %d", WEXITSTATUS(wstatus));
@@ -153,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() {}
@@ -267,12 +252,19 @@
singleThreaded ? "_single_threaded" : "",
noKernel ? "_no_kernel" : "");
- base::unique_fd bootstrapClientFd, bootstrapServerFd;
- // 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);
+ base::unique_fd bootstrapClientFd, socketFd;
+
+ auto addr = allocateSocketAddress();
+ // Initializes the socket before the fork/exec.
+ if (socketType == SocketType::UNIX_RAW) {
+ socketFd = initUnixSocket(addr);
+ } else if (socketType == SocketType::UNIX_BOOTSTRAP) {
+ // 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, &socketFd)) {
+ int savedErrno = errno;
+ LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno);
+ }
}
auto ret = std::make_unique<LinuxProcessSession>(
@@ -289,8 +281,8 @@
serverConfig.rpcSecurity = static_cast<int32_t>(rpcSecurity);
serverConfig.serverVersion = serverVersion;
serverConfig.vsockPort = allocateVsockPort();
- serverConfig.addr = allocateSocketAddress();
- serverConfig.unixBootstrapFd = bootstrapServerFd.get();
+ serverConfig.addr = addr;
+ serverConfig.socketFd = socketFd.get();
for (auto mode : options.serverSupportedFileDescriptorTransportModes) {
serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
static_cast<int32_t>(mode));
@@ -336,6 +328,7 @@
return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
});
break;
+ case SocketType::UNIX_RAW:
case SocketType::UNIX:
status = session->setupUnixDomainClient(serverConfig.addr.c_str());
break;
@@ -362,380 +355,6 @@
return ret;
}
-TEST_P(BinderRpc, Ping) {
- auto proc = createRpcTestSocketServerProcess({});
- ASSERT_NE(proc.rootBinder, nullptr);
- EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-}
-
-TEST_P(BinderRpc, GetInterfaceDescriptor) {
- auto proc = createRpcTestSocketServerProcess({});
- ASSERT_NE(proc.rootBinder, nullptr);
- EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
-}
-
-TEST_P(BinderRpc, MultipleSessions) {
- if (serverSingleThreaded()) {
- // Tests with multiple sessions require a multi-threaded service,
- // but work fine on a single-threaded client
- GTEST_SKIP() << "This test requires a multi-threaded service";
- }
-
- auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
- for (auto session : proc.proc->sessions) {
- ASSERT_NE(nullptr, session.root);
- EXPECT_EQ(OK, session.root->pingBinder());
- }
-}
-
-TEST_P(BinderRpc, SeparateRootObject) {
- if (serverSingleThreaded()) {
- GTEST_SKIP() << "This test requires a multi-threaded service";
- }
-
- SocketType type = std::get<0>(GetParam());
- if (type == SocketType::PRECONNECTED || type == SocketType::UNIX ||
- type == SocketType::UNIX_BOOTSTRAP) {
- // we can't get port numbers for unix sockets
- return;
- }
-
- auto proc = createRpcTestSocketServerProcess({.numSessions = 2});
-
- int port1 = 0;
- EXPECT_OK(proc.rootIface->getClientPort(&port1));
-
- sp<IBinderRpcTest> rootIface2 = interface_cast<IBinderRpcTest>(proc.proc->sessions.at(1).root);
- int port2;
- EXPECT_OK(rootIface2->getClientPort(&port2));
-
- // we should have a different IBinderRpcTest object created for each
- // session, because we use setPerSessionRootObject
- EXPECT_NE(port1, port2);
-}
-
-TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
- auto proc = createRpcTestSocketServerProcess({});
- Parcel data;
- Parcel reply;
- EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0));
-}
-
-TEST_P(BinderRpc, AppendSeparateFormats) {
- auto proc1 = createRpcTestSocketServerProcess({});
- auto proc2 = createRpcTestSocketServerProcess({});
-
- Parcel pRaw;
-
- Parcel p1;
- p1.markForBinder(proc1.rootBinder);
- p1.writeInt32(3);
-
- EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, pRaw.dataSize()));
- EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
-
- Parcel p2;
- p2.markForBinder(proc2.rootBinder);
- p2.writeInt32(7);
-
- EXPECT_EQ(BAD_TYPE, p1.appendFrom(&p2, 0, p2.dataSize()));
- EXPECT_EQ(BAD_TYPE, p2.appendFrom(&p1, 0, p1.dataSize()));
-}
-
-TEST_P(BinderRpc, UnknownTransaction) {
- auto proc = createRpcTestSocketServerProcess({});
- Parcel data;
- data.markForBinder(proc.rootBinder);
- Parcel reply;
- EXPECT_EQ(UNKNOWN_TRANSACTION, proc.rootBinder->transact(1337, data, &reply, 0));
-}
-
-TEST_P(BinderRpc, SendSomethingOneway) {
- auto proc = createRpcTestSocketServerProcess({});
- EXPECT_OK(proc.rootIface->sendString("asdf"));
-}
-
-TEST_P(BinderRpc, SendAndGetResultBack) {
- auto proc = createRpcTestSocketServerProcess({});
- std::string doubled;
- EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
- EXPECT_EQ("cool cool ", doubled);
-}
-
-TEST_P(BinderRpc, SendAndGetResultBackBig) {
- auto proc = createRpcTestSocketServerProcess({});
- std::string single = std::string(1024, 'a');
- std::string doubled;
- EXPECT_OK(proc.rootIface->doubleString(single, &doubled));
- EXPECT_EQ(single + single, doubled);
-}
-
-TEST_P(BinderRpc, InvalidNullBinderReturn) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> outBinder;
- EXPECT_EQ(proc.rootIface->getNullBinder(&outBinder).transactionError(), UNEXPECTED_NULL);
-}
-
-TEST_P(BinderRpc, CallMeBack) {
- auto proc = createRpcTestSocketServerProcess({});
-
- int32_t pingResult;
- EXPECT_OK(proc.rootIface->pingMe(new MyBinderRpcSession("foo"), &pingResult));
- EXPECT_EQ(OK, pingResult);
-
- EXPECT_EQ(0, MyBinderRpcSession::gNum);
-}
-
-TEST_P(BinderRpc, RepeatBinder) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> inBinder = new MyBinderRpcSession("foo");
- sp<IBinder> outBinder;
- EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
- EXPECT_EQ(inBinder, outBinder);
-
- wp<IBinder> weak = inBinder;
- inBinder = nullptr;
- outBinder = nullptr;
-
- // Force reading a reply, to process any pending dec refs from the other
- // process (the other process will process dec refs there before processing
- // the ping here).
- EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-
- EXPECT_EQ(nullptr, weak.promote());
-
- EXPECT_EQ(0, MyBinderRpcSession::gNum);
-}
-
-TEST_P(BinderRpc, RepeatTheirBinder) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinderRpcSession> session;
- EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
-
- sp<IBinder> inBinder = IInterface::asBinder(session);
- sp<IBinder> outBinder;
- EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
- EXPECT_EQ(inBinder, outBinder);
-
- wp<IBinder> weak = inBinder;
- session = nullptr;
- inBinder = nullptr;
- outBinder = nullptr;
-
- // Force reading a reply, to process any pending dec refs from the other
- // process (the other process will process dec refs there before processing
- // the ping here).
- EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-
- EXPECT_EQ(nullptr, weak.promote());
-}
-
-TEST_P(BinderRpc, RepeatBinderNull) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> outBinder;
- EXPECT_OK(proc.rootIface->repeatBinder(nullptr, &outBinder));
- EXPECT_EQ(nullptr, outBinder);
-}
-
-TEST_P(BinderRpc, HoldBinder) {
- auto proc = createRpcTestSocketServerProcess({});
-
- IBinder* ptr = nullptr;
- {
- sp<IBinder> binder = new BBinder();
- ptr = binder.get();
- EXPECT_OK(proc.rootIface->holdBinder(binder));
- }
-
- sp<IBinder> held;
- EXPECT_OK(proc.rootIface->getHeldBinder(&held));
-
- EXPECT_EQ(held.get(), ptr);
-
- // stop holding binder, because we test to make sure references are cleaned
- // up
- EXPECT_OK(proc.rootIface->holdBinder(nullptr));
- // and flush ref counts
- EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-}
-
-// START TESTS FOR LIMITATIONS OF SOCKET BINDER
-// These are behavioral differences form regular binder, where certain usecases
-// aren't supported.
-
-TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketSessions) {
- auto proc1 = createRpcTestSocketServerProcess({});
- auto proc2 = createRpcTestSocketServerProcess({});
-
- sp<IBinder> outBinder;
- EXPECT_EQ(INVALID_OPERATION,
- proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
-}
-
-TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
- if (serverSingleThreaded()) {
- GTEST_SKIP() << "This test requires a multi-threaded service";
- }
-
- auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2});
-
- sp<IBinder> outBinder;
- EXPECT_EQ(INVALID_OPERATION,
- proc.rootIface->repeatBinder(proc.proc->sessions.at(1).root, &outBinder)
- .transactionError());
-}
-
-TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
- if (!kEnableKernelIpc || noKernel()) {
- GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
- "at build time.";
- }
-
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
- sp<IBinder> outBinder;
- EXPECT_EQ(INVALID_OPERATION,
- proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
-}
-
-TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
- if (!kEnableKernelIpc || noKernel()) {
- GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
- "at build time.";
- }
-
- auto proc = createRpcTestSocketServerProcess({});
-
- // for historical reasons, IServiceManager interface only returns the
- // exception code
- EXPECT_EQ(binder::Status::EX_TRANSACTION_FAILED,
- defaultServiceManager()->addService(String16("not_suspicious"), proc.rootBinder));
-}
-
-// END TESTS FOR LIMITATIONS OF SOCKET BINDER
-
-TEST_P(BinderRpc, RepeatRootObject) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> outBinder;
- EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &outBinder));
- EXPECT_EQ(proc.rootBinder, outBinder);
-}
-
-TEST_P(BinderRpc, NestedTransactions) {
- auto proc = createRpcTestSocketServerProcess({
- // Enable FD support because it uses more stack space and so represents
- // something closer to a worst case scenario.
- .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
- .serverSupportedFileDescriptorTransportModes =
- {RpcSession::FileDescriptorTransportMode::UNIX},
- });
-
- auto nastyNester = sp<MyBinderRpcTest>::make();
- EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
-
- wp<IBinder> weak = nastyNester;
- nastyNester = nullptr;
- EXPECT_EQ(nullptr, weak.promote());
-}
-
-TEST_P(BinderRpc, SameBinderEquality) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> a;
- EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
-
- sp<IBinder> b;
- EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
-
- EXPECT_EQ(a, b);
-}
-
-TEST_P(BinderRpc, SameBinderEqualityWeak) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> a;
- EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
- wp<IBinder> weak = a;
- a = nullptr;
-
- sp<IBinder> b;
- EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
-
- // this is the wrong behavior, since BpBinder
- // doesn't implement onIncStrongAttempted
- // but make sure there is no crash
- EXPECT_EQ(nullptr, weak.promote());
-
- GTEST_SKIP() << "Weak binders aren't currently re-promotable for RPC binder.";
-
- // In order to fix this:
- // - need to have incStrongAttempted reflected across IPC boundary (wait for
- // response to promote - round trip...)
- // - sendOnLastWeakRef, to delete entries out of RpcState table
- EXPECT_EQ(b, weak.promote());
-}
-
-#define expectSessions(expected, iface) \
- do { \
- int session; \
- EXPECT_OK((iface)->getNumOpenSessions(&session)); \
- EXPECT_EQ(expected, session); \
- } while (false)
-
-TEST_P(BinderRpc, SingleSession) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinderRpcSession> session;
- EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
- std::string out;
- EXPECT_OK(session->getName(&out));
- EXPECT_EQ("aoeu", out);
-
- expectSessions(1, proc.rootIface);
- session = nullptr;
- expectSessions(0, proc.rootIface);
-}
-
-TEST_P(BinderRpc, ManySessions) {
- auto proc = createRpcTestSocketServerProcess({});
-
- std::vector<sp<IBinderRpcSession>> sessions;
-
- for (size_t i = 0; i < 15; i++) {
- expectSessions(i, proc.rootIface);
- sp<IBinderRpcSession> session;
- EXPECT_OK(proc.rootIface->openSession(std::to_string(i), &session));
- sessions.push_back(session);
- }
- expectSessions(sessions.size(), proc.rootIface);
- for (size_t i = 0; i < sessions.size(); i++) {
- std::string out;
- EXPECT_OK(sessions.at(i)->getName(&out));
- EXPECT_EQ(std::to_string(i), out);
- }
- expectSessions(sessions.size(), proc.rootIface);
-
- while (!sessions.empty()) {
- sessions.pop_back();
- expectSessions(sessions.size(), proc.rootIface);
- }
- expectSessions(0, proc.rootIface);
-}
-
-size_t epochMillis() {
- using std::chrono::duration_cast;
- using std::chrono::milliseconds;
- using std::chrono::seconds;
- using std::chrono::system_clock;
- return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
-}
-
TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
if (clientOrServerSingleThreaded()) {
GTEST_SKIP() << "This test requires multiple threads";
@@ -873,20 +492,6 @@
saturateThreadPool(kNumServerThreads, proc.rootIface);
}
-TEST_P(BinderRpc, OnewayCallDoesNotWait) {
- constexpr size_t kReallyLongTimeMs = 100;
- constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
-
- auto proc = createRpcTestSocketServerProcess({});
-
- size_t epochMsBefore = epochMillis();
-
- EXPECT_OK(proc.rootIface->sleepMsAsync(kSleepMs));
-
- size_t epochMsAfter = epochMillis();
- EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
-}
-
TEST_P(BinderRpc, OnewayCallQueueingWithFds) {
if (!supportsFdTransport()) {
GTEST_SKIP() << "Would fail trivially (which is tested elsewhere)";
@@ -1003,65 +608,6 @@
proc.proc->sessions.erase(proc.proc->sessions.begin() + 1);
}
-TEST_P(BinderRpc, Callbacks) {
- const static std::string kTestString = "good afternoon!";
-
- for (bool callIsOneway : {true, false}) {
- for (bool callbackIsOneway : {true, false}) {
- for (bool delayed : {true, false}) {
- if (clientOrServerSingleThreaded() &&
- (callIsOneway || callbackIsOneway || delayed)) {
- // we have no incoming connections to receive the callback
- continue;
- }
-
- size_t numIncomingConnections = clientOrServerSingleThreaded() ? 0 : 1;
- auto proc = createRpcTestSocketServerProcess(
- {.numThreads = 1,
- .numSessions = 1,
- .numIncomingConnections = numIncomingConnections});
- auto cb = sp<MyBinderRpcCallback>::make();
-
- if (callIsOneway) {
- EXPECT_OK(proc.rootIface->doCallbackAsync(cb, callbackIsOneway, delayed,
- kTestString));
- } else {
- EXPECT_OK(
- proc.rootIface->doCallback(cb, callbackIsOneway, delayed, kTestString));
- }
-
- // if both transactions are synchronous and the response is sent back on the
- // same thread, everything should have happened in a nested call. Otherwise,
- // the callback will be processed on another thread.
- if (callIsOneway || callbackIsOneway || delayed) {
- using std::literals::chrono_literals::operator""s;
- RpcMutexUniqueLock _l(cb->mMutex);
- cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
- }
-
- EXPECT_EQ(cb->mValues.size(), 1)
- << "callIsOneway: " << callIsOneway
- << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
- if (cb->mValues.empty()) continue;
- EXPECT_EQ(cb->mValues.at(0), kTestString)
- << "callIsOneway: " << callIsOneway
- << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
-
- // since we are severing the connection, we need to go ahead and
- // tell the server to shutdown and exit so that waitpid won't hang
- if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
- EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
- }
-
- // since this session has an incoming connection w/ a threadpool, we
- // need to manually shut it down
- EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
- proc.expectAlreadyShutdown = true;
- }
- }
- }
-}
-
TEST_P(BinderRpc, SingleDeathRecipient) {
if (clientOrServerSingleThreaded()) {
GTEST_SKIP() << "This test requires multiple threads";
@@ -1178,14 +724,6 @@
proc.expectAlreadyShutdown = true;
}
-TEST_P(BinderRpc, OnewayCallbackWithNoThread) {
- auto proc = createRpcTestSocketServerProcess({});
- auto cb = sp<MyBinderRpcCallback>::make();
-
- Status status = proc.rootIface->doCallback(cb, true /*oneway*/, false /*delayed*/, "anything");
- EXPECT_EQ(WOULD_BLOCK, status.transactionError());
-}
-
TEST_P(BinderRpc, Die) {
for (bool doDeathCleanup : {true, false}) {
auto proc = createRpcTestSocketServerProcess({});
@@ -1431,16 +969,6 @@
ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
}
-TEST_P(BinderRpc, AidlDelegatorTest) {
- auto proc = createRpcTestSocketServerProcess({});
- auto myDelegator = sp<IBinderRpcTestDelegator>::make(proc.rootIface);
- ASSERT_NE(nullptr, myDelegator);
-
- std::string doubled;
- EXPECT_OK(myDelegator->doubleString("cool ", &doubled));
- EXPECT_EQ("cool cool ", doubled);
-}
-
static bool testSupportVsockLoopback() {
// We don't need to enable TLS to know if vsock is supported.
unsigned int vsockPort = allocateVsockPort();
@@ -1531,7 +1059,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);
@@ -1773,6 +1302,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 823bbf6..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:
@@ -91,6 +94,14 @@
}
}
+static inline size_t epochMillis() {
+ using std::chrono::duration_cast;
+ using std::chrono::milliseconds;
+ using std::chrono::seconds;
+ using std::chrono::system_clock;
+ return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+}
+
struct BinderRpcOptions {
size_t numThreads = 1;
size_t numSessions = 1;
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..995e761 100644
--- a/libs/binder/tests/binderRpcTestService.cpp
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -42,7 +42,7 @@
server->setSupportedFileDescriptorTransportModes(serverSupportedFileDescriptorTransportModes);
unsigned int outPort = 0;
- base::unique_fd unixBootstrapFd(serverConfig.unixBootstrapFd);
+ base::unique_fd socketFd(serverConfig.socketFd);
switch (socketType) {
case SocketType::PRECONNECTED:
@@ -52,7 +52,10 @@
<< serverConfig.addr;
break;
case SocketType::UNIX_BOOTSTRAP:
- CHECK_EQ(OK, server->setupUnixDomainSocketBootstrapServer(std::move(unixBootstrapFd)));
+ CHECK_EQ(OK, server->setupUnixDomainSocketBootstrapServer(std::move(socketFd)));
+ break;
+ case SocketType::UNIX_RAW:
+ CHECK_EQ(OK, server->setupRawSocketServer(std::move(socketFd)));
break;
case SocketType::VSOCK:
CHECK_EQ(OK, server->setupVsockServer(serverConfig.vsockPort));
diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp
new file mode 100644
index 0000000..f960442
--- /dev/null
+++ b/libs/binder/tests/binderRpcUniversalTests.cpp
@@ -0,0 +1,513 @@
+/*
+ * 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 <chrono>
+#include <cstdlib>
+#include <type_traits>
+
+#include "binderRpcTestCommon.h"
+#include "binderRpcTestFixture.h"
+
+using namespace std::chrono_literals;
+using namespace std::placeholders;
+using testing::AssertionFailure;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
+
+namespace android {
+
+static_assert(RPC_WIRE_PROTOCOL_VERSION + 1 == RPC_WIRE_PROTOCOL_VERSION_NEXT ||
+ RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+
+TEST(BinderRpcParcel, EntireParcelFormatted) {
+ Parcel p;
+ p.writeInt32(3);
+
+ EXPECT_DEATH_IF_SUPPORTED(p.markForBinder(sp<BBinder>::make()),
+ "format must be set before data is written");
+}
+
+TEST(BinderRpc, CannotUseNextWireVersion) {
+ auto session = RpcSession::make();
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT));
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 1));
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 2));
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 15));
+}
+
+TEST(BinderRpc, CanUseExperimentalWireVersion) {
+ auto session = RpcSession::make();
+ EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL));
+}
+
+TEST_P(BinderRpc, Ping) {
+ auto proc = createRpcTestSocketServerProcess({});
+ ASSERT_NE(proc.rootBinder, nullptr);
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+}
+
+TEST_P(BinderRpc, GetInterfaceDescriptor) {
+ auto proc = createRpcTestSocketServerProcess({});
+ ASSERT_NE(proc.rootBinder, nullptr);
+ EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
+}
+
+TEST_P(BinderRpc, MultipleSessions) {
+ if (serverSingleThreaded()) {
+ // Tests with multiple sessions require a multi-threaded service,
+ // but work fine on a single-threaded client
+ GTEST_SKIP() << "This test requires a multi-threaded service";
+ }
+
+ auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
+ for (auto session : proc.proc->sessions) {
+ ASSERT_NE(nullptr, session.root);
+ EXPECT_EQ(OK, session.root->pingBinder());
+ }
+}
+
+TEST_P(BinderRpc, SeparateRootObject) {
+ if (serverSingleThreaded()) {
+ GTEST_SKIP() << "This test requires a multi-threaded service";
+ }
+
+ SocketType type = std::get<0>(GetParam());
+ if (type == SocketType::PRECONNECTED || type == SocketType::UNIX ||
+ type == SocketType::UNIX_BOOTSTRAP || type == SocketType::UNIX_RAW) {
+ // we can't get port numbers for unix sockets
+ return;
+ }
+
+ auto proc = createRpcTestSocketServerProcess({.numSessions = 2});
+
+ int port1 = 0;
+ EXPECT_OK(proc.rootIface->getClientPort(&port1));
+
+ sp<IBinderRpcTest> rootIface2 = interface_cast<IBinderRpcTest>(proc.proc->sessions.at(1).root);
+ int port2;
+ EXPECT_OK(rootIface2->getClientPort(&port2));
+
+ // we should have a different IBinderRpcTest object created for each
+ // session, because we use setPerSessionRootObject
+ EXPECT_NE(port1, port2);
+}
+
+TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
+ auto proc = createRpcTestSocketServerProcess({});
+ Parcel data;
+ Parcel reply;
+ EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0));
+}
+
+TEST_P(BinderRpc, AppendSeparateFormats) {
+ auto proc1 = createRpcTestSocketServerProcess({});
+ auto proc2 = createRpcTestSocketServerProcess({});
+
+ Parcel pRaw;
+
+ Parcel p1;
+ p1.markForBinder(proc1.rootBinder);
+ p1.writeInt32(3);
+
+ EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, pRaw.dataSize()));
+ EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
+
+ Parcel p2;
+ p2.markForBinder(proc2.rootBinder);
+ p2.writeInt32(7);
+
+ EXPECT_EQ(BAD_TYPE, p1.appendFrom(&p2, 0, p2.dataSize()));
+ EXPECT_EQ(BAD_TYPE, p2.appendFrom(&p1, 0, p1.dataSize()));
+}
+
+TEST_P(BinderRpc, UnknownTransaction) {
+ auto proc = createRpcTestSocketServerProcess({});
+ Parcel data;
+ data.markForBinder(proc.rootBinder);
+ Parcel reply;
+ EXPECT_EQ(UNKNOWN_TRANSACTION, proc.rootBinder->transact(1337, data, &reply, 0));
+}
+
+TEST_P(BinderRpc, SendSomethingOneway) {
+ auto proc = createRpcTestSocketServerProcess({});
+ EXPECT_OK(proc.rootIface->sendString("asdf"));
+}
+
+TEST_P(BinderRpc, SendAndGetResultBack) {
+ auto proc = createRpcTestSocketServerProcess({});
+ std::string doubled;
+ EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
+ EXPECT_EQ("cool cool ", doubled);
+}
+
+TEST_P(BinderRpc, SendAndGetResultBackBig) {
+ auto proc = createRpcTestSocketServerProcess({});
+ std::string single = std::string(1024, 'a');
+ std::string doubled;
+ EXPECT_OK(proc.rootIface->doubleString(single, &doubled));
+ EXPECT_EQ(single + single, doubled);
+}
+
+TEST_P(BinderRpc, InvalidNullBinderReturn) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> outBinder;
+ EXPECT_EQ(proc.rootIface->getNullBinder(&outBinder).transactionError(), UNEXPECTED_NULL);
+}
+
+TEST_P(BinderRpc, CallMeBack) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ int32_t pingResult;
+ EXPECT_OK(proc.rootIface->pingMe(new MyBinderRpcSession("foo"), &pingResult));
+ EXPECT_EQ(OK, pingResult);
+
+ EXPECT_EQ(0, MyBinderRpcSession::gNum);
+}
+
+TEST_P(BinderRpc, RepeatBinder) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> inBinder = new MyBinderRpcSession("foo");
+ sp<IBinder> outBinder;
+ EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
+ EXPECT_EQ(inBinder, outBinder);
+
+ wp<IBinder> weak = inBinder;
+ inBinder = nullptr;
+ outBinder = nullptr;
+
+ // Force reading a reply, to process any pending dec refs from the other
+ // process (the other process will process dec refs there before processing
+ // the ping here).
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ EXPECT_EQ(nullptr, weak.promote());
+
+ EXPECT_EQ(0, MyBinderRpcSession::gNum);
+}
+
+TEST_P(BinderRpc, RepeatTheirBinder) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinderRpcSession> session;
+ EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
+
+ sp<IBinder> inBinder = IInterface::asBinder(session);
+ sp<IBinder> outBinder;
+ EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
+ EXPECT_EQ(inBinder, outBinder);
+
+ wp<IBinder> weak = inBinder;
+ session = nullptr;
+ inBinder = nullptr;
+ outBinder = nullptr;
+
+ // Force reading a reply, to process any pending dec refs from the other
+ // process (the other process will process dec refs there before processing
+ // the ping here).
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ EXPECT_EQ(nullptr, weak.promote());
+}
+
+TEST_P(BinderRpc, RepeatBinderNull) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> outBinder;
+ EXPECT_OK(proc.rootIface->repeatBinder(nullptr, &outBinder));
+ EXPECT_EQ(nullptr, outBinder);
+}
+
+TEST_P(BinderRpc, HoldBinder) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ IBinder* ptr = nullptr;
+ {
+ sp<IBinder> binder = new BBinder();
+ ptr = binder.get();
+ EXPECT_OK(proc.rootIface->holdBinder(binder));
+ }
+
+ sp<IBinder> held;
+ EXPECT_OK(proc.rootIface->getHeldBinder(&held));
+
+ EXPECT_EQ(held.get(), ptr);
+
+ // stop holding binder, because we test to make sure references are cleaned
+ // up
+ EXPECT_OK(proc.rootIface->holdBinder(nullptr));
+ // and flush ref counts
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+}
+
+// START TESTS FOR LIMITATIONS OF SOCKET BINDER
+// These are behavioral differences form regular binder, where certain usecases
+// aren't supported.
+
+TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketSessions) {
+ auto proc1 = createRpcTestSocketServerProcess({});
+ auto proc2 = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> outBinder;
+ EXPECT_EQ(INVALID_OPERATION,
+ proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
+}
+
+TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
+ if (serverSingleThreaded()) {
+ GTEST_SKIP() << "This test requires a multi-threaded service";
+ }
+
+ auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2});
+
+ sp<IBinder> outBinder;
+ EXPECT_EQ(INVALID_OPERATION,
+ proc.rootIface->repeatBinder(proc.proc->sessions.at(1).root, &outBinder)
+ .transactionError());
+}
+
+TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
+ if (!kEnableKernelIpc || noKernel()) {
+ GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+ "at build time.";
+ }
+
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
+ sp<IBinder> outBinder;
+ EXPECT_EQ(INVALID_OPERATION,
+ proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
+}
+
+TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
+ if (!kEnableKernelIpc || noKernel()) {
+ GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+ "at build time.";
+ }
+
+ auto proc = createRpcTestSocketServerProcess({});
+
+ // for historical reasons, IServiceManager interface only returns the
+ // exception code
+ EXPECT_EQ(binder::Status::EX_TRANSACTION_FAILED,
+ defaultServiceManager()->addService(String16("not_suspicious"), proc.rootBinder));
+}
+
+// END TESTS FOR LIMITATIONS OF SOCKET BINDER
+
+TEST_P(BinderRpc, RepeatRootObject) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> outBinder;
+ EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &outBinder));
+ EXPECT_EQ(proc.rootBinder, outBinder);
+}
+
+TEST_P(BinderRpc, NestedTransactions) {
+ auto proc = createRpcTestSocketServerProcess({
+ // Enable FD support because it uses more stack space and so represents
+ // something closer to a worst case scenario.
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::UNIX},
+ });
+
+ auto nastyNester = sp<MyBinderRpcTest>::make();
+ EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
+
+ wp<IBinder> weak = nastyNester;
+ nastyNester = nullptr;
+ EXPECT_EQ(nullptr, weak.promote());
+}
+
+TEST_P(BinderRpc, SameBinderEquality) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> a;
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
+
+ sp<IBinder> b;
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
+
+ EXPECT_EQ(a, b);
+}
+
+TEST_P(BinderRpc, SameBinderEqualityWeak) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> a;
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
+ wp<IBinder> weak = a;
+ a = nullptr;
+
+ sp<IBinder> b;
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
+
+ // this is the wrong behavior, since BpBinder
+ // doesn't implement onIncStrongAttempted
+ // but make sure there is no crash
+ EXPECT_EQ(nullptr, weak.promote());
+
+ GTEST_SKIP() << "Weak binders aren't currently re-promotable for RPC binder.";
+
+ // In order to fix this:
+ // - need to have incStrongAttempted reflected across IPC boundary (wait for
+ // response to promote - round trip...)
+ // - sendOnLastWeakRef, to delete entries out of RpcState table
+ EXPECT_EQ(b, weak.promote());
+}
+
+#define expectSessions(expected, iface) \
+ do { \
+ int session; \
+ EXPECT_OK((iface)->getNumOpenSessions(&session)); \
+ EXPECT_EQ(expected, session); \
+ } while (false)
+
+TEST_P(BinderRpc, SingleSession) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinderRpcSession> session;
+ EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
+ std::string out;
+ EXPECT_OK(session->getName(&out));
+ EXPECT_EQ("aoeu", out);
+
+ expectSessions(1, proc.rootIface);
+ session = nullptr;
+ expectSessions(0, proc.rootIface);
+}
+
+TEST_P(BinderRpc, ManySessions) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ std::vector<sp<IBinderRpcSession>> sessions;
+
+ for (size_t i = 0; i < 15; i++) {
+ expectSessions(i, proc.rootIface);
+ sp<IBinderRpcSession> session;
+ EXPECT_OK(proc.rootIface->openSession(std::to_string(i), &session));
+ sessions.push_back(session);
+ }
+ expectSessions(sessions.size(), proc.rootIface);
+ for (size_t i = 0; i < sessions.size(); i++) {
+ std::string out;
+ EXPECT_OK(sessions.at(i)->getName(&out));
+ EXPECT_EQ(std::to_string(i), out);
+ }
+ expectSessions(sessions.size(), proc.rootIface);
+
+ while (!sessions.empty()) {
+ sessions.pop_back();
+ expectSessions(sessions.size(), proc.rootIface);
+ }
+ expectSessions(0, proc.rootIface);
+}
+
+TEST_P(BinderRpc, OnewayCallDoesNotWait) {
+ constexpr size_t kReallyLongTimeMs = 100;
+ constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
+
+ auto proc = createRpcTestSocketServerProcess({});
+
+ size_t epochMsBefore = epochMillis();
+
+ EXPECT_OK(proc.rootIface->sleepMsAsync(kSleepMs));
+
+ size_t epochMsAfter = epochMillis();
+ EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
+}
+
+TEST_P(BinderRpc, Callbacks) {
+ const static std::string kTestString = "good afternoon!";
+
+ for (bool callIsOneway : {true, false}) {
+ for (bool callbackIsOneway : {true, false}) {
+ for (bool delayed : {true, false}) {
+ if (clientOrServerSingleThreaded() &&
+ (callIsOneway || callbackIsOneway || delayed)) {
+ // we have no incoming connections to receive the callback
+ continue;
+ }
+
+ size_t numIncomingConnections = clientOrServerSingleThreaded() ? 0 : 1;
+ auto proc = createRpcTestSocketServerProcess(
+ {.numThreads = 1,
+ .numSessions = 1,
+ .numIncomingConnections = numIncomingConnections});
+ auto cb = sp<MyBinderRpcCallback>::make();
+
+ if (callIsOneway) {
+ EXPECT_OK(proc.rootIface->doCallbackAsync(cb, callbackIsOneway, delayed,
+ kTestString));
+ } else {
+ EXPECT_OK(
+ proc.rootIface->doCallback(cb, callbackIsOneway, delayed, kTestString));
+ }
+
+ // if both transactions are synchronous and the response is sent back on the
+ // same thread, everything should have happened in a nested call. Otherwise,
+ // the callback will be processed on another thread.
+ if (callIsOneway || callbackIsOneway || delayed) {
+ using std::literals::chrono_literals::operator""s;
+ RpcMutexUniqueLock _l(cb->mMutex);
+ cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
+ }
+
+ EXPECT_EQ(cb->mValues.size(), 1)
+ << "callIsOneway: " << callIsOneway
+ << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
+ if (cb->mValues.empty()) continue;
+ EXPECT_EQ(cb->mValues.at(0), kTestString)
+ << "callIsOneway: " << callIsOneway
+ << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
+
+ // since we are severing the connection, we need to go ahead and
+ // tell the server to shutdown and exit so that waitpid won't hang
+ if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
+ EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+ }
+
+ // since this session has an incoming connection w/ a threadpool, we
+ // need to manually shut it down
+ EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
+ proc.expectAlreadyShutdown = true;
+ }
+ }
+ }
+}
+
+TEST_P(BinderRpc, OnewayCallbackWithNoThread) {
+ auto proc = createRpcTestSocketServerProcess({});
+ auto cb = sp<MyBinderRpcCallback>::make();
+
+ Status status = proc.rootIface->doCallback(cb, true /*oneway*/, false /*delayed*/, "anything");
+ EXPECT_EQ(WOULD_BLOCK, status.transactionError());
+}
+
+TEST_P(BinderRpc, AidlDelegatorTest) {
+ auto proc = createRpcTestSocketServerProcess({});
+ auto myDelegator = sp<IBinderRpcTestDelegator>::make(proc.rootIface);
+ ASSERT_NE(nullptr, myDelegator);
+
+ std::string doubled;
+ EXPECT_OK(myDelegator->doubleString("cool ", &doubled));
+ EXPECT_EQ("cool cool ", doubled);
+}
+
+} // namespace android
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/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp
index 1a8fc1a..2d863c2 100644
--- a/libs/gui/SyncFeatures.cpp
+++ b/libs/gui/SyncFeatures.cpp
@@ -36,8 +36,12 @@
mHasFenceSync(false),
mHasWaitSync(false) {
EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- // This can only be called after EGL has been initialized; otherwise the
- // check below will abort.
+ // eglQueryString can only be called after EGL has been initialized;
+ // otherwise the check below will abort. If RenderEngine is using SkiaVk,
+ // EGL will not have been initialized. There's no problem with initializing
+ // it again here (it is ref counted), and then terminating it later.
+ EGLBoolean initialized = eglInitialize(dpy, nullptr, nullptr);
+ LOG_ALWAYS_FATAL_IF(!initialized, "eglInitialize failed");
const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
LOG_ALWAYS_FATAL_IF(exts == nullptr, "eglQueryString failed");
if (strstr(exts, "EGL_ANDROID_native_fence_sync")) {
@@ -63,6 +67,8 @@
mString.append(" EGL_KHR_wait_sync");
}
mString.append("]");
+ // Terminate EGL to match the eglInitialize above
+ eglTerminate(dpy);
}
bool SyncFeatures::useNativeFenceSync() const {
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/input/VelocityControl.cpp b/libs/input/VelocityControl.cpp
index e2bfb50..5c008b1 100644
--- a/libs/input/VelocityControl.cpp
+++ b/libs/input/VelocityControl.cpp
@@ -37,6 +37,10 @@
reset();
}
+VelocityControlParameters& VelocityControl::getParameters() {
+ return mParameters;
+}
+
void VelocityControl::setParameters(const VelocityControlParameters& parameters) {
mParameters = parameters;
reset();
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
index 8e9b07b..ef9112e 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
@@ -66,7 +66,6 @@
/*
* Convert from scene luminance in nits to HLG, according to BT.2100.
*/
-float hlgOetf(float e);
Color hlgOetf(Color e);
/*
diff --git a/libs/jpegrecoverymap/recoverymapmath.cpp b/libs/jpegrecoverymap/recoverymapmath.cpp
index 3e110bc..368783f 100644
--- a/libs/jpegrecoverymap/recoverymapmath.cpp
+++ b/libs/jpegrecoverymap/recoverymapmath.cpp
@@ -56,7 +56,7 @@
}
}
-float hlgOetf(float e) {
+static float hlgOetf(float e) {
if (e <= 1.0f/12.0f) {
return sqrt(3.0f * e);
} else {
@@ -68,7 +68,7 @@
return {{{ hlgOetf(e.r), hlgOetf(e.g), hlgOetf(e.b) }}};
}
-uint8_t EncodeRecovery(float y_sdr, float y_hdr, float hdr_ratio) {
+uint8_t encodeRecovery(float y_sdr, float y_hdr, float hdr_ratio) {
float gain = 1.0f;
if (y_sdr > 0.0f) {
gain = y_hdr / y_sdr;
@@ -80,8 +80,14 @@
return static_cast<uint8_t>(log2(gain) / log2(hdr_ratio) * 127.5f + 127.5f);
}
-float applyRecovery(float y_sdr, float recovery, float hdr_ratio) {
- return exp2(log2(y_sdr) + recovery * log2(hdr_ratio));
+static float applyRecovery(float e, float recovery, float hdr_ratio) {
+ return exp2(log2(e) + recovery * log2(hdr_ratio));
+}
+
+Color applyRecovery(Color e, float recovery, float hdr_ratio) {
+ return {{{ applyRecovery(e.r, recovery, hdr_ratio),
+ applyRecovery(e.g, recovery, hdr_ratio),
+ applyRecovery(e.b, recovery, hdr_ratio) }}};
}
// TODO: do we need something more clever for filtering either the map or images
@@ -166,4 +172,5 @@
float sampleP010Y(jr_uncompressed_ptr image, size_t map_scale_factor, size_t x, size_t y) {
return sampleComponent(image, map_scale_factor, x, y, getP010Y);
}
+
} // namespace android::recoverymap
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 0540538..04e24ed 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -42,6 +42,7 @@
"libsync",
"libui",
"libutils",
+ "libvulkan",
],
static_libs: [
@@ -97,6 +98,7 @@
"skia/ColorSpaces.cpp",
"skia/SkiaRenderEngine.cpp",
"skia/SkiaGLRenderEngine.cpp",
+ "skia/SkiaVkRenderEngine.cpp",
"skia/debug/CaptureTimer.cpp",
"skia/debug/CommonPool.cpp",
"skia/debug/SkiaCapture.cpp",
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index f1fc0a4..d08c221 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -23,6 +23,7 @@
#include "threaded/RenderEngineThreaded.h"
#include "skia/SkiaGLRenderEngine.h"
+#include "skia/SkiaVkRenderEngine.h"
namespace android {
namespace renderengine {
@@ -37,6 +38,9 @@
case RenderEngineType::SKIA_GL:
ALOGD("RenderEngine with SkiaGL Backend");
return renderengine::skia::SkiaGLRenderEngine::create(args);
+ case RenderEngineType::SKIA_VK:
+ ALOGD("RenderEngine with SkiaVK Backend");
+ return renderengine::skia::SkiaVkRenderEngine::create(args);
case RenderEngineType::SKIA_GL_THREADED: {
ALOGD("Threaded RenderEngine with SkiaGL Backend");
return renderengine::threaded::RenderEngineThreaded::create(
@@ -45,6 +49,13 @@
},
args.renderEngineType);
}
+ case RenderEngineType::SKIA_VK_THREADED:
+ ALOGD("Threaded RenderEngine with SkiaVK Backend");
+ return renderengine::threaded::RenderEngineThreaded::create(
+ [args]() {
+ return android::renderengine::skia::SkiaVkRenderEngine::create(args);
+ },
+ args.renderEngineType);
case RenderEngineType::GLES:
default:
ALOGD("RenderEngine with GLES Backend");
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index d44eb46..bd7b617 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -39,6 +39,10 @@
return "skiaglthreaded";
case RenderEngine::RenderEngineType::SKIA_GL:
return "skiagl";
+ case RenderEngine::RenderEngineType::SKIA_VK:
+ return "skiavk";
+ case RenderEngine::RenderEngineType::SKIA_VK_THREADED:
+ return "skiavkthreaded";
case RenderEngine::RenderEngineType::GLES:
case RenderEngine::RenderEngineType::THREADED:
LOG_ALWAYS_FATAL("GLESRenderEngine is deprecated - why time it?");
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/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 9182feb..39621cd 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -99,6 +99,8 @@
THREADED = 2,
SKIA_GL = 3,
SKIA_GL_THREADED = 4,
+ SKIA_VK = 5,
+ SKIA_VK_THREADED = 6,
};
static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args);
@@ -170,9 +172,16 @@
virtual void cleanupPostRender() = 0;
virtual void cleanFramebufferCache() = 0;
- // Returns the priority this context was actually created with. Note: this may not be
- // the same as specified at context creation time, due to implementation limits on the
- // number of contexts that can be created at a specific priority level in the system.
+
+ // Returns the priority this context was actually created with. Note: this
+ // may not be the same as specified at context creation time, due to
+ // implementation limits on the number of contexts that can be created at a
+ // specific priority level in the system.
+ //
+ // This should return a valid EGL context priority enum as described by
+ // https://registry.khronos.org/EGL/extensions/IMG/EGL_IMG_context_priority.txt
+ // or
+ // https://registry.khronos.org/EGL/extensions/NV/EGL_NV_context_priority_realtime.txt
virtual int getContextPriority() = 0;
// Returns true if blur was requested in the RenderEngineCreationArgs and the implementation
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 347b8b7..ff598e7 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -193,9 +193,9 @@
}
// initialize the renderer while GL is current
- std::unique_ptr<SkiaGLRenderEngine> engine =
- std::make_unique<SkiaGLRenderEngine>(args, display, ctxt, placeholder, protectedContext,
- protectedPlaceholder);
+ std::unique_ptr<SkiaGLRenderEngine> engine(new SkiaGLRenderEngine(args, display, ctxt,
+ placeholder, protectedContext,
+ protectedPlaceholder));
engine->ensureGrContextsCreated();
ALOGI("OpenGL ES informations:");
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 4a37ffe..af33110 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -52,9 +52,6 @@
class SkiaGLRenderEngine : public skia::SkiaRenderEngine {
public:
static std::unique_ptr<SkiaGLRenderEngine> create(const RenderEngineCreationArgs& args);
- SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLContext ctxt,
- EGLSurface placeholder, EGLContext protectedContext,
- EGLSurface protectedPlaceholder);
~SkiaGLRenderEngine() override;
int getContextPriority() override;
@@ -70,6 +67,9 @@
void appendBackendSpecificInfoToDump(std::string& result) override;
private:
+ SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLContext ctxt,
+ EGLSurface placeholder, EGLContext protectedContext,
+ EGLSurface protectedPlaceholder);
bool waitGpuFence(base::borrowed_fd fenceFd);
base::unique_fd flush();
static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index b9aa5ac..413811e 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -388,9 +388,11 @@
void SkiaRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
bool isRenderable) {
- // Only run this if RE is running on its own thread. This way the access to GL
- // operations is guaranteed to be happening on the same thread.
- if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED) {
+ // Only run this if RE is running on its own thread. This
+ // way the access to GL operations is guaranteed to be happening on the
+ // same thread.
+ if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED &&
+ mRenderEngineType != RenderEngineType::SKIA_VK_THREADED) {
return;
}
// We currently don't attempt to map a buffer if the buffer contains protected content
@@ -636,7 +638,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/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
new file mode 100644
index 0000000..f9424f0
--- /dev/null
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -0,0 +1,675 @@
+/*
+ * 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.
+ */
+
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "SkiaVkRenderEngine.h"
+
+#include <GrBackendSemaphore.h>
+#include <GrContextOptions.h>
+#include <vk/GrVkExtensions.h>
+#include <vk/GrVkTypes.h>
+
+#include <android-base/stringprintf.h>
+#include <gui/TraceUtils.h>
+#include <sync/sync.h>
+#include <utils/Trace.h>
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include <vulkan/vulkan.h>
+#include "log/log_main.h"
+
+namespace android {
+namespace renderengine {
+
+struct VulkanFuncs {
+ PFN_vkCreateSemaphore vkCreateSemaphore = nullptr;
+ PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR = nullptr;
+ PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR = nullptr;
+ PFN_vkDestroySemaphore vkDestroySemaphore = nullptr;
+
+ PFN_vkDeviceWaitIdle vkDeviceWaitIdle = nullptr;
+ PFN_vkDestroyDevice vkDestroyDevice = nullptr;
+ PFN_vkDestroyInstance vkDestroyInstance = nullptr;
+};
+
+struct VulkanInterface {
+ bool initialized = false;
+ VkInstance instance;
+ VkPhysicalDevice physicalDevice;
+ VkDevice device;
+ VkQueue queue;
+ int queueIndex;
+ uint32_t apiVersion;
+ GrVkExtensions grExtensions;
+ VkPhysicalDeviceFeatures2* physicalDeviceFeatures2 = nullptr;
+ VkPhysicalDeviceSamplerYcbcrConversionFeatures* samplerYcbcrConversionFeatures = nullptr;
+ VkPhysicalDeviceProtectedMemoryProperties* protectedMemoryFeatures = nullptr;
+ GrVkGetProc grGetProc;
+ bool isProtected;
+ bool isRealtimePriority;
+
+ VulkanFuncs funcs;
+
+ std::vector<std::string> instanceExtensionNames;
+ std::vector<std::string> deviceExtensionNames;
+
+ GrVkBackendContext getBackendContext() {
+ GrVkBackendContext backendContext;
+ backendContext.fInstance = instance;
+ backendContext.fPhysicalDevice = physicalDevice;
+ backendContext.fDevice = device;
+ backendContext.fQueue = queue;
+ backendContext.fGraphicsQueueIndex = queueIndex;
+ backendContext.fMaxAPIVersion = apiVersion;
+ backendContext.fVkExtensions = &grExtensions;
+ backendContext.fDeviceFeatures2 = physicalDeviceFeatures2;
+ backendContext.fGetProc = grGetProc;
+ backendContext.fProtectedContext = isProtected ? GrProtected::kYes : GrProtected::kNo;
+ return backendContext;
+ };
+
+ VkSemaphore createExportableSemaphore() {
+ VkExportSemaphoreCreateInfo exportInfo;
+ exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
+ exportInfo.pNext = nullptr;
+ exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+
+ VkSemaphoreCreateInfo semaphoreInfo;
+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semaphoreInfo.pNext = &exportInfo;
+ semaphoreInfo.flags = 0;
+
+ VkSemaphore semaphore;
+ VkResult err = funcs.vkCreateSemaphore(device, &semaphoreInfo, nullptr, &semaphore);
+ if (VK_SUCCESS != err) {
+ ALOGE("%s: failed to create semaphore. err %d\n", __func__, err);
+ return VK_NULL_HANDLE;
+ }
+
+ return semaphore;
+ }
+
+ // syncFd cannot be <= 0
+ VkSemaphore importSemaphoreFromSyncFd(int syncFd) {
+ VkSemaphoreCreateInfo semaphoreInfo;
+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semaphoreInfo.pNext = nullptr;
+ semaphoreInfo.flags = 0;
+
+ VkSemaphore semaphore;
+ VkResult err = funcs.vkCreateSemaphore(device, &semaphoreInfo, nullptr, &semaphore);
+ if (VK_SUCCESS != err) {
+ ALOGE("%s: failed to create import semaphore", __func__);
+ return VK_NULL_HANDLE;
+ }
+
+ VkImportSemaphoreFdInfoKHR importInfo;
+ importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
+ importInfo.pNext = nullptr;
+ importInfo.semaphore = semaphore;
+ importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
+ importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+ importInfo.fd = syncFd;
+
+ err = funcs.vkImportSemaphoreFdKHR(device, &importInfo);
+ if (VK_SUCCESS != err) {
+ funcs.vkDestroySemaphore(device, semaphore, nullptr);
+ ALOGE("%s: failed to import semaphore", __func__);
+ return VK_NULL_HANDLE;
+ }
+
+ return semaphore;
+ }
+
+ int exportSemaphoreSyncFd(VkSemaphore semaphore) {
+ int res;
+
+ VkSemaphoreGetFdInfoKHR getFdInfo;
+ getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
+ getFdInfo.pNext = nullptr;
+ getFdInfo.semaphore = semaphore;
+ getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+
+ VkResult err = funcs.vkGetSemaphoreFdKHR(device, &getFdInfo, &res);
+ if (VK_SUCCESS != err) {
+ ALOGE("%s: failed to export semaphore, err: %d", __func__, err);
+ return -1;
+ }
+ return res;
+ }
+
+ void destroySemaphore(VkSemaphore semaphore) {
+ funcs.vkDestroySemaphore(device, semaphore, nullptr);
+ }
+};
+
+static GrVkGetProc sGetProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
+ if (device != VK_NULL_HANDLE) {
+ return vkGetDeviceProcAddr(device, proc_name);
+ }
+ return vkGetInstanceProcAddr(instance, proc_name);
+};
+
+#define BAIL(fmt, ...) \
+ { \
+ ALOGE("%s: " fmt ", bailing", __func__, ##__VA_ARGS__); \
+ return interface; \
+ }
+
+#define CHECK_NONNULL(expr) \
+ if ((expr) == nullptr) { \
+ BAIL("[%s] null", #expr); \
+ }
+
+#define VK_CHECK(expr) \
+ if ((expr) != VK_SUCCESS) { \
+ BAIL("[%s] failed. err = %d", #expr, expr); \
+ return interface; \
+ }
+
+#define VK_GET_PROC(F) \
+ PFN_vk##F vk##F = (PFN_vk##F)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vk" #F); \
+ CHECK_NONNULL(vk##F)
+#define VK_GET_INST_PROC(instance, F) \
+ PFN_vk##F vk##F = (PFN_vk##F)vkGetInstanceProcAddr(instance, "vk" #F); \
+ CHECK_NONNULL(vk##F)
+#define VK_GET_DEV_PROC(device, F) \
+ PFN_vk##F vk##F = (PFN_vk##F)vkGetDeviceProcAddr(device, "vk" #F); \
+ CHECK_NONNULL(vk##F)
+
+VulkanInterface initVulkanInterface(bool protectedContent = false) {
+ VulkanInterface interface;
+
+ VK_GET_PROC(EnumerateInstanceVersion);
+ uint32_t instanceVersion;
+ VK_CHECK(vkEnumerateInstanceVersion(&instanceVersion));
+
+ if (instanceVersion < VK_MAKE_VERSION(1, 1, 0)) {
+ return interface;
+ }
+
+ const VkApplicationInfo appInfo = {
+ VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr, "surfaceflinger", 0, "android platform", 0,
+ VK_MAKE_VERSION(1, 1, 0),
+ };
+
+ VK_GET_PROC(EnumerateInstanceExtensionProperties);
+
+ uint32_t extensionCount = 0;
+ VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr));
+ std::vector<VkExtensionProperties> instanceExtensions(extensionCount);
+ VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount,
+ instanceExtensions.data()));
+ std::vector<const char*> enabledInstanceExtensionNames;
+ enabledInstanceExtensionNames.reserve(instanceExtensions.size());
+ interface.instanceExtensionNames.reserve(instanceExtensions.size());
+ for (const auto& instExt : instanceExtensions) {
+ enabledInstanceExtensionNames.push_back(instExt.extensionName);
+ interface.instanceExtensionNames.push_back(instExt.extensionName);
+ }
+
+ const VkInstanceCreateInfo instanceCreateInfo = {
+ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+ nullptr,
+ 0,
+ &appInfo,
+ 0,
+ nullptr,
+ (uint32_t)enabledInstanceExtensionNames.size(),
+ enabledInstanceExtensionNames.data(),
+ };
+
+ VK_GET_PROC(CreateInstance);
+ VkInstance instance;
+ VK_CHECK(vkCreateInstance(&instanceCreateInfo, nullptr, &instance));
+
+ VK_GET_INST_PROC(instance, DestroyInstance);
+ interface.funcs.vkDestroyInstance = vkDestroyInstance;
+ VK_GET_INST_PROC(instance, EnumeratePhysicalDevices);
+ VK_GET_INST_PROC(instance, EnumerateDeviceExtensionProperties);
+ VK_GET_INST_PROC(instance, GetPhysicalDeviceProperties2);
+ VK_GET_INST_PROC(instance, GetPhysicalDeviceExternalSemaphoreProperties);
+ VK_GET_INST_PROC(instance, GetPhysicalDeviceQueueFamilyProperties);
+ VK_GET_INST_PROC(instance, GetPhysicalDeviceFeatures2);
+ VK_GET_INST_PROC(instance, CreateDevice);
+
+ uint32_t physdevCount;
+ VK_CHECK(vkEnumeratePhysicalDevices(instance, &physdevCount, nullptr));
+ if (physdevCount == 0) {
+ BAIL("Could not find any physical devices");
+ }
+
+ physdevCount = 1;
+ VkPhysicalDevice physicalDevice;
+ VkResult enumeratePhysDevsErr =
+ vkEnumeratePhysicalDevices(instance, &physdevCount, &physicalDevice);
+ if (enumeratePhysDevsErr != VK_SUCCESS && VK_INCOMPLETE != enumeratePhysDevsErr) {
+ BAIL("vkEnumeratePhysicalDevices failed with non-VK_INCOMPLETE error: %d",
+ enumeratePhysDevsErr);
+ }
+
+ VkPhysicalDeviceProperties2 physDevProps = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
+ 0,
+ {},
+ };
+ VkPhysicalDeviceProtectedMemoryProperties protMemProps = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
+ 0,
+ {},
+ };
+
+ if (protectedContent) {
+ physDevProps.pNext = &protMemProps;
+ }
+
+ vkGetPhysicalDeviceProperties2(physicalDevice, &physDevProps);
+ if (physDevProps.properties.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
+ BAIL("Could not find a Vulkan 1.1+ physical device");
+ }
+
+ // Check for syncfd support. Bail if we cannot both import and export them.
+ VkPhysicalDeviceExternalSemaphoreInfo semInfo = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
+ nullptr,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+ };
+ VkExternalSemaphoreProperties semProps = {
+ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, nullptr, 0, 0, 0,
+ };
+ vkGetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, &semInfo, &semProps);
+
+ bool sufficientSemaphoreSyncFdSupport = (semProps.exportFromImportedHandleTypes &
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
+ (semProps.compatibleHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
+ (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) &&
+ (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
+
+ if (!sufficientSemaphoreSyncFdSupport) {
+ BAIL("Vulkan device does not support sufficient external semaphore sync fd features. "
+ "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
+ "compatibleHandleTypes 0x%x (needed 0x%x) "
+ "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
+ semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+ semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+ semProps.externalSemaphoreFeatures,
+ VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
+ VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
+ } else {
+ ALOGD("Vulkan device supports sufficient external semaphore sync fd features. "
+ "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
+ "compatibleHandleTypes 0x%x (needed 0x%x) "
+ "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
+ semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+ semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+ semProps.externalSemaphoreFeatures,
+ VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
+ VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
+ }
+
+ uint32_t queueCount;
+ vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, nullptr);
+ if (queueCount == 0) {
+ BAIL("Could not find queues for physical device");
+ }
+
+ std::vector<VkQueueFamilyProperties> queueProps(queueCount);
+ vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps.data());
+
+ int graphicsQueueIndex = -1;
+ for (uint32_t i = 0; i < queueCount; ++i) {
+ if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+ graphicsQueueIndex = i;
+ break;
+ }
+ }
+
+ if (graphicsQueueIndex == -1) {
+ BAIL("Could not find a graphics queue family");
+ }
+
+ uint32_t deviceExtensionCount;
+ VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
+ nullptr));
+ std::vector<VkExtensionProperties> deviceExtensions(deviceExtensionCount);
+ VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
+ deviceExtensions.data()));
+
+ std::vector<const char*> enabledDeviceExtensionNames;
+ enabledDeviceExtensionNames.reserve(deviceExtensions.size());
+ interface.deviceExtensionNames.reserve(deviceExtensions.size());
+ for (const auto& devExt : deviceExtensions) {
+ enabledDeviceExtensionNames.push_back(devExt.extensionName);
+ interface.deviceExtensionNames.push_back(devExt.extensionName);
+ }
+
+ interface.grExtensions.init(sGetProc, instance, physicalDevice,
+ enabledInstanceExtensionNames.size(),
+ enabledInstanceExtensionNames.data(),
+ enabledDeviceExtensionNames.size(),
+ enabledDeviceExtensionNames.data());
+
+ if (!interface.grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
+ BAIL("Vulkan driver doesn't support external semaphore fd");
+ }
+
+ interface.physicalDeviceFeatures2 = new VkPhysicalDeviceFeatures2;
+ interface.physicalDeviceFeatures2->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ interface.physicalDeviceFeatures2->pNext = nullptr;
+
+ interface.samplerYcbcrConversionFeatures = new VkPhysicalDeviceSamplerYcbcrConversionFeatures;
+ interface.samplerYcbcrConversionFeatures->sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
+ interface.samplerYcbcrConversionFeatures->pNext = nullptr;
+
+ interface.physicalDeviceFeatures2->pNext = interface.samplerYcbcrConversionFeatures;
+ void** tailPnext = &interface.samplerYcbcrConversionFeatures->pNext;
+
+ if (protectedContent) {
+ interface.protectedMemoryFeatures = new VkPhysicalDeviceProtectedMemoryProperties;
+ interface.protectedMemoryFeatures->sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
+ interface.protectedMemoryFeatures->pNext = nullptr;
+ *tailPnext = interface.protectedMemoryFeatures;
+ tailPnext = &interface.protectedMemoryFeatures->pNext;
+ }
+
+ vkGetPhysicalDeviceFeatures2(physicalDevice, interface.physicalDeviceFeatures2);
+ // Looks like this would slow things down and we can't depend on it on all platforms
+ interface.physicalDeviceFeatures2->features.robustBufferAccess = VK_FALSE;
+
+ float queuePriorities[1] = {0.0f};
+ void* queueNextPtr = nullptr;
+
+ VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo = {
+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT,
+ nullptr,
+ // If queue priority is supported, RE should always have realtime priority.
+ VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT,
+ };
+
+ if (interface.grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
+ queueNextPtr = &queuePriorityCreateInfo;
+ interface.isRealtimePriority = true;
+ }
+
+ VkDeviceQueueCreateFlags deviceQueueCreateFlags =
+ (VkDeviceQueueCreateFlags)(protectedContent ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0);
+
+ const VkDeviceQueueCreateInfo queueInfo = {
+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ queueNextPtr,
+ deviceQueueCreateFlags,
+ (uint32_t)graphicsQueueIndex,
+ 1,
+ queuePriorities,
+ };
+
+ const VkDeviceCreateInfo deviceInfo = {
+ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ interface.physicalDeviceFeatures2,
+ 0,
+ 1,
+ &queueInfo,
+ 0,
+ nullptr,
+ (uint32_t)enabledDeviceExtensionNames.size(),
+ enabledDeviceExtensionNames.data(),
+ nullptr,
+ };
+
+ ALOGD("Trying to create Vk device with protectedContent=%d", protectedContent);
+ VkDevice device;
+ VK_CHECK(vkCreateDevice(physicalDevice, &deviceInfo, nullptr, &device));
+ ALOGD("Trying to create Vk device with protectedContent=%d (success)", protectedContent);
+
+ VkQueue graphicsQueue;
+ VK_GET_DEV_PROC(device, GetDeviceQueue);
+ vkGetDeviceQueue(device, graphicsQueueIndex, 0, &graphicsQueue);
+
+ VK_GET_DEV_PROC(device, DeviceWaitIdle);
+ VK_GET_DEV_PROC(device, DestroyDevice);
+ interface.funcs.vkDeviceWaitIdle = vkDeviceWaitIdle;
+ interface.funcs.vkDestroyDevice = vkDestroyDevice;
+
+ VK_GET_DEV_PROC(device, CreateSemaphore);
+ VK_GET_DEV_PROC(device, ImportSemaphoreFdKHR);
+ VK_GET_DEV_PROC(device, GetSemaphoreFdKHR);
+ VK_GET_DEV_PROC(device, DestroySemaphore);
+ interface.funcs.vkCreateSemaphore = vkCreateSemaphore;
+ interface.funcs.vkImportSemaphoreFdKHR = vkImportSemaphoreFdKHR;
+ interface.funcs.vkGetSemaphoreFdKHR = vkGetSemaphoreFdKHR;
+ interface.funcs.vkDestroySemaphore = vkDestroySemaphore;
+
+ // At this point, everything's succeeded and we can continue
+ interface.initialized = true;
+ interface.instance = instance;
+ interface.physicalDevice = physicalDevice;
+ interface.device = device;
+ interface.queue = graphicsQueue;
+ interface.queueIndex = graphicsQueueIndex;
+ interface.apiVersion = physDevProps.properties.apiVersion;
+ // grExtensions already constructed
+ // feature pointers already constructed
+ interface.grGetProc = sGetProc;
+ interface.isProtected = protectedContent;
+ // funcs already initialized
+
+ ALOGD("%s: Success init Vulkan interface", __func__);
+ return interface;
+}
+
+void teardownVulkanInterface(VulkanInterface* interface) {
+ interface->initialized = false;
+
+ if (interface->device != VK_NULL_HANDLE) {
+ interface->funcs.vkDeviceWaitIdle(interface->device);
+ interface->funcs.vkDestroyDevice(interface->device, nullptr);
+ interface->device = VK_NULL_HANDLE;
+ }
+ if (interface->instance != VK_NULL_HANDLE) {
+ interface->funcs.vkDestroyInstance(interface->instance, nullptr);
+ interface->instance = VK_NULL_HANDLE;
+ }
+
+ if (interface->protectedMemoryFeatures) {
+ delete interface->protectedMemoryFeatures;
+ }
+
+ if (interface->samplerYcbcrConversionFeatures) {
+ delete interface->samplerYcbcrConversionFeatures;
+ }
+
+ if (interface->physicalDeviceFeatures2) {
+ delete interface->physicalDeviceFeatures2;
+ }
+
+ interface->samplerYcbcrConversionFeatures = nullptr;
+ interface->physicalDeviceFeatures2 = nullptr;
+ interface->protectedMemoryFeatures = nullptr;
+}
+
+static VulkanInterface sVulkanInterface;
+static VulkanInterface sProtectedContentVulkanInterface;
+
+static void sSetupVulkanInterface() {
+ if (!sVulkanInterface.initialized) {
+ sVulkanInterface = initVulkanInterface(false /* no protected content */);
+ // We will have to abort if non-protected VkDevice creation fails (then nothing works).
+ LOG_ALWAYS_FATAL_IF(!sVulkanInterface.initialized,
+ "Could not initialize Vulkan RenderEngine!");
+ }
+ if (!sProtectedContentVulkanInterface.initialized) {
+ sProtectedContentVulkanInterface = initVulkanInterface(true /* protected content */);
+ if (!sProtectedContentVulkanInterface.initialized) {
+ ALOGE("Could not initialize protected content Vulkan RenderEngine.");
+ }
+ }
+}
+
+namespace skia {
+
+using base::StringAppendF;
+
+bool SkiaVkRenderEngine::canSupportSkiaVkRenderEngine() {
+ VulkanInterface temp = initVulkanInterface(false /* no protected content */);
+ ALOGD("SkiaVkRenderEngine::canSupportSkiaVkRenderEngine(): initialized == %s.",
+ temp.initialized ? "true" : "false");
+ return temp.initialized;
+}
+
+std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create(
+ const RenderEngineCreationArgs& args) {
+ std::unique_ptr<SkiaVkRenderEngine> engine(new SkiaVkRenderEngine(args));
+ engine->ensureGrContextsCreated();
+
+ if (sVulkanInterface.initialized) {
+ ALOGD("SkiaVkRenderEngine::%s: successfully initialized SkiaVkRenderEngine", __func__);
+ return engine;
+ } else {
+ ALOGD("SkiaVkRenderEngine::%s: could not create SkiaVkRenderEngine. "
+ "Likely insufficient Vulkan support",
+ __func__);
+ return {};
+ }
+}
+
+SkiaVkRenderEngine::SkiaVkRenderEngine(const RenderEngineCreationArgs& args)
+ : SkiaRenderEngine(args.renderEngineType, static_cast<PixelFormat>(args.pixelFormat),
+ args.useColorManagement, args.supportsBackgroundBlur) {}
+
+SkiaVkRenderEngine::~SkiaVkRenderEngine() {
+ finishRenderingAndAbandonContext();
+}
+
+SkiaRenderEngine::Contexts SkiaVkRenderEngine::createDirectContexts(
+ const GrContextOptions& options) {
+ sSetupVulkanInterface();
+
+ SkiaRenderEngine::Contexts contexts;
+ contexts.first = GrDirectContext::MakeVulkan(sVulkanInterface.getBackendContext(), options);
+ if (supportsProtectedContentImpl()) {
+ contexts.second =
+ GrDirectContext::MakeVulkan(sProtectedContentVulkanInterface.getBackendContext(),
+ options);
+ }
+
+ return contexts;
+}
+
+bool SkiaVkRenderEngine::supportsProtectedContentImpl() const {
+ return sProtectedContentVulkanInterface.initialized;
+}
+
+bool SkiaVkRenderEngine::useProtectedContextImpl(GrProtected) {
+ return true;
+}
+
+static void delete_semaphore(void* _semaphore) {
+ VkSemaphore semaphore = (VkSemaphore)_semaphore;
+ sVulkanInterface.destroySemaphore(semaphore);
+}
+
+static void delete_semaphore_protected(void* _semaphore) {
+ VkSemaphore semaphore = (VkSemaphore)_semaphore;
+ sProtectedContentVulkanInterface.destroySemaphore(semaphore);
+}
+
+static VulkanInterface& getVulkanInterface(bool protectedContext) {
+ if (protectedContext) {
+ return sProtectedContentVulkanInterface;
+ }
+ return sVulkanInterface;
+}
+
+void SkiaVkRenderEngine::waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) {
+ if (fenceFd.get() < 0) return;
+
+ int dupedFd = dup(fenceFd.get());
+ if (dupedFd < 0) {
+ ALOGE("failed to create duplicate fence fd: %d", dupedFd);
+ sync_wait(fenceFd.get(), -1);
+ return;
+ }
+
+ base::unique_fd fenceDup(dupedFd);
+ VkSemaphore waitSemaphore =
+ getVulkanInterface(isProtected()).importSemaphoreFromSyncFd(fenceDup.release());
+ GrBackendSemaphore beSemaphore;
+ beSemaphore.initVulkan(waitSemaphore);
+ grContext->wait(1, &beSemaphore, true /* delete after wait */);
+}
+
+base::unique_fd SkiaVkRenderEngine::flushAndSubmit(GrDirectContext* grContext) {
+ VkSemaphore signalSemaphore = getVulkanInterface(isProtected()).createExportableSemaphore();
+ GrBackendSemaphore beSignalSemaphore;
+ beSignalSemaphore.initVulkan(signalSemaphore);
+ GrFlushInfo flushInfo;
+ flushInfo.fNumSemaphores = 1;
+ flushInfo.fSignalSemaphores = &beSignalSemaphore;
+ flushInfo.fFinishedProc = isProtected() ? delete_semaphore_protected : delete_semaphore;
+ flushInfo.fFinishedContext = (void*)signalSemaphore;
+ GrSemaphoresSubmitted submitted = grContext->flush(flushInfo);
+ grContext->submit(false /* no cpu sync */);
+ int drawFenceFd = -1;
+ if (GrSemaphoresSubmitted::kYes == submitted) {
+ drawFenceFd = getVulkanInterface(isProtected()).exportSemaphoreSyncFd(signalSemaphore);
+ }
+ base::unique_fd res(drawFenceFd);
+ return res;
+}
+
+int SkiaVkRenderEngine::getContextPriority() {
+ // EGL_CONTEXT_PRIORITY_REALTIME_NV
+ constexpr int kRealtimePriority = 0x3357;
+ if (getVulkanInterface(isProtected()).isRealtimePriority) {
+ return kRealtimePriority;
+ } else {
+ return 0;
+ }
+}
+
+void SkiaVkRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
+ StringAppendF(&result, "\n ------------RE Vulkan----------\n");
+ StringAppendF(&result, "\n Vulkan device initialized: %d\n", sVulkanInterface.initialized);
+ StringAppendF(&result, "\n Vulkan protected device initialized: %d\n",
+ sProtectedContentVulkanInterface.initialized);
+
+ if (!sVulkanInterface.initialized) {
+ return;
+ }
+
+ StringAppendF(&result, "\n Instance extensions:\n");
+ for (const auto& name : sVulkanInterface.instanceExtensionNames) {
+ StringAppendF(&result, "\n %s\n", name.c_str());
+ }
+
+ StringAppendF(&result, "\n Device extensions:\n");
+ for (const auto& name : sVulkanInterface.deviceExtensionNames) {
+ StringAppendF(&result, "\n %s\n", name.c_str());
+ }
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.h b/libs/renderengine/skia/SkiaVkRenderEngine.h
new file mode 100644
index 0000000..2e0cf45
--- /dev/null
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef SF_SKIAVKRENDERENGINE_H_
+#define SF_SKIAVKRENDERENGINE_H_
+
+#include <vk/GrVkBackendContext.h>
+
+#include "SkiaRenderEngine.h"
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+class SkiaVkRenderEngine : public SkiaRenderEngine {
+public:
+ // Returns false if Vulkan implementation can't support SkiaVkRenderEngine.
+ static bool canSupportSkiaVkRenderEngine();
+ static std::unique_ptr<SkiaVkRenderEngine> create(const RenderEngineCreationArgs& args);
+ ~SkiaVkRenderEngine() override;
+
+ int getContextPriority() override;
+
+protected:
+ // Implementations of abstract SkiaRenderEngine functions specific to
+ // rendering backend
+ virtual SkiaRenderEngine::Contexts createDirectContexts(const GrContextOptions& options);
+ bool supportsProtectedContentImpl() const override;
+ bool useProtectedContextImpl(GrProtected isProtected) override;
+ void waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) override;
+ base::unique_fd flushAndSubmit(GrDirectContext* context) override;
+ void appendBackendSpecificInfoToDump(std::string& result) override;
+
+private:
+ SkiaVkRenderEngine(const RenderEngineCreationArgs& args);
+ base::unique_fd flush();
+
+ GrVkBackendContext mBackendContext;
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
+
+#endif
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 777d02f..f3f2da8 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -38,6 +38,7 @@
#include <fstream>
#include "../skia/SkiaGLRenderEngine.h"
+#include "../skia/SkiaVkRenderEngine.h"
#include "../threaded/RenderEngineThreaded.h"
constexpr int DEFAULT_DISPLAY_WIDTH = 128;
@@ -107,9 +108,50 @@
virtual std::string name() = 0;
virtual renderengine::RenderEngine::RenderEngineType type() = 0;
virtual std::unique_ptr<renderengine::RenderEngine> createRenderEngine() = 0;
+ virtual bool typeSupported() = 0;
virtual bool useColorManagement() const = 0;
};
+class SkiaVkRenderEngineFactory : public RenderEngineFactory {
+public:
+ std::string name() override { return "SkiaVkRenderEngineFactory"; }
+
+ renderengine::RenderEngine::RenderEngineType type() {
+ return renderengine::RenderEngine::RenderEngineType::SKIA_VK;
+ }
+
+ std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
+ std::unique_ptr<renderengine::RenderEngine> re = createSkiaVkRenderEngine();
+ return re;
+ }
+
+ std::unique_ptr<renderengine::skia::SkiaVkRenderEngine> createSkiaVkRenderEngine() {
+ renderengine::RenderEngineCreationArgs reCreationArgs =
+ renderengine::RenderEngineCreationArgs::Builder()
+ .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+ .setImageCacheSize(1)
+ .setUseColorManagerment(false)
+ .setEnableProtectedContext(false)
+ .setPrecacheToneMapperShaderOnly(false)
+ .setSupportsBackgroundBlur(true)
+ .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
+ .setRenderEngineType(type())
+ .setUseColorManagerment(useColorManagement())
+ .build();
+ return renderengine::skia::SkiaVkRenderEngine::create(reCreationArgs);
+ }
+
+ bool typeSupported() override {
+ return skia::SkiaVkRenderEngine::canSupportSkiaVkRenderEngine();
+ }
+ bool useColorManagement() const override { return false; }
+ void skip() { GTEST_SKIP(); }
+};
+
+class SkiaVkCMRenderEngineFactory : public SkiaVkRenderEngineFactory {
+public:
+ bool useColorManagement() const override { return true; }
+};
class SkiaGLESRenderEngineFactory : public RenderEngineFactory {
public:
std::string name() override { return "SkiaGLRenderEngineFactory"; }
@@ -133,6 +175,7 @@
return renderengine::skia::SkiaGLRenderEngine::create(reCreationArgs);
}
+ bool typeSupported() override { return true; }
bool useColorManagement() const override { return false; }
};
@@ -159,6 +202,7 @@
return renderengine::skia::SkiaGLRenderEngine::create(reCreationArgs);
}
+ bool typeSupported() override { return true; }
bool useColorManagement() const override { return true; }
};
@@ -1515,14 +1559,22 @@
INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
testing::Values(std::make_shared<SkiaGLESRenderEngineFactory>(),
- std::make_shared<SkiaGLESCMRenderEngineFactory>()));
+ std::make_shared<SkiaGLESCMRenderEngineFactory>(),
+ std::make_shared<SkiaVkRenderEngineFactory>(),
+ std::make_shared<SkiaVkCMRenderEngineFactory>()));
TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
drawEmptyLayers();
}
TEST_P(RenderEngineTest, drawLayers_fillRedBufferAndEmptyBuffer) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
@@ -1547,6 +1599,9 @@
}
TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
renderengine::DisplaySettings settings;
@@ -1578,6 +1633,9 @@
}
TEST_P(RenderEngineTest, drawLayers_nullOutputBuffer) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
renderengine::DisplaySettings settings;
@@ -1597,56 +1655,89 @@
}
TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillRedBuffer<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillGreenBuffer<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBlueBuffer<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillRedTransparentBuffer<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferPhysicalOffset<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferCheckersRotate0<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferCheckersRotate90<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferCheckersRotate180<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferCheckersRotate270<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferLayerTransform<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferColorTransform<ColorSourceVariant>();
}
@@ -1654,7 +1745,7 @@
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_sourceDataspace) {
const auto& renderEngineFactory = GetParam();
// skip for non color management
- if (!renderEngineFactory->useColorManagement()) {
+ if (!renderEngineFactory->typeSupported() || !renderEngineFactory->useColorManagement()) {
GTEST_SKIP();
}
@@ -1665,7 +1756,7 @@
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_outputDataspace) {
const auto& renderEngineFactory = GetParam();
// skip for non color management
- if (!renderEngineFactory->useColorManagement()) {
+ if (!renderEngineFactory->typeSupported() || !renderEngineFactory->useColorManagement()) {
GTEST_SKIP();
}
@@ -1674,81 +1765,129 @@
}
TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferWithRoundedCorners<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferColorTransformZeroLayerAlpha<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferAndBlurBackground<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillSmallLayerAndBlurBackground<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
overlayCorners<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillRedBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillGreenBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBlueBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillRedTransparentBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferPhysicalOffset<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferCheckersRotate0<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferCheckersRotate90<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferCheckersRotate180<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferCheckersRotate270<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferColorTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
@@ -1756,7 +1895,7 @@
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_opaqueBufferSource) {
const auto& renderEngineFactory = GetParam();
// skip for non color management
- if (!renderEngineFactory->useColorManagement()) {
+ if (!renderEngineFactory->typeSupported() || !renderEngineFactory->useColorManagement()) {
GTEST_SKIP();
}
@@ -1767,7 +1906,7 @@
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_opaqueBufferSource) {
const auto& renderEngineFactory = GetParam();
// skip for non color management
- if (!renderEngineFactory->useColorManagement()) {
+ if (!renderEngineFactory->typeSupported() || !renderEngineFactory->useColorManagement()) {
GTEST_SKIP();
}
@@ -1776,81 +1915,129 @@
}
TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillSmallLayerAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillRedBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillGreenBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBlueBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillRedTransparentBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferPhysicalOffset<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferCheckersRotate0<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferCheckersRotate90<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferCheckersRotate180<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferCheckersRotate270<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferColorTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
@@ -1858,7 +2045,7 @@
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_bufferSource) {
const auto& renderEngineFactory = GetParam();
// skip for non color management
- if (!renderEngineFactory->useColorManagement()) {
+ if (!renderEngineFactory->typeSupported() || !renderEngineFactory->useColorManagement()) {
GTEST_SKIP();
}
@@ -1869,7 +2056,7 @@
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_bufferSource) {
const auto& renderEngineFactory = GetParam();
// skip for non color management
- if (!renderEngineFactory->useColorManagement()) {
+ if (!renderEngineFactory->typeSupported() || !renderEngineFactory->useColorManagement()) {
GTEST_SKIP();
}
@@ -1878,46 +2065,73 @@
}
TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillSmallLayerAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferTextureTransform();
}
TEST_P(RenderEngineTest, drawLayers_fillBuffer_premultipliesAlpha) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferWithPremultiplyAlpha();
}
TEST_P(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
fillBufferWithoutPremultiplyAlpha();
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const ubyte4 backgroundColor(static_cast<uint8_t>(255), static_cast<uint8_t>(255),
@@ -1934,6 +2148,9 @@
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const ubyte4 casterColor(static_cast<uint8_t>(255), static_cast<uint8_t>(0),
@@ -1955,6 +2172,9 @@
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterColorLayer) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const ubyte4 casterColor(static_cast<uint8_t>(255), static_cast<uint8_t>(0),
@@ -1977,6 +2197,9 @@
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterOpaqueBufferLayer) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const ubyte4 casterColor(static_cast<uint8_t>(255), static_cast<uint8_t>(0),
@@ -2000,6 +2223,9 @@
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const ubyte4 casterColor(static_cast<uint8_t>(255), static_cast<uint8_t>(0),
@@ -2024,6 +2250,9 @@
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_translucentCasterWithAlpha) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const ubyte4 casterColor(255, 0, 0, 255);
@@ -2051,6 +2280,9 @@
}
TEST_P(RenderEngineTest, cleanupPostRender_cleansUpOnce) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
renderengine::DisplaySettings settings;
@@ -2081,12 +2313,20 @@
fenceTwo->waitForever(LOG_TAG);
// Only cleanup the first time.
- EXPECT_FALSE(mRE->canSkipPostRenderCleanup());
- mRE->cleanupPostRender();
- EXPECT_TRUE(mRE->canSkipPostRenderCleanup());
+ if (mRE->canSkipPostRenderCleanup()) {
+ // Skia's Vk backend may keep the texture alive beyond drawLayersInternal, so
+ // it never gets added to the cleanup list. In those cases, we can skip.
+ EXPECT_TRUE(GetParam()->type() == renderengine::RenderEngine::RenderEngineType::SKIA_VK);
+ } else {
+ mRE->cleanupPostRender();
+ EXPECT_TRUE(mRE->canSkipPostRenderCleanup());
+ }
}
TEST_P(RenderEngineTest, testRoundedCornersCrop) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
renderengine::DisplaySettings settings;
@@ -2137,6 +2377,9 @@
}
TEST_P(RenderEngineTest, testRoundedCornersParentCrop) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
renderengine::DisplaySettings settings;
@@ -2182,6 +2425,9 @@
}
TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
renderengine::DisplaySettings settings;
@@ -2259,6 +2505,9 @@
}
TEST_P(RenderEngineTest, testClear) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const auto rect = fullscreenRect();
@@ -2288,6 +2537,9 @@
}
TEST_P(RenderEngineTest, testDisableBlendingBuffer) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const auto rect = Rect(0, 0, 1, 1);
@@ -2385,6 +2637,9 @@
}
TEST_P(RenderEngineTest, testDimming) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -2457,6 +2712,9 @@
}
TEST_P(RenderEngineTest, testDimming_inGammaSpace) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
@@ -2532,6 +2790,9 @@
}
TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
@@ -2592,6 +2853,9 @@
}
TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform_deviceHandles) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
@@ -2653,6 +2917,9 @@
}
TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const auto displayRect = Rect(2, 1);
@@ -2704,6 +2971,9 @@
}
TEST_P(RenderEngineTest, test_isOpaque) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const auto rect = Rect(0, 0, 1, 1);
@@ -2755,7 +3025,7 @@
}
TEST_P(RenderEngineTest, test_tonemapPQMatches) {
- if (!GetParam()->useColorManagement()) {
+ if (!GetParam()->typeSupported() || !GetParam()->useColorManagement()) {
GTEST_SKIP();
}
@@ -2772,7 +3042,7 @@
}
TEST_P(RenderEngineTest, test_tonemapHLGMatches) {
- if (!GetParam()->useColorManagement()) {
+ if (!GetParam()->typeSupported() || !GetParam()->useColorManagement()) {
GTEST_SKIP();
}
@@ -2789,6 +3059,9 @@
}
TEST_P(RenderEngineTest, r8_behaves_as_mask) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const auto r8Buffer = allocateR8Buffer(2, 1);
@@ -2846,6 +3119,9 @@
}
TEST_P(RenderEngineTest, r8_respects_color_transform) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const auto r8Buffer = allocateR8Buffer(2, 1);
@@ -2908,6 +3184,9 @@
}
TEST_P(RenderEngineTest, r8_respects_color_transform_when_device_handles) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
const auto r8Buffer = allocateR8Buffer(2, 1);
@@ -2973,6 +3252,9 @@
}
TEST_P(RenderEngineTest, primeShaderCache) {
+ if (!GetParam()->typeSupported()) {
+ GTEST_SKIP();
+ }
initializeRenderEngine();
auto fut = mRE->primeCache();
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 4091310..87a4ff4 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,
@@ -482,11 +484,11 @@
isStylusToolType(entry.pointerProperties[pointerIndex].toolType);
}
-// 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.
@@ -1099,7 +1101,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));
}
}
@@ -1370,7 +1372,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();
@@ -1444,7 +1446,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});
@@ -1481,7 +1483,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;
@@ -1594,7 +1596,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.
@@ -1707,7 +1709,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);
}
}
@@ -1759,7 +1762,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});
}
@@ -2194,20 +2197,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.
@@ -2231,11 +2234,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;
}
@@ -2275,7 +2277,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.
@@ -2283,17 +2285,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;
@@ -2316,7 +2319,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
@@ -2329,7 +2333,7 @@
newHoverWindowHandle->getName().c_str());
}
tempTouchState.addOrUpdateWindow(newHoverWindowHandle,
- InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER,
+ InputTarget::Flags::DISPATCH_AS_HOVER_ENTER,
BitSet32(0));
}
}
@@ -2342,7 +2346,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());
@@ -2354,7 +2358,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;
@@ -2379,11 +2383,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));
}
}
@@ -2410,13 +2414,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);
}
}
}
@@ -2442,10 +2445,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();
@@ -2461,9 +2462,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) {
@@ -2611,7 +2610,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 =
@@ -2659,7 +2659,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()) {
@@ -2691,7 +2691,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) {
@@ -2920,9 +2920,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());
}
@@ -2939,9 +2939,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);
@@ -2990,17 +2990,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()) {
@@ -3011,18 +3011,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.
@@ -3059,15 +3061,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;
@@ -3087,10 +3089,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;
}
@@ -3190,8 +3192,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
}
@@ -3250,7 +3251,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++) {
@@ -3263,7 +3264,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();
@@ -3665,7 +3666,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();
@@ -3700,7 +3701,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.
@@ -3736,7 +3737,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) {
@@ -3762,7 +3763,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.
@@ -4825,7 +4826,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();
@@ -5143,16 +5144,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);
@@ -5206,7 +5207,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(),
@@ -5319,22 +5320,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..5657d61 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) {
@@ -117,6 +117,10 @@
toString(mCursorScrollAccumulator.haveRelativeVWheel()));
dump += StringPrintf(INDENT3 "HaveHWheel: %s\n",
toString(mCursorScrollAccumulator.haveRelativeHWheel()));
+ dump += StringPrintf(INDENT3 "WheelYVelocityControlParameters: %s",
+ mWheelYVelocityControl.getParameters().dump().c_str());
+ dump += StringPrintf(INDENT3 "WheelXVelocityControlParameters: %s",
+ mWheelXVelocityControl.getParameters().dump().c_str());
dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
dump += StringPrintf(INDENT3 "DisplayId: %s\n", toString(mDisplayId).c_str());
@@ -276,6 +280,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 +300,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 e8fcdc8..380c3a5 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -1467,6 +1467,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 85af1f7..788ec58 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -325,7 +325,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 461fd5d..5c5fc77 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);
@@ -3593,13 +3599,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();
}
@@ -3637,15 +3643,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;
}
@@ -5834,6 +5841,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 {
@@ -8181,7 +8288,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) {
@@ -8294,8 +8402,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) {
@@ -10965,6 +11074,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 438bb9a..8721bd8 100644
--- a/services/inputflinger/tests/TestInputListenerMatchers.h
+++ b/services/inputflinger/tests/TestInputListenerMatchers.h
@@ -96,4 +96,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/powermanager/Android.bp b/services/powermanager/Android.bp
index b7de619..7fb33e5 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -40,7 +40,7 @@
"android.hardware.power@1.1",
"android.hardware.power@1.2",
"android.hardware.power@1.3",
- "android.hardware.power-V3-cpp",
+ "android.hardware.power-V4-cpp",
],
cflags: [
diff --git a/services/powermanager/benchmarks/Android.bp b/services/powermanager/benchmarks/Android.bp
index 0286a81..4343aec 100644
--- a/services/powermanager/benchmarks/Android.bp
+++ b/services/powermanager/benchmarks/Android.bp
@@ -40,7 +40,7 @@
"android.hardware.power@1.1",
"android.hardware.power@1.2",
"android.hardware.power@1.3",
- "android.hardware.power-V3-cpp",
+ "android.hardware.power-V4-cpp",
],
static_libs: [
"libtestUtil",
diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp
index eec6801..54dffcf 100644
--- a/services/powermanager/tests/Android.bp
+++ b/services/powermanager/tests/Android.bp
@@ -51,7 +51,7 @@
"android.hardware.power@1.1",
"android.hardware.power@1.2",
"android.hardware.power@1.3",
- "android.hardware.power-V3-cpp",
+ "android.hardware.power-V4-cpp",
],
static_libs: [
"libgmock",
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 999c03f..14fdd12 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -189,6 +189,7 @@
"Scheduler/VsyncConfiguration.cpp",
"Scheduler/VsyncModulator.cpp",
"Scheduler/VsyncSchedule.cpp",
+ "ScreenCaptureOutput.cpp",
"StartPropertySetThread.cpp",
"SurfaceFlinger.cpp",
"SurfaceFlingerDefaultFactory.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index c1460cf..30d34a5 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -140,6 +140,11 @@
"libgmock",
"libgtest",
],
+ // For some reason, libvulkan isn't picked up from librenderengine
+ // Probably ASAN related?
+ shared_libs: [
+ "libvulkan",
+ ],
sanitize: {
// By using the address sanitizer, we not only uncover any issues
// with the test, but also any issues with the code under test.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 23d5570..9ca5da9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -134,9 +134,11 @@
void applyCompositionStrategy(const std::optional<DeviceRequestedChanges>&) override{};
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
+ virtual renderengine::DisplaySettings generateClientCompositionDisplaySettings() const;
std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
bool supportsProtectedContent, ui::Dataspace outputDataspace,
std::vector<LayerFE*> &outLayerFEs) override;
+ virtual bool layerNeedsFiltering(const OutputLayer*) const;
void appendRegionFlashRequests(const Region&, std::vector<LayerFE::LayerSettings>&) override;
void setExpensiveRenderingExpected(bool enabled) override;
void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) override;
@@ -153,6 +155,8 @@
bool mustRecompose() const;
+ const std::string& getNamePlusId() const { return mNamePlusId; }
+
private:
void dirtyEntireOutput();
void updateCompositionStateForBorder(const compositionengine::CompositionRefreshArgs&);
@@ -163,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 c2b1f06..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);
@@ -1226,40 +1230,8 @@
ALOGV("hasClientComposition");
- renderengine::DisplaySettings clientCompositionDisplay;
- clientCompositionDisplay.physicalDisplay = outputState.framebufferSpace.getContent();
- clientCompositionDisplay.clip = outputState.layerStackSpace.getContent();
- clientCompositionDisplay.orientation =
- ui::Transform::toRotationFlags(outputState.displaySpace.getOrientation());
- clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut()
- ? outputState.dataspace
- : ui::Dataspace::UNKNOWN;
-
- // If we have a valid current display brightness use that, otherwise fall back to the
- // display's max desired
- clientCompositionDisplay.currentLuminanceNits = outputState.displayBrightnessNits > 0.f
- ? outputState.displayBrightnessNits
- : mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
- clientCompositionDisplay.maxLuminance =
- mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
- clientCompositionDisplay.targetLuminanceNits =
- outputState.clientTargetBrightness * outputState.displayBrightnessNits;
- clientCompositionDisplay.dimmingStage = outputState.clientTargetDimmingStage;
- clientCompositionDisplay.renderIntent =
- static_cast<aidl::android::hardware::graphics::composer3::RenderIntent>(
- outputState.renderIntent);
-
- // Compute the global color transform matrix.
- clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
- for (auto& info : outputState.borderInfoList) {
- renderengine::BorderRenderInfo borderInfo;
- borderInfo.width = info.width;
- borderInfo.color = info.color;
- borderInfo.combinedRegion = info.combinedRegion;
- clientCompositionDisplay.borderInfoList.emplace_back(std::move(borderInfo));
- }
- clientCompositionDisplay.deviceHandlesColorTransform =
- outputState.usesDeviceComposition || getSkipColorTransform();
+ renderengine::DisplaySettings clientCompositionDisplay =
+ generateClientCompositionDisplaySettings();
// Generate the client composition requests for the layers on this output.
auto& renderEngine = getCompositionEngine().getRenderEngine();
@@ -1350,6 +1322,47 @@
return base::unique_fd(fence->dup());
}
+renderengine::DisplaySettings Output::generateClientCompositionDisplaySettings() const {
+ const auto& outputState = getState();
+
+ renderengine::DisplaySettings clientCompositionDisplay;
+ clientCompositionDisplay.namePlusId = mNamePlusId;
+ clientCompositionDisplay.physicalDisplay = outputState.framebufferSpace.getContent();
+ clientCompositionDisplay.clip = outputState.layerStackSpace.getContent();
+ clientCompositionDisplay.orientation =
+ ui::Transform::toRotationFlags(outputState.displaySpace.getOrientation());
+ clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut()
+ ? outputState.dataspace
+ : ui::Dataspace::UNKNOWN;
+
+ // If we have a valid current display brightness use that, otherwise fall back to the
+ // display's max desired
+ clientCompositionDisplay.currentLuminanceNits = outputState.displayBrightnessNits > 0.f
+ ? outputState.displayBrightnessNits
+ : mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
+ clientCompositionDisplay.maxLuminance =
+ mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
+ clientCompositionDisplay.targetLuminanceNits =
+ outputState.clientTargetBrightness * outputState.displayBrightnessNits;
+ clientCompositionDisplay.dimmingStage = outputState.clientTargetDimmingStage;
+ clientCompositionDisplay.renderIntent =
+ static_cast<aidl::android::hardware::graphics::composer3::RenderIntent>(
+ outputState.renderIntent);
+
+ // Compute the global color transform matrix.
+ clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
+ for (auto& info : outputState.borderInfoList) {
+ renderengine::BorderRenderInfo borderInfo;
+ borderInfo.width = info.width;
+ borderInfo.color = info.color;
+ borderInfo.combinedRegion = info.combinedRegion;
+ clientCompositionDisplay.borderInfoList.emplace_back(std::move(borderInfo));
+ }
+ clientCompositionDisplay.deviceHandlesColorTransform =
+ outputState.usesDeviceComposition || getSkipColorTransform();
+ return clientCompositionDisplay;
+}
+
std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests(
bool supportsProtectedContent, ui::Dataspace outputDataspace, std::vector<LayerFE*>& outLayerFEs) {
std::vector<LayerFE::LayerSettings> clientCompositionLayers;
@@ -1415,7 +1428,7 @@
Enabled);
compositionengine::LayerFE::ClientCompositionTargetSettings
targetSettings{.clip = clip,
- .needsFiltering = layer->needsFiltering() ||
+ .needsFiltering = layerNeedsFiltering(layer) ||
outputState.needsFiltering,
.isSecure = outputState.isSecure,
.supportsProtectedContent = supportsProtectedContent,
@@ -1446,6 +1459,10 @@
return clientCompositionLayers;
}
+bool Output::layerNeedsFiltering(const compositionengine::OutputLayer* layer) const {
+ return layer->needsFiltering();
+}
+
void Output::appendRegionFlashRequests(
const Region& flashRegion, std::vector<LayerFE::LayerSettings>& clientCompositionLayers) {
if (flashRegion.isEmpty()) {
@@ -1476,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 83a46ae..be5fffc 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -195,8 +195,7 @@
mDrawingState.color.b = -1.0_hf;
}
- mFrameTracker.setDisplayRefreshPeriod(
- args.flinger->mScheduler->getVsyncPeriodFromRefreshRateSelector());
+ mFrameTracker.setDisplayRefreshPeriod(args.flinger->mScheduler->getLeaderVsyncPeriod());
mOwnerUid = args.ownerUid;
mOwnerPid = args.ownerPid;
@@ -2841,7 +2840,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 +2886,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 +3185,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 +3204,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;
}
@@ -3499,6 +3497,12 @@
return mSnapshot.get();
}
+sp<LayerFE> Layer::copyCompositionEngineLayerFE() const {
+ auto result = mFlinger->getFactory().createLayerFE(mLayerFE->getDebugName());
+ result->mSnapshot = std::make_unique<LayerSnapshot>(*mSnapshot);
+ return result;
+}
+
void Layer::useSurfaceDamage() {
if (mFlinger->mForceFullDamage) {
surfaceDamageRegion = Region::INVALID_REGION;
@@ -3964,6 +3968,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 a3c4e59..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*/);
@@ -323,6 +325,7 @@
ui::Dataspace getRequestedDataSpace() const;
virtual sp<LayerFE> getCompositionEngineLayerFE() const;
+ virtual sp<LayerFE> copyCompositionEngineLayerFE() const;
const LayerSnapshot* getLayerSnapshot() const;
LayerSnapshot* editLayerSnapshot();
@@ -810,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/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index 0e80817..65ee487 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -363,14 +363,16 @@
}
}
- void resetIdleTimer(bool kernelOnly) {
- if (!mIdleTimer) {
- return;
+ void resetKernelIdleTimer() {
+ if (mIdleTimer && mConfig.kernelIdleTimerController) {
+ mIdleTimer->reset();
}
- if (kernelOnly && !mConfig.kernelIdleTimerController.has_value()) {
- return;
+ }
+
+ void resetIdleTimer() {
+ if (mIdleTimer) {
+ mIdleTimer->reset();
}
- mIdleTimer->reset();
}
void dump(utils::Dumper&) const EXCLUDES(mLock);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 6108d92..f1fcc88 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -70,7 +70,7 @@
mTouchTimer.reset();
// Stop idle timer and clear callbacks, as the RefreshRateSelector may outlive the Scheduler.
- setRefreshRateSelector(nullptr);
+ demoteLeaderDisplay();
}
void Scheduler::startTimers() {
@@ -95,40 +95,29 @@
}
}
-void Scheduler::setRefreshRateSelector(RefreshRateSelectorPtr newSelectorPtr) {
- // No need to lock for reads on kMainThreadContext.
- if (const auto& selectorPtr = FTL_FAKE_GUARD(mRefreshRateSelectorLock, mRefreshRateSelector)) {
- unbindIdleTimer(*selectorPtr);
- }
+void Scheduler::setLeaderDisplay(std::optional<PhysicalDisplayId> leaderIdOpt) {
+ demoteLeaderDisplay();
- {
- // Clear state that depends on the current RefreshRateSelector.
- std::scoped_lock lock(mPolicyLock);
- mPolicy = {};
- }
-
- std::scoped_lock lock(mRefreshRateSelectorLock);
- mRefreshRateSelector = std::move(newSelectorPtr);
-
- if (mRefreshRateSelector) {
- bindIdleTimer(*mRefreshRateSelector);
- }
+ std::scoped_lock lock(mDisplayLock);
+ promoteLeaderDisplay(leaderIdOpt);
}
void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) {
- if (!mLeaderDisplayId) {
- mLeaderDisplayId = displayId;
- }
+ demoteLeaderDisplay();
+ std::scoped_lock lock(mDisplayLock);
mRefreshRateSelectors.emplace_or_replace(displayId, std::move(selectorPtr));
+
+ promoteLeaderDisplay();
}
void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
- if (mLeaderDisplayId == displayId) {
- mLeaderDisplayId.reset();
- }
+ demoteLeaderDisplay();
+ std::scoped_lock lock(mDisplayLock);
mRefreshRateSelectors.erase(displayId);
+
+ promoteLeaderDisplay();
}
void Scheduler::run() {
@@ -163,7 +152,7 @@
std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
const bool supportsFrameRateOverrideByContent =
- holdRefreshRateSelector()->supportsFrameRateOverrideByContent();
+ leaderSelectorPtr()->supportsFrameRateOverrideByContent();
return mFrameRateOverrideMappings
.getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent);
}
@@ -178,8 +167,6 @@
}
impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const {
- std::scoped_lock lock(mRefreshRateSelectorLock);
-
return [this](nsecs_t expectedVsyncTimestamp, uid_t uid) {
return !isVsyncValid(TimePoint::fromNs(expectedVsyncTimestamp), uid);
};
@@ -187,7 +174,7 @@
impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
return [this](uid_t uid) {
- const Fps refreshRate = holdRefreshRateSelector()->getActiveModePtr()->getFps();
+ const Fps refreshRate = leaderSelectorPtr()->getActiveModePtr()->getFps();
const nsecs_t currentPeriod = mVsyncSchedule->period().ns() ?: refreshRate.getPeriodNsecs();
const auto frameRate = getFrameRateOverride(uid);
@@ -281,7 +268,7 @@
void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) {
const bool supportsFrameRateOverrideByContent =
- holdRefreshRateSelector()->supportsFrameRateOverrideByContent();
+ leaderSelectorPtr()->supportsFrameRateOverrideByContent();
std::vector<FrameRateOverride> overrides =
mFrameRateOverrideMappings.getAllFrameRateOverrides(supportsFrameRateOverrideByContent);
@@ -322,8 +309,7 @@
// If the mode is not the current mode, this means that a
// mode change is in progress. In that case we shouldn't dispatch an event
// as it will be dispatched when the current mode changes.
- if (std::scoped_lock lock(mRefreshRateSelectorLock);
- mRefreshRateSelector->getActiveModePtr() != mPolicy.mode) {
+ if (leaderSelectorPtr()->getActiveModePtr() != mPolicy.mode) {
return;
}
@@ -416,10 +402,7 @@
const nsecs_t last = mLastResyncTime.exchange(now);
if (now - last > kIgnoreDelay) {
- const auto refreshRate = [&] {
- std::scoped_lock lock(mRefreshRateSelectorLock);
- return mRefreshRateSelector->getActiveModePtr()->getFps();
- }();
+ const auto refreshRate = leaderSelectorPtr()->getActiveModePtr()->getFps();
resyncToHardwareVsync(false, refreshRate);
}
}
@@ -478,12 +461,9 @@
void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime,
LayerHistory::LayerUpdateType updateType) {
- {
- std::scoped_lock lock(mRefreshRateSelectorLock);
- if (!mRefreshRateSelector->canSwitch()) return;
+ if (leaderSelectorPtr()->canSwitch()) {
+ mLayerHistory.record(layer, presentTime, systemTime(), updateType);
}
-
- mLayerHistory.record(layer, presentTime, systemTime(), updateType);
}
void Scheduler::setModeChangePending(bool pending) {
@@ -496,7 +476,7 @@
}
void Scheduler::chooseRefreshRateForContent() {
- const auto selectorPtr = holdRefreshRateSelector();
+ const auto selectorPtr = leaderSelectorPtr();
if (!selectorPtr->canSwitch()) return;
ATRACE_CALL();
@@ -506,16 +486,13 @@
}
void Scheduler::resetIdleTimer() {
- std::scoped_lock lock(mRefreshRateSelectorLock);
- mRefreshRateSelector->resetIdleTimer(/*kernelOnly*/ false);
+ leaderSelectorPtr()->resetIdleTimer();
}
void Scheduler::onTouchHint() {
if (mTouchTimer) {
mTouchTimer->reset();
-
- std::scoped_lock lock(mRefreshRateSelectorLock);
- mRefreshRateSelector->resetIdleTimer(/*kernelOnly*/ true);
+ leaderSelectorPtr()->resetKernelIdleTimer();
}
}
@@ -535,30 +512,12 @@
mLayerHistory.clear();
}
-void Scheduler::bindIdleTimer(RefreshRateSelector& selector) {
- selector.setIdleTimerCallbacks(
- {.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); },
- .onExpired = [this] { idleTimerCallback(TimerState::Expired); }},
- .kernel = {.onReset = [this] { kernelIdleTimerCallback(TimerState::Reset); },
- .onExpired = [this] { kernelIdleTimerCallback(TimerState::Expired); }}});
-
- selector.startIdleTimer();
-}
-
-void Scheduler::unbindIdleTimer(RefreshRateSelector& selector) {
- selector.stopIdleTimer();
- selector.clearIdleTimerCallbacks();
-}
-
void Scheduler::kernelIdleTimerCallback(TimerState state) {
ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
// TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate
// magic number
- const Fps refreshRate = [&] {
- std::scoped_lock lock(mRefreshRateSelectorLock);
- return mRefreshRateSelector->getActiveModePtr()->getFps();
- }();
+ const Fps refreshRate = leaderSelectorPtr()->getActiveModePtr()->getFps();
constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz;
using namespace fps_approx_ops;
@@ -614,7 +573,11 @@
}
{
utils::Dumper::Section section(dumper, "Policy"sv);
-
+ {
+ std::scoped_lock lock(mDisplayLock);
+ ftl::FakeGuard guard(kMainThreadContext);
+ dumper.dump("leaderDisplayId"sv, mLeaderDisplayId);
+ }
dumper.dump("layerHistory"sv, mLayerHistory.dump());
dumper.dump("touchTimer"sv, mTouchTimer.transform(&OneShotTimer::interval));
dumper.dump("displayPowerTimer"sv, mDisplayPowerTimer.transform(&OneShotTimer::interval));
@@ -638,17 +601,44 @@
}
bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) {
- // we always update mFrameRateOverridesByContent here
- // supportsFrameRateOverridesByContent will be checked
- // when getting FrameRateOverrides from mFrameRateOverrideMappings
- if (!consideredSignals.idle) {
- const auto frameRateOverrides =
- holdRefreshRateSelector()->getFrameRateOverrides(mPolicy.contentRequirements,
- displayRefreshRate,
- consideredSignals);
- return mFrameRateOverrideMappings.updateFrameRateOverridesByContent(frameRateOverrides);
+ if (consideredSignals.idle) return false;
+
+ const auto frameRateOverrides =
+ leaderSelectorPtr()->getFrameRateOverrides(mPolicy.contentRequirements,
+ displayRefreshRate, consideredSignals);
+
+ // Note that RefreshRateSelector::supportsFrameRateOverrideByContent is checked when querying
+ // the FrameRateOverrideMappings rather than here.
+ return mFrameRateOverrideMappings.updateFrameRateOverridesByContent(frameRateOverrides);
+}
+
+void Scheduler::promoteLeaderDisplay(std::optional<PhysicalDisplayId> leaderIdOpt) {
+ // TODO(b/241286431): Choose the leader display.
+ mLeaderDisplayId = leaderIdOpt.value_or(mRefreshRateSelectors.begin()->first);
+ ALOGI("Display %s is the leader", to_string(*mLeaderDisplayId).c_str());
+
+ if (const auto leaderPtr = leaderSelectorPtrLocked()) {
+ leaderPtr->setIdleTimerCallbacks(
+ {.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); },
+ .onExpired = [this] { idleTimerCallback(TimerState::Expired); }},
+ .kernel = {.onReset = [this] { kernelIdleTimerCallback(TimerState::Reset); },
+ .onExpired =
+ [this] { kernelIdleTimerCallback(TimerState::Expired); }}});
+
+ leaderPtr->startIdleTimer();
}
- return false;
+}
+
+void Scheduler::demoteLeaderDisplay() {
+ // No need to lock for reads on kMainThreadContext.
+ if (const auto leaderPtr = FTL_FAKE_GUARD(mDisplayLock, leaderSelectorPtrLocked())) {
+ leaderPtr->stopIdleTimer();
+ leaderPtr->clearIdleTimerCallbacks();
+ }
+
+ // Clear state that depends on the leader's RefreshRateSelector.
+ std::scoped_lock lock(mPolicyLock);
+ mPolicy = {};
}
template <typename S, typename T>
@@ -660,23 +650,29 @@
bool frameRateOverridesChanged;
{
- std::lock_guard<std::mutex> lock(mPolicyLock);
+ std::scoped_lock lock(mPolicyLock);
auto& currentState = mPolicy.*statePtr;
if (currentState == newState) return {};
currentState = std::forward<T>(newState);
- auto modeChoices = chooseDisplayModes();
-
- // TODO(b/240743786): The leader display's mode must change for any DisplayModeRequest to go
- // through. Fix this by tracking per-display Scheduler::Policy and timers.
+ DisplayModeChoiceMap modeChoices;
DisplayModePtr modePtr;
- std::tie(modePtr, consideredSignals) =
- modeChoices.get(*mLeaderDisplayId)
- .transform([](const DisplayModeChoice& choice) {
- return std::make_pair(choice.modePtr, choice.consideredSignals);
- })
- .value();
+ {
+ std::scoped_lock lock(mDisplayLock);
+ ftl::FakeGuard guard(kMainThreadContext);
+
+ modeChoices = chooseDisplayModes();
+
+ // TODO(b/240743786): The leader display's mode must change for any DisplayModeRequest
+ // to go through. Fix this by tracking per-display Scheduler::Policy and timers.
+ std::tie(modePtr, consideredSignals) =
+ modeChoices.get(*mLeaderDisplayId)
+ .transform([](const DisplayModeChoice& choice) {
+ return std::make_pair(choice.modePtr, choice.consideredSignals);
+ })
+ .value();
+ }
modeRequests.reserve(modeChoices.size());
for (auto& [id, choice] : modeChoices) {
@@ -807,7 +803,7 @@
// Make sure the stored mode is up to date.
if (mPolicy.mode) {
const auto ranking =
- holdRefreshRateSelector()
+ leaderSelectorPtr()
->getRankedRefreshRates(mPolicy.contentRequirements, makeGlobalSignals())
.ranking;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 04f3b69..fb23071 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -22,7 +22,6 @@
#include <future>
#include <memory>
#include <mutex>
-#include <optional>
#include <unordered_map>
#include <utility>
@@ -33,6 +32,8 @@
#include <ui/GraphicTypes.h>
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
+#include <ftl/fake_guard.h>
+#include <ftl/optional.h>
#include <scheduler/Features.h>
#include <scheduler/Time.h>
#include <ui/DisplayId.h>
@@ -108,12 +109,15 @@
void startTimers();
- using RefreshRateSelectorPtr = std::shared_ptr<RefreshRateSelector>;
- void setRefreshRateSelector(RefreshRateSelectorPtr) REQUIRES(kMainThreadContext)
- EXCLUDES(mRefreshRateSelectorLock);
+ // TODO(b/241285191): Remove this API by promoting leader in onScreen{Acquired,Released}.
+ void setLeaderDisplay(std::optional<PhysicalDisplayId>) REQUIRES(kMainThreadContext)
+ EXCLUDES(mDisplayLock);
- void registerDisplay(PhysicalDisplayId, RefreshRateSelectorPtr);
- void unregisterDisplay(PhysicalDisplayId);
+ using RefreshRateSelectorPtr = std::shared_ptr<RefreshRateSelector>;
+
+ void registerDisplay(PhysicalDisplayId, RefreshRateSelectorPtr) REQUIRES(kMainThreadContext)
+ EXCLUDES(mDisplayLock);
+ void unregisterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
void run();
@@ -165,7 +169,7 @@
// Otherwise, if hardware vsync is not already enabled then this method will
// no-op.
void resyncToHardwareVsync(bool makeAvailable, Fps refreshRate);
- void resync() EXCLUDES(mRefreshRateSelectorLock);
+ void resync() EXCLUDES(mDisplayLock);
void forceNextResync() { mLastResyncTime = 0; }
// Passes a vsync sample to VsyncController. periodFlushed will be true if
@@ -176,14 +180,14 @@
// Layers are registered on creation, and unregistered when the weak reference expires.
void registerLayer(Layer*);
- void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType)
- EXCLUDES(mRefreshRateSelectorLock);
+ void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType)
+ EXCLUDES(mDisplayLock);
void setModeChangePending(bool pending);
void setDefaultFrameRateCompatibility(Layer*);
void deregisterLayer(Layer*);
// Detects content using layer history, and selects a matching refresh rate.
- void chooseRefreshRateForContent() EXCLUDES(mRefreshRateSelectorLock);
+ void chooseRefreshRateForContent() EXCLUDES(mDisplayLock);
void resetIdleTimer();
@@ -228,11 +232,10 @@
void setGameModeRefreshRateForUid(FrameRateOverride);
// Retrieves the overridden refresh rate for a given uid.
- std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mRefreshRateSelectorLock);
+ std::optional<Fps> getFrameRateOverride(uid_t) const EXCLUDES(mDisplayLock);
- nsecs_t getVsyncPeriodFromRefreshRateSelector() const EXCLUDES(mRefreshRateSelectorLock) {
- std::scoped_lock lock(mRefreshRateSelectorLock);
- return mRefreshRateSelector->getActiveModePtr()->getFps().getPeriodNsecs();
+ nsecs_t getLeaderVsyncPeriod() const EXCLUDES(mDisplayLock) {
+ return leaderSelectorPtr()->getActiveModePtr()->getFps().getPeriodNsecs();
}
// Returns the framerate of the layer with the given sequence ID
@@ -255,21 +258,23 @@
sp<EventThreadConnection> createConnectionInternal(
EventThread*, EventRegistrationFlags eventRegistration = {});
- void bindIdleTimer(RefreshRateSelector&) REQUIRES(kMainThreadContext, mRefreshRateSelectorLock);
-
- // Blocks until the timer thread exits. `mRefreshRateSelectorLock` must not be locked by the
- // caller on the main thread to avoid deadlock, since the timer thread locks it before exit.
- static void unbindIdleTimer(RefreshRateSelector&) REQUIRES(kMainThreadContext)
- EXCLUDES(mRefreshRateSelectorLock);
-
// Update feature state machine to given state when corresponding timer resets or expires.
- void kernelIdleTimerCallback(TimerState) EXCLUDES(mRefreshRateSelectorLock);
+ void kernelIdleTimerCallback(TimerState) EXCLUDES(mDisplayLock);
void idleTimerCallback(TimerState);
void touchTimerCallback(TimerState);
void displayPowerTimerCallback(TimerState);
void setVsyncPeriod(nsecs_t period);
+ // Chooses a leader among the registered displays, unless `leaderIdOpt` is specified. The new
+ // `mLeaderDisplayId` is never `std::nullopt`.
+ void promoteLeaderDisplay(std::optional<PhysicalDisplayId> leaderIdOpt = std::nullopt)
+ REQUIRES(kMainThreadContext, mDisplayLock);
+
+ // Blocks until the leader's idle timer thread exits. `mDisplayLock` must not be locked by the
+ // caller on the main thread to avoid deadlock, since the timer thread locks it before exit.
+ void demoteLeaderDisplay() REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock, mPolicyLock);
+
struct Policy;
// Sets the S state of the policy to the T value under mPolicyLock, and chooses a display mode
@@ -296,23 +301,20 @@
};
using DisplayModeChoiceMap = display::PhysicalDisplayMap<PhysicalDisplayId, DisplayModeChoice>;
- DisplayModeChoiceMap chooseDisplayModes() const REQUIRES(mPolicyLock);
+
+ // See mDisplayLock for thread safety.
+ DisplayModeChoiceMap chooseDisplayModes() const
+ REQUIRES(mPolicyLock, mDisplayLock, kMainThreadContext);
GlobalSignals makeGlobalSignals() const REQUIRES(mPolicyLock);
bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock);
- void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateSelectorLock);
+ void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mDisplayLock);
- android::impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const
- EXCLUDES(mRefreshRateSelectorLock);
+ android::impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const;
android::impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const;
- RefreshRateSelectorPtr holdRefreshRateSelector() const EXCLUDES(mRefreshRateSelectorLock) {
- std::scoped_lock lock(mRefreshRateSelectorLock);
- return mRefreshRateSelector;
- }
-
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
struct Connection {
sp<EventThreadConnection> connection;
@@ -342,10 +344,34 @@
ISchedulerCallback& mSchedulerCallback;
+ // mDisplayLock may be locked while under mPolicyLock.
mutable std::mutex mPolicyLock;
- display::PhysicalDisplayMap<PhysicalDisplayId, RefreshRateSelectorPtr> mRefreshRateSelectors;
- std::optional<PhysicalDisplayId> mLeaderDisplayId;
+ // Only required for reads outside kMainThreadContext. kMainThreadContext is the only writer, so
+ // must lock for writes but not reads. See also mPolicyLock for locking order.
+ mutable std::mutex mDisplayLock;
+
+ display::PhysicalDisplayMap<PhysicalDisplayId, RefreshRateSelectorPtr> mRefreshRateSelectors
+ GUARDED_BY(mDisplayLock) GUARDED_BY(kMainThreadContext);
+
+ ftl::Optional<PhysicalDisplayId> mLeaderDisplayId GUARDED_BY(mDisplayLock)
+ GUARDED_BY(kMainThreadContext);
+
+ RefreshRateSelectorPtr leaderSelectorPtr() const EXCLUDES(mDisplayLock) {
+ std::scoped_lock lock(mDisplayLock);
+ return leaderSelectorPtrLocked();
+ }
+
+ RefreshRateSelectorPtr leaderSelectorPtrLocked() const REQUIRES(mDisplayLock) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ const RefreshRateSelectorPtr noLeader;
+ return mLeaderDisplayId
+ .and_then([this](PhysicalDisplayId leaderId)
+ REQUIRES(mDisplayLock, kMainThreadContext) {
+ return mRefreshRateSelectors.get(leaderId);
+ })
+ .value_or(std::cref(noLeader));
+ }
struct Policy {
// Policy for choosing the display mode.
@@ -367,10 +393,6 @@
std::optional<ModeChangedParams> cachedModeChangedParams;
} mPolicy GUARDED_BY(mPolicyLock);
- // TODO(b/255635821): Remove this by instead looking up the `mLeaderDisplayId` selector.
- mutable std::mutex mRefreshRateSelectorLock;
- RefreshRateSelectorPtr mRefreshRateSelector GUARDED_BY(mRefreshRateSelectorLock);
-
std::mutex mVsyncTimelineLock;
std::optional<hal::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline
GUARDED_BY(mVsyncTimelineLock);
diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp
new file mode 100644
index 0000000..37b3218
--- /dev/null
+++ b/services/surfaceflinger/ScreenCaptureOutput.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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 "ScreenCaptureOutput.h"
+#include "ScreenCaptureRenderSurface.h"
+
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/impl/DisplayColorProfile.h>
+#include <ui/Rotation.h>
+
+namespace android {
+
+std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutputArgs args) {
+ std::shared_ptr<ScreenCaptureOutput> output = compositionengine::impl::createOutputTemplated<
+ ScreenCaptureOutput, compositionengine::CompositionEngine, const RenderArea&,
+ std::unordered_set<compositionengine::LayerFE*>,
+ const compositionengine::Output::ColorProfile&, bool>(args.compositionEngine,
+ args.renderArea,
+ std::move(
+ args.filterForScreenshot),
+ args.colorProfile,
+ args.regionSampling);
+ output->editState().isSecure = args.renderArea.isSecure();
+ output->setCompositionEnabled(true);
+ output->setLayerFilter({args.layerStack});
+ output->setRenderSurface(std::make_unique<ScreenCaptureRenderSurface>(std::move(args.buffer)));
+ output->setDisplayBrightness(args.sdrWhitePointNits, args.displayBrightnessNits);
+
+ output->setDisplayColorProfile(std::make_unique<compositionengine::impl::DisplayColorProfile>(
+ compositionengine::DisplayColorProfileCreationArgsBuilder()
+ .setHasWideColorGamut(true)
+ .Build()));
+
+ ui::Rotation orientation = ui::Transform::toRotation(args.renderArea.getRotationFlags());
+ Rect orientedDisplaySpaceRect{args.renderArea.getReqWidth(), args.renderArea.getReqHeight()};
+ output->setProjection(orientation, args.renderArea.getLayerStackSpaceRect(),
+ orientedDisplaySpaceRect);
+
+ Rect sourceCrop = args.renderArea.getSourceCrop();
+ output->setDisplaySize({sourceCrop.getWidth(), sourceCrop.getHeight()});
+
+ return output;
+}
+
+ScreenCaptureOutput::ScreenCaptureOutput(
+ const RenderArea& renderArea,
+ std::unordered_set<compositionengine::LayerFE*> filterForScreenshot,
+ const compositionengine::Output::ColorProfile& colorProfile, bool regionSampling)
+ : mRenderArea(renderArea),
+ mFilterForScreenshot(std::move(filterForScreenshot)),
+ mColorProfile(colorProfile),
+ mRegionSampling(regionSampling) {}
+
+void ScreenCaptureOutput::updateColorProfile(const compositionengine::CompositionRefreshArgs&) {
+ auto& outputState = editState();
+ outputState.dataspace = mColorProfile.dataspace;
+ outputState.renderIntent = mColorProfile.renderIntent;
+}
+
+renderengine::DisplaySettings ScreenCaptureOutput::generateClientCompositionDisplaySettings()
+ const {
+ auto clientCompositionDisplay =
+ compositionengine::impl::Output::generateClientCompositionDisplaySettings();
+ clientCompositionDisplay.clip = mRenderArea.getSourceCrop();
+ clientCompositionDisplay.targetLuminanceNits = -1;
+ return clientCompositionDisplay;
+}
+
+std::vector<compositionengine::LayerFE::LayerSettings>
+ScreenCaptureOutput::generateClientCompositionRequests(
+ bool supportsProtectedContent, ui::Dataspace outputDataspace,
+ std::vector<compositionengine::LayerFE*>& outLayerFEs) {
+ auto clientCompositionLayers = compositionengine::impl::Output::
+ generateClientCompositionRequests(supportsProtectedContent, outputDataspace,
+ outLayerFEs);
+
+ if (mRegionSampling) {
+ for (auto& layer : clientCompositionLayers) {
+ layer.backgroundBlurRadius = 0;
+ layer.blurRegions.clear();
+ }
+ }
+
+ Rect sourceCrop = mRenderArea.getSourceCrop();
+ compositionengine::LayerFE::LayerSettings fillLayer;
+ fillLayer.source.buffer.buffer = nullptr;
+ fillLayer.source.solidColor = half3(0.0f, 0.0f, 0.0f);
+ fillLayer.geometry.boundaries =
+ FloatRect(static_cast<float>(sourceCrop.left), static_cast<float>(sourceCrop.top),
+ static_cast<float>(sourceCrop.right), static_cast<float>(sourceCrop.bottom));
+ fillLayer.alpha = half(RenderArea::getCaptureFillValue(mRenderArea.getCaptureFill()));
+ clientCompositionLayers.insert(clientCompositionLayers.begin(), fillLayer);
+
+ return clientCompositionLayers;
+}
+
+bool ScreenCaptureOutput::layerNeedsFiltering(const compositionengine::OutputLayer* layer) const {
+ return mRenderArea.needsFiltering() ||
+ mFilterForScreenshot.find(&layer->getLayerFE()) != mFilterForScreenshot.end();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/ScreenCaptureOutput.h b/services/surfaceflinger/ScreenCaptureOutput.h
new file mode 100644
index 0000000..5dffc1d
--- /dev/null
+++ b/services/surfaceflinger/ScreenCaptureOutput.h
@@ -0,0 +1,72 @@
+/*
+ * 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 <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/Output.h>
+#include <ui/Rect.h>
+
+#include "RenderArea.h"
+
+namespace android {
+
+struct ScreenCaptureOutputArgs {
+ const compositionengine::CompositionEngine& compositionEngine;
+ const compositionengine::Output::ColorProfile& colorProfile;
+ const RenderArea& renderArea;
+ ui::LayerStack layerStack;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
+ float sdrWhitePointNits;
+ float displayBrightnessNits;
+ std::unordered_set<compositionengine::LayerFE*> filterForScreenshot;
+ bool regionSampling;
+};
+
+// ScreenCaptureOutput is used to compose a set of layers into a preallocated buffer.
+//
+// SurfaceFlinger passes instances of ScreenCaptureOutput to CompositionEngine in calls to
+// SurfaceFlinger::captureLayers and SurfaceFlinger::captureDisplay.
+class ScreenCaptureOutput : public compositionengine::impl::Output {
+public:
+ ScreenCaptureOutput(const RenderArea& renderArea,
+ std::unordered_set<compositionengine::LayerFE*> filterForScreenshot,
+ const compositionengine::Output::ColorProfile& colorProfile,
+ bool regionSampling);
+
+ void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override;
+
+ std::vector<compositionengine::LayerFE::LayerSettings> generateClientCompositionRequests(
+ bool supportsProtectedContent, ui::Dataspace outputDataspace,
+ std::vector<compositionengine::LayerFE*>& outLayerFEs) override;
+
+ bool layerNeedsFiltering(const compositionengine::OutputLayer*) const override;
+
+protected:
+ bool getSkipColorTransform() const override { return false; }
+ renderengine::DisplaySettings generateClientCompositionDisplaySettings() const override;
+
+private:
+ const RenderArea& mRenderArea;
+ const std::unordered_set<compositionengine::LayerFE*> mFilterForScreenshot;
+ const compositionengine::Output::ColorProfile& mColorProfile;
+ const bool mRegionSampling;
+};
+
+std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutputArgs);
+
+} // namespace android
diff --git a/services/surfaceflinger/ScreenCaptureRenderSurface.h b/services/surfaceflinger/ScreenCaptureRenderSurface.h
new file mode 100644
index 0000000..2097300
--- /dev/null
+++ b/services/surfaceflinger/ScreenCaptureRenderSurface.h
@@ -0,0 +1,81 @@
+/*
+ * 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 <memory>
+
+#include <compositionengine/RenderSurface.h>
+#include <renderengine/impl/ExternalTexture.h>
+#include <ui/Fence.h>
+#include <ui/Size.h>
+
+namespace android {
+
+// ScreenCaptureRenderSurface is a RenderSurface that returns a preallocated buffer used by
+// ScreenCaptureOutput.
+class ScreenCaptureRenderSurface : public compositionengine::RenderSurface {
+public:
+ ScreenCaptureRenderSurface(std::shared_ptr<renderengine::ExternalTexture> buffer)
+ : mBuffer(std::move(buffer)){};
+
+ std::shared_ptr<renderengine::ExternalTexture> dequeueBuffer(
+ base::unique_fd* /* bufferFence */) override {
+ return mBuffer;
+ }
+
+ void queueBuffer(base::unique_fd readyFence) override {
+ mRenderFence = sp<Fence>::make(readyFence.release());
+ }
+
+ const sp<Fence>& getClientTargetAcquireFence() const override { return mRenderFence; }
+
+ bool supportsCompositionStrategyPrediction() const override { return false; }
+
+ bool isValid() const override { return true; }
+
+ void initialize() override {}
+
+ const ui::Size& getSize() const override { return mSize; }
+
+ bool isProtected() const override { return mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED; }
+
+ void setDisplaySize(const ui::Size&) override {}
+
+ void setBufferDataspace(ui::Dataspace) override {}
+
+ void setBufferPixelFormat(ui::PixelFormat) override {}
+
+ void setProtected(bool /* useProtected */) override {}
+
+ status_t beginFrame(bool /* mustRecompose */) override { return OK; }
+
+ void prepareFrame(bool /* usesClientComposition */, bool /* usesDeviceComposition */) override {
+ }
+
+ void onPresentDisplayCompleted() override {}
+
+ void dump(std::string& /* result */) const override {}
+
+private:
+ std::shared_ptr<renderengine::ExternalTexture> mBuffer;
+
+ sp<Fence> mRenderFence = Fence::NO_FENCE;
+
+ ui::Size mSize;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a4fb0dc..dc9129c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -44,10 +44,12 @@
#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
#include <compositionengine/DisplayCreationArgs.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/DisplayColorProfile.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <configstore/Utils.h>
@@ -105,6 +107,7 @@
#include <optional>
#include <type_traits>
#include <unordered_map>
+#include <vector>
#include <ui/DisplayIdentification.h>
#include "BackgroundExecutor.h"
@@ -138,6 +141,7 @@
#include "Scheduler/LayerHistory.h"
#include "Scheduler/Scheduler.h"
#include "Scheduler/VsyncConfiguration.h"
+#include "ScreenCaptureOutput.h"
#include "StartPropertySetThread.h"
#include "SurfaceFlingerProperties.h"
#include "TimeStats/TimeStats.h"
@@ -310,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());
@@ -369,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");
@@ -731,6 +736,10 @@
return renderengine::RenderEngine::RenderEngineType::SKIA_GL;
} else if (strcmp(prop, "skiaglthreaded") == 0) {
return renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED;
+ } else if (strcmp(prop, "skiavk") == 0) {
+ return renderengine::RenderEngine::RenderEngineType::SKIA_VK;
+ } else if (strcmp(prop, "skiavkthreaded") == 0) {
+ return renderengine::RenderEngine::RenderEngineType::SKIA_VK_THREADED;
} else {
ALOGE("Unrecognized RenderEngineType %s; ignoring!", prop);
return {};
@@ -2950,18 +2959,16 @@
displaySurface, producer);
if (mScheduler && !display->isVirtual()) {
- auto selectorPtr = display->holdRefreshRateSelector();
-
- // Display modes are reloaded on hotplug reconnect.
- if (display->isPrimary()) {
+ const auto displayId = display->getPhysicalId();
+ {
// TODO(b/241285876): Annotate `processDisplayAdded` instead.
ftl::FakeGuard guard(kMainThreadContext);
- mScheduler->setRefreshRateSelector(selectorPtr);
+
+ // For hotplug reconnect, renew the registration since display modes have been reloaded.
+ mScheduler->registerDisplay(displayId, display->holdRefreshRateSelector());
}
- const auto displayId = display->getPhysicalId();
- mScheduler->registerDisplay(displayId, std::move(selectorPtr));
- dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
+ dispatchDisplayHotplugEvent(displayId, true);
}
mDisplays.try_emplace(displayToken, std::move(display));
@@ -3420,9 +3427,7 @@
!getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
features |= Feature::kPresentFences;
}
-
- auto selectorPtr = display->holdRefreshRateSelector();
- if (selectorPtr->kernelIdleTimerController()) {
+ if (display->refreshRateSelector().kernelIdleTimerController()) {
features |= Feature::kKernelIdleTimer;
}
@@ -3430,8 +3435,7 @@
static_cast<ISchedulerCallback&>(*this),
features);
mScheduler->createVsyncSchedule(features);
- mScheduler->setRefreshRateSelector(selectorPtr);
- mScheduler->registerDisplay(display->getPhysicalId(), std::move(selectorPtr));
+ mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector());
setVsyncEnabled(false);
mScheduler->startTimers();
@@ -3896,7 +3900,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,
@@ -3928,7 +3932,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,
@@ -3937,11 +3963,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);
}
@@ -3960,7 +3981,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,
@@ -3982,13 +4003,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,
@@ -4100,7 +4120,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) {
@@ -4395,11 +4415,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) {
@@ -4607,7 +4625,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 |
@@ -5147,7 +5165,7 @@
Layer::miniDumpHeader(result);
const DisplayDevice& ref = *display;
- mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, ref); });
+ mDrawingState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, ref); });
result.append("\n");
}
}
@@ -6279,7 +6297,8 @@
return BAD_VALUE;
}
- Rect layerStackSpaceRect(0, 0, reqSize.width, reqSize.height);
+ Rect layerStackSpaceRect(crop.left, crop.top, crop.left + reqSize.width,
+ crop.top + reqSize.height);
bool childrenOnly = args.childrenOnly;
RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr<RenderArea> {
return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, dataspace,
@@ -6399,7 +6418,7 @@
ftl::SharedFuture<FenceResult> renderFuture;
renderArea->render([&]() FTL_FAKE_GUARD(kMainThreadContext) {
- renderFuture = renderScreenImpl(*renderArea, traverseLayers, buffer,
+ renderFuture = renderScreenImpl(std::move(renderArea), traverseLayers, buffer,
canCaptureBlackoutContent, regionSampling,
grayscale, captureResults);
});
@@ -6427,19 +6446,19 @@
}
ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
- const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+ std::unique_ptr<RenderArea> renderArea, TraverseLayersFunction traverseLayers,
const std::shared_ptr<renderengine::ExternalTexture>& buffer,
bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
ScreenCaptureResults& captureResults) {
ATRACE_CALL();
+ size_t layerCount = 0;
traverseLayers([&](Layer* layer) {
+ layerCount++;
captureResults.capturedSecureLayers =
captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure());
});
- const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
-
// We allow the system server to take screenshots of secure layers for
// use in situations like the Screen-rotation animation and place
// the impetus on WindowManager to not persist them.
@@ -6449,8 +6468,8 @@
}
captureResults.buffer = buffer->getBuffer();
- auto dataspace = renderArea.getReqDataSpace();
- auto parent = renderArea.getParentLayer();
+ auto dataspace = renderArea->getReqDataSpace();
+ auto parent = renderArea->getParentLayer();
auto renderIntent = RenderIntent::TONE_MAP_COLORIMETRIC;
auto sdrWhitePointNits = DisplayDevice::sDefaultMaxLumiance;
auto displayBrightnessNits = DisplayDevice::sDefaultMaxLumiance;
@@ -6472,122 +6491,107 @@
}
captureResults.capturedDataspace = dataspace;
- const auto reqWidth = renderArea.getReqWidth();
- const auto reqHeight = renderArea.getReqHeight();
- const auto sourceCrop = renderArea.getSourceCrop();
- const auto transform = renderArea.getTransform();
- const auto rotation = renderArea.getRotationFlags();
- const auto& layerStackSpaceRect = renderArea.getLayerStackSpaceRect();
+ const auto transform = renderArea->getTransform();
+ const auto display = renderArea->getDisplayDevice();
- renderengine::DisplaySettings clientCompositionDisplay;
- std::vector<compositionengine::LayerFE::LayerSettings> clientCompositionLayers;
-
- // assume that bounds are never offset, and that they are the same as the
- // buffer bounds.
- clientCompositionDisplay.physicalDisplay = Rect(reqWidth, reqHeight);
- clientCompositionDisplay.clip = sourceCrop;
- clientCompositionDisplay.orientation = rotation;
-
- clientCompositionDisplay.outputDataspace = dataspace;
- clientCompositionDisplay.currentLuminanceNits = displayBrightnessNits;
- clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance;
- clientCompositionDisplay.renderIntent =
- static_cast<aidl::android::hardware::graphics::composer3::RenderIntent>(renderIntent);
-
- const float colorSaturation = grayscale ? 0 : 1;
- clientCompositionDisplay.colorTransform = calculateColorMatrix(colorSaturation);
-
- const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
-
- compositionengine::LayerFE::LayerSettings fillLayer;
- fillLayer.source.buffer.buffer = nullptr;
- fillLayer.source.solidColor = half3(0.0, 0.0, 0.0);
- fillLayer.geometry.boundaries =
- FloatRect(sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom);
- fillLayer.alpha = half(alpha);
- clientCompositionLayers.push_back(fillLayer);
-
- const auto display = renderArea.getDisplayDevice();
- std::vector<Layer*> renderedLayers;
- bool disableBlurs = false;
- traverseLayers([&](Layer* layer) FTL_FAKE_GUARD(kMainThreadContext) {
+ std::vector<std::pair<Layer*, sp<LayerFE>>> layers;
+ layers.reserve(layerCount);
+ std::unordered_set<compositionengine::LayerFE*> filterForScreenshot;
+ traverseLayers([&](Layer* layer) {
auto strongLayer = sp<Layer>::fromExisting(layer);
- auto layerFE = layer->getCompositionEngineLayerFE();
- if (!layerFE) {
- return;
- }
+ captureResults.capturedHdrLayers |= isHdrLayer(layer);
// Layer::prepareClientComposition uses the layer's snapshot to populate the resulting
// LayerSettings. Calling Layer::updateSnapshot ensures that LayerSettings are
// generated with the layer's current buffer and geometry.
layer->updateSnapshot(true /* updateGeometry */);
- disableBlurs |= layer->getDrawingState().sidebandStream != nullptr;
+ layers.emplace_back(layer, layer->copyCompositionEngineLayerFE());
- Region clip(renderArea.getBounds());
- compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
- clip,
- layer->needsFilteringForScreenshots(display.get(), transform) ||
- renderArea.needsFiltering(),
- renderArea.isSecure(),
- useProtected,
- layerStackSpaceRect,
- clientCompositionDisplay.outputDataspace,
- true, /* realContentIsVisible */
- false, /* clearContent */
- disableBlurs ? compositionengine::LayerFE::ClientCompositionTargetSettings::
- BlurSetting::Disabled
- : compositionengine::LayerFE::ClientCompositionTargetSettings::
- BlurSetting::Enabled,
- isHdrLayer(layer) ? displayBrightnessNits : sdrWhitePointNits,
+ sp<LayerFE>& layerFE = layers.back().second;
- };
- std::optional<compositionengine::LayerFE::LayerSettings> settings;
- {
- LayerSnapshotGuard layerSnapshotGuard(layer);
- settings = layerFE->prepareClientComposition(targetSettings);
+ layerFE->mSnapshot->geomLayerTransform =
+ renderArea->getTransform() * layerFE->mSnapshot->geomLayerTransform;
+
+ if (layer->needsFilteringForScreenshots(display.get(), transform)) {
+ filterForScreenshot.insert(layerFE.get());
}
-
- if (!settings) {
- return;
- }
-
- settings->geometry.positionTransform =
- transform.asMatrix4() * settings->geometry.positionTransform;
- // There's no need to process blurs when we're executing region sampling,
- // we're just trying to understand what we're drawing, and doing so without
- // blurs is already a pretty good approximation.
- if (regionSampling) {
- settings->backgroundBlurRadius = 0;
- settings->blurRegions.clear();
- }
- captureResults.capturedHdrLayers |= isHdrLayer(layer);
-
- clientCompositionLayers.push_back(std::move(*settings));
- renderedLayers.push_back(layer);
});
- std::vector<renderengine::LayerSettings> clientRenderEngineLayers;
- clientRenderEngineLayers.reserve(clientCompositionLayers.size());
- std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(),
- std::back_inserter(clientRenderEngineLayers),
- [](compositionengine::LayerFE::LayerSettings& settings)
- -> renderengine::LayerSettings { return settings; });
-
- // Use an empty fence for the buffer fence, since we just created the buffer so
- // there is no need for synchronization with the GPU.
- base::unique_fd bufferFence;
-
- constexpr bool kUseFramebufferCache = false;
- const auto future = getRenderEngine()
- .drawLayers(clientCompositionDisplay, clientRenderEngineLayers,
- buffer, kUseFramebufferCache, std::move(bufferFence))
- .share();
-
- for (auto* layer : renderedLayers) {
- layer->onLayerDisplayed(future);
+ ui::LayerStack layerStack{ui::DEFAULT_LAYER_STACK};
+ if (!layers.empty()) {
+ const sp<LayerFE>& layerFE = layers.back().second;
+ layerStack = layerFE->getCompositionState()->outputFilter.layerStack;
}
- return future;
+ auto copyLayerFEs = [&layers]() {
+ std::vector<sp<compositionengine::LayerFE>> layerFEs;
+ layerFEs.reserve(layers.size());
+ for (const auto& [_, layerFE] : layers) {
+ layerFEs.push_back(layerFE);
+ }
+ return layerFEs;
+ };
+
+ auto present = [this, buffer = std::move(buffer), dataspace, sdrWhitePointNits,
+ displayBrightnessNits, filterForScreenshot = std::move(filterForScreenshot),
+ grayscale, layerFEs = copyLayerFEs(), layerStack, regionSampling,
+ renderArea = std::move(renderArea), renderIntent]() -> FenceResult {
+ std::unique_ptr<compositionengine::CompositionEngine> compositionEngine =
+ mFactory.createCompositionEngine();
+ compositionEngine->setRenderEngine(mRenderEngine.get());
+
+ compositionengine::Output::ColorProfile colorProfile{.dataspace = dataspace,
+ .renderIntent = renderIntent};
+
+ std::shared_ptr<ScreenCaptureOutput> output = createScreenCaptureOutput(
+ ScreenCaptureOutputArgs{.compositionEngine = *compositionEngine,
+ .colorProfile = colorProfile,
+ .renderArea = *renderArea,
+ .layerStack = layerStack,
+ .buffer = std::move(buffer),
+ .sdrWhitePointNits = sdrWhitePointNits,
+ .displayBrightnessNits = displayBrightnessNits,
+ .filterForScreenshot = std::move(filterForScreenshot),
+ .regionSampling = regionSampling});
+
+ const float colorSaturation = grayscale ? 0 : 1;
+ compositionengine::CompositionRefreshArgs refreshArgs{
+ .outputs = {output},
+ .layers = std::move(layerFEs),
+ .updatingOutputGeometryThisFrame = true,
+ .updatingGeometryThisFrame = true,
+ .colorTransformMatrix = calculateColorMatrix(colorSaturation),
+ };
+ compositionEngine->present(refreshArgs);
+
+ return output->getRenderSurface()->getClientTargetAcquireFence();
+ };
+
+ // If RenderEngine is threaded, we can safely call CompositionEngine::present off the main
+ // thread as the RenderEngine::drawLayers call will run on RenderEngine's thread. Otherwise,
+ // we need RenderEngine to run on the main thread so we call CompositionEngine::present
+ // immediately.
+ //
+ // TODO(b/196334700) Once we use RenderEngineThreaded everywhere we can always defer the call
+ // to CompositionEngine::present.
+ const bool renderEngineIsThreaded = [&]() {
+ using Type = renderengine::RenderEngine::RenderEngineType;
+ const auto type = mRenderEngine->getRenderEngineType();
+ return type == Type::THREADED || type == Type::SKIA_GL_THREADED;
+ }();
+ auto presentFuture = renderEngineIsThreaded ? ftl::defer(std::move(present)).share()
+ : ftl::yield(present()).share();
+
+ for (auto& [layer, layerFE] : layers) {
+ layer->onLayerDisplayed(
+ ftl::Future(presentFuture)
+ .then([layerFE = std::move(layerFE)](FenceResult) {
+ return layerFE->stealCompositionResult().releaseFences.back().get();
+ })
+ .share());
+ }
+
+ return presentFuture;
}
// ---------------------------------------------------------------------------
@@ -6990,9 +6994,11 @@
}
mActiveDisplayId = activeDisplay->getPhysicalId();
activeDisplay->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true);
+
updateInternalDisplayVsyncLocked(activeDisplay);
mScheduler->setModeChangePending(false);
- mScheduler->setRefreshRateSelector(activeDisplay->holdRefreshRateSelector());
+ mScheduler->setLeaderDisplay(mActiveDisplayId);
+
onActiveDisplaySizeChanged(activeDisplay);
mActiveDisplayTransformHint = activeDisplay->getTransformHint();
@@ -7017,9 +7023,16 @@
BufferData& bufferData, const char* layerName, uint64_t transactionId) {
if (bufferData.buffer &&
exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(), bufferData.buffer->getHeight())) {
- ALOGE("Attempted to create an ExternalTexture for layer %s that exceeds render target "
- "size limit.",
- layerName);
+ std::string errorMessage =
+ base::StringPrintf("Attempted to create an ExternalTexture with size (%u, %u) for "
+ "layer %s that exceeds render target size limit of %u.",
+ bufferData.buffer->getWidth(), bufferData.buffer->getHeight(),
+ layerName, static_cast<uint32_t>(mMaxRenderTargetSize));
+ ALOGD("%s", errorMessage.c_str());
+ if (bufferData.releaseBufferListener) {
+ bufferData.releaseBufferListener->onTransactionQueueStalled(
+ String8(errorMessage.c_str()));
+ }
return nullptr;
}
@@ -7032,9 +7045,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 df9006e..c2d3343 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -464,8 +464,7 @@
typename Handler = VsyncModulator::VsyncConfigOpt (VsyncModulator::*)(Args...)>
void modulateVsync(Handler handler, Args... args) {
if (const auto config = (*mVsyncModulator.*handler)(args...)) {
- const auto vsyncPeriod = mScheduler->getVsyncPeriodFromRefreshRateSelector();
- setVsyncConfig(*config, vsyncPeriod);
+ setVsyncConfig(*config, mScheduler->getLeaderVsyncPeriod());
}
}
@@ -490,9 +489,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 +691,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 +713,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);
@@ -780,7 +779,7 @@
const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
bool grayscale, const sp<IScreenCaptureListener>&);
ftl::SharedFuture<FenceResult> renderScreenImpl(
- const RenderArea&, TraverseLayersFunction,
+ std::unique_ptr<RenderArea>, TraverseLayersFunction,
const std::shared_ptr<renderengine::ExternalTexture>&, bool canCaptureBlackoutContent,
bool regionSampling, bool grayscale, ScreenCaptureResults&) EXCLUDES(mStateLock)
REQUIRES(kMainThreadContext);
@@ -928,7 +927,8 @@
const sp<compositionengine::DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer) REQUIRES(mStateLock);
void processDisplayChangesLocked() REQUIRES(mStateLock, kMainThreadContext);
- void processDisplayRemoved(const wp<IBinder>& displayToken) REQUIRES(mStateLock);
+ void processDisplayRemoved(const wp<IBinder>& displayToken)
+ REQUIRES(mStateLock, kMainThreadContext);
void processDisplayChanged(const wp<IBinder>& displayToken,
const DisplayDeviceState& currentState,
const DisplayDeviceState& drawingState)
@@ -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..577f84e 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -230,7 +230,10 @@
ISchedulerCallback& callback)
: Scheduler(*this, callback, Feature::kContentDetection) {
mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller)));
- setRefreshRateSelector(std::move(selectorPtr));
+
+ const auto displayId = FTL_FAKE_GUARD(kMainThreadContext,
+ selectorPtr->getActiveMode().getPhysicalDisplayId());
+ registerDisplay(displayId, std::move(selectorPtr));
}
ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) {
@@ -242,7 +245,7 @@
auto &mutableLayerHistory() { return mLayerHistory; }
- auto refreshRateSelector() { return holdRefreshRateSelector(); }
+ auto refreshRateSelector() { return leaderSelectorPtr(); }
void replaceTouchTimer(int64_t millis) {
if (mTouchTimer) {
@@ -730,12 +733,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/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 7148c11..06b9caa 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -244,8 +244,8 @@
HAL_PIXEL_FORMAT_RGBA_8888, 1,
usage);
- auto future = mFlinger.renderScreenImpl(*renderArea, traverseLayers, mCaptureScreenBuffer,
- forSystem, regionSampling);
+ auto future = mFlinger.renderScreenImpl(std::move(renderArea), traverseLayers,
+ mCaptureScreenBuffer, forSystem, regionSampling);
ASSERT_TRUE(future.valid());
const auto fenceResult = future.get();
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/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index ea4666e..8e333a3 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -190,8 +190,10 @@
sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
ASSERT_EQ(1u, mScheduler->layerHistorySize());
- mScheduler->setRefreshRateSelector(
- std::make_shared<RefreshRateSelector>(kDisplay1Modes, kDisplay1Mode60->getId()));
+ // Replace `mSelector` with a new `RefreshRateSelector` that has different display modes.
+ mScheduler->registerDisplay(kDisplayId1,
+ std::make_shared<RefreshRateSelector>(kDisplay1Modes,
+ kDisplay1Mode60->getId()));
ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
@@ -234,11 +236,9 @@
}
TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) {
- const auto selectorPtr =
- std::make_shared<RefreshRateSelector>(kDisplay1Modes, kDisplay1Mode60->getId());
-
- mScheduler->registerDisplay(kDisplayId1, selectorPtr);
- mScheduler->setRefreshRateSelector(selectorPtr);
+ mScheduler->registerDisplay(kDisplayId1,
+ std::make_shared<RefreshRateSelector>(kDisplay1Modes,
+ kDisplay1Mode60->getId()));
const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true));
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index ba214d5..3f8fe0d 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -43,7 +43,10 @@
ISchedulerCallback& callback)
: Scheduler(*this, callback, Feature::kContentDetection) {
mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller)));
- setRefreshRateSelector(std::move(selectorPtr));
+
+ const auto displayId = FTL_FAKE_GUARD(kMainThreadContext,
+ selectorPtr->getActiveMode().getPhysicalDisplayId());
+ registerDisplay(displayId, std::move(selectorPtr));
ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) {
// Execute task to prevent broken promise exception on destruction.
@@ -67,12 +70,27 @@
auto& mutablePrimaryHWVsyncEnabled() { return mPrimaryHWVsyncEnabled; }
auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; }
- auto refreshRateSelector() { return holdRefreshRateSelector(); }
- bool hasRefreshRateSelectors() const { return !mRefreshRateSelectors.empty(); }
+ auto refreshRateSelector() { return leaderSelectorPtr(); }
- void setRefreshRateSelector(RefreshRateSelectorPtr selectorPtr) {
+ const auto& refreshRateSelectors() const NO_THREAD_SAFETY_ANALYSIS {
+ return mRefreshRateSelectors;
+ }
+
+ bool hasRefreshRateSelectors() const { return !refreshRateSelectors().empty(); }
+
+ void registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) {
ftl::FakeGuard guard(kMainThreadContext);
- return Scheduler::setRefreshRateSelector(std::move(selectorPtr));
+ Scheduler::registerDisplay(displayId, std::move(selectorPtr));
+ }
+
+ void unregisterDisplay(PhysicalDisplayId displayId) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ Scheduler::unregisterDisplay(displayId);
+ }
+
+ void setLeaderDisplay(PhysicalDisplayId displayId) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ Scheduler::setLeaderDisplay(displayId);
}
auto& mutableLayerHistory() { return mLayerHistory; }
@@ -115,14 +133,13 @@
using Scheduler::DisplayModeChoice;
using Scheduler::DisplayModeChoiceMap;
- DisplayModeChoiceMap chooseDisplayModes() {
- std::lock_guard<std::mutex> lock(mPolicyLock);
+ DisplayModeChoiceMap chooseDisplayModes() NO_THREAD_SAFETY_ANALYSIS {
return Scheduler::chooseDisplayModes();
}
void dispatchCachedReportedMode() {
std::lock_guard<std::mutex> lock(mPolicyLock);
- return Scheduler::dispatchCachedReportedMode();
+ Scheduler::dispatchCachedReportedMode();
}
void clearCachedReportedMode() {
@@ -131,7 +148,7 @@
}
void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
- return Scheduler::onNonPrimaryDisplayModeChanged(handle, mode);
+ Scheduler::onNonPrimaryDisplayModeChanged(handle, mode);
}
private:
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 46eca69..c15b3c8 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -37,6 +37,7 @@
#include "FrontEnd/LayerHandle.h"
#include "Layer.h"
#include "NativeWindowSurface.h"
+#include "RenderArea.h"
#include "Scheduler/MessageQueue.h"
#include "Scheduler/RefreshRateSelector.h"
#include "StartPropertySetThread.h"
@@ -399,14 +400,14 @@
return mFlinger->setPowerModeInternal(display, mode);
}
- auto renderScreenImpl(const RenderArea& renderArea,
- SurfaceFlinger::TraverseLayersFunction traverseLayers,
- const std::shared_ptr<renderengine::ExternalTexture>& buffer,
- bool forSystem, bool regionSampling) {
+ auto renderScreenImpl(std::unique_ptr<RenderArea> renderArea,
+ SurfaceFlinger::TraverseLayersFunction traverseLayers,
+ const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+ bool forSystem, bool regionSampling) {
ScreenCaptureResults captureResults;
return FTL_FAKE_GUARD(kMainThreadContext,
- mFlinger->renderScreenImpl(renderArea, traverseLayers, buffer,
- forSystem, regionSampling,
+ mFlinger->renderScreenImpl(std::move(renderArea), traverseLayers,
+ buffer, forSystem, regionSampling,
false /* grayscale */, captureResults));
}
@@ -428,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));
}
@@ -836,33 +843,36 @@
sp<DisplayDevice> display = sp<DisplayDevice>::make(mCreationArgs);
mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display);
- if (mFlinger.scheduler()) {
- mFlinger.scheduler()->registerDisplay(display->getPhysicalId(),
- display->holdRefreshRateSelector());
- }
DisplayDeviceState state;
state.isSecure = mCreationArgs.isSecure;
if (mConnectionType) {
LOG_ALWAYS_FATAL_IF(!displayId);
- const auto physicalId = PhysicalDisplayId::tryCast(*displayId);
- LOG_ALWAYS_FATAL_IF(!physicalId);
+ const auto physicalIdOpt = PhysicalDisplayId::tryCast(*displayId);
+ LOG_ALWAYS_FATAL_IF(!physicalIdOpt);
+ const auto physicalId = *physicalIdOpt;
+
LOG_ALWAYS_FATAL_IF(!mHwcDisplayId);
const auto activeMode = modes.get(activeModeId);
LOG_ALWAYS_FATAL_IF(!activeMode);
- state.physical = {.id = *physicalId,
+ state.physical = {.id = physicalId,
.hwcDisplayId = *mHwcDisplayId,
.activeMode = activeMode->get()};
const auto it = mFlinger.mutablePhysicalDisplays()
- .emplace_or_replace(*physicalId, mDisplayToken, *physicalId,
+ .emplace_or_replace(physicalId, mDisplayToken, physicalId,
*mConnectionType, std::move(modes),
ui::ColorModes(), std::nullopt)
.first;
+ if (mFlinger.scheduler()) {
+ mFlinger.scheduler()->registerDisplay(physicalId,
+ display->holdRefreshRateSelector());
+ }
+
display->setActiveMode(activeModeId, it->second.snapshot());
}
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/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h
index ba98696..40cf9fb 100644
--- a/vulkan/include/vulkan/vk_android_native_buffer.h
+++ b/vulkan/include/vulkan/vk_android_native_buffer.h
@@ -49,7 +49,13 @@
* in VkBindImageMemorySwapchainInfoKHR will be additionally chained to the
* pNext chain of VkBindImageMemoryInfo and passed down to the driver.
*/
-#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 8
+/*
+ * NOTE ON VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 9
+ *
+ * This version of the extension is largely designed to clean up the mix of
+ * GrallocUsage and GrallocUsage2
+ */
+#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 9
#define VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME "VK_ANDROID_native_buffer"
#define VK_ANDROID_NATIVE_BUFFER_ENUM(type, id) \
@@ -61,6 +67,8 @@
VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 1)
#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID \
VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 2)
+#define VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID \
+ VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 3)
/* clang-format off */
typedef enum VkSwapchainImageUsageFlagBitsANDROID {
@@ -90,6 +98,7 @@
* format: gralloc format requested when the buffer was allocated
* usage: gralloc usage requested when the buffer was allocated
* usage2: gralloc usage requested when the buffer was allocated
+ * usage3: gralloc usage requested when the buffer was allocated
*/
typedef struct {
VkStructureType sType;
@@ -98,7 +107,8 @@
int stride;
int format;
int usage; /* DEPRECATED in SPEC_VERSION 6 */
- VkNativeBufferUsage2ANDROID usage2; /* ADDED in SPEC_VERSION 6 */
+ VkNativeBufferUsage2ANDROID usage2; /* DEPRECATED in SPEC_VERSION 9 */
+ uint64_t usage3; /* ADDED in SPEC_VERSION 9 */
} VkNativeBufferANDROID;
/*
@@ -127,6 +137,21 @@
VkBool32 sharedImage;
} VkPhysicalDevicePresentationPropertiesANDROID;
+/*
+ * struct VkGrallocUsageInfoANDROID
+ *
+ * sType: VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID
+ * pNext: NULL or a pointer to a structure extending this structure
+ * format: value specifying the format the image will be created with
+ * imageUsage: bitmask of VkImageUsageFlagBits describing intended usage
+ */
+typedef struct {
+ VkStructureType sType;
+ const void* pNext;
+ VkFormat format;
+ VkImageUsageFlags imageUsage;
+} VkGrallocUsageInfoANDROID;
+
/* DEPRECATED in SPEC_VERSION 6 */
typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsageANDROID)(
VkDevice device,
@@ -134,7 +159,7 @@
VkImageUsageFlags imageUsage,
int* grallocUsage);
-/* ADDED in SPEC_VERSION 6 */
+/* DEPRECATED in SPEC_VERSION 9 */
typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsage2ANDROID)(
VkDevice device,
VkFormat format,
@@ -143,6 +168,12 @@
uint64_t* grallocConsumerUsage,
uint64_t* grallocProducerUsage);
+/* ADDED in SPEC_VERSION 9 */
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsage3ANDROID)(
+ VkDevice device,
+ const VkGrallocUsageInfoANDROID* grallocUsageInfo,
+ uint64_t* grallocUsage);
+
typedef VkResult (VKAPI_PTR *PFN_vkAcquireImageANDROID)(
VkDevice device,
VkImage image,
@@ -167,7 +198,7 @@
int* grallocUsage
);
-/* ADDED in SPEC_VERSION 6 */
+/* DEPRECATED in SPEC_VERSION 9 */
VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage2ANDROID(
VkDevice device,
VkFormat format,
@@ -177,6 +208,13 @@
uint64_t* grallocProducerUsage
);
+/* ADDED in SPEC_VERSION 9 */
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage3ANDROID(
+ VkDevice device,
+ const VkGrallocUsageInfoANDROID* grallocUsageInfo,
+ uint64_t* grallocUsage
+);
+
VKAPI_ATTR VkResult VKAPI_CALL vkAcquireImageANDROID(
VkDevice device,
VkImage image,
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 7664518..4927150 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -1027,6 +1027,39 @@
}
}
+bool GetAndroidNativeBufferSpecVersion9Support(
+ VkPhysicalDevice physicalDevice) {
+ const InstanceData& data = GetData(physicalDevice);
+
+ // Call to get propertyCount
+ uint32_t propertyCount = 0;
+ ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
+ VkResult result = data.driver.EnumerateDeviceExtensionProperties(
+ physicalDevice, nullptr, &propertyCount, nullptr);
+ ATRACE_END();
+
+ // Call to enumerate properties
+ std::vector<VkExtensionProperties> properties(propertyCount);
+ ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
+ result = data.driver.EnumerateDeviceExtensionProperties(
+ physicalDevice, nullptr, &propertyCount, properties.data());
+ ATRACE_END();
+
+ for (uint32_t i = 0; i < propertyCount; i++) {
+ auto& prop = properties[i];
+
+ if (strcmp(prop.extensionName,
+ VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) != 0)
+ continue;
+
+ if (prop.specVersion >= 9) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
VkResult EnumerateDeviceExtensionProperties(
VkPhysicalDevice physicalDevice,
const char* pLayerName,
@@ -1061,6 +1094,37 @@
VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION});
}
+ // Conditionally add VK_EXT_IMAGE_COMPRESSION_CONTROL* if feature and ANB
+ // support is provided by the driver
+ VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT
+ swapchainCompFeats = {};
+ swapchainCompFeats.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT;
+ swapchainCompFeats.pNext = nullptr;
+ VkPhysicalDeviceImageCompressionControlFeaturesEXT imageCompFeats = {};
+ imageCompFeats.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT;
+ imageCompFeats.pNext = &swapchainCompFeats;
+
+ VkPhysicalDeviceFeatures2 feats2 = {};
+ feats2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ feats2.pNext = &imageCompFeats;
+
+ GetPhysicalDeviceFeatures2(physicalDevice, &feats2);
+
+ bool anb9 = GetAndroidNativeBufferSpecVersion9Support(physicalDevice);
+
+ if (anb9 && imageCompFeats.imageCompressionControl) {
+ loader_extensions.push_back(
+ {VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME,
+ VK_EXT_IMAGE_COMPRESSION_CONTROL_SPEC_VERSION});
+ }
+ if (anb9 && swapchainCompFeats.imageCompressionControlSwapchain) {
+ loader_extensions.push_back(
+ {VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME,
+ VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION});
+ }
+
// enumerate our extensions first
if (!pLayerName && pProperties) {
uint32_t count = std::min(
@@ -1254,15 +1318,18 @@
return VK_ERROR_INCOMPATIBLE_DRIVER;
}
- // sanity check ANDROID_native_buffer implementation, whose set of
+ // Confirming ANDROID_native_buffer implementation, whose set of
// entrypoints varies according to the spec version.
if ((wrapper.GetHalExtensions()[ProcHook::ANDROID_native_buffer]) &&
!data->driver.GetSwapchainGrallocUsageANDROID &&
- !data->driver.GetSwapchainGrallocUsage2ANDROID) {
- ALOGE("Driver's implementation of ANDROID_native_buffer is broken;"
- " must expose at least one of "
- "vkGetSwapchainGrallocUsageANDROID or "
- "vkGetSwapchainGrallocUsage2ANDROID");
+ !data->driver.GetSwapchainGrallocUsage2ANDROID &&
+ !data->driver.GetSwapchainGrallocUsage3ANDROID) {
+ ALOGE(
+ "Driver's implementation of ANDROID_native_buffer is broken;"
+ " must expose at least one of "
+ "vkGetSwapchainGrallocUsageANDROID or "
+ "vkGetSwapchainGrallocUsage2ANDROID or "
+ "vkGetSwapchainGrallocUsage3ANDROID");
data->driver.DestroyDevice(dev, pAllocator);
FreeDeviceData(data, data_allocator);
@@ -1441,10 +1508,83 @@
if (driver.GetPhysicalDeviceFeatures2) {
driver.GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
+ } else {
+ driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, pFeatures);
+ }
+
+ // Conditionally add imageCompressionControlSwapchain if
+ // imageCompressionControl is supported Check for imageCompressionControl in
+ // the pChain
+ bool imageCompressionControl = false;
+ bool imageCompressionControlInChain = false;
+ bool imageCompressionControlSwapchainInChain = false;
+ VkPhysicalDeviceFeatures2* pFeats = pFeatures;
+ while (pFeats) {
+ switch (pFeats->sType) {
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT: {
+ const VkPhysicalDeviceImageCompressionControlFeaturesEXT*
+ compressionFeat = reinterpret_cast<
+ const VkPhysicalDeviceImageCompressionControlFeaturesEXT*>(
+ pFeats);
+ imageCompressionControl =
+ compressionFeat->imageCompressionControl;
+ imageCompressionControlInChain = true;
+ } break;
+
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: {
+ imageCompressionControlSwapchainInChain = true;
+ } break;
+
+ default:
+ break;
+ }
+ pFeats = reinterpret_cast<VkPhysicalDeviceFeatures2*>(pFeats->pNext);
+ }
+
+ if (!imageCompressionControlSwapchainInChain) {
return;
}
- driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, pFeatures);
+ // If not in pchain, explicitly query for imageCompressionControl
+ if (!imageCompressionControlInChain) {
+ VkPhysicalDeviceImageCompressionControlFeaturesEXT imageCompFeats = {};
+ imageCompFeats.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT;
+ imageCompFeats.pNext = nullptr;
+
+ VkPhysicalDeviceFeatures2 feats2 = {};
+ feats2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ feats2.pNext = &imageCompFeats;
+
+ if (driver.GetPhysicalDeviceFeatures2) {
+ driver.GetPhysicalDeviceFeatures2(physicalDevice, &feats2);
+ } else {
+ driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, &feats2);
+ }
+
+ imageCompressionControl = imageCompFeats.imageCompressionControl;
+ }
+
+ // Only enumerate imageCompressionControlSwapchin if imageCompressionControl
+ if (imageCompressionControl) {
+ pFeats = pFeatures;
+ while (pFeats) {
+ switch (pFeats->sType) {
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: {
+ VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT*
+ compressionFeat = reinterpret_cast<
+ VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT*>(
+ pFeats);
+ compressionFeat->imageCompressionControlSwapchain = true;
+ } break;
+
+ default:
+ break;
+ }
+ pFeats =
+ reinterpret_cast<VkPhysicalDeviceFeatures2*>(pFeats->pNext);
+ }
+ }
}
void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 14c516b..4d2bbd6 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -107,6 +107,8 @@
VkPhysicalDevice physicalDevice,
VkPhysicalDevicePresentationPropertiesANDROID* presentation_properties);
+bool GetAndroidNativeBufferSpecVersion9Support(VkPhysicalDevice physicalDevice);
+
VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
const char* pName);
VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device,
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index b436db1..de98aa7 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -496,6 +496,13 @@
nullptr,
},
{
+ "vkGetSwapchainGrallocUsage3ANDROID",
+ ProcHook::DEVICE,
+ ProcHook::ANDROID_native_buffer,
+ nullptr,
+ nullptr,
+ },
+ {
"vkGetSwapchainGrallocUsageANDROID",
ProcHook::DEVICE,
ProcHook::ANDROID_native_buffer,
@@ -664,6 +671,7 @@
INIT_PROC(false, dev, GetDeviceQueue2);
INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsageANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage2ANDROID);
+ INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage3ANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, true, dev, AcquireImageANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, true, dev, QueueSignalReleaseImageANDROID);
// clang-format on
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 079f9cc..2f60086 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -123,6 +123,7 @@
PFN_vkGetDeviceQueue2 GetDeviceQueue2;
PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
PFN_vkGetSwapchainGrallocUsage2ANDROID GetSwapchainGrallocUsage2ANDROID;
+ PFN_vkGetSwapchainGrallocUsage3ANDROID GetSwapchainGrallocUsage3ANDROID;
PFN_vkAcquireImageANDROID AcquireImageANDROID;
PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
// clang-format on
diff --git a/vulkan/libvulkan/libvulkan.map.txt b/vulkan/libvulkan/libvulkan.map.txt
index f49e8f3..b189c68 100644
--- a/vulkan/libvulkan/libvulkan.map.txt
+++ b/vulkan/libvulkan/libvulkan.map.txt
@@ -178,6 +178,7 @@
vkGetImageSparseMemoryRequirements;
vkGetImageSparseMemoryRequirements2; # introduced=28
vkGetImageSubresourceLayout;
+ vkGetImageSubresourceLayout2EXT; # introduced=UpsideDownCake
vkGetInstanceProcAddr;
vkGetMemoryAndroidHardwareBufferANDROID; # introduced=28
vkGetPhysicalDeviceExternalBufferProperties; # introduced=28
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index abcac3c..4f7b923 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
@@ -938,11 +948,60 @@
surface_formats.data());
if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
+ const auto& driver = GetData(physicalDevice).driver;
+
// marshal results individually due to stride difference.
- // completely ignore any chained extension structs.
uint32_t formats_to_marshal = *pSurfaceFormatCount;
for (uint32_t i = 0u; i < formats_to_marshal; i++) {
pSurfaceFormats[i].surfaceFormat = surface_formats[i];
+
+ // Query the compression properties for the surface format
+ if (pSurfaceFormats[i].pNext) {
+ VkImageCompressionPropertiesEXT* surfaceCompressionProps =
+ reinterpret_cast<VkImageCompressionPropertiesEXT*>(
+ pSurfaceFormats[i].pNext);
+
+ if (surfaceCompressionProps &&
+ driver.GetPhysicalDeviceImageFormatProperties2KHR) {
+ VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
+ imageFormatInfo.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
+ imageFormatInfo.format =
+ pSurfaceFormats[i].surfaceFormat.format;
+ imageFormatInfo.pNext = nullptr;
+
+ VkImageCompressionControlEXT compressionControl = {};
+ compressionControl.sType =
+ VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT;
+ compressionControl.pNext = imageFormatInfo.pNext;
+
+ imageFormatInfo.pNext = &compressionControl;
+
+ VkImageCompressionPropertiesEXT compressionProps = {};
+ compressionProps.sType =
+ VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT;
+ compressionProps.pNext = nullptr;
+
+ VkImageFormatProperties2KHR imageFormatProps = {};
+ imageFormatProps.sType =
+ VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR;
+ imageFormatProps.pNext = &compressionProps;
+
+ VkResult compressionRes =
+ driver.GetPhysicalDeviceImageFormatProperties2KHR(
+ physicalDevice, &imageFormatInfo,
+ &imageFormatProps);
+ if (compressionRes == VK_SUCCESS) {
+ surfaceCompressionProps->imageCompressionFlags =
+ compressionProps.imageCompressionFlags;
+ surfaceCompressionProps
+ ->imageCompressionFixedRateFlags =
+ compressionProps.imageCompressionFixedRateFlags;
+ } else {
+ return compressionRes;
+ }
+ }
+ }
}
}
@@ -1360,8 +1419,48 @@
num_images = 1;
}
+ void* usage_info_pNext = nullptr;
+ VkImageCompressionControlEXT image_compression = {};
uint64_t native_usage = 0;
- if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
+ if (dispatch.GetSwapchainGrallocUsage3ANDROID) {
+ ATRACE_BEGIN("GetSwapchainGrallocUsage3ANDROID");
+ VkGrallocUsageInfoANDROID gralloc_usage_info = {};
+ gralloc_usage_info.sType = VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID;
+ gralloc_usage_info.format = create_info->imageFormat;
+ gralloc_usage_info.imageUsage = create_info->imageUsage;
+
+ // Look through the pNext chain for an image compression control struct
+ // if one is found AND the appropriate extensions are enabled,
+ // append it to be the gralloc usage pNext chain
+ const VkSwapchainCreateInfoKHR* create_infos = create_info;
+ while (create_infos->pNext) {
+ create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
+ create_infos->pNext);
+ switch (create_infos->sType) {
+ case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
+ const VkImageCompressionControlEXT* compression_infos =
+ reinterpret_cast<const VkImageCompressionControlEXT*>(
+ create_infos);
+ image_compression = *compression_infos;
+ image_compression.pNext = nullptr;
+ usage_info_pNext = &image_compression;
+ } break;
+
+ default:
+ // Ignore all other info structs
+ break;
+ }
+ }
+ gralloc_usage_info.pNext = usage_info_pNext;
+
+ result = dispatch.GetSwapchainGrallocUsage3ANDROID(
+ device, &gralloc_usage_info, &native_usage);
+ ATRACE_END();
+ if (result != VK_SUCCESS) {
+ ALOGE("vkGetSwapchainGrallocUsage3ANDROID failed: %d", result);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ } else if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
uint64_t consumer_usage, producer_usage;
ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID");
result = dispatch.GetSwapchainGrallocUsage2ANDROID(
@@ -1373,7 +1472,7 @@
return VK_ERROR_SURFACE_LOST_KHR;
}
native_usage =
- convertGralloc1ToBufferUsage(consumer_usage, producer_usage);
+ convertGralloc1ToBufferUsage(producer_usage, consumer_usage);
} else if (dispatch.GetSwapchainGrallocUsageANDROID) {
ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID");
int32_t legacy_usage = 0;
@@ -1427,7 +1526,7 @@
#pragma clang diagnostic ignored "-Wold-style-cast"
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID,
#pragma clang diagnostic pop
- .pNext = nullptr,
+ .pNext = usage_info_pNext,
.usage = swapchain_image_usage,
};
VkNativeBufferANDROID image_native_buffer = {
@@ -1485,6 +1584,7 @@
android_convertGralloc0To1Usage(int(img.buffer->usage),
&image_native_buffer.usage2.producer,
&image_native_buffer.usage2.consumer);
+ image_native_buffer.usage3 = img.buffer->usage;
ATRACE_BEGIN("CreateImage");
result =
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 3c91150..f998b1a 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -948,6 +948,17 @@
return VK_SUCCESS;
}
+VkResult GetSwapchainGrallocUsage3ANDROID(
+ VkDevice,
+ const VkGrallocUsageInfoANDROID* grallocUsageInfo,
+ uint64_t* grallocUsage) {
+ // The null driver never reads or writes the gralloc buffer
+ ALOGV("TODO: vk%s - grallocUsageInfo->format:%i", __FUNCTION__,
+ grallocUsageInfo->format);
+ *grallocUsage = 0;
+ return VK_SUCCESS;
+}
+
VkResult AcquireImageANDROID(VkDevice,
VkImage,
int fence,
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index f6dcf09..0cb7bd3 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -261,6 +261,7 @@
{"vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetRenderAreaGranularity>(GetRenderAreaGranularity))},
{"vkGetSemaphoreCounterValue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSemaphoreCounterValue>(GetSemaphoreCounterValue))},
{"vkGetSwapchainGrallocUsage2ANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsage2ANDROID>(GetSwapchainGrallocUsage2ANDROID))},
+ {"vkGetSwapchainGrallocUsage3ANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsage3ANDROID>(GetSwapchainGrallocUsage3ANDROID))},
{"vkGetSwapchainGrallocUsageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(GetSwapchainGrallocUsageANDROID))},
{"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkInvalidateMappedMemoryRanges>(InvalidateMappedMemoryRanges))},
{"vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkMapMemory>(MapMemory))},
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 3e003e3..5c7fea0 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -209,6 +209,7 @@
VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
+VKAPI_ATTR VkResult GetSwapchainGrallocUsage3ANDROID(VkDevice device, const VkGrallocUsageInfoANDROID* grallocUsageInfo, uint64_t* grallocUsage);
VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index 4176509..c25c6cb 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -69,6 +69,7 @@
_OPTIONAL_COMMANDS = [
'vkGetSwapchainGrallocUsageANDROID',
'vkGetSwapchainGrallocUsage2ANDROID',
+ 'vkGetSwapchainGrallocUsage3ANDROID',
]
# Dict for mapping dispatch table to a type.