Merge changes If83c9084,Iee87316e
* changes:
SF: Identify the active display with its ID
SF: Refactor setter for DM and override policy
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 6fb9a4d..48d48ac 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -193,8 +193,9 @@
{ OPT, "events/ext4/ext4_da_write_end/enable" },
{ OPT, "events/ext4/ext4_sync_file_enter/enable" },
{ OPT, "events/ext4/ext4_sync_file_exit/enable" },
- { REQ, "events/block/block_rq_issue/enable" },
- { REQ, "events/block/block_rq_complete/enable" },
+ { OPT, "events/block/block_bio_queue/enable" },
+ { OPT, "events/block/block_bio_complete/enable" },
+ { OPT, "events/ufs/ufshcd_command/enable" },
} },
{ "mmc", "eMMC commands", 0, {
{ REQ, "events/mmc/enable" },
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index fe91341..60c2077 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1052,7 +1052,7 @@
return;
}
RunCommandToFd(fd, "", {"dumpsys", "netstats", "--proto"},
- CommandOptions::WithTimeout(120).Build());
+ CommandOptions::WithTimeout(5).Build());
bool empty = 0 == lseek(fd, 0, SEEK_END);
if (!empty) {
ds.EnqueueAddZipEntryAndCleanupIfNeeded(kProtoPath + "netstats" + kProtoExt,
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index e978e79..6a3120c 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -27,6 +27,7 @@
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/mman.h>
+#include <sys/wait.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
@@ -504,6 +505,11 @@
return 0;
}
+ if (WIFSIGNALED(dexopt_result)) {
+ LOG(WARNING) << "Interrupted by signal " << WTERMSIG(dexopt_result) ;
+ return dexopt_result;
+ }
+
// If this was a profile-guided run, we may have profile version issues. Try to downgrade,
// if possible.
if ((parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) {
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index a99ccae..3681d5b 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -49,14 +49,14 @@
#ifdef __ANDROID_RECOVERY__
auto vintfObject = vintf::VintfObjectRecovery::GetInstance();
if (vintfObject == nullptr) {
- LOG(ERROR) << "NULL VintfObjectRecovery!";
+ ALOGE("NULL VintfObjectRecovery!");
return {};
}
return {ManifestWithDescription{vintfObject->getRecoveryHalManifest(), "recovery"}};
#else
auto vintfObject = vintf::VintfObject::GetInstance();
if (vintfObject == nullptr) {
- LOG(ERROR) << "NULL VintfObject!";
+ ALOGE("NULL VintfObject!");
return {};
}
return {ManifestWithDescription{vintfObject->getDeviceHalManifest(), "device"},
@@ -68,10 +68,10 @@
static bool forEachManifest(const std::function<bool(const ManifestWithDescription&)>& func) {
for (const ManifestWithDescription& mwd : GetManifestsWithDescription()) {
if (mwd.manifest == nullptr) {
- LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description;
- // note, we explicitly do not retry here, so that we can detect VINTF
- // or other bugs (b/151696835)
- continue;
+ ALOGE("NULL VINTF MANIFEST!: %s", mwd.description);
+ // note, we explicitly do not retry here, so that we can detect VINTF
+ // or other bugs (b/151696835)
+ continue;
}
if (func(mwd)) return true;
}
@@ -87,8 +87,9 @@
size_t firstSlash = name.find('/');
size_t lastDot = name.rfind('.', firstSlash);
if (firstSlash == std::string::npos || lastDot == std::string::npos) {
- LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. "
- << "some.package.foo.IFoo/default) but got: " << name;
+ ALOGE("VINTF HALs require names in the format type/instance (e.g. "
+ "some.package.foo.IFoo/default) but got: %s",
+ name.c_str());
return false;
}
aname->package = name.substr(0, lastDot);
@@ -104,7 +105,7 @@
bool found = forEachManifest([&](const ManifestWithDescription& mwd) {
if (mwd.manifest->hasAidlInstance(aname.package, aname.iface, aname.instance)) {
- LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest.";
+ ALOGI("Found %s in %s VINTF manifest.", name.c_str(), mwd.description);
return true; // break
}
return false; // continue
@@ -113,8 +114,8 @@
if (!found) {
// Although it is tested, explicitly rebuilding qualified name, in case it
// becomes something unexpected.
- LOG(INFO) << "Could not find " << aname.package << "." << aname.iface << "/"
- << aname.instance << " in the VINTF manifest.";
+ ALOGI("Could not find %s.%s/%s in the VINTF manifest.", aname.package.c_str(),
+ aname.iface.c_str(), aname.instance.c_str());
}
return found;
@@ -173,7 +174,9 @@
static std::vector<std::string> getVintfInstances(const std::string& interface) {
size_t lastDot = interface.rfind('.');
if (lastDot == std::string::npos) {
- LOG(ERROR) << "VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) but got: " << interface;
+ ALOGE("VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) "
+ "but got: %s",
+ interface.c_str());
return {};
}
const std::string package = interface.substr(0, lastDot);
@@ -308,7 +311,7 @@
}
if (!isValidServiceName(name)) {
- LOG(ERROR) << "Invalid service name: " << name;
+ ALOGE("Invalid service name: %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name");
}
@@ -322,7 +325,7 @@
// implicitly unlinked when the binder is removed
if (binder->remoteBinder() != nullptr &&
binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
- LOG(ERROR) << "Could not linkToDeath when adding " << name;
+ ALOGE("Could not linkToDeath when adding %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "linkToDeath failure");
}
@@ -335,21 +338,20 @@
// only trying to detect when two different services are accidentally installed.
if (existing.ctx.uid != ctx.uid) {
- LOG(WARNING) << "Service '" << name << "' originally registered from UID "
- << existing.ctx.uid << " but it is now being registered from UID "
- << ctx.uid << ". Multiple instances installed?";
+ ALOGW("Service '%s' originally registered from UID %u but it is now being registered "
+ "from UID %u. Multiple instances installed?",
+ name.c_str(), existing.ctx.uid, ctx.uid);
}
if (existing.ctx.sid != ctx.sid) {
- LOG(WARNING) << "Service '" << name << "' originally registered from SID "
- << existing.ctx.sid << " but it is now being registered from SID "
- << ctx.sid << ". Multiple instances installed?";
+ ALOGW("Service '%s' originally registered from SID %s but it is now being registered "
+ "from SID %s. Multiple instances installed?",
+ name.c_str(), existing.ctx.sid.c_str(), ctx.sid.c_str());
}
- LOG(INFO) << "Service '" << name << "' originally registered from PID "
- << existing.ctx.debugPid << " but it is being registered again from PID "
- << ctx.debugPid
- << ". Bad state? Late death notification? Multiple instances installed?";
+ ALOGI("Service '%s' originally registered from PID %d but it is being registered again "
+ "from PID %d. Bad state? Late death notification? Multiple instances installed?",
+ name.c_str(), existing.ctx.debugPid, ctx.debugPid);
}
// Overwrite the old service if it exists
@@ -406,7 +408,7 @@
}
if (!isValidServiceName(name)) {
- LOG(ERROR) << "Invalid service name: " << name;
+ ALOGE("Invalid service name: %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
@@ -417,7 +419,7 @@
if (OK !=
IInterface::asBinder(callback)->linkToDeath(
sp<ServiceManager>::fromExisting(this))) {
- LOG(ERROR) << "Could not linkToDeath when adding " << name;
+ ALOGE("Could not linkToDeath when adding %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -449,7 +451,7 @@
}
if (!found) {
- LOG(ERROR) << "Trying to unregister callback, but none exists " << name;
+ ALOGE("Trying to unregister callback, but none exists %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -571,10 +573,11 @@
std::thread([=] {
if (!base::SetProperty("ctl.interface_start", "aidl/" + name)) {
- LOG(INFO) << "Tried to start aidl service " << name
- << " as a lazy service, but was unable to. Usually this happens when a "
- "service is not installed, but if the service is intended to be used as a "
- "lazy service, then it may be configured incorrectly.";
+ ALOGI("Tried to start aidl service %s as a lazy service, but was unable to. Usually "
+ "this happens when a "
+ "service is not installed, but if the service is intended to be used as a "
+ "lazy service, then it may be configured incorrectly.",
+ name.c_str());
}
}).detach();
}
@@ -592,24 +595,25 @@
auto serviceIt = mNameToService.find(name);
if (serviceIt == mNameToService.end()) {
- LOG(ERROR) << "Could not add callback for nonexistent service: " << name;
+ ALOGE("Could not add callback for nonexistent service: %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
if (serviceIt->second.ctx.debugPid != IPCThreadState::self()->getCallingPid()) {
- LOG(WARNING) << "Only a server can register for client callbacks (for " << name << ")";
+ ALOGW("Only a server can register for client callbacks (for %s)", name.c_str());
return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
}
if (serviceIt->second.binder != service) {
- LOG(WARNING) << "Tried to register client callback for " << name
- << " but a different service is registered under this name.";
+ ALOGW("Tried to register client callback for %s but a different service is registered "
+ "under this name.",
+ name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
if (OK !=
IInterface::asBinder(cb)->linkToDeath(sp<ServiceManager>::fromExisting(this))) {
- LOG(ERROR) << "Could not linkToDeath when adding client callback for " << name;
+ ALOGE("Could not linkToDeath when adding client callback for %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -694,7 +698,7 @@
void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName, bool hasClients) {
auto serviceIt = mNameToService.find(serviceName);
if (serviceIt == mNameToService.end()) {
- LOG(WARNING) << "sendClientCallbackNotifications could not find service " << serviceName;
+ ALOGW("sendClientCallbackNotifications could not find service %s", serviceName.c_str());
return;
}
Service& service = serviceIt->second;
@@ -702,7 +706,7 @@
CHECK(hasClients != service.hasClients) << "Record shows: " << service.hasClients
<< " so we can't tell clients again that we have client: " << hasClients;
- LOG(INFO) << "Notifying " << serviceName << " they have clients: " << hasClients;
+ ALOGI("Notifying %s they have clients: %d", serviceName.c_str(), hasClients);
auto ccIt = mNameToClientCallback.find(serviceName);
CHECK(ccIt != mNameToClientCallback.end())
@@ -727,26 +731,26 @@
auto serviceIt = mNameToService.find(name);
if (serviceIt == mNameToService.end()) {
- LOG(WARNING) << "Tried to unregister " << name
- << ", but that service wasn't registered to begin with.";
+ ALOGW("Tried to unregister %s, but that service wasn't registered to begin with.",
+ name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
if (serviceIt->second.ctx.debugPid != IPCThreadState::self()->getCallingPid()) {
- LOG(WARNING) << "Only a server can unregister itself (for " << name << ")";
+ ALOGW("Only a server can unregister itself (for %s)", name.c_str());
return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
}
sp<IBinder> storedBinder = serviceIt->second.binder;
if (binder != storedBinder) {
- LOG(WARNING) << "Tried to unregister " << name
- << ", but a different service is registered under this name.";
+ ALOGW("Tried to unregister %s, but a different service is registered under this name.",
+ name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
if (serviceIt->second.guaranteeClient) {
- LOG(INFO) << "Tried to unregister " << name << ", but there is about to be a client.";
+ ALOGI("Tried to unregister %s, but there is about to be a client.", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -759,7 +763,7 @@
// So, if clients > 2, then at least one other service on the system must hold a refcount.
if (clients < 0 || clients > 2) {
// client callbacks are either disabled or there are other clients
- LOG(INFO) << "Tried to unregister " << name << ", but there are clients: " << clients;
+ ALOGI("Tried to unregister %s, but there are clients: %d", name.c_str(), clients);
// Set this flag to ensure the clients are acknowledged in the next callback
serviceIt->second.guaranteeClient = true;
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 481d704..5e725a9 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -232,7 +232,10 @@
: mRpcServer(rpcServer), mKeepAliveBinder(keepAliveBinder), mBinder(binder) {}
virtual ~RpcServerLink();
void binderDied(const wp<IBinder>&) override {
- LOG_RPC_DETAIL("RpcServerLink: binder died, shutting down RpcServer");
+ auto promoted = mBinder.promote();
+ ALOGI("RpcBinder: binder died, shutting down RpcServer for %s",
+ promoted ? String8(promoted->getInterfaceDescriptor()).c_str() : "<NULL>");
+
if (mRpcServer == nullptr) {
ALOGW("RpcServerLink: Unable to shut down RpcServer because it does not exist.");
} else {
@@ -241,11 +244,7 @@
}
mRpcServer.clear();
- auto promoted = mBinder.promote();
- if (promoted == nullptr) {
- ALOGW("RpcServerLink: Unable to remove link from parent binder object because parent "
- "binder object is gone.");
- } else {
+ if (promoted) {
promoted->removeRpcServerLink(sp<RpcServerLink>::fromExisting(this));
}
mBinder.clear();
@@ -706,6 +705,7 @@
return status;
}
rpcServer->setMaxThreads(binderThreadPoolMaxCount);
+ LOG(INFO) << "RpcBinder: Started Binder debug on " << getInterfaceDescriptor();
rpcServer->start();
e->mRpcServerLinks.emplace(link);
LOG_RPC_DETAIL("%s(fd=%d) successful", __PRETTY_FUNCTION__, socketFdForPrint);
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index c411f4f..7067328 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -886,6 +886,7 @@
it->second.asyncTodo.push(BinderNode::AsyncTodo{
.ref = target,
.data = std::move(transactionData),
+ .ancillaryFds = std::move(ancillaryFds),
.asyncNumber = transaction->asyncNumber,
});
@@ -1046,6 +1047,7 @@
// reset up arguments
transactionData = std::move(todo.data);
+ ancillaryFds = std::move(todo.ancillaryFds);
LOG_ALWAYS_FATAL_IF(target != todo.ref,
"async list should be associated with a binder");
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 7aab5ee..ac86585 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -250,6 +250,7 @@
struct AsyncTodo {
sp<IBinder> ref;
CommandData data;
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>> ancillaryFds;
uint64_t asyncNumber = 0;
bool operator<(const AsyncTodo& o) const {
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index 7ea9be7..fccc0af 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -349,7 +349,7 @@
/**
* See AIBinder_Weak_promote.
*/
- SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
+ SpAIBinder promote() const { return SpAIBinder(AIBinder_Weak_promote(get())); }
};
namespace internal {
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 6d29238..01b9472 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -670,6 +670,26 @@
EXPECT_EQ(42, pparcel->readInt32());
}
+TEST(NdkBinder, GetAndVerifyScopedAIBinder_Weak) {
+ for (const ndk::SpAIBinder& binder :
+ {// remote
+ ndk::SpAIBinder(AServiceManager_getService(kBinderNdkUnitTestService)),
+ // local
+ ndk::SharedRefBase::make<MyBinderNdkUnitTest>()->asBinder()}) {
+ // get a const ScopedAIBinder_Weak and verify promote
+ EXPECT_NE(binder.get(), nullptr);
+ const ndk::ScopedAIBinder_Weak wkAIBinder =
+ ndk::ScopedAIBinder_Weak(AIBinder_Weak_new(binder.get()));
+ EXPECT_EQ(wkAIBinder.promote().get(), binder.get());
+ // get another ScopedAIBinder_Weak and verify
+ ndk::ScopedAIBinder_Weak wkAIBinder2 =
+ ndk::ScopedAIBinder_Weak(AIBinder_Weak_new(binder.get()));
+ EXPECT_FALSE(AIBinder_Weak_lt(wkAIBinder.get(), wkAIBinder2.get()));
+ EXPECT_FALSE(AIBinder_Weak_lt(wkAIBinder2.get(), wkAIBinder.get()));
+ EXPECT_EQ(wkAIBinder2.promote(), wkAIBinder.promote());
+ }
+}
+
class MyResultReceiver : public BnResultReceiver {
public:
Mutex mMutex;
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index b15a225..a3ed571 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -71,4 +71,13 @@
ParcelFileDescriptor echoAsFile(@utf8InCpp String content);
ParcelFileDescriptor concatFiles(in List<ParcelFileDescriptor> files);
+
+ // FDs sent via `blockingSendFdOneway` can be received via
+ // `blockingRecvFd`. The handler for `blockingSendFdOneway` will block
+ // until the next `blockingRecvFd` call.
+ //
+ // This is useful for carefully controlling how/when oneway transactions
+ // get queued.
+ oneway void blockingSendFdOneway(in ParcelFileDescriptor fd);
+ ParcelFileDescriptor blockingRecvFd();
}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 9a6d4df..2b70492 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -181,8 +181,10 @@
wp<RpcSession> weakSession = session;
session = nullptr;
- EXPECT_EQ(nullptr, weakSession.promote())
- << (debugBacktrace(host.getPid()), debugBacktrace(getpid()), "Leaked session");
+ sp<RpcSession> strongSession = weakSession.promote();
+ EXPECT_EQ(nullptr, strongSession)
+ << (debugBacktrace(host.getPid()), debugBacktrace(getpid()), "Leaked sess: ")
+ << strongSession->getStrongCount();
}
}
};
@@ -786,12 +788,12 @@
ts.push_back(std::thread([&] { proc.rootIface->lockUnlock(); }));
}
- usleep(100000); // give chance for calls on other threads
+ usleep(10000); // give chance for calls on other threads
// other calls still work
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
- constexpr size_t blockTimeMs = 500;
+ constexpr size_t blockTimeMs = 50;
size_t epochMsBefore = epochMillis();
// after this, we should never see a response within this time
EXPECT_OK(proc.rootIface->unlockInMsAsync(blockTimeMs));
@@ -920,6 +922,45 @@
EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
}
+TEST_P(BinderRpc, OnewayCallQueueingWithFds) {
+ if (!supportsFdTransport()) {
+ GTEST_SKIP() << "Would fail trivially (which is tested elsewhere)";
+ }
+ if (clientOrServerSingleThreaded()) {
+ GTEST_SKIP() << "This test requires multiple threads";
+ }
+
+ // This test forces a oneway transaction to be queued by issuing two
+ // `blockingSendFdOneway` calls, then drains the queue by issuing two
+ // `blockingRecvFd` calls.
+ //
+ // For more details about the queuing semantics see
+ // https://developer.android.com/reference/android/os/IBinder#FLAG_ONEWAY
+
+ auto proc = createRpcTestSocketServerProcess({
+ .numThreads = 3,
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::UNIX},
+ });
+
+ EXPECT_OK(proc.rootIface->blockingSendFdOneway(
+ android::os::ParcelFileDescriptor(mockFileDescriptor("a"))));
+ EXPECT_OK(proc.rootIface->blockingSendFdOneway(
+ android::os::ParcelFileDescriptor(mockFileDescriptor("b"))));
+
+ android::os::ParcelFileDescriptor fdA;
+ EXPECT_OK(proc.rootIface->blockingRecvFd(&fdA));
+ std::string result;
+ CHECK(android::base::ReadFdToString(fdA.get(), &result));
+ EXPECT_EQ(result, "a");
+
+ android::os::ParcelFileDescriptor fdB;
+ EXPECT_OK(proc.rootIface->blockingRecvFd(&fdB));
+ CHECK(android::base::ReadFdToString(fdB.get(), &result));
+ EXPECT_EQ(result, "b");
+}
+
TEST_P(BinderRpc, OnewayCallQueueing) {
if (clientOrServerSingleThreaded()) {
GTEST_SKIP() << "This test requires multiple threads";
@@ -1083,7 +1124,7 @@
}
std::unique_lock<std::mutex> lock(dr->mMtx);
- ASSERT_TRUE(dr->mCv.wait_for(lock, 1000ms, [&]() { return dr->dead; }));
+ ASSERT_TRUE(dr->mCv.wait_for(lock, 100ms, [&]() { return dr->dead; }));
// need to wait for the session to shutdown so we don't "Leak session"
EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
@@ -1118,7 +1159,7 @@
std::unique_lock<std::mutex> lock(dr->mMtx);
if (!dr->dead) {
- EXPECT_EQ(std::cv_status::no_timeout, dr->mCv.wait_for(lock, 1000ms));
+ EXPECT_EQ(std::cv_status::no_timeout, dr->mCv.wait_for(lock, 100ms));
}
EXPECT_TRUE(dr->dead) << "Failed to receive the death notification.";
@@ -1701,7 +1742,7 @@
bool shutdown = false;
for (int i = 0; i < 10 && !shutdown; i++) {
- usleep(300 * 1000); // 300ms; total 3s
+ usleep(30 * 1000); // 30ms; total 300ms
if (server->shutdown()) shutdown = true;
}
ASSERT_TRUE(shutdown) << "server->shutdown() never returns true";
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
index 4513d36..fddf5f3 100644
--- a/libs/binder/tests/binderRpcTestCommon.h
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -167,6 +167,42 @@
return readFd;
}
+// A threadsafe channel where writes block until the value is read.
+template <typename T>
+class HandoffChannel {
+public:
+ void write(T v) {
+ {
+ RpcMutexUniqueLock lock(mMutex);
+ // Wait for space to send.
+ mCvEmpty.wait(lock, [&]() { return !mValue.has_value(); });
+ mValue.emplace(std::move(v));
+ }
+ mCvFull.notify_all();
+ RpcMutexUniqueLock lock(mMutex);
+ // Wait for it to be taken.
+ mCvEmpty.wait(lock, [&]() { return !mValue.has_value(); });
+ }
+
+ T read() {
+ RpcMutexUniqueLock lock(mMutex);
+ if (!mValue.has_value()) {
+ mCvFull.wait(lock, [&]() { return mValue.has_value(); });
+ }
+ T v = std::move(mValue.value());
+ mValue.reset();
+ lock.unlock();
+ mCvEmpty.notify_all();
+ return std::move(v);
+ }
+
+private:
+ RpcMutex mMutex;
+ RpcConditionVariable mCvEmpty;
+ RpcConditionVariable mCvFull;
+ std::optional<T> mValue;
+};
+
using android::binder::Status;
class MyBinderRpcSession : public BnBinderRpcSession {
@@ -374,6 +410,18 @@
out->reset(mockFileDescriptor(acc));
return Status::ok();
}
+
+ HandoffChannel<android::base::unique_fd> mFdChannel;
+
+ Status blockingSendFdOneway(const android::os::ParcelFileDescriptor& fd) override {
+ mFdChannel.write(android::base::unique_fd(fcntl(fd.get(), F_DUPFD_CLOEXEC, 0)));
+ return Status::ok();
+ }
+
+ Status blockingRecvFd(android::os::ParcelFileDescriptor* fd) override {
+ fd->reset(mFdChannel.read());
+ return Status::ok();
+ }
};
} // namespace android
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 3afa339..8b9a878 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -307,7 +307,6 @@
BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
"empty.");
}
-
decStrong((void*)transactionCommittedCallbackThunk);
}
}
@@ -350,6 +349,20 @@
stat.latchTime,
stat.frameEventStats.dequeueReadyTime);
}
+ auto currFrameNumber = stat.frameEventStats.frameNumber;
+ std::vector<ReleaseCallbackId> staleReleases;
+ for (const auto& [key, value]: mSubmitted) {
+ if (currFrameNumber > key.framenumber) {
+ staleReleases.push_back(key);
+ }
+ }
+ for (const auto& staleRelease : staleReleases) {
+ BQA_LOGE("Faking releaseBufferCallback from transactionCompleteCallback");
+ BBQ_TRACE("FakeReleaseCallback");
+ releaseBufferCallbackLocked(staleRelease,
+ stat.previousReleaseFence ? stat.previousReleaseFence : Fence::NO_FENCE,
+ stat.currentMaxAcquiredBufferCount);
+ }
} else {
BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
}
@@ -390,7 +403,14 @@
const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount) {
BBQ_TRACE();
+
std::unique_lock _lock{mMutex};
+ releaseBufferCallbackLocked(id, releaseFence, currentMaxAcquiredBufferCount);
+}
+
+void BLASTBufferQueue::releaseBufferCallbackLocked(const ReleaseCallbackId& id,
+ const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount) {
+ ATRACE_CALL();
BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str());
// Calculate how many buffers we need to hold before we release them back
@@ -408,7 +428,11 @@
const auto numPendingBuffersToHold =
isEGL ? std::max(0u, mMaxAcquiredBuffers - mCurrentMaxAcquiredBufferCount) : 0;
- mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence});
+
+ auto rb = ReleasedBuffer{id, releaseFence};
+ if (std::find(mPendingRelease.begin(), mPendingRelease.end(), rb) == mPendingRelease.end()) {
+ mPendingRelease.emplace_back(rb);
+ }
// Release all buffers that are beyond the ones that we need to hold
while (mPendingRelease.size() > numPendingBuffersToHold) {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 72bd1fb..d780173 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "SurfaceComposerClient"
+#include <semaphore.h>
#include <stdint.h>
#include <sys/types.h>
@@ -356,7 +357,8 @@
transactionStats.latchTime, surfaceStats.acquireTimeOrFence,
transactionStats.presentFence,
surfaceStats.previousReleaseFence, surfaceStats.transformHint,
- surfaceStats.eventStats);
+ surfaceStats.eventStats,
+ surfaceStats.currentMaxAcquiredBufferCount);
}
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
@@ -381,7 +383,8 @@
transactionStats.latchTime, surfaceStats.acquireTimeOrFence,
transactionStats.presentFence,
surfaceStats.previousReleaseFence, surfaceStats.transformHint,
- surfaceStats.eventStats);
+ surfaceStats.eventStats,
+ surfaceStats.currentMaxAcquiredBufferCount);
if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]) {
callbacksMap[callbackId]
.surfaceControls[surfaceStats.surfaceControl]
@@ -958,12 +961,55 @@
}
}
+class SyncCallback {
+public:
+ static void function(void* callbackContext, nsecs_t /* latchTime */,
+ const sp<Fence>& /* presentFence */,
+ const std::vector<SurfaceControlStats>& /* stats */) {
+ if (!callbackContext) {
+ ALOGE("failed to get callback context for SyncCallback");
+ }
+ SyncCallback* helper = static_cast<SyncCallback*>(callbackContext);
+ LOG_ALWAYS_FATAL_IF(sem_post(&helper->mSemaphore), "sem_post failed");
+ }
+ ~SyncCallback() {
+ if (mInitialized) {
+ LOG_ALWAYS_FATAL_IF(sem_destroy(&mSemaphore), "sem_destroy failed");
+ }
+ }
+ void init() {
+ LOG_ALWAYS_FATAL_IF(clock_gettime(CLOCK_MONOTONIC, &mTimeoutTimespec) == -1,
+ "clock_gettime() fail! in SyncCallback::init");
+ mTimeoutTimespec.tv_sec += 4;
+ LOG_ALWAYS_FATAL_IF(sem_init(&mSemaphore, 0, 0), "sem_init failed");
+ mInitialized = true;
+ }
+ void wait() {
+ int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &mTimeoutTimespec);
+ if (result && errno != ETIMEDOUT && errno != EINTR) {
+ LOG_ALWAYS_FATAL("sem_clockwait failed(%d)", errno);
+ } else if (errno == ETIMEDOUT) {
+ ALOGW("Sync transaction timed out waiting for commit callback.");
+ }
+ }
+ void* getContext() { return static_cast<void*>(this); }
+
+private:
+ sem_t mSemaphore;
+ bool mInitialized = false;
+ timespec mTimeoutTimespec;
+};
+
status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay) {
if (mStatus != NO_ERROR) {
return mStatus;
}
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ SyncCallback syncCallback;
+ if (synchronous) {
+ syncCallback.init();
+ addTransactionCommittedCallback(syncCallback.function, syncCallback.getContext());
+ }
bool hasListenerCallbacks = !mListenerCallbacks.empty();
std::vector<ListenerCallbacks> listenerCallbacks;
@@ -998,15 +1044,12 @@
Vector<DisplayState> displayStates;
uint32_t flags = 0;
- for (auto const& kv : mComposerStates){
+ for (auto const& kv : mComposerStates) {
composerStates.add(kv.second);
}
displayStates = std::move(mDisplayStates);
- if (synchronous) {
- flags |= ISurfaceComposer::eSynchronous;
- }
if (mAnimation) {
flags |= ISurfaceComposer::eAnimation;
}
@@ -1030,6 +1073,7 @@
sp<IBinder> applyToken = mApplyToken ? mApplyToken : sApplyToken;
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
{} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
@@ -1039,6 +1083,10 @@
// Clear the current states and flags
clear();
+ if (synchronous) {
+ syncCallback.wait();
+ }
+
mStatus = NO_ERROR;
return NO_ERROR;
}
diff --git a/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp b/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
index c97770b..7829e94 100644
--- a/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
+++ b/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
@@ -145,7 +145,8 @@
sp<Fence> presentFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
SurfaceControlStats controlStats(surface, mFdp.ConsumeIntegral<int64_t>(),
mFdp.ConsumeIntegral<int64_t>(), presentFence, previousFence,
- mFdp.ConsumeIntegral<uint32_t>(), frameStats);
+ mFdp.ConsumeIntegral<uint32_t>(), frameStats,
+ mFdp.ConsumeIntegral<uint32_t>());
stats.push_back(controlStats);
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 4535c98..827a6cc 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -92,9 +92,12 @@
const std::vector<SurfaceControlStats>& stats);
void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount);
+ void releaseBufferCallbackLocked(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
+ std::optional<uint32_t> currentMaxAcquiredBufferCount);
void syncNextTransaction(std::function<void(SurfaceComposerClient::Transaction*)> callback,
bool acquireSingleBuffer = true);
void stopContinuousSyncTransaction();
+
void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
void applyPendingTransactions(uint64_t frameNumber);
SurfaceComposerClient::Transaction* gatherPendingTransactions(uint64_t frameNumber);
@@ -173,6 +176,12 @@
struct ReleasedBuffer {
ReleaseCallbackId callbackId;
sp<Fence> releaseFence;
+ bool operator==(const ReleasedBuffer& rhs) const {
+ // Only compare Id so if we somehow got two callbacks
+ // with different fences we don't decrement mNumAcquired
+ // too far.
+ return rhs.callbackId == callbackId;
+ }
};
std::deque<ReleasedBuffer> mPendingRelease GUARDED_BY(mMutex);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 1e85131..d46c2e7 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -95,7 +95,6 @@
// flags for setTransactionState()
enum {
- eSynchronous = 0x01,
eAnimation = 0x02,
// Explicit indication that this transaction and others to follow will likely result in a
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 61d4714..242eceb 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -69,14 +69,16 @@
SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime,
std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence,
const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
- uint32_t hint, FrameEventHistoryStats eventStats)
+ uint32_t hint, FrameEventHistoryStats eventStats,
+ uint32_t currentMaxAcquiredBufferCount)
: surfaceControl(sc),
latchTime(latchTime),
acquireTimeOrFence(std::move(acquireTimeOrFence)),
presentFence(presentFence),
previousReleaseFence(prevReleaseFence),
transformHint(hint),
- frameEventStats(eventStats) {}
+ frameEventStats(eventStats),
+ currentMaxAcquiredBufferCount(currentMaxAcquiredBufferCount) {}
sp<SurfaceControl> surfaceControl;
nsecs_t latchTime = -1;
@@ -85,6 +87,7 @@
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
FrameEventHistoryStats frameEventStats;
+ uint32_t currentMaxAcquiredBufferCount = 0;
};
using TransactionCompletedCallbackTakesContext =
diff --git a/libs/gui/include/gui/test/CallbackUtils.h b/libs/gui/include/gui/test/CallbackUtils.h
index 62d1496..08785b4 100644
--- a/libs/gui/include/gui/test/CallbackUtils.h
+++ b/libs/gui/include/gui/test/CallbackUtils.h
@@ -135,7 +135,8 @@
void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
nsecs_t latchTime) const {
const auto& [surfaceControl, latch, acquireTimeOrFence, presentFence,
- previousReleaseFence, transformHint, frameEvents] = surfaceControlStats;
+ previousReleaseFence, transformHint, frameEvents, ignore] =
+ surfaceControlStats;
ASSERT_TRUE(std::holds_alternative<nsecs_t>(acquireTimeOrFence));
ASSERT_EQ(std::get<nsecs_t>(acquireTimeOrFence) > 0,
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index e48012b..bd12663 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -65,8 +65,15 @@
EXPECT_NEAR(actual, target, tolerance);
}
-static void checkVelocity(float Vactual, float Vtarget) {
- EXPECT_NEAR_BY_FRACTION(Vactual, Vtarget, VELOCITY_TOLERANCE);
+static void checkVelocity(std::optional<float> Vactual, std::optional<float> Vtarget) {
+ if (Vactual != std::nullopt) {
+ if (Vtarget == std::nullopt) {
+ FAIL() << "Expected no velocity, but found " << *Vactual;
+ }
+ EXPECT_NEAR_BY_FRACTION(*Vactual, *Vtarget, VELOCITY_TOLERANCE);
+ } else if (Vtarget != std::nullopt) {
+ FAIL() << "Expected velocity, but found no velocity";
+ }
}
static void checkCoefficient(float actual, float target) {
@@ -262,26 +269,16 @@
static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy,
const std::vector<PlanarMotionEventEntry>& motions,
- int32_t axis, float targetVelocity,
+ int32_t axis, std::optional<float> targetVelocity,
uint32_t pointerId = DEFAULT_POINTER_ID) {
- checkVelocity(computePlanarVelocity(strategy, motions, axis, pointerId).value_or(0),
- targetVelocity);
+ checkVelocity(computePlanarVelocity(strategy, motions, axis, pointerId), targetVelocity);
}
static void computeAndCheckAxisScrollVelocity(
const VelocityTracker::Strategy strategy,
const std::vector<std::pair<std::chrono::nanoseconds, float>>& motions,
std::optional<float> targetVelocity) {
- std::optional<float> velocity = computeVelocity(strategy, motions, AMOTION_EVENT_AXIS_SCROLL);
- if (velocity && !targetVelocity) {
- FAIL() << "Expected no velocity, but found " << *velocity;
- }
- if (!velocity && targetVelocity) {
- FAIL() << "Expected velocity, but found no velocity";
- }
- if (velocity) {
- checkVelocity(*velocity, *targetVelocity);
- }
+ checkVelocity(computeVelocity(strategy, motions, AMOTION_EVENT_AXIS_SCROLL), targetVelocity);
}
static void computeAndCheckQuadraticEstimate(const std::vector<PlanarMotionEventEntry>& motions,
@@ -1013,7 +1010,7 @@
/**
* ================== Multiple pointers ============================================================
*
- * Three fingers quickly tap the screen. Since this is a tap, the velocities should be zero.
+ * Three fingers quickly tap the screen. Since this is a tap, the velocities should be empty.
* If the events with POINTER_UP or POINTER_DOWN are not handled correctly (these should not be
* part of the fitted data), this can cause large velocity values to be reported instead.
*/
@@ -1027,12 +1024,14 @@
{ 272700us, {{1063, 1128}, {NAN, NAN}, {NAN, NAN}} },
};
- // Velocity should actually be zero, but we expect 0.016 here instead.
- // This is close enough to zero, and is likely caused by division by a very small number.
- computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0);
- computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, 0);
- computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0);
- computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y, 0);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ std::nullopt);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ std::nullopt);
}
/**
@@ -1055,7 +1054,7 @@
/**
* The last movement of a single pointer is ACTION_UP. If there's a long delay between the last
- * ACTION_MOVE and the final ACTION_UP, velocity should be reported as zero because the pointer
+ * ACTION_MOVE and the final ACTION_UP, velocity should be reported as empty because the pointer
* should be assumed to have stopped.
*/
TEST_F(VelocityTrackerTest, LongDelayBeforeActionUp) {
@@ -1065,14 +1064,16 @@
{20ms, {{30, 0}}},
{3000ms, {{30, 0}}}, // ACTION_UP
};
- computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0);
- computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt);
}
/**
* The last movement of a pointer is always ACTION_POINTER_UP or ACTION_UP. If there's a long delay
* before ACTION_POINTER_UP event, the movement should be assumed to have stopped.
- * The final velocity should be reported as zero for all pointers.
+ * The final velocity should be reported as empty for all pointers.
*/
TEST_F(VelocityTrackerTest, LongDelayBeforeActionPointerUp) {
std::vector<PlanarMotionEventEntry> motions = {
@@ -1083,13 +1084,17 @@
{40ms, {{30, 0}, {400, 0}}},
{3000ms, {{30, 0}}}, // ACTION_POINTER_UP
};
- computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0,
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt,
/*pointerId*/ 0);
- computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0,
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt,
/*pointerId*/ 0);
- computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0,
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt,
/*pointerId*/ 1);
- computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0,
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt,
/*pointerId*/ 1);
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 399153c..a793f57 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -524,6 +524,21 @@
return {};
}
+Point resolveTouchedPosition(const MotionEntry& entry) {
+ const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE);
+ // Always dispatch mouse events to cursor position.
+ if (isFromMouse) {
+ return Point(static_cast<int32_t>(entry.xCursorPosition),
+ static_cast<int32_t>(entry.yCursorPosition));
+ }
+
+ const int32_t pointerIndex = getMotionEventActionPointerIndex(entry.action);
+ return Point(static_cast<int32_t>(
+ entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X)),
+ static_cast<int32_t>(
+ entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)));
+}
+
} // namespace
// --- InputDispatcher ---
@@ -921,13 +936,10 @@
// If the application takes too long to catch up then we drop all events preceding
// the touch into the other window.
if (isPointerDownEvent && mAwaitedFocusedApplication != nullptr) {
- int32_t displayId = motionEntry.displayId;
- int32_t x = static_cast<int32_t>(
- motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = static_cast<int32_t>(
- motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
-
+ const int32_t displayId = motionEntry.displayId;
+ const auto [x, y] = resolveTouchedPosition(motionEntry);
const bool isStylus = isPointerFromStylus(motionEntry, 0 /*pointerIndex*/);
+
sp<WindowInfoHandle> touchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y, nullptr, isStylus);
if (touchedWindowHandle != nullptr &&
@@ -2067,18 +2079,8 @@
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
/* Case 1: New splittable pointer going down, or need target for hover or scroll. */
-
- int32_t x;
- int32_t y;
+ const auto [x, y] = resolveTouchedPosition(entry);
const int32_t pointerIndex = getMotionEventActionPointerIndex(action);
- // Always dispatch mouse events to cursor position.
- if (isFromMouse) {
- x = int32_t(entry.xCursorPosition);
- y = int32_t(entry.yCursorPosition);
- } else {
- x = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));
- y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
- }
const bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;
const bool isStylus = isPointerFromStylus(entry, pointerIndex);
newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
@@ -2141,43 +2143,7 @@
}
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
- const WindowInfo& info = *windowHandle->getInfo();
-
- // Skip spy window targets that are not valid for targeted injection.
- if (const auto err = verifyTargetedInjection(windowHandle, entry); err) {
- continue;
- }
-
- if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
- ALOGI("Not sending touch event to %s because it is paused",
- windowHandle->getName().c_str());
- continue;
- }
-
- // Ensure the window has a connection and the connection is responsive
- const bool isResponsive = hasResponsiveConnectionLocked(*windowHandle);
- if (!isResponsive) {
- ALOGW("Not sending touch gesture to %s because it is not responsive",
- windowHandle->getName().c_str());
- continue;
- }
-
- // Drop events that can't be trusted due to occlusion
- TouchOcclusionInfo occlusionInfo = computeTouchOcclusionInfoLocked(windowHandle, x, y);
- if (!isTouchTrustedLocked(occlusionInfo)) {
- if (DEBUG_TOUCH_OCCLUSION) {
- ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
- for (const auto& log : occlusionInfo.debugInfo) {
- ALOGD("%s", log.c_str());
- }
- }
- ALOGW("Dropping untrusted touch event due to %s/%d",
- occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);
- continue;
- }
-
- // Drop touch events if requested by input feature
- if (shouldDropInput(entry, windowHandle)) {
+ if (!canWindowReceiveMotionLocked(windowHandle, entry)) {
continue;
}
@@ -2233,9 +2199,7 @@
// Check whether touches should slip outside of the current foreground window.
if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry.pointerCount == 1 &&
tempTouchState.isSlippery()) {
- const int32_t x = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
- const int32_t y = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
-
+ const auto [x, y] = resolveTouchedPosition(entry);
const bool isStylus = isPointerFromStylus(entry, 0 /*pointerIndex*/);
sp<WindowInfoHandle> oldTouchedWindowHandle =
tempTouchState.getFirstForegroundWindowHandle();
@@ -4607,26 +4571,58 @@
return getWindowHandleLocked(focusedToken, displayId);
}
-bool InputDispatcher::hasResponsiveConnectionLocked(WindowInfoHandle& windowHandle) const {
- sp<Connection> connection = getConnectionLocked(windowHandle.getToken());
- const bool noInputChannel =
- windowHandle.getInfo()->inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL);
- if (connection != nullptr && noInputChannel) {
- ALOGW("%s has feature NO_INPUT_CHANNEL, but it matched to connection %s",
- windowHandle.getName().c_str(), connection->inputChannel->getName().c_str());
+bool InputDispatcher::canWindowReceiveMotionLocked(const sp<WindowInfoHandle>& window,
+ const MotionEntry& motionEntry) const {
+ const WindowInfo& info = *window->getInfo();
+
+ // Skip spy window targets that are not valid for targeted injection.
+ if (const auto err = verifyTargetedInjection(window, motionEntry); err) {
return false;
}
+ if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
+ ALOGI("Not sending touch event to %s because it is paused", window->getName().c_str());
+ return false;
+ }
+
+ if (info.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) {
+ ALOGW("Not sending touch gesture to %s because it has config NO_INPUT_CHANNEL",
+ window->getName().c_str());
+ return false;
+ }
+
+ sp<Connection> connection = getConnectionLocked(window->getToken());
if (connection == nullptr) {
- if (!noInputChannel) {
- ALOGI("Could not find connection for %s", windowHandle.getName().c_str());
- }
+ ALOGW("Not sending touch to %s because there's no corresponding connection",
+ window->getName().c_str());
return false;
}
+
if (!connection->responsive) {
- ALOGW("Window %s is not responsive", windowHandle.getName().c_str());
+ ALOGW("Not sending touch to %s because it is not responsive", window->getName().c_str());
return false;
}
+
+ // Drop events that can't be trusted due to occlusion
+ const auto [x, y] = resolveTouchedPosition(motionEntry);
+ TouchOcclusionInfo occlusionInfo = computeTouchOcclusionInfoLocked(window, x, y);
+ if (!isTouchTrustedLocked(occlusionInfo)) {
+ if (DEBUG_TOUCH_OCCLUSION) {
+ ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
+ for (const auto& log : occlusionInfo.debugInfo) {
+ ALOGD("%s", log.c_str());
+ }
+ }
+ ALOGW("Dropping untrusted touch event due to %s/%d", occlusionInfo.obscuringPackage.c_str(),
+ occlusionInfo.obscuringUid);
+ return false;
+ }
+
+ // Drop touch events if requested by input feature
+ if (shouldDropInput(motionEntry, window)) {
+ return false;
+ }
+
return true;
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 630d21a..14b046a 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -384,8 +384,8 @@
REQUIRES(mLock);
sp<android::gui::WindowInfoHandle> getFocusedWindowHandleLocked(int displayId) const
REQUIRES(mLock);
- bool hasResponsiveConnectionLocked(android::gui::WindowInfoHandle& windowHandle) const
- REQUIRES(mLock);
+ bool canWindowReceiveMotionLocked(const sp<android::gui::WindowInfoHandle>& window,
+ const MotionEntry& motionEntry) const REQUIRES(mLock);
// Returns all the input targets (with their respective input channels) from the window handles
// passed as argument.
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index 8f5dc9b..047f068 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -38,13 +38,9 @@
bool usingSlotsProtocol) {
mUsingSlotsProtocol = usingSlotsProtocol;
mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE);
-
mSlots = std::vector<Slot>(slotCount);
-}
-void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) {
- // Unfortunately there is no way to read the initial contents of the slots.
- // So when we reset the accumulator, we must assume they are all zeroes.
+ mCurrentSlot = -1;
if (mUsingSlotsProtocol) {
// Query the driver for the current slot index and use it as the initial slot
// before we start reading events from the device. It is possible that the
@@ -56,22 +52,20 @@
// This can cause the touch point to "jump", but at least there will be
// no stuck touches.
int32_t initialSlot;
- status_t status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot);
- if (status) {
- ALOGD("Could not retrieve current multitouch slot index. status=%d", status);
- initialSlot = -1;
+ if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot);
+ status == OK) {
+ mCurrentSlot = initialSlot;
+ } else {
+ ALOGD("Could not retrieve current multi-touch slot index. status=%d", status);
}
- clearSlots(initialSlot);
- } else {
- clearSlots(-1);
}
}
-void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
+void MultiTouchMotionAccumulator::resetSlots() {
for (Slot& slot : mSlots) {
slot.clear();
}
- mCurrentSlot = initialSlot;
+ mCurrentSlot = -1;
}
void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
@@ -159,7 +153,7 @@
void MultiTouchMotionAccumulator::finishSync() {
if (!mUsingSlotsProtocol) {
- clearSlots(-1);
+ resetSlots();
}
}
@@ -198,10 +192,12 @@
MultiTouchInputMapper::~MultiTouchInputMapper() {}
void MultiTouchInputMapper::reset(nsecs_t when) {
- mMultiTouchMotionAccumulator.reset(getDeviceContext());
-
- mPointerIdBits.clear();
-
+ // The evdev multi-touch protocol does not allow userspace applications to query the initial or
+ // current state of the pointers at any time. This means if we clear our accumulated state when
+ // resetting the input mapper, there's no way to rebuild the full initial state of the pointers.
+ // We can only wait for updates to all the pointers and axes. Rather than clearing the state and
+ // rebuilding the state from scratch, we work around this kernel API limitation by never
+ // fully clearing any state specific to the multi-touch protocol.
TouchInputMapper::reset(when);
}
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index 212c9c9..75cde8e 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -68,7 +68,6 @@
MultiTouchMotionAccumulator();
void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol);
- void reset(InputDeviceContext& deviceContext);
void process(const RawEvent* rawEvent);
void finishSync();
bool hasStylus() const;
@@ -85,7 +84,7 @@
bool mUsingSlotsProtocol;
bool mHaveStylus;
- void clearSlots(int32_t initialSlot);
+ void resetSlots();
void warnIfNotInUse(const RawEvent& event, const Slot& slot);
};
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 4cd2cce..5d0f188 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -1495,6 +1495,10 @@
}
void TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) {
+ if (mDeviceMode == DeviceMode::DISABLED) {
+ // Only save the last pending state when the device is disabled.
+ mRawStatesPending.clear();
+ }
// Push a new state.
mRawStatesPending.emplace_back();
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 31806e1..76fdf5d 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -320,6 +320,8 @@
int32_t rawVScroll;
int32_t rawHScroll;
+ explicit inline RawState() { clear(); }
+
void copyFrom(const RawState& other) {
when = other.when;
readTime = other.readTime;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 78ea692..8972e9f 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -6835,6 +6835,32 @@
toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
}
+TEST_F(SingleTouchInputMapperTest, Reset_RecreatesTouchState) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
+ prepareAxes(POSITION | PRESSURE);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+
+ // Set the initial state for the touch pointer.
+ mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_X, 100);
+ mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_Y, 200);
+ mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_PRESSURE, RAW_PRESSURE_MAX);
+ mFakeEventHub->setScanCodeState(EVENTHUB_ID, BTN_TOUCH, 1);
+
+ // Reset the mapper. When the mapper is reset, we expect it to attempt to recreate the touch
+ // state by reading the current axis values.
+ mapper.reset(ARBITRARY_TIME);
+
+ // Send a sync to simulate an empty touch frame where nothing changes. The mapper should use
+ // the recreated touch state to generate a down event.
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPressure(1.f))));
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+}
+
TEST_F(SingleTouchInputMapperTest,
Process_WhenViewportDisplayIdChanged_TouchIsCanceledAndDeviceIsReset) {
addConfigurationProperty("touch.deviceType", "touchScreen");
@@ -6894,10 +6920,17 @@
// No events are generated while the viewport is inactive.
processMove(mapper, 101, 201);
processSync(mapper);
- processDown(mapper, 102, 202);
+ processUp(mapper);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+ // Start a new gesture while the viewport is still inactive.
+ processDown(mapper, 300, 400);
+ mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_X, 300);
+ mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_Y, 400);
+ mFakeEventHub->setScanCodeState(EVENTHUB_ID, BTN_TOUCH, 1);
+ processSync(mapper);
+
// Make the viewport active again. The device should resume processing events.
viewport->isActive = true;
mFakePolicy->updateViewport(*viewport);
@@ -6907,11 +6940,10 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
- // Start a new gesture.
- processDown(mapper, 100, 200);
+ // In the next sync, the touch state that was recreated when the device was reset is reported.
processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN)));
// No more events.
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
@@ -9443,6 +9475,74 @@
ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
}
+TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT | PRESSURE);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ // First finger down.
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, 100, 200);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN)));
+
+ // Second finger down.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, SECOND_TRACKING_ID);
+ processPosition(mapper, 300, 400);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(
+ mFakeListener->assertNotifyMotionWasCalled(WithMotionAction(ACTION_POINTER_1_DOWN)));
+
+ // Reset the mapper. When the mapper is reset, we expect the current multi-touch state to be
+ // preserved. Resetting should not generate any events.
+ mapper.reset(ARBITRARY_TIME);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+ // Send a sync to simulate an empty touch frame where nothing changes. The mapper should use
+ // the existing touch state to generate a down event.
+ processPosition(mapper, 301, 302);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPressure(1.f))));
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(ACTION_POINTER_1_DOWN), WithPressure(1.f))));
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+}
+
+TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState_NoPointersDown) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT | PRESSURE);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ // First finger touches down and releases.
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, 100, 200);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN)));
+ processId(mapper, INVALID_TRACKING_ID);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(
+ mFakeListener->assertNotifyMotionWasCalled(WithMotionAction(AMOTION_EVENT_ACTION_UP)));
+
+ // Reset the mapper. When the mapper is reset, we expect it to restore the latest
+ // raw state where no pointers are down.
+ mapper.reset(ARBITRARY_TIME);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+ // Send an empty sync frame. Since there are no pointers, no events are generated.
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+}
+
// --- MultiTouchInputMapperTest_ExternalDevice ---
class MultiTouchInputMapperTest_ExternalDevice : public MultiTouchInputMapperTest {
diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h
index 03736a3..2580405 100644
--- a/services/inputflinger/tests/TestInputListenerMatchers.h
+++ b/services/inputflinger/tests/TestInputListenerMatchers.h
@@ -50,6 +50,12 @@
return argX == x && argY == y;
}
+MATCHER_P(WithPressure, pressure, "InputEvent with specified pressure") {
+ const auto argPressure = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
+ *result_listener << "expected pressure " << pressure << ", but got " << pressure;
+ return argPressure;
+}
+
MATCHER_P(WithFlags, flags, "InputEvent with specified flags") {
*result_listener << "expected flags " << flags << ", but got " << arg.flags;
return arg.flags == flags;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cae49b7..fac0792 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3186,7 +3186,6 @@
}
doCommitTransactions();
- signalSynchronousTransactions(CountDownLatch::eSyncTransaction);
}
void SurfaceFlinger::updateInputFlinger() {
@@ -3783,10 +3782,6 @@
transaction.permissions, transaction.hasListenerCallbacks,
transaction.listenerCallbacks, transaction.originPid,
transaction.originUid, transaction.id);
- if (transaction.transactionCommittedSignal) {
- mTransactionCommittedSignals.emplace_back(
- std::move(transaction.transactionCommittedSignal));
- }
}
if (mTransactionTracing) {
@@ -3962,12 +3957,6 @@
}
void SurfaceFlinger::queueTransaction(TransactionState& state) {
- // Generate a CountDownLatch pending state if this is a synchronous transaction.
- if (state.flags & eSynchronous) {
- state.transactionCommittedSignal =
- std::make_shared<CountDownLatch>(CountDownLatch::eSyncTransaction);
- }
-
mLocklessTransactionQueue.push(state);
mPendingTransactionCount++;
ATRACE_INT("TransactionQueue", mPendingTransactionCount.load());
@@ -3983,28 +3972,6 @@
setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint);
}
-void SurfaceFlinger::waitForSynchronousTransaction(
- const CountDownLatch& transactionCommittedSignal) {
- // applyTransactionState is called on the main SF thread. While a given process may wish
- // to wait on synchronous transactions, the main SF thread should apply the transaction and
- // set the value to notify this after committed.
- if (!transactionCommittedSignal.wait_until(
- std::chrono::nanoseconds(mAnimationTransactionTimeout))) {
- ALOGE("setTransactionState timed out!");
- }
-}
-
-void SurfaceFlinger::signalSynchronousTransactions(const uint32_t flag) {
- for (auto it = mTransactionCommittedSignals.begin();
- it != mTransactionCommittedSignals.end();) {
- if ((*it)->countDown(flag)) {
- it = mTransactionCommittedSignals.erase(it);
- } else {
- it++;
- }
- }
-}
-
status_t SurfaceFlinger::setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
@@ -4057,11 +4024,6 @@
}
queueTransaction(state);
- // Check the pending state to make sure the transaction is synchronous.
- if (state.transactionCommittedSignal) {
- waitForSynchronousTransaction(*state.transactionCommittedSignal);
- }
-
return NO_ERROR;
}
@@ -4118,8 +4080,7 @@
// anyway. This can be used as a flush mechanism for previous async transactions.
// Empty animation transaction can be used to simulate back-pressure, so also force a
// transaction for empty animation transactions.
- if (transactionFlags == 0 &&
- ((flags & eSynchronous) || (flags & eAnimation))) {
+ if (transactionFlags == 0 && (flags & eAnimation)) {
transactionFlags = eTransactionNeeded;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index cf07f30..cf226a5 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1085,8 +1085,6 @@
// Add transaction to the Transaction Queue
void queueTransaction(TransactionState& state);
- void waitForSynchronousTransaction(const CountDownLatch& transactionCommittedSignal);
- void signalSynchronousTransactions(const uint32_t flag);
/*
* Generic Layer Metadata
@@ -1114,7 +1112,6 @@
mutable Mutex mStateLock;
State mCurrentState{LayerVector::StateSet::Current};
std::atomic<int32_t> mTransactionFlags = 0;
- std::vector<std::shared_ptr<CountDownLatch>> mTransactionCommittedSignals;
std::atomic<uint32_t> mUniqueTransactionId = 1;
SortedVector<sp<Layer>> mLayersPendingRemoval;
@@ -1408,8 +1405,6 @@
bool early = false;
} mPowerHintSessionMode;
- nsecs_t mAnimationTransactionTimeout = s2ns(5);
-
friend class SurfaceComposerAIDL;
};
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 6797aa6..c90ae4c 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -127,7 +127,6 @@
{
Transaction* transaction(increment->mutable_transaction());
const uint32_t layerFlags = layer->getTransactionFlags();
- transaction->set_synchronous(layerFlags & BnSurfaceComposer::eSynchronous);
transaction->set_animation(layerFlags & BnSurfaceComposer::eAnimation);
const int32_t layerId(getLayerId(layer));
@@ -495,7 +494,6 @@
const Vector<DisplayState>& changedDisplays, uint32_t transactionFlags, int originPid,
int originUid, uint64_t transactionId) {
Transaction* transaction(increment->mutable_transaction());
- transaction->set_synchronous(transactionFlags & BnSurfaceComposer::eSynchronous);
transaction->set_animation(transactionFlags & BnSurfaceComposer::eAnimation);
setTransactionOriginLocked(transaction, originPid, originUid);
transaction->set_id(transactionId);
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index 61f0fa6..95eb503 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -26,8 +26,6 @@
namespace android {
-class CountDownLatch;
-
struct TransactionState {
TransactionState() = default;
@@ -97,49 +95,7 @@
int originPid;
int originUid;
uint64_t id;
- std::shared_ptr<CountDownLatch> transactionCommittedSignal;
bool sentFenceTimeoutWarning = false;
};
-class CountDownLatch {
-public:
- enum {
- eSyncTransaction = 1 << 0,
- };
- explicit CountDownLatch(uint32_t flags) : mFlags(flags) {}
-
- // True if there is no waiting condition after count down.
- bool countDown(uint32_t flag) {
- std::unique_lock<std::mutex> lock(mMutex);
- if (mFlags == 0) {
- return true;
- }
- mFlags &= ~flag;
- if (mFlags == 0) {
- mCountDownComplete.notify_all();
- return true;
- }
- return false;
- }
-
- // Return true if triggered.
- bool wait_until(const std::chrono::nanoseconds& timeout) const {
- std::unique_lock<std::mutex> lock(mMutex);
- const auto untilTime = std::chrono::system_clock::now() + timeout;
- while (mFlags != 0) {
- // Conditional variables can be woken up sporadically, so we check count
- // to verify the wakeup was triggered by |countDown|.
- if (std::cv_status::timeout == mCountDownComplete.wait_until(lock, untilTime)) {
- return false;
- }
- }
- return true;
- }
-
-private:
- uint32_t mFlags;
- mutable std::condition_variable mCountDownComplete;
- mutable std::mutex mMutex;
-};
-
} // namespace android
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 82158d8..c96520d 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -455,10 +455,6 @@
mFlinger->calculateColorMatrix(fdp->ConsumeFloatingPoint<float>());
mFlinger->updateColorMatrixLocked();
mFlinger->CheckTransactCodeCredentials(fdp->ConsumeIntegral<uint32_t>());
-
- const CountDownLatch transactionCommittedSignal(fdp->ConsumeIntegral<uint32_t>());
- mFlinger->waitForSynchronousTransaction(transactionCommittedSignal);
- mFlinger->signalSynchronousTransactions(fdp->ConsumeIntegral<uint32_t>());
}
void getCompositionPreference() {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index fdd55a5..eedd9cf 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -158,7 +158,6 @@
if (!mFlinger) {
mFlinger = sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization);
}
- mFlinger->mAnimationTransactionTimeout = ms2ns(10);
}
SurfaceFlinger* flinger() { return mFlinger.get(); }
@@ -420,7 +419,6 @@
auto& getTransactionQueue() { return mFlinger->mLocklessTransactionQueue; }
auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
- auto& getTransactionCommittedSignals() { return mFlinger->mTransactionCommittedSignals; }
auto setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,
@@ -493,10 +491,6 @@
return static_cast<mock::FrameTracer*>(mFlinger->mFrameTracer.get());
}
- nsecs_t getAnimationTransactionTimeout() const {
- return mFlinger->mAnimationTransactionTimeout;
- }
-
/* ------------------------------------------------------------------------
* Read-write access to private data to set up preconditions and assert
* post-conditions.
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index b493d11..b4030b3 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -37,7 +37,7 @@
using testing::Return;
using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
-
+constexpr nsecs_t TRANSACTION_TIMEOUT = s2ns(5);
class TransactionApplicationTest : public testing::Test {
public:
TransactionApplicationTest() {
@@ -112,7 +112,7 @@
void setupSingle(TransactionInfo& transaction, uint32_t flags, int64_t desiredPresentTime,
bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo) {
mTransactionNumber++;
- transaction.flags |= flags; // ISurfaceComposer::eSynchronous;
+ transaction.flags |= flags;
transaction.desiredPresentTime = desiredPresentTime;
transaction.isAutoTimestamp = isAutoTimestamp;
transaction.frameTimelineInfo = frameTimelineInfo;
@@ -136,11 +136,7 @@
// If transaction is synchronous, SF applyTransactionState should time out (5s) wating for
// SF to commit the transaction. If this is animation, it should not time out waiting.
nsecs_t returnedTime = systemTime();
- if (flags & ISurfaceComposer::eSynchronous) {
- EXPECT_GE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout());
- } else {
- EXPECT_LE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout());
- }
+ EXPECT_LE(returnedTime, applicationTime + TRANSACTION_TIMEOUT);
// Each transaction should have been placed on the transaction queue
auto& transactionQueue = mFlinger.getTransactionQueue();
EXPECT_FALSE(transactionQueue.isEmpty());
@@ -165,13 +161,7 @@
transaction.id);
nsecs_t returnedTime = systemTime();
- if (flags & ISurfaceComposer::eSynchronous) {
- EXPECT_GE(systemTime(),
- applicationSentTime + mFlinger.getAnimationTransactionTimeout());
- } else {
- EXPECT_LE(returnedTime,
- applicationSentTime + mFlinger.getAnimationTransactionTimeout());
- }
+ EXPECT_LE(returnedTime, applicationSentTime + TRANSACTION_TIMEOUT);
// This transaction should have been placed on the transaction queue
auto& transactionQueue = mFlinger.getTransactionQueue();
EXPECT_FALSE(transactionQueue.isEmpty());
@@ -204,7 +194,7 @@
// This thread should not have been blocked by the above transaction
// (5s is the timeout period that applyTransactionState waits for SF to
// commit the transaction)
- EXPECT_LE(systemTime(), applicationSentTime + mFlinger.getAnimationTransactionTimeout());
+ EXPECT_LE(systemTime(), applicationSentTime + TRANSACTION_TIMEOUT);
// transaction that would goes to pending transaciton queue.
mFlinger.flushTransactionQueues();
@@ -220,13 +210,7 @@
// if this is an animation, this thread should be blocked for 5s
// in setTransactionState waiting for transactionA to flush. Otherwise,
// the transaction should be placed on the pending queue
- if (flags & ISurfaceComposer::eSynchronous) {
- EXPECT_GE(systemTime(),
- applicationSentTime + mFlinger.getAnimationTransactionTimeout());
- } else {
- EXPECT_LE(systemTime(),
- applicationSentTime + mFlinger.getAnimationTransactionTimeout());
- }
+ EXPECT_LE(systemTime(), applicationSentTime + TRANSACTION_TIMEOUT);
// transaction that would goes to pending transaciton queue.
mFlinger.flushTransactionQueues();
@@ -294,26 +278,14 @@
EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
}
-TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) {
- NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous);
-}
-
TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_SyncInputWindows) {
NotPlacedOnTransactionQueue(/*flags*/ 0);
}
-TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Synchronous) {
- PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous);
-}
-
TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_SyncInputWindows) {
PlaceOnTransactionQueue(/*flags*/ 0);
}
-TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Synchronous) {
- BlockedByPriorTransaction(ISurfaceComposer::eSynchronous);
-}
-
TEST_F(TransactionApplicationTest, FromHandle) {
sp<IBinder> badHandle;
auto ret = mFlinger.fromHandle(badHandle);
@@ -329,7 +301,6 @@
mFlinger.getTransactionQueue().pop();
}
mFlinger.getPendingTransactionQueue().clear();
- mFlinger.getTransactionCommittedSignals().clear();
mFlinger.commitTransactionsLocked(eTransactionMask);
mFlinger.mutableCurrentState().layersSortedByZ.clear();
mFlinger.mutableDrawingState().layersSortedByZ.clear();
@@ -361,7 +332,7 @@
TransactionInfo createTransactionInfo(const sp<IBinder>& applyToken,
const std::vector<ComposerState>& states) {
TransactionInfo transaction;
- const uint32_t kFlags = ISurfaceComposer::eSynchronous;
+ const uint32_t kFlags = 0;
const nsecs_t kDesiredPresentTime = systemTime();
const bool kIsAutoTimestamp = true;
const auto kFrameTimelineInfo = FrameTimelineInfo{};
@@ -376,7 +347,6 @@
}
void setTransactionStates(const std::vector<TransactionInfo>& transactions,
- size_t expectedTransactionsApplied,
size_t expectedTransactionsPending) {
EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
@@ -392,7 +362,6 @@
mFlinger.flushTransactionQueues();
EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
EXPECT_EQ(expectedTransactionsPending, mFlinger.getPendingTransactionQueue().size());
- EXPECT_EQ(expectedTransactionsApplied, mFlinger.getTransactionCommittedSignals().size());
}
};
@@ -408,22 +377,19 @@
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
createTransactionInfo(kApplyToken,
{createComposerState(kLayerId, fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged)});
- setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({signaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSingleUnSignaledFromTheQueue) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto unsignaledTransaction =
@@ -433,15 +399,13 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBufferCropChange) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -451,15 +415,13 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eCropChanged),
});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -471,15 +433,13 @@
layer_state_t::
eBufferChanged),
});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsInTheQueueSameApplyTokenMultiState) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto mixedTransaction =
@@ -492,8 +452,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({mixedTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsInTheQueue_MultipleStateTransaction) {
@@ -501,7 +460,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto mixedTransaction =
@@ -514,8 +472,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({mixedTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSignaledFromTheQueue) {
@@ -523,7 +480,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
@@ -540,8 +496,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest,
@@ -552,7 +507,6 @@
const sp<IBinder> kApplyToken3 = sp<BBinder>::make();
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -579,7 +533,7 @@
});
setTransactionStates({unsignaledTransaction, signaledTransaction, signaledTransaction2},
- kExpectedTransactionsApplied, kExpectedTransactionsPending);
+ kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, UnsignaledNotAppliedWhenThereAreSignaled_SignaledFirst) {
@@ -589,7 +543,6 @@
const sp<IBinder> kApplyToken3 = sp<BBinder>::make();
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 1u;
const auto signaledTransaction =
@@ -615,7 +568,7 @@
});
setTransactionStates({signaledTransaction, signaledTransaction2, unsignaledTransaction},
- kExpectedTransactionsApplied, kExpectedTransactionsPending);
+ kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueueSameApplyToken) {
@@ -623,7 +576,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -640,7 +592,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied,
+ setTransactionStates({unsignaledTransaction, signaledTransaction},
kExpectedTransactionsPending);
}
@@ -650,7 +602,6 @@
const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -668,14 +619,13 @@
layer_state_t::eBufferChanged),
});
setTransactionStates({unsignaledTransaction, unsignaledTransaction2},
- kExpectedTransactionsApplied, kExpectedTransactionsPending);
+ kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, DontLatchUnsignaledWhenEarlyOffset) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -689,8 +639,7 @@
// Get VsyncModulator out of the default config
static_cast<void>(mFlinger.mutableVsyncModulator()->onRefreshRateChangeInitiated());
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
class LatchUnsignaledDisabledTest : public LatchUnsignaledTest {
@@ -705,22 +654,19 @@
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
createTransactionInfo(kApplyToken,
{createComposerState(kLayerId, fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged)});
- setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({signaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueue) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -730,15 +676,13 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueueSameLayerId) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -751,8 +695,7 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueueDifferentLayerId) {
@@ -760,7 +703,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -773,8 +715,7 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledDisabledTest, Flush_RemovesSignaledFromTheQueue_MultipleLayers) {
@@ -782,7 +723,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
@@ -799,8 +739,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheQueueDifferentApplyToken) {
@@ -809,7 +748,6 @@
const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -826,7 +764,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied,
+ setTransactionStates({unsignaledTransaction, signaledTransaction},
kExpectedTransactionsPending);
}
@@ -835,7 +773,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 1u;
const auto signaledTransaction =
@@ -852,7 +789,7 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied,
+ setTransactionStates({signaledTransaction, unsignaledTransaction},
kExpectedTransactionsPending);
}
@@ -861,7 +798,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -879,7 +815,7 @@
layer_state_t::eBufferChanged),
});
setTransactionStates({unsignaledTransaction, unsignaledTransaction2},
- kExpectedTransactionsApplied, kExpectedTransactionsPending);
+ kExpectedTransactionsPending);
}
class LatchUnsignaledAlwaysTest : public LatchUnsignaledTest {
@@ -894,37 +830,32 @@
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
createTransactionInfo(kApplyToken,
{createComposerState(kLayerId, fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged)});
- setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({signaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueue) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto unsignaledTransaction =
createTransactionInfo(kApplyToken,
{createComposerState(kLayerId, fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged)});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueSameLayerId) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto mixedTransaction =
@@ -933,8 +864,7 @@
layer_state_t::eBufferChanged),
createComposerState(kLayerId, fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged)});
- setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({mixedTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueDifferentLayerId) {
@@ -942,7 +872,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto mixedTransaction =
@@ -951,8 +880,7 @@
layer_state_t::eBufferChanged),
createComposerState(kLayerId2, fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged)});
- setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({mixedTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesSignaledFromTheQueue_MultipleLayers) {
@@ -960,7 +888,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
@@ -977,8 +904,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueDifferentApplyToken) {
@@ -987,7 +913,6 @@
const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
@@ -1004,7 +929,7 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied,
+ setTransactionStates({signaledTransaction, unsignaledTransaction},
kExpectedTransactionsPending);
}
@@ -1013,7 +938,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 0u;
const auto unsignaledTransaction =
@@ -1030,7 +954,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied,
+ setTransactionStates({unsignaledTransaction, signaledTransaction},
kExpectedTransactionsPending);
}
@@ -1040,7 +964,6 @@
const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 0u;
const auto unsignaledTransaction =
@@ -1058,14 +981,13 @@
layer_state_t::eBufferChanged),
});
setTransactionStates({unsignaledTransaction, unsignaledTransaction2},
- kExpectedTransactionsApplied, kExpectedTransactionsPending);
+ kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAlwaysTest, LatchUnsignaledWhenEarlyOffset) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto unsignaledTransaction =
@@ -1079,8 +1001,7 @@
// Get VsyncModulator out of the default config
static_cast<void>(mFlinger.mutableVsyncModulator()->onRefreshRateChangeInitiated());
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
} // namespace android
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 9c6d19f..abcac3c 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -668,10 +668,11 @@
// VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following
// four values cannot be known without a surface. Default values will
// be supplied anyway, but cannot be relied upon.
- width = 1000;
- height = 1000;
- transform_hint = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- max_buffer_count = 10;
+ width = 0xFFFFFFFF;
+ height = 0xFFFFFFFF;
+ transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
+ capabilities->minImageCount = 0xFFFFFFFF;
+ capabilities->maxImageCount = 0xFFFFFFFF;
} else {
ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
@@ -703,9 +704,9 @@
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
+ capabilities->minImageCount = std::min(max_buffer_count, 3);
+ capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
}
- capabilities->minImageCount = std::min(max_buffer_count, 3);
- capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
capabilities->currentExtent =
VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};