diff options
154 files changed, 2309 insertions, 1099 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 17e5cc119d..dd0ee5fb22 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1526,7 +1526,7 @@ static void DumpExternalFragmentationInfo() { } static void DumpstateLimitedOnly() { - // Trimmed-down version of dumpstate to only include a whitelisted + // Trimmed-down version of dumpstate to only include a allowlisted // set of logs (system log, event log, and system server / system app // crashes, and networking logs). See b/136273873 and b/138459828 // for context. diff --git a/include/binder/unique_fd.h b/include/binder/unique_fd.h new file mode 120000 index 0000000000..433c968151 --- /dev/null +++ b/include/binder/unique_fd.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/unique_fd.h
\ No newline at end of file diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 4f53c36d6f..59b9495c42 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -240,7 +240,7 @@ public: android::base::unique_fd fd, sp<IBinder> token); InputChannel() = default; InputChannel(const InputChannel& other) - : mName(other.mName), mFd(::dup(other.mFd)), mToken(other.mToken){}; + : mName(other.mName), mFd(other.dupFd()), mToken(other.mToken){}; InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token); ~InputChannel() override; /** @@ -310,7 +310,7 @@ public: if (fstat(mFd.get(), &lhs) != 0) { return false; } - if (fstat(inputChannel.getFd(), &rhs) != 0) { + if (fstat(inputChannel.getFd().get(), &rhs) != 0) { return false; } // If file descriptors are pointing to same inode they are duplicated fds. @@ -322,7 +322,7 @@ private: base::unique_fd dupFd() const; std::string mName; - android::base::unique_fd mFd; + base::unique_fd mFd; sp<IBinder> mToken; }; diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index f90c618a94..eccd5dbc3a 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -92,6 +92,7 @@ cc_defaults { "TextOutput.cpp", "Trace.cpp", "Utils.cpp", + "file.cpp", ], shared_libs: [ @@ -653,4 +654,7 @@ cc_binary { "libutils", "android.debug_aidl-cpp", ], + static_libs: [ + "libc++fs", + ], } diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 301dbf6cdf..c57c9cdd62 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -19,7 +19,6 @@ #include <atomic> #include <set> -#include <android-base/unique_fd.h> #include <binder/BpBinder.h> #include <binder/IInterface.h> #include <binder/IPCThreadState.h> @@ -28,6 +27,7 @@ #include <binder/Parcel.h> #include <binder/RecordedTransaction.h> #include <binder/RpcServer.h> +#include <binder/unique_fd.h> #include <pthread.h> #include <inttypes.h> @@ -43,6 +43,8 @@ namespace android { +using android::binder::unique_fd; + constexpr uid_t kUidRoot = 0; // Service implementations inherit from BBinder and IBinder, and this is frozen @@ -167,8 +169,7 @@ status_t IBinder::getDebugPid(pid_t* out) { return OK; } -status_t IBinder::setRpcClientDebug(android::base::unique_fd socketFd, - const sp<IBinder>& keepAliveBinder) { +status_t IBinder::setRpcClientDebug(unique_fd socketFd, const sp<IBinder>& keepAliveBinder) { if (!kEnableRpcDevServers) { ALOGW("setRpcClientDebug disallowed because RPC is not enabled"); return INVALID_OPERATION; @@ -273,7 +274,7 @@ public: std::set<sp<RpcServerLink>> mRpcServerLinks; BpBinder::ObjectManager mObjects; - android::base::unique_fd mRecordingFd; + unique_fd mRecordingFd; }; // --------------------------------------------------------------------------- @@ -640,7 +641,7 @@ status_t BBinder::setRpcClientDebug(const Parcel& data) { } status_t status; bool hasSocketFd; - android::base::unique_fd clientFd; + unique_fd clientFd; if (status = data.readBool(&hasSocketFd); status != OK) return status; if (hasSocketFd) { @@ -652,8 +653,7 @@ status_t BBinder::setRpcClientDebug(const Parcel& data) { return setRpcClientDebug(std::move(clientFd), keepAliveBinder); } -status_t BBinder::setRpcClientDebug(android::base::unique_fd socketFd, - const sp<IBinder>& keepAliveBinder) { +status_t BBinder::setRpcClientDebug(unique_fd socketFd, const sp<IBinder>& keepAliveBinder) { if (!kEnableRpcDevServers) { ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__); return INVALID_OPERATION; diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 49038b1974..42dd6916c7 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -27,14 +27,15 @@ #include <stdio.h> #include "BuildFlags.h" - -#include <android-base/file.h> +#include "file.h" //#undef ALOGV //#define ALOGV(...) fprintf(stderr, __VA_ARGS__) namespace android { +using android::binder::unique_fd; + // --------------------------------------------------------------------------- RpcMutex BpBinder::sTrackingLock; @@ -318,7 +319,7 @@ status_t BpBinder::pingBinder() return transact(PING_TRANSACTION, data, &reply); } -status_t BpBinder::startRecordingBinder(const android::base::unique_fd& fd) { +status_t BpBinder::startRecordingBinder(const unique_fd& fd) { Parcel send, reply; send.writeUniqueFileDescriptor(fd); return transact(START_RECORDING_TRANSACTION, send, &reply); diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp index 895690f9b8..455a4338e5 100644 --- a/libs/binder/FdTrigger.cpp +++ b/libs/binder/FdTrigger.cpp @@ -23,6 +23,7 @@ #include <binder/Functional.h> +#include "FdUtils.h" #include "RpcState.h" #include "Utils.h" @@ -33,7 +34,7 @@ using namespace android::binder::impl; std::unique_ptr<FdTrigger> FdTrigger::make() { auto ret = std::make_unique<FdTrigger>(); #ifndef BINDER_RPC_SINGLE_THREADED - if (!android::base::Pipe(&ret->mRead, &ret->mWrite)) { + if (!binder::Pipe(&ret->mRead, &ret->mWrite)) { ALOGE("Could not create pipe %s", strerror(errno)); return nullptr; } diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h index dba1dc9f6d..e4a02839dc 100644 --- a/libs/binder/FdTrigger.h +++ b/libs/binder/FdTrigger.h @@ -17,10 +17,10 @@ #include <memory> -#include <android-base/unique_fd.h> #include <utils/Errors.h> #include <binder/RpcTransport.h> +#include <binder/unique_fd.h> namespace android { @@ -61,8 +61,8 @@ private: #ifdef BINDER_RPC_SINGLE_THREADED bool mTriggered = false; #else - base::unique_fd mWrite; - base::unique_fd mRead; + binder::unique_fd mWrite; + binder::unique_fd mRead; #endif }; } // namespace android diff --git a/libs/binder/FdUtils.h b/libs/binder/FdUtils.h new file mode 100644 index 0000000000..52ae48728f --- /dev/null +++ b/libs/binder/FdUtils.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <binder/unique_fd.h> + +#if defined(_WIN32) || defined(__TRUSTY__) +// Pipe and Socketpair are missing there +#elif !defined(BINDER_NO_LIBBASE) + +namespace android::binder { +using android::base::Pipe; +using android::base::Socketpair; +} // namespace android::binder + +#else // BINDER_NO_LIBBASE + +#include <sys/socket.h> + +namespace android::binder { + +// Inline functions, so that they can be used header-only. + +// See pipe(2). +// This helper hides the details of converting to unique_fd, and also hides the +// fact that macOS doesn't support O_CLOEXEC or O_NONBLOCK directly. +inline bool Pipe(unique_fd* read, unique_fd* write, int flags = O_CLOEXEC) { + int pipefd[2]; + +#if defined(__APPLE__) + if (flags & ~(O_CLOEXEC | O_NONBLOCK)) { + return false; + } + if (pipe(pipefd) != 0) { + return false; + } + + if (flags & O_CLOEXEC) { + if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 || + fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) != 0) { + close(pipefd[0]); + close(pipefd[1]); + return false; + } + } + if (flags & O_NONBLOCK) { + if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) != 0 || + fcntl(pipefd[1], F_SETFL, O_NONBLOCK) != 0) { + close(pipefd[0]); + close(pipefd[1]); + return false; + } + } +#else + if (pipe2(pipefd, flags) != 0) { + return false; + } +#endif + + read->reset(pipefd[0]); + write->reset(pipefd[1]); + return true; +} + +// See socketpair(2). +// This helper hides the details of converting to unique_fd. +inline bool Socketpair(int domain, int type, int protocol, unique_fd* left, unique_fd* right) { + int sockfd[2]; + if (socketpair(domain, type, protocol, sockfd) != 0) { + return false; + } + left->reset(sockfd[0]); + right->reset(sockfd[1]); + return true; +} + +// See socketpair(2). +// This helper hides the details of converting to unique_fd. +inline bool Socketpair(int type, unique_fd* left, unique_fd* right) { + return Socketpair(AF_UNIX, type, 0, left, right); +} + +} // namespace android::binder + +#endif // BINDER_NO_LIBBASE diff --git a/libs/binder/OS.h b/libs/binder/OS.h index bb7caa951b..c5f0730d6b 100644 --- a/libs/binder/OS.h +++ b/libs/binder/OS.h @@ -18,13 +18,13 @@ #include <stddef.h> #include <cstdint> -#include <android-base/unique_fd.h> #include <binder/RpcTransport.h> +#include <binder/unique_fd.h> #include <utils/Errors.h> namespace android::binder::os { -status_t setNonBlocking(android::base::borrowed_fd fd); +status_t setNonBlocking(borrowed_fd fd); status_t getRandomBytes(uint8_t* data, size_t size); @@ -32,13 +32,11 @@ status_t dupFileDescriptor(int oldFd, int* newFd); std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory(); -ssize_t sendMessageOnSocket( - const RpcTransportFd& socket, iovec* iovs, int niovs, - const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds); +ssize_t sendMessageOnSocket(const RpcTransportFd& socket, iovec* iovs, int niovs, + const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds); -ssize_t receiveMessageFromSocket( - const RpcTransportFd& socket, iovec* iovs, int niovs, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds); +ssize_t receiveMessageFromSocket(const RpcTransportFd& socket, iovec* iovs, int niovs, + std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds); uint64_t GetThreadId(); diff --git a/libs/binder/OS_unix_base.cpp b/libs/binder/OS_unix_base.cpp index a3cf117326..ca998d46d3 100644 --- a/libs/binder/OS_unix_base.cpp +++ b/libs/binder/OS_unix_base.cpp @@ -16,18 +16,21 @@ #include "OS.h" #include "Utils.h" +#include "file.h" -#include <android-base/file.h> #include <binder/RpcTransportRaw.h> #include <log/log.h> #include <string.h> +#include <sys/socket.h> + +using android::binder::ReadFully; namespace android::binder::os { // Linux kernel supports up to 253 (from SCM_MAX_FD) for unix sockets. constexpr size_t kMaxFdsPerMsg = 253; -status_t setNonBlocking(android::base::borrowed_fd fd) { +status_t setNonBlocking(borrowed_fd fd) { int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL)); if (flags == -1) { PLOGE("Failed setNonBlocking: Could not get flags for fd"); @@ -41,13 +44,12 @@ status_t setNonBlocking(android::base::borrowed_fd fd) { } status_t getRandomBytes(uint8_t* data, size_t size) { - int ret = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); - if (ret == -1) { + unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW))); + if (!fd.ok()) { return -errno; } - base::unique_fd fd(ret); - if (!base::ReadFully(fd, data, size)) { + if (!ReadFully(fd, data, size)) { return -errno; } return OK; @@ -67,9 +69,8 @@ std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory() { return RpcTransportCtxFactoryRaw::make(); } -ssize_t sendMessageOnSocket( - const RpcTransportFd& socket, iovec* iovs, int niovs, - const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) { +ssize_t sendMessageOnSocket(const RpcTransportFd& socket, iovec* iovs, int niovs, + const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) { if (ancillaryFds != nullptr && !ancillaryFds->empty()) { if (ancillaryFds->size() > kMaxFdsPerMsg) { errno = EINVAL; @@ -112,9 +113,8 @@ ssize_t sendMessageOnSocket( return TEMP_FAILURE_RETRY(sendmsg(socket.fd.get(), &msg, MSG_NOSIGNAL)); } -ssize_t receiveMessageFromSocket( - const RpcTransportFd& socket, iovec* iovs, int niovs, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) { +ssize_t receiveMessageFromSocket(const RpcTransportFd& socket, iovec* iovs, int niovs, + std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) { if (ancillaryFds != nullptr) { int fdBuffer[kMaxFdsPerMsg]; alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(fdBuffer))]; @@ -140,7 +140,7 @@ ssize_t receiveMessageFromSocket( size_t fdCount = dataLen / sizeof(int); ancillaryFds->reserve(ancillaryFds->size() + fdCount); for (size_t i = 0; i < fdCount; i++) { - ancillaryFds->emplace_back(base::unique_fd(fdBuffer[i])); + ancillaryFds->emplace_back(unique_fd(fdBuffer[i])); } break; } diff --git a/libs/binder/OWNERS b/libs/binder/OWNERS index bb17683a23..a70b55826f 100644 --- a/libs/binder/OWNERS +++ b/libs/binder/OWNERS @@ -1,4 +1,5 @@ # Bug component: 32456 -maco@google.com + smoreland@google.com -tkjos@google.com +tkjos@google.com # kernel +maco@google.com # historical diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 334940298f..146ddef8ba 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -97,6 +97,8 @@ static size_t pad_size(size_t s) { namespace android { using namespace android::binder::impl; +using binder::borrowed_fd; +using binder::unique_fd; // many things compile this into prebuilts on the stack #ifdef __LP64__ @@ -211,7 +213,7 @@ static void release_object(const sp<ProcessState>& proc, const flat_binder_objec } #endif // BINDER_WITH_KERNEL_IPC -static int toRawFd(const std::variant<base::unique_fd, base::borrowed_fd>& v) { +static int toRawFd(const std::variant<unique_fd, borrowed_fd>& v) { return std::visit([](const auto& fd) { return fd.get(); }, v); } @@ -667,7 +669,7 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { if (status_t status = binder::os::dupFileDescriptor(oldFd, &newFd); status != OK) { ALOGW("Failed to duplicate file descriptor %d: %s", oldFd, strerror(-status)); } - rpcFields->mFds->emplace_back(base::unique_fd(newFd)); + rpcFields->mFds->emplace_back(unique_fd(newFd)); // Fixup the index in the data. mDataPos = newDataPos + 4; if (status_t status = writeInt32(rpcFields->mFds->size() - 1); status != OK) { @@ -1247,9 +1249,16 @@ status_t Parcel::writeUtf8VectorAsUtf16Vector( const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) { return writeData(val); } status_t Parcel::writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val) { return writeData(val); } -status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<base::unique_fd>& val) { return writeData(val); } -status_t Parcel::writeUniqueFileDescriptorVector(const std::optional<std::vector<base::unique_fd>>& val) { return writeData(val); } -status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<base::unique_fd>>& val) { return writeData(val); } +status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<unique_fd>& val) { + return writeData(val); +} +status_t Parcel::writeUniqueFileDescriptorVector(const std::optional<std::vector<unique_fd>>& val) { + return writeData(val); +} +status_t Parcel::writeUniqueFileDescriptorVector( + const std::unique_ptr<std::vector<unique_fd>>& val) { + return writeData(val); +} status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val) { return writeData(val); } status_t Parcel::writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val) { return writeData(val); } @@ -1302,9 +1311,16 @@ status_t Parcel::readUtf8VectorFromUtf16Vector( std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const { return readData(val); } status_t Parcel::readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const { return readData(val); } -status_t Parcel::readUniqueFileDescriptorVector(std::optional<std::vector<base::unique_fd>>* val) const { return readData(val); } -status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const { return readData(val); } -status_t Parcel::readUniqueFileDescriptorVector(std::vector<base::unique_fd>* val) const { return readData(val); } +status_t Parcel::readUniqueFileDescriptorVector(std::optional<std::vector<unique_fd>>* val) const { + return readData(val); +} +status_t Parcel::readUniqueFileDescriptorVector( + std::unique_ptr<std::vector<unique_fd>>* val) const { + return readData(val); +} +status_t Parcel::readUniqueFileDescriptorVector(std::vector<unique_fd>* val) const { + return readData(val); +} status_t Parcel::readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const { return readData(val); } status_t Parcel::readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const { return readData(val); } @@ -1504,11 +1520,11 @@ status_t Parcel::writeNativeHandle(const native_handle* handle) status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) { if (auto* rpcFields = maybeRpcFields()) { - std::variant<base::unique_fd, base::borrowed_fd> fdVariant; + std::variant<unique_fd, borrowed_fd> fdVariant; if (takeOwnership) { - fdVariant = base::unique_fd(fd); + fdVariant = unique_fd(fd); } else { - fdVariant = base::borrowed_fd(fd); + fdVariant = borrowed_fd(fd); } if (!mAllowFds) { return FDS_NOT_ALLOWED; @@ -1587,7 +1603,7 @@ status_t Parcel::writeDupParcelFileDescriptor(int fd) return err; } -status_t Parcel::writeUniqueFileDescriptor(const base::unique_fd& fd) { +status_t Parcel::writeUniqueFileDescriptor(const unique_fd& fd) { return writeDupFileDescriptor(fd.get()); } @@ -2390,8 +2406,7 @@ int Parcel::readParcelFileDescriptor() const { return fd; } -status_t Parcel::readUniqueFileDescriptor(base::unique_fd* val) const -{ +status_t Parcel::readUniqueFileDescriptor(unique_fd* val) const { int got = readFileDescriptor(); if (got == BAD_TYPE) { @@ -2412,8 +2427,7 @@ status_t Parcel::readUniqueFileDescriptor(base::unique_fd* val) const return OK; } -status_t Parcel::readUniqueParcelFileDescriptor(base::unique_fd* val) const -{ +status_t Parcel::readUniqueParcelFileDescriptor(unique_fd* val) const { int got = readParcelFileDescriptor(); if (got == BAD_TYPE) { @@ -2710,8 +2724,7 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const bin status_t Parcel::rpcSetDataReference( const sp<RpcSession>& session, const uint8_t* data, size_t dataSize, const uint32_t* objectTable, size_t objectTableSize, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds, - release_func relFunc) { + std::vector<std::variant<unique_fd, borrowed_fd>>&& ancillaryFds, release_func relFunc) { // this code uses 'mOwner == nullptr' to understand whether it owns memory LOG_ALWAYS_FATAL_IF(relFunc == nullptr, "must provide cleanup function"); diff --git a/libs/binder/ParcelFileDescriptor.cpp b/libs/binder/ParcelFileDescriptor.cpp index 4f8b76f7d9..c3c487442b 100644 --- a/libs/binder/ParcelFileDescriptor.cpp +++ b/libs/binder/ParcelFileDescriptor.cpp @@ -19,9 +19,11 @@ namespace android { namespace os { +using android::binder::unique_fd; + ParcelFileDescriptor::ParcelFileDescriptor() = default; -ParcelFileDescriptor::ParcelFileDescriptor(android::base::unique_fd fd) : mFd(std::move(fd)) {} +ParcelFileDescriptor::ParcelFileDescriptor(unique_fd fd) : mFd(std::move(fd)) {} ParcelFileDescriptor::~ParcelFileDescriptor() = default; diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 0344eb04d6..7de94e3c6c 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -61,6 +61,7 @@ const char* kDefaultDriver = "/dev/binder"; namespace android { using namespace android::binder::impl; +using android::binder::unique_fd; class PoolThread : public Thread { @@ -514,8 +515,8 @@ String8 ProcessState::getDriverName() { return mDriverName; } -static base::unique_fd open_driver(const char* driver) { - auto fd = base::unique_fd(open(driver, O_RDWR | O_CLOEXEC)); +static unique_fd open_driver(const char* driver) { + auto fd = unique_fd(open(driver, O_RDWR | O_CLOEXEC)); if (!fd.ok()) { PLOGE("Opening '%s' failed", driver); return {}; @@ -563,7 +564,7 @@ ProcessState::ProcessState(const char* driver) mThreadPoolStarted(false), mThreadPoolSeq(1), mCallRestriction(CallRestriction::NONE) { - base::unique_fd opened = open_driver(driver); + unique_fd opened = open_driver(driver); if (opened.ok()) { // mmap the binder, providing a chunk of virtual address space to receive transactions. diff --git a/libs/binder/RecordedTransaction.cpp b/libs/binder/RecordedTransaction.cpp index f7b5a55a31..525ba2e9b9 100644 --- a/libs/binder/RecordedTransaction.cpp +++ b/libs/binder/RecordedTransaction.cpp @@ -14,18 +14,23 @@ * limitations under the License. */ -#include <android-base/file.h> -#include <android-base/unique_fd.h> +#include "file.h" + #include <binder/Functional.h> #include <binder/RecordedTransaction.h> +#include <binder/unique_fd.h> + #include <inttypes.h> #include <sys/mman.h> +#include <sys/stat.h> #include <algorithm> using namespace android::binder::impl; using android::Parcel; -using android::base::borrowed_fd; -using android::base::unique_fd; +using android::binder::borrowed_fd; +using android::binder::ReadFully; +using android::binder::unique_fd; +using android::binder::WriteFully; using android::binder::debug::RecordedTransaction; #define PADDING8(s) ((8 - (s) % 8) % 8) @@ -182,7 +187,7 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd return std::nullopt; } - if (!android::base::ReadFully(fd, &chunk, sizeof(ChunkDescriptor))) { + if (!ReadFully(fd, &chunk, sizeof(ChunkDescriptor))) { ALOGE("Failed to read ChunkDescriptor from fd %d. %s", fd.get(), strerror(errno)); return std::nullopt; } @@ -317,7 +322,7 @@ android::status_t RecordedTransaction::writeChunk(borrowed_fd fd, uint32_t chunk buffer.insert(buffer.end(), checksumBytes, checksumBytes + sizeof(transaction_checksum_t)); // Write buffer to file - if (!android::base::WriteFully(fd, buffer.data(), buffer.size())) { + if (!WriteFully(fd, buffer.data(), buffer.size())) { ALOGE("Failed to write chunk fd %d", fd.get()); return UNKNOWN_ERROR; } diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index fefaa810d2..d9e926a9d5 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -45,7 +45,8 @@ namespace android { constexpr size_t kSessionIdBytes = 32; using namespace android::binder::impl; -using base::unique_fd; +using android::binder::borrowed_fd; +using android::binder::unique_fd; RpcServer::RpcServer(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) {} RpcServer::~RpcServer() { @@ -166,7 +167,7 @@ void RpcServer::setConnectionFilter(std::function<bool(const void*, size_t)>&& f mConnectionFilter = std::move(filter); } -void RpcServer::setServerSocketModifier(std::function<void(base::borrowed_fd)>&& modifier) { +void RpcServer::setServerSocketModifier(std::function<void(borrowed_fd)>&& modifier) { RpcMutexLockGuard _l(mLock); LOG_ALWAYS_FATAL_IF(mServer.fd.ok(), "Already started"); mServerSocketModifier = std::move(modifier); @@ -213,7 +214,7 @@ status_t RpcServer::acceptSocketConnection(const RpcServer& server, RpcTransport status_t RpcServer::recvmsgSocketConnection(const RpcServer& server, RpcTransportFd* out) { int zero = 0; iovec iov{&zero, sizeof(zero)}; - std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; + std::vector<std::variant<unique_fd, borrowed_fd>> fds; ssize_t num_bytes = binder::os::receiveMessageFromSocket(server.mServer, &iov, 1, &fds); if (num_bytes < 0) { @@ -644,8 +645,7 @@ unique_fd RpcServer::releaseServer() { } status_t RpcServer::setupExternalServer( - base::unique_fd serverFd, - std::function<status_t(const RpcServer&, RpcTransportFd*)>&& acceptFn) { + unique_fd serverFd, std::function<status_t(const RpcServer&, RpcTransportFd*)>&& acceptFn) { RpcMutexLockGuard _l(mLock); if (mServer.fd.ok()) { ALOGE("Each RpcServer can only have one server."); @@ -656,7 +656,7 @@ status_t RpcServer::setupExternalServer( return OK; } -status_t RpcServer::setupExternalServer(base::unique_fd serverFd) { +status_t RpcServer::setupExternalServer(unique_fd serverFd) { return setupExternalServer(std::move(serverFd), &RpcServer::acceptSocketConnection); } diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index cd8f41711f..16a7f9fd48 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -51,7 +51,8 @@ extern "C" JavaVM* AndroidRuntimeGetJavaVM(); namespace android { using namespace android::binder::impl; -using base::unique_fd; +using android::binder::borrowed_fd; +using android::binder::unique_fd; RpcSession::RpcSession(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) { LOG_RPC_DETAIL("RpcSession created %p", this); @@ -157,7 +158,7 @@ status_t RpcSession::setupUnixDomainSocketBootstrapClient(unique_fd bootstrapFd) int zero = 0; iovec iov{&zero, sizeof(zero)}; - std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; + std::vector<std::variant<unique_fd, borrowed_fd>> fds; fds.push_back(std::move(serverFd)); status_t status = mBootstrapTransport->interruptableWriteFully(mShutdownTrigger.get(), &iov, @@ -186,8 +187,7 @@ status_t RpcSession::setupInetClient(const char* addr, unsigned int port) { return NAME_NOT_FOUND; } -status_t RpcSession::setupPreconnectedClient(base::unique_fd fd, - std::function<unique_fd()>&& request) { +status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) { return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) -> status_t { if (!fd.ok()) { fd = request(); diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 008e5d21f0..fe6e1a3318 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -39,6 +39,8 @@ namespace android { using namespace android::binder::impl; +using android::binder::borrowed_fd; +using android::binder::unique_fd; #if RPC_FLAKE_PRONE void rpcMaybeWaitToFlake() { @@ -355,11 +357,10 @@ RpcState::CommandData::CommandData(size_t size) : mSize(size) { mData.reset(new (std::nothrow) uint8_t[size]); } -status_t RpcState::rpcSend( - const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, - const char* what, iovec* iovs, int niovs, - const std::optional<SmallFunction<status_t()>>& altPoll, - const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) { +status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection, + const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs, + const std::optional<SmallFunction<status_t()>>& altPoll, + const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) { for (int i = 0; i < niovs; i++) { LOG_RPC_DETAIL("Sending %s (part %d of %d) on RpcTransport %p: %s", what, i + 1, niovs, connection->rpcTransport.get(), @@ -380,10 +381,9 @@ status_t RpcState::rpcSend( return OK; } -status_t RpcState::rpcRec( - const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, - const char* what, iovec* iovs, int niovs, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) { +status_t RpcState::rpcRec(const sp<RpcSession::RpcConnection>& connection, + const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs, + std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) { if (status_t status = connection->rpcTransport->interruptableReadFully(session->mShutdownTrigger.get(), iovs, niovs, std::nullopt, @@ -649,7 +649,7 @@ static void cleanup_reply_data(const uint8_t* data, size_t dataSize, const binde status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, Parcel* reply) { - std::vector<std::variant<base::unique_fd, base::borrowed_fd>> ancillaryFds; + std::vector<std::variant<unique_fd, borrowed_fd>> ancillaryFds; RpcWireHeader command; while (true) { iovec iov{&command, sizeof(command)}; @@ -767,7 +767,7 @@ status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& con const sp<RpcSession>& session, CommandType type) { LOG_RPC_DETAIL("getAndExecuteCommand on RpcTransport %p", connection->rpcTransport.get()); - std::vector<std::variant<base::unique_fd, base::borrowed_fd>> ancillaryFds; + std::vector<std::variant<unique_fd, borrowed_fd>> ancillaryFds; RpcWireHeader command; iovec iov{&command, sizeof(command)}; if (status_t status = @@ -796,7 +796,7 @@ status_t RpcState::drainCommands(const sp<RpcSession::RpcConnection>& connection status_t RpcState::processCommand( const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, const RpcWireHeader& command, CommandType type, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds) { + std::vector<std::variant<unique_fd, borrowed_fd>>&& ancillaryFds) { #ifdef BINDER_WITH_KERNEL_IPC IPCThreadState* kernelBinderState = IPCThreadState::selfOrNull(); IPCThreadState::SpGuard spGuard{ @@ -836,7 +836,7 @@ status_t RpcState::processCommand( status_t RpcState::processTransact( const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, const RpcWireHeader& command, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds) { + std::vector<std::variant<unique_fd, borrowed_fd>>&& ancillaryFds) { LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_TRANSACT, "command: %d", command.command); CommandData transactionData(command.bodySize); @@ -863,7 +863,7 @@ static void do_nothing_to_transact_data(const uint8_t* data, size_t dataSize, status_t RpcState::processTransactInternal( const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, CommandData transactionData, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds) { + std::vector<std::variant<unique_fd, borrowed_fd>>&& ancillaryFds) { // for 'recursive' calls to this, we have already read and processed the // binder from the transaction data and taken reference counts into account, // so it is cached here. diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h index 2a954e632b..8b84602fee 100644 --- a/libs/binder/RpcState.h +++ b/libs/binder/RpcState.h @@ -15,12 +15,12 @@ */ #pragma once -#include <android-base/unique_fd.h> #include <binder/Functional.h> #include <binder/IBinder.h> #include <binder/Parcel.h> #include <binder/RpcSession.h> #include <binder/RpcThreads.h> +#include <binder/unique_fd.h> #include <map> #include <optional> @@ -192,27 +192,28 @@ private: const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs, const std::optional<binder::impl::SmallFunction<status_t()>>& altPoll, - const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds = + const std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>>* ancillaryFds = nullptr); - [[nodiscard]] status_t rpcRec( - const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, - const char* what, iovec* iovs, int niovs, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds = nullptr); + [[nodiscard]] status_t rpcRec(const sp<RpcSession::RpcConnection>& connection, + const sp<RpcSession>& session, const char* what, iovec* iovs, + int niovs, + std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>>* + ancillaryFds = nullptr); [[nodiscard]] status_t waitForReply(const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, Parcel* reply); [[nodiscard]] status_t processCommand( const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, const RpcWireHeader& command, CommandType type, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds); + std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>>&& ancillaryFds); [[nodiscard]] status_t processTransact( const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, const RpcWireHeader& command, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds); + std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>>&& ancillaryFds); [[nodiscard]] status_t processTransactInternal( const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, CommandData transactionData, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds); + std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>>&& ancillaryFds); [[nodiscard]] status_t processDecStrong(const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session, const RpcWireHeader& command); @@ -254,7 +255,7 @@ private: struct AsyncTodo { sp<IBinder> ref; CommandData data; - std::vector<std::variant<base::unique_fd, base::borrowed_fd>> ancillaryFds; + std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>> ancillaryFds; uint64_t asyncNumber = 0; bool operator<(const AsyncTodo& o) const { diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp index ffa315191d..aa3a6e506d 100644 --- a/libs/binder/RpcTransportRaw.cpp +++ b/libs/binder/RpcTransportRaw.cpp @@ -19,6 +19,7 @@ #include <poll.h> #include <stddef.h> +#include <sys/socket.h> #include <binder/RpcTransportRaw.h> @@ -30,6 +31,8 @@ namespace android { using namespace android::binder::impl; +using android::binder::borrowed_fd; +using android::binder::unique_fd; // RpcTransport with TLS disabled. class RpcTransportRaw : public RpcTransport { @@ -57,8 +60,7 @@ public: status_t interruptableWriteFully( FdTrigger* fdTrigger, iovec* iovs, int niovs, const std::optional<SmallFunction<status_t()>>& altPoll, - const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) - override { + const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override { bool sentFds = false; auto send = [&](iovec* iovs, int niovs) -> ssize_t { ssize_t ret = binder::os::sendMessageOnSocket(mSocket, iovs, niovs, @@ -73,7 +75,7 @@ public: status_t interruptableReadFully( FdTrigger* fdTrigger, iovec* iovs, int niovs, const std::optional<SmallFunction<status_t()>>& altPoll, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override { + std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override { auto recv = [&](iovec* iovs, int niovs) -> ssize_t { return binder::os::receiveMessageFromSocket(mSocket, iovs, niovs, ancillaryFds); }; diff --git a/libs/binder/RpcTransportTipcAndroid.cpp b/libs/binder/RpcTransportTipcAndroid.cpp index 188ba3b0cb..3819fb6472 100644 --- a/libs/binder/RpcTransportTipcAndroid.cpp +++ b/libs/binder/RpcTransportTipcAndroid.cpp @@ -27,6 +27,8 @@ #include "RpcTransportUtils.h" using namespace android::binder::impl; +using android::binder::borrowed_fd; +using android::binder::unique_fd; namespace android { @@ -75,8 +77,7 @@ public: status_t interruptableWriteFully( FdTrigger* fdTrigger, iovec* iovs, int niovs, const std::optional<SmallFunction<status_t()>>& altPoll, - const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) - override { + const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override { auto writeFn = [&](iovec* iovs, size_t niovs) -> ssize_t { // TODO: send ancillaryFds. For now, we just abort if anyone tries // to send any. @@ -93,8 +94,7 @@ public: status_t interruptableReadFully( FdTrigger* fdTrigger, iovec* iovs, int niovs, const std::optional<SmallFunction<status_t()>>& altPoll, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/) - override { + std::vector<std::variant<unique_fd, borrowed_fd>>* /*ancillaryFds*/) override { auto readFn = [&](iovec* iovs, size_t niovs) -> ssize_t { // Fill the read buffer at most once per readFn call, then try to // return as much of it as possible. If the input iovecs are spread diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp index fef4be4545..579694c321 100644 --- a/libs/binder/RpcTransportTls.cpp +++ b/libs/binder/RpcTransportTls.cpp @@ -18,6 +18,7 @@ #include <log/log.h> #include <poll.h> +#include <sys/socket.h> #include <openssl/bn.h> #include <openssl/ssl.h> @@ -42,6 +43,8 @@ namespace android { using namespace android::binder::impl; +using android::binder::borrowed_fd; +using android::binder::unique_fd; namespace { @@ -56,7 +59,7 @@ int socketFree(BIO* bio) { return 1; } int socketRead(BIO* bio, char* buf, int size) { - android::base::borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio)))); + borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio)))); int ret = TEMP_FAILURE_RETRY(::recv(fd.get(), buf, size, MSG_NOSIGNAL)); BIO_clear_retry_flags(bio); if (errno == EAGAIN || errno == EWOULDBLOCK) { @@ -66,7 +69,7 @@ int socketRead(BIO* bio, char* buf, int size) { } int socketWrite(BIO* bio, const char* buf, int size) { - android::base::borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio)))); + borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio)))); int ret = TEMP_FAILURE_RETRY(::send(fd.get(), buf, size, MSG_NOSIGNAL)); BIO_clear_retry_flags(bio); if (errno == EAGAIN || errno == EWOULDBLOCK) { @@ -76,13 +79,13 @@ int socketWrite(BIO* bio, const char* buf, int size) { } long socketCtrl(BIO* bio, int cmd, long num, void*) { // NOLINT - android::base::borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio)))); + borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio)))); if (cmd == BIO_CTRL_FLUSH) return 1; LOG_ALWAYS_FATAL("sockCtrl(fd=%d, %d, %ld)", fd.get(), cmd, num); return 0; } -bssl::UniquePtr<BIO> newSocketBio(android::base::borrowed_fd fd) { +bssl::UniquePtr<BIO> newSocketBio(borrowed_fd fd) { static const BIO_METHOD* gMethods = ([] { auto methods = BIO_meth_new(BIO_get_new_index(), "socket_no_signal"); LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_write(methods, socketWrite), "BIO_meth_set_write"); @@ -289,12 +292,11 @@ public: status_t interruptableWriteFully( FdTrigger* fdTrigger, iovec* iovs, int niovs, const std::optional<SmallFunction<status_t()>>& altPoll, - const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) - override; + const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override; status_t interruptableReadFully( FdTrigger* fdTrigger, iovec* iovs, int niovs, const std::optional<SmallFunction<status_t()>>& altPoll, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override; + std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override; bool isWaiting() override { return mSocket.isInPollingState(); }; @@ -325,7 +327,7 @@ status_t RpcTransportTls::pollRead(void) { status_t RpcTransportTls::interruptableWriteFully( FdTrigger* fdTrigger, iovec* iovs, int niovs, const std::optional<SmallFunction<status_t()>>& altPoll, - const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) { + const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) { (void)ancillaryFds; MAYBE_WAIT_IN_FLAKE_MODE; @@ -371,7 +373,7 @@ status_t RpcTransportTls::interruptableWriteFully( status_t RpcTransportTls::interruptableReadFully( FdTrigger* fdTrigger, iovec* iovs, int niovs, const std::optional<SmallFunction<status_t()>>& altPoll, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) { + std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) { (void)ancillaryFds; MAYBE_WAIT_IN_FLAKE_MODE; diff --git a/libs/binder/RpcTransportUtils.h b/libs/binder/RpcTransportUtils.h index a0e502e92a..fcf6675588 100644 --- a/libs/binder/RpcTransportUtils.h +++ b/libs/binder/RpcTransportUtils.h @@ -15,7 +15,7 @@ */ #pragma once -#include <android-base/unique_fd.h> +#include <binder/unique_fd.h> #include <poll.h> #include "FdTrigger.h" diff --git a/libs/binder/RpcTrusty.cpp b/libs/binder/RpcTrusty.cpp index 2f2fe7d276..a445196ca9 100644 --- a/libs/binder/RpcTrusty.cpp +++ b/libs/binder/RpcTrusty.cpp @@ -16,14 +16,14 @@ #define LOG_TAG "RpcTrusty" -#include <android-base/unique_fd.h> #include <binder/RpcSession.h> #include <binder/RpcTransportTipcAndroid.h> +#include <binder/unique_fd.h> #include <trusty/tipc.h> namespace android { -using android::base::unique_fd; +using android::binder::unique_fd; sp<RpcSession> RpcTrustyConnectWithSessionInitializer( const char* device, const char* port, diff --git a/libs/binder/UtilsHost.cpp b/libs/binder/UtilsHost.cpp index 3db038f03f..ae1a6c44d7 100644 --- a/libs/binder/UtilsHost.cpp +++ b/libs/binder/UtilsHost.cpp @@ -25,10 +25,13 @@ #include <log/log.h> +#include "FdUtils.h" #include "Utils.h" namespace android { +using android::binder::unique_fd; + CommandResult::~CommandResult() { if (!pid.has_value()) return; if (*pid == 0) { @@ -83,13 +86,13 @@ std::optional<CommandResult> execute(std::vector<std::string> argStringVec, argv.push_back(nullptr); CommandResult ret; - android::base::unique_fd outWrite; - if (!android::base::Pipe(&ret.outPipe, &outWrite)) { + unique_fd outWrite; + if (!binder::Pipe(&ret.outPipe, &outWrite)) { PLOGE("pipe() for outPipe"); return {}; } - android::base::unique_fd errWrite; - if (!android::base::Pipe(&ret.errPipe, &errWrite)) { + unique_fd errWrite; + if (!binder::Pipe(&ret.errPipe, &errWrite)) { PLOGE("pipe() for errPipe"); return {}; } @@ -120,7 +123,7 @@ std::optional<CommandResult> execute(std::vector<std::string> argStringVec, errWrite.reset(); ret.pid = pid; - auto handlePoll = [](android::base::unique_fd* fd, const pollfd* pfd, std::string* s) { + auto handlePoll = [](unique_fd* fd, const pollfd* pfd, std::string* s) { if (!fd->ok()) return true; if (pfd->revents & POLLIN) { char buf[1024]; diff --git a/libs/binder/UtilsHost.h b/libs/binder/UtilsHost.h index 5de0980d8e..b582f17c1a 100644 --- a/libs/binder/UtilsHost.h +++ b/libs/binder/UtilsHost.h @@ -23,7 +23,7 @@ #include <vector> #include <android-base/macros.h> -#include <android-base/unique_fd.h> +#include <binder/unique_fd.h> #include <utils/Errors.h> /** @@ -46,8 +46,8 @@ struct CommandResult { std::string stdoutStr; std::string stderrStr; - android::base::unique_fd outPipe; - android::base::unique_fd errPipe; + binder::unique_fd outPipe; + binder::unique_fd errPipe; CommandResult() = default; CommandResult(CommandResult&& other) noexcept { (*this) = std::move(other); } diff --git a/libs/binder/file.cpp b/libs/binder/file.cpp new file mode 100644 index 0000000000..bac667e4e5 --- /dev/null +++ b/libs/binder/file.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "file.h" + +#ifdef BINDER_NO_LIBBASE + +#include <stdint.h> + +// clang-format off + +namespace android::binder { + +bool ReadFully(borrowed_fd fd, void* data, size_t byte_count) { + uint8_t* p = reinterpret_cast<uint8_t*>(data); + size_t remaining = byte_count; + while (remaining > 0) { + ssize_t n = TEMP_FAILURE_RETRY(read(fd.get(), p, remaining)); + if (n == 0) { // EOF + errno = ENODATA; + return false; + } + if (n == -1) return false; + p += n; + remaining -= n; + } + return true; +} + +bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count) { + const uint8_t* p = reinterpret_cast<const uint8_t*>(data); + size_t remaining = byte_count; + while (remaining > 0) { + ssize_t n = TEMP_FAILURE_RETRY(write(fd.get(), p, remaining)); + if (n == -1) return false; + p += n; + remaining -= n; + } + return true; +} + +} // namespace android::binder + +#endif // BINDER_NO_LIBBASE diff --git a/libs/binder/file.h b/libs/binder/file.h new file mode 100644 index 0000000000..bcbfa31836 --- /dev/null +++ b/libs/binder/file.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifndef BINDER_NO_LIBBASE + +#include <android-base/file.h> + +namespace android::binder { +using android::base::ReadFully; +using android::base::WriteFully; +} // namespace android::binder + +#else // BINDER_NO_LIBBASE + +#include <binder/unique_fd.h> + +#include <string_view> + +namespace android::binder { + +bool ReadFully(borrowed_fd fd, void* data, size_t byte_count); +bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count); + +} // namespace android::binder + +#endif // BINDER_NO_LIBBASE diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index 744da0f825..7a65ff4e45 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -102,7 +102,7 @@ public: // to another process. void setParceled(); - [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd clientFd, + [[nodiscard]] status_t setRpcClientDebug(binder::unique_fd clientFd, const sp<IBinder>& keepAliveBinder); protected: diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index d78ea0d6b1..89a4d273ad 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -16,9 +16,9 @@ #pragma once -#include <android-base/unique_fd.h> #include <binder/IBinder.h> #include <binder/RpcThreads.h> +#include <binder/unique_fd.h> #include <map> #include <optional> @@ -94,7 +94,7 @@ public: // Start recording transactions to the unique_fd. // See RecordedTransaction.h for more details. - status_t startRecordingBinder(const android::base::unique_fd& fd); + status_t startRecordingBinder(const binder::unique_fd& fd); // Stop the current recording. status_t stopRecordingBinder(); diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h index e75d548bd8..dad9a1782d 100644 --- a/libs/binder/include/binder/IBinder.h +++ b/libs/binder/include/binder/IBinder.h @@ -16,7 +16,7 @@ #pragma once -#include <android-base/unique_fd.h> +#include <binder/unique_fd.h> #include <utils/Errors.h> #include <utils/RefBase.h> #include <utils/String16.h> @@ -175,7 +175,7 @@ public: * * On death of @a keepAliveBinder, the RpcServer shuts down. */ - [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd socketFd, + [[nodiscard]] status_t setRpcClientDebug(binder::unique_fd socketFd, const sp<IBinder>& keepAliveBinder); // NOLINTNEXTLINE(google-default-arguments) diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index dc572ac953..ac845bc003 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -119,8 +119,8 @@ public: "The preferred way to add interfaces is to define " \ "an .aidl file to auto-generate the interface. If " \ "an interface must be manually written, add its " \ - "name to the whitelist."); \ - DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ + "name to the allowlist."); \ + DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) #else @@ -305,10 +305,10 @@ constexpr bool equals(const char* a, const char* b) { return equals(a + 1, b + 1); } -constexpr bool inList(const char* a, const char* const* whitelist) { - if (*whitelist == nullptr) return false; - if (equals(a, *whitelist)) return true; - return inList(a, whitelist + 1); +constexpr bool inList(const char* a, const char* const* allowlist) { + if (*allowlist == nullptr) return false; + if (equals(a, *allowlist)) return true; + return inList(a, allowlist + 1); } constexpr bool allowedManualInterface(const char* name) { diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 6961abc64b..09da6e3c4a 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -25,7 +25,7 @@ #include <variant> #include <vector> -#include <android-base/unique_fd.h> +#include <binder/unique_fd.h> #ifndef BINDER_DISABLE_NATIVE_HANDLE #include <cutils/native_handle.h> #endif @@ -354,17 +354,16 @@ public: // Place a file descriptor into the parcel. This will not affect the // semantics of the smart file descriptor. A new descriptor will be // created, and will be closed when the parcel is destroyed. - status_t writeUniqueFileDescriptor( - const base::unique_fd& fd); + status_t writeUniqueFileDescriptor(const binder::unique_fd& fd); // Place a vector of file desciptors into the parcel. Each descriptor is // dup'd as in writeDupFileDescriptor - status_t writeUniqueFileDescriptorVector( - const std::optional<std::vector<base::unique_fd>>& val); - status_t writeUniqueFileDescriptorVector( - const std::unique_ptr<std::vector<base::unique_fd>>& val) __attribute__((deprecated("use std::optional version instead"))); - status_t writeUniqueFileDescriptorVector( - const std::vector<base::unique_fd>& val); + status_t writeUniqueFileDescriptorVector( + const std::optional<std::vector<binder::unique_fd>>& val); + status_t writeUniqueFileDescriptorVector( + const std::unique_ptr<std::vector<binder::unique_fd>>& val) + __attribute__((deprecated("use std::optional version instead"))); + status_t writeUniqueFileDescriptorVector(const std::vector<binder::unique_fd>& val); // Writes a blob to the parcel. // If the blob is small, then it is stored in-place, otherwise it is @@ -579,20 +578,17 @@ public: int readParcelFileDescriptor() const; // Retrieve a smart file descriptor from the parcel. - status_t readUniqueFileDescriptor( - base::unique_fd* val) const; + status_t readUniqueFileDescriptor(binder::unique_fd* val) const; // Retrieve a Java "parcel file descriptor" from the parcel. - status_t readUniqueParcelFileDescriptor(base::unique_fd* val) const; - + status_t readUniqueParcelFileDescriptor(binder::unique_fd* val) const; // Retrieve a vector of smart file descriptors from the parcel. - status_t readUniqueFileDescriptorVector( - std::optional<std::vector<base::unique_fd>>* val) const; - status_t readUniqueFileDescriptorVector( - std::unique_ptr<std::vector<base::unique_fd>>* val) const __attribute__((deprecated("use std::optional version instead"))); - status_t readUniqueFileDescriptorVector( - std::vector<base::unique_fd>* val) const; + status_t readUniqueFileDescriptorVector( + std::optional<std::vector<binder::unique_fd>>* val) const; + status_t readUniqueFileDescriptorVector(std::unique_ptr<std::vector<binder::unique_fd>>* val) + const __attribute__((deprecated("use std::optional version instead"))); + status_t readUniqueFileDescriptorVector(std::vector<binder::unique_fd>* val) const; // Reads a blob from the parcel. // The caller should call release() on the blob after reading its contents. @@ -629,7 +625,7 @@ private: status_t rpcSetDataReference( const sp<RpcSession>& session, const uint8_t* data, size_t dataSize, const uint32_t* objectTable, size_t objectTableSize, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds, + std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>>&& ancillaryFds, release_func relFunc); status_t finishWrite(size_t len); @@ -706,7 +702,7 @@ private: // 5) Nullable objects contained in std::optional, std::unique_ptr, or std::shared_ptr. // // And active objects from the Android ecosystem such as: - // 6) File descriptors, base::unique_fd (kernel object handles) + // 6) File descriptors, unique_fd (kernel object handles) // 7) Binder objects, sp<IBinder> (active Android RPC handles) // // Objects from (1) through (5) serialize into the mData buffer. @@ -957,9 +953,7 @@ private: return writeUtf8AsUtf16(t); } - status_t writeData(const base::unique_fd& t) { - return writeUniqueFileDescriptor(t); - } + status_t writeData(const binder::unique_fd& t) { return writeUniqueFileDescriptor(t); } status_t writeData(const Parcelable& t) { // std::is_base_of_v<Parcelable, T> // implemented here. writeParcelable() calls this. @@ -1106,9 +1100,7 @@ private: return readUtf8FromUtf16(t); } - status_t readData(base::unique_fd* t) const { - return readUniqueFileDescriptor(t); - } + status_t readData(binder::unique_fd* t) const { return readUniqueFileDescriptor(t); } status_t readData(Parcelable* t) const { // std::is_base_of_v<Parcelable, T> // implemented here. readParcelable() calls this. @@ -1328,7 +1320,7 @@ private: // same order as `mObjectPositions`. // // Boxed to save space. Lazy allocated. - std::unique_ptr<std::vector<std::variant<base::unique_fd, base::borrowed_fd>>> mFds; + std::unique_ptr<std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>>> mFds; }; std::variant<KernelFields, RpcFields> mVariantFields; diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h index 08d8e43106..c4ef3547e9 100644 --- a/libs/binder/include/binder/ParcelFileDescriptor.h +++ b/libs/binder/include/binder/ParcelFileDescriptor.h @@ -16,9 +16,9 @@ #pragma once -#include <android-base/unique_fd.h> #include <binder/Parcel.h> #include <binder/Parcelable.h> +#include <binder/unique_fd.h> namespace android { namespace os { @@ -29,14 +29,14 @@ namespace os { class ParcelFileDescriptor : public android::Parcelable { public: ParcelFileDescriptor(); - explicit ParcelFileDescriptor(android::base::unique_fd fd); + explicit ParcelFileDescriptor(binder::unique_fd fd); ParcelFileDescriptor(ParcelFileDescriptor&& other) noexcept : mFd(std::move(other.mFd)) { } ParcelFileDescriptor& operator=(ParcelFileDescriptor&& other) noexcept = default; ~ParcelFileDescriptor() override; int get() const { return mFd.get(); } - android::base::unique_fd release() { return std::move(mFd); } - void reset(android::base::unique_fd fd = android::base::unique_fd()) { mFd = std::move(fd); } + binder::unique_fd release() { return std::move(mFd); } + void reset(binder::unique_fd fd = binder::unique_fd()) { mFd = std::move(fd); } // android::Parcelable override: android::status_t writeToParcel(android::Parcel* parcel) const override; @@ -62,7 +62,7 @@ public: return mFd.get() >= rhs.mFd.get(); } private: - android::base::unique_fd mFd; + binder::unique_fd mFd; }; } // namespace os diff --git a/libs/binder/include/binder/RecordedTransaction.h b/libs/binder/include/binder/RecordedTransaction.h index eb765fe8ec..505c1992b9 100644 --- a/libs/binder/include/binder/RecordedTransaction.h +++ b/libs/binder/include/binder/RecordedTransaction.h @@ -16,8 +16,8 @@ #pragma once -#include <android-base/unique_fd.h> #include <binder/Parcel.h> +#include <binder/unique_fd.h> #include <mutex> namespace android { @@ -31,7 +31,8 @@ namespace binder::debug { class RecordedTransaction { public: // Filled with the first transaction from fd. - static std::optional<RecordedTransaction> fromFile(const android::base::unique_fd& fd); + + static std::optional<RecordedTransaction> fromFile(const binder::unique_fd& fd); // Filled with the arguments. static std::optional<RecordedTransaction> fromDetails(const String16& interfaceName, uint32_t code, uint32_t flags, @@ -39,7 +40,7 @@ public: const Parcel& reply, status_t err); RecordedTransaction(RecordedTransaction&& t) noexcept; - [[nodiscard]] status_t dumpToFile(const android::base::unique_fd& fd) const; + [[nodiscard]] status_t dumpToFile(const binder::unique_fd& fd) const; const std::string& getInterfaceName() const; uint32_t getCode() const; @@ -53,8 +54,8 @@ public: private: RecordedTransaction() = default; - android::status_t writeChunk(const android::base::borrowed_fd, uint32_t chunkType, - size_t byteCount, const uint8_t* data) const; + android::status_t writeChunk(const binder::borrowed_fd, uint32_t chunkType, size_t byteCount, + const uint8_t* data) const; #pragma clang diagnostic push #pragma clang diagnostic error "-Wpadded" diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index 2153f162e5..a07880dd65 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -15,11 +15,11 @@ */ #pragma once -#include <android-base/unique_fd.h> #include <binder/IBinder.h> #include <binder/RpcSession.h> #include <binder/RpcThreads.h> #include <binder/RpcTransport.h> +#include <binder/unique_fd.h> #include <utils/Errors.h> #include <utils/RefBase.h> @@ -59,7 +59,7 @@ public: * to RpcSession::setupUnixDomainSocketBootstrapClient. Multiple client * session can be created from the client end of the pair. */ - [[nodiscard]] status_t setupUnixDomainSocketBootstrapServer(base::unique_fd serverFd); + [[nodiscard]] status_t setupUnixDomainSocketBootstrapServer(binder::unique_fd serverFd); /** * This represents a session for responses, e.g.: @@ -79,7 +79,7 @@ public: * This method is used in the libbinder_rpc_unstable API * RunInitUnixDomainRpcServer(). */ - [[nodiscard]] status_t setupRawSocketServer(base::unique_fd socket_fd); + [[nodiscard]] status_t setupRawSocketServer(binder::unique_fd socket_fd); /** * Creates an RPC server binding to the given CID at the given port. @@ -111,13 +111,13 @@ public: /** * If hasServer(), return the server FD. Otherwise return invalid FD. */ - [[nodiscard]] base::unique_fd releaseServer(); + [[nodiscard]] binder::unique_fd releaseServer(); /** * Set up server using an external FD previously set up by releaseServer(). * Return false if there's already a server. */ - [[nodiscard]] status_t setupExternalServer(base::unique_fd serverFd); + [[nodiscard]] status_t setupExternalServer(binder::unique_fd serverFd); /** * This must be called before adding a client session. This corresponds @@ -193,7 +193,7 @@ public: * * The only argument is a successfully created file descriptor, not bound to an address yet. */ - void setServerSocketModifier(std::function<void(base::borrowed_fd)>&& modifier); + void setServerSocketModifier(std::function<void(binder::borrowed_fd)>&& modifier); /** * See RpcTransportCtx::getCertificate @@ -249,7 +249,7 @@ private: void onSessionIncomingThreadEnded() override; status_t setupExternalServer( - base::unique_fd serverFd, + binder::unique_fd serverFd, std::function<status_t(const RpcServer&, RpcTransportFd*)>&& acceptFn); static constexpr size_t kRpcAddressSize = 128; @@ -279,7 +279,7 @@ private: wp<IBinder> mRootObjectWeak; std::function<sp<IBinder>(wp<RpcSession>, const void*, size_t)> mRootObjectFactory; std::function<bool(const void*, size_t)> mConnectionFilter; - std::function<void(base::borrowed_fd)> mServerSocketModifier; + std::function<void(binder::borrowed_fd)> mServerSocketModifier; std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions; std::unique_ptr<FdTrigger> mShutdownTrigger; RpcConditionVariable mShutdownCv; diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h index e3805ac888..11fbde9ace 100644 --- a/libs/binder/include/binder/RpcSession.h +++ b/libs/binder/include/binder/RpcSession.h @@ -15,10 +15,10 @@ */ #pragma once -#include <android-base/unique_fd.h> #include <binder/IBinder.h> #include <binder/RpcThreads.h> #include <binder/RpcTransport.h> +#include <binder/unique_fd.h> #include <utils/Errors.h> #include <utils/RefBase.h> @@ -123,7 +123,7 @@ public: /** * Connects to an RPC server over a nameless Unix domain socket pair. */ - [[nodiscard]] status_t setupUnixDomainSocketBootstrapClient(base::unique_fd bootstrap); + [[nodiscard]] status_t setupUnixDomainSocketBootstrapClient(binder::unique_fd bootstrap); /** * Connects to an RPC server at the CVD & port. @@ -145,8 +145,8 @@ public: * * For future compatibility, 'request' should not reference any stack data. */ - [[nodiscard]] status_t setupPreconnectedClient(base::unique_fd fd, - std::function<base::unique_fd()>&& request); + [[nodiscard]] status_t setupPreconnectedClient(binder::unique_fd fd, + std::function<binder::unique_fd()>&& request); /** * For debugging! diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h index 115a1732d7..a50cdc1db0 100644 --- a/libs/binder/include/binder/RpcTransport.h +++ b/libs/binder/include/binder/RpcTransport.h @@ -25,12 +25,12 @@ #include <variant> #include <vector> -#include <android-base/unique_fd.h> #include <utils/Errors.h> #include <binder/Functional.h> #include <binder/RpcCertificateFormat.h> #include <binder/RpcThreads.h> +#include <binder/unique_fd.h> #include <sys/uio.h> @@ -87,11 +87,12 @@ public: [[nodiscard]] virtual status_t interruptableWriteFully( FdTrigger* fdTrigger, iovec* iovs, int niovs, const std::optional<binder::impl::SmallFunction<status_t()>>& altPoll, - const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) = 0; + const std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>>* + ancillaryFds) = 0; [[nodiscard]] virtual status_t interruptableReadFully( FdTrigger* fdTrigger, iovec* iovs, int niovs, const std::optional<binder::impl::SmallFunction<status_t()>>& altPoll, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) = 0; + std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>>* ancillaryFds) = 0; /** * Check whether any threads are blocked while polling the transport @@ -177,10 +178,10 @@ private: void setPollingState(bool state) const { isPolling = state; } public: - base::unique_fd fd; + binder::unique_fd fd; RpcTransportFd() = default; - explicit RpcTransportFd(base::unique_fd &&descriptor) + explicit RpcTransportFd(binder::unique_fd&& descriptor) : isPolling(false), fd(std::move(descriptor)) {} RpcTransportFd(RpcTransportFd &&transportFd) noexcept @@ -192,7 +193,7 @@ public: return *this; } - RpcTransportFd &operator=(base::unique_fd &&descriptor) noexcept { + RpcTransportFd& operator=(binder::unique_fd&& descriptor) noexcept { fd = std::move(descriptor); isPolling = false; return *this; diff --git a/libs/binder/include/binder/unique_fd.h b/libs/binder/include/binder/unique_fd.h new file mode 100644 index 0000000000..439b8a2e4e --- /dev/null +++ b/libs/binder/include/binder/unique_fd.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifndef BINDER_NO_LIBBASE + +#include <android-base/unique_fd.h> + +namespace android::binder { +using android::base::borrowed_fd; +using android::base::unique_fd; +} // namespace android::binder + +#else // BINDER_NO_LIBBASE + +#include <errno.h> +#include <fcntl.h> // not needed for unique_fd, but a lot of users depend on open(3) +#include <unistd.h> + +namespace android::binder { + +// Container for a file descriptor that automatically closes the descriptor as +// it goes out of scope. +// +// unique_fd ufd(open("/some/path", "r")); +// if (!ufd.ok()) return error; +// +// // Do something useful with ufd.get(), possibly including early 'return'. +// +// return 0; // Descriptor is closed for you. +// +class unique_fd final { +public: + unique_fd() {} + + explicit unique_fd(int fd) { reset(fd); } + ~unique_fd() { reset(); } + + unique_fd(const unique_fd&) = delete; + void operator=(const unique_fd&) = delete; + unique_fd(unique_fd&& other) noexcept { reset(other.release()); } + unique_fd& operator=(unique_fd&& s) noexcept { + int fd = s.fd_; + s.fd_ = -1; + reset(fd); + return *this; + } + + [[clang::reinitializes]] void reset(int new_value = -1) { + int previous_errno = errno; + + if (fd_ != -1) { + ::close(fd_); + } + + fd_ = new_value; + errno = previous_errno; + } + + int get() const { return fd_; } + + bool ok() const { return get() >= 0; } + + [[nodiscard]] int release() { + int ret = fd_; + fd_ = -1; + return ret; + } + +private: + int fd_ = -1; +}; + +// A wrapper type that can be implicitly constructed from either int or +// unique_fd. This supports cases where you don't actually own the file +// descriptor, and can't take ownership, but are temporarily acting as if +// you're the owner. +// +// One example would be a function that needs to also allow +// STDERR_FILENO, not just a newly-opened fd. Another example would be JNI code +// that's using a file descriptor that's actually owned by a +// ParcelFileDescriptor or whatever on the Java side, but where the JNI code +// would like to enforce this weaker sense of "temporary ownership". +// +// If you think of unique_fd as being like std::string in that represents +// ownership, borrowed_fd is like std::string_view (and int is like const +// char*). +struct borrowed_fd { + /* implicit */ borrowed_fd(int fd) : fd_(fd) {} // NOLINT + /* implicit */ borrowed_fd(const unique_fd& ufd) : fd_(ufd.get()) {} // NOLINT + + int get() const { return fd_; } + +private: + int fd_ = -1; +}; + +} // namespace android::binder + +#endif // BINDER_NO_LIBBASE diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp index 118409eeff..ddd82e8ef7 100644 --- a/libs/binder/libbinder_rpc_unstable.cpp +++ b/libs/binder/libbinder_rpc_unstable.cpp @@ -16,10 +16,10 @@ #include <binder_rpc_unstable.hpp> -#include <android-base/unique_fd.h> #include <android/binder_libbinder.h> #include <binder/RpcServer.h> #include <binder/RpcSession.h> +#include <binder/unique_fd.h> #include <cutils/sockets.h> #include <linux/vm_sockets.h> @@ -29,7 +29,7 @@ using android::RpcSession; using android::sp; using android::status_t; using android::statusToString; -using android::base::unique_fd; +using android::binder::unique_fd; // Opaque handle for RpcServer. struct ARpcServer {}; diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index c15bcf968d..88ce5f4d9b 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -14,11 +14,11 @@ * limitations under the License. */ -#include <android-base/unique_fd.h> #include <android/binder_parcel.h> #include <android/binder_parcel_platform.h> #include <binder/Parcel.h> #include <binder/ParcelFileDescriptor.h> +#include <binder/unique_fd.h> #include <inttypes.h> #include <utils/Unicode.h> @@ -32,7 +32,7 @@ using ::android::IBinder; using ::android::Parcel; using ::android::sp; using ::android::status_t; -using ::android::base::unique_fd; +using ::android::binder::unique_fd; using ::android::os::ParcelFileDescriptor; template <typename T> diff --git a/libs/binder/rust/tests/serialization.cpp b/libs/binder/rust/tests/serialization.cpp index 3f59dab3a9..0cdf8c56ab 100644 --- a/libs/binder/rust/tests/serialization.cpp +++ b/libs/binder/rust/tests/serialization.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +#include "serialization.hpp" +#include "../../FdUtils.h" +#include "../../tests/FileUtils.h" + #include <android/binder_ibinder_platform.h> #include <android/binder_libbinder.h> #include <binder/IServiceManager.h> @@ -24,8 +28,6 @@ #include <gtest/gtest.h> #include <utils/Errors.h> #include <utils/String16.h> -#include "android-base/file.h" -#include "serialization.hpp" #include <cmath> #include <cstdint> @@ -34,7 +36,7 @@ using namespace std; using namespace android; -using android::base::unique_fd; +using android::binder::unique_fd; using android::os::ParcelFileDescriptor; // defined in Rust @@ -349,7 +351,7 @@ TEST_F(SerializationTest, SerializeString) { TEST_F(SerializationTest, SerializeFileDescriptor) { unique_fd out_file, in_file; - ASSERT_TRUE(base::Pipe(&out_file, &in_file)); + ASSERT_TRUE(binder::Pipe(&out_file, &in_file)); vector<ParcelFileDescriptor> file_descriptors; file_descriptors.push_back(ParcelFileDescriptor(std::move(out_file))); diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp index f2693dda95..18b178b9b1 100644 --- a/libs/binder/servicedispatcher.cpp +++ b/libs/binder/servicedispatcher.cpp @@ -17,9 +17,9 @@ #include <sysexits.h> #include <unistd.h> +#include <filesystem> #include <iostream> -#include <android-base/file.h> #include <android-base/logging.h> #include <android-base/properties.h> #include <android/debug/BnAdbCallback.h> @@ -30,6 +30,8 @@ #include <binder/ProcessState.h> #include <binder/RpcServer.h> +#include "file.h" + using android::BBinder; using android::defaultServiceManager; using android::OK; @@ -38,7 +40,6 @@ using android::sp; using android::status_t; using android::statusToString; using android::String16; -using android::base::Basename; using android::base::GetBoolProperty; using android::base::InitLogging; using android::base::LogdLogger; @@ -53,8 +54,8 @@ const char* kLocalInetAddress = "127.0.0.1"; using ServiceRetriever = decltype(&android::IServiceManager::checkService); using android::debug::IAdbManager; -int Usage(const char* program) { - auto basename = Basename(program); +int Usage(std::filesystem::path program) { + auto basename = program.filename(); // clang-format off LOG(ERROR) << R"(dispatch calls to RPC service. Usage: @@ -253,7 +254,8 @@ public: mLogdLogger(id, severity, tag, file, line, message); if (severity >= LogSeverity::WARNING) { std::cout << std::flush; - std::cerr << Basename(getprogname()) << ": " << message << std::endl; + auto progname = std::filesystem::path(getprogname()).filename(); + std::cerr << progname << ": " << message << std::endl; } } diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index cd3e7c0fef..ba8fb39438 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -172,6 +172,30 @@ cc_library_static { ], } +cc_library_static { + name: "libbinder_test_utils", + host_supported: true, + vendor_available: true, + target: { + darwin: { + enabled: false, + }, + }, + defaults: [ + "binder_test_defaults", + ], + shared_libs: [ + "libbase", + "liblog", + ], + srcs: [ + "FileUtils.cpp", + ], + visibility: [ + ":__subpackages__", + ], +} + cc_defaults { name: "binderRpcTest_common_defaults", host_supported: true, @@ -185,6 +209,7 @@ cc_defaults { ], static_libs: [ + "libbinder_test_utils", "libbinder_tls_static", "libbinder_tls_test_utils", "binderRpcTestIface-cpp", diff --git a/libs/binder/tests/FileUtils.cpp b/libs/binder/tests/FileUtils.cpp new file mode 100644 index 0000000000..61509fe18e --- /dev/null +++ b/libs/binder/tests/FileUtils.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FileUtils.h" + +#ifdef BINDER_NO_LIBBASE + +#include <sys/stat.h> +#include <filesystem> + +#if defined(__APPLE__) +#include <mach-o/dyld.h> +#endif +#if defined(_WIN32) +#include <direct.h> +#include <windows.h> +#endif + +namespace android::binder { + +bool ReadFdToString(borrowed_fd fd, std::string* content) { + content->clear(); + + // Although original we had small files in mind, this code gets used for + // very large files too, where the std::string growth heuristics might not + // be suitable. https://code.google.com/p/android/issues/detail?id=258500. + struct stat sb; + if (fstat(fd.get(), &sb) != -1 && sb.st_size > 0) { + content->reserve(sb.st_size); + } + + char buf[4096] __attribute__((__uninitialized__)); + ssize_t n; + while ((n = TEMP_FAILURE_RETRY(read(fd.get(), &buf[0], sizeof(buf)))) > 0) { + content->append(buf, n); + } + return (n == 0) ? true : false; +} + +bool WriteStringToFd(std::string_view content, borrowed_fd fd) { + const char* p = content.data(); + size_t left = content.size(); + while (left > 0) { + ssize_t n = TEMP_FAILURE_RETRY(write(fd.get(), p, left)); + if (n == -1) { + return false; + } + p += n; + left -= n; + } + return true; +} + +static std::filesystem::path GetExecutablePath2() { +#if defined(__linux__) + return std::filesystem::read_symlink("/proc/self/exe"); +#elif defined(__APPLE__) + char path[PATH_MAX + 1]; + uint32_t path_len = sizeof(path); + int rc = _NSGetExecutablePath(path, &path_len); + if (rc < 0) { + std::unique_ptr<char> path_buf(new char[path_len]); + _NSGetExecutablePath(path_buf.get(), &path_len); + return path_buf.get(); + } + return path; +#elif defined(_WIN32) + char path[PATH_MAX + 1]; + DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1); + if (result == 0 || result == sizeof(path) - 1) return ""; + path[PATH_MAX - 1] = 0; + return path; +#elif defined(__EMSCRIPTEN__) + abort(); +#else +#error unknown OS +#endif +} + +std::string GetExecutableDirectory() { + return GetExecutablePath2().parent_path(); +} + +} // namespace android::binder + +#endif // BINDER_NO_LIBBASE diff --git a/libs/binder/tests/FileUtils.h b/libs/binder/tests/FileUtils.h new file mode 100644 index 0000000000..2cbe5e7f25 --- /dev/null +++ b/libs/binder/tests/FileUtils.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "../file.h" + +#ifndef BINDER_NO_LIBBASE + +namespace android::binder { +using android::base::GetExecutableDirectory; +using android::base::ReadFdToString; +using android::base::WriteStringToFd; +} // namespace android::binder + +#else // BINDER_NO_LIBBASE + +#include <binder/unique_fd.h> + +#include <string_view> + +#if !defined(_WIN32) && !defined(O_BINARY) +/** Windows needs O_BINARY, but Unix never mangles line endings. */ +#define O_BINARY 0 +#endif + +namespace android::binder { + +bool ReadFdToString(borrowed_fd fd, std::string* content); +bool WriteStringToFd(std::string_view content, borrowed_fd fd); + +std::string GetExecutableDirectory(); + +} // namespace android::binder + +#endif // BINDER_NO_LIBBASE diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index f3969f1a01..cb1a1ee443 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -30,7 +30,6 @@ #include <android-base/properties.h> #include <android-base/result-gmock.h> #include <android-base/strings.h> -#include <android-base/unique_fd.h> #include <binder/Binder.h> #include <binder/BpBinder.h> #include <binder/Functional.h> @@ -39,6 +38,7 @@ #include <binder/IServiceManager.h> #include <binder/RpcServer.h> #include <binder/RpcSession.h> +#include <binder/unique_fd.h> #include <utils/Flattenable.h> #include <linux/sched.h> @@ -57,6 +57,7 @@ using namespace std::string_literals; using namespace std::chrono_literals; using android::base::testing::HasValue; using android::base::testing::Ok; +using android::binder::unique_fd; using testing::ExplainMatchResult; using testing::Matcher; using testing::Not; @@ -847,7 +848,7 @@ TEST_F(BinderLibTest, PassParcelFileDescriptor) { writebuf[i] = i; } - android::base::unique_fd read_end, write_end; + unique_fd read_end, write_end; { int pipefd[2]; ASSERT_EQ(0, pipe2(pipefd, O_NONBLOCK)); @@ -1177,7 +1178,7 @@ TEST_F(BinderLibTest, FileDescriptorRemainsNonBlocking) { Parcel reply; EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_NON_BLOCKING_FD, {} /*data*/, &reply), StatusEq(NO_ERROR)); - base::unique_fd fd; + unique_fd fd; EXPECT_THAT(reply.readUniqueFileDescriptor(&fd), StatusEq(OK)); const int result = fcntl(fd.get(), F_GETFL); @@ -1486,7 +1487,7 @@ public: BinderLibTest::SetUp(); } - std::tuple<android::base::unique_fd, unsigned int> CreateSocket() { + std::tuple<unique_fd, unsigned int> CreateSocket() { auto rpcServer = RpcServer::make(); EXPECT_NE(nullptr, rpcServer); if (rpcServer == nullptr) return {}; @@ -1553,7 +1554,7 @@ public: TEST_P(BinderLibRpcTestP, SetRpcClientDebugNoFd) { auto binder = GetService(); ASSERT_TRUE(binder != nullptr); - EXPECT_THAT(binder->setRpcClientDebug(android::base::unique_fd(), sp<BBinder>::make()), + EXPECT_THAT(binder->setRpcClientDebug(unique_fd(), sp<BBinder>::make()), Debuggable(StatusEq(BAD_VALUE))); } @@ -1823,7 +1824,7 @@ public: int ret; int32_t size; const void *buf; - android::base::unique_fd fd; + unique_fd fd; ret = data.readUniqueParcelFileDescriptor(&fd); if (ret != NO_ERROR) { @@ -1888,7 +1889,7 @@ public: ALOGE("Could not make socket non-blocking: %s", strerror(errno)); return UNKNOWN_ERROR; } - base::unique_fd out(sockets[0]); + unique_fd out(sockets[0]); status_t writeResult = reply->writeUniqueFileDescriptor(out); if (writeResult != NO_ERROR) { ALOGE("Could not write unique_fd"); diff --git a/libs/binder/tests/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp index 0a0dae0f59..34fc43f926 100644 --- a/libs/binder/tests/binderParcelUnitTest.cpp +++ b/libs/binder/tests/binderParcelUnitTest.cpp @@ -29,8 +29,8 @@ using android::sp; using android::status_t; using android::String16; using android::String8; -using android::base::unique_fd; using android::binder::Status; +using android::binder::unique_fd; TEST(Parcel, NonNullTerminatedString8) { String8 kTestString = String8("test-is-good"); diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp index d08a9bb430..73c0a94ce2 100644 --- a/libs/binder/tests/binderRecordReplayTest.cpp +++ b/libs/binder/tests/binderRecordReplayTest.cpp @@ -15,15 +15,14 @@ */ #include <BnBinderRecordReplayTest.h> -#include <android-base/file.h> #include <android-base/logging.h> -#include <android-base/unique_fd.h> #include <binder/Binder.h> #include <binder/BpBinder.h> #include <binder/IBinder.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/RecordedTransaction.h> +#include <binder/unique_fd.h> #include <fuzzbinder/libbinder_driver.h> #include <fuzzer/FuzzedDataProvider.h> @@ -33,11 +32,14 @@ #include <sys/prctl.h> +#include "../file.h" #include "parcelables/SingleDataParcelable.h" using namespace android; using android::generateSeedsFromRecording; +using android::binder::borrowed_fd; using android::binder::Status; +using android::binder::unique_fd; using android::binder::debug::RecordedTransaction; using parcelables::SingleDataParcelable; @@ -91,7 +93,7 @@ public: GENERATE_GETTER_SETTER(SingleDataParcelableArray, std::vector<SingleDataParcelable>); }; -std::vector<uint8_t> retrieveData(base::borrowed_fd fd) { +std::vector<uint8_t> retrieveData(borrowed_fd fd) { struct stat fdStat; EXPECT_TRUE(fstat(fd.get(), &fdStat) != -1); EXPECT_TRUE(fdStat.st_size != 0); @@ -103,8 +105,8 @@ std::vector<uint8_t> retrieveData(base::borrowed_fd fd) { } void replayFuzzService(const sp<BpBinder>& binder, const RecordedTransaction& transaction) { - base::unique_fd seedFd(open("/data/local/tmp/replayFuzzService", - O_RDWR | O_CREAT | O_CLOEXEC | O_TRUNC, 0666)); + unique_fd seedFd(open("/data/local/tmp/replayFuzzService", + O_RDWR | O_CREAT | O_CLOEXEC | O_TRUNC, 0666)); ASSERT_TRUE(seedFd.ok()); // generate corpus from this transaction. @@ -148,8 +150,8 @@ public: Status (IBinderRecordReplayTest::*get)(U*), U changedValue) { auto replayFunctions = {&replayBinder, &replayFuzzService}; for (auto replayFunc : replayFunctions) { - base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec", - O_RDWR | O_CREAT | O_CLOEXEC, 0666)); + unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec", + O_RDWR | O_CREAT | O_CLOEXEC, 0666)); ASSERT_TRUE(fd.ok()); // record a transaction diff --git a/libs/binder/tests/binderRecordedTransactionTest.cpp b/libs/binder/tests/binderRecordedTransactionTest.cpp index 30172cce87..6eb78d037d 100644 --- a/libs/binder/tests/binderRecordedTransactionTest.cpp +++ b/libs/binder/tests/binderRecordedTransactionTest.cpp @@ -20,7 +20,7 @@ using android::Parcel; using android::status_t; -using android::base::unique_fd; +using android::binder::unique_fd; using android::binder::debug::RecordedTransaction; TEST(BinderRecordedTransaction, RoundTripEncoding) { diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 624edba9cd..2769a88342 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -25,6 +25,7 @@ #include <thread> #include <type_traits> +#include <dirent.h> #include <dlfcn.h> #include <poll.h> #include <sys/prctl.h> @@ -41,6 +42,10 @@ using namespace std::chrono_literals; using namespace std::placeholders; +using android::binder::borrowed_fd; +using android::binder::GetExecutableDirectory; +using android::binder::ReadFdToString; +using android::binder::unique_fd; using testing::AssertionFailure; using testing::AssertionResult; using testing::AssertionSuccess; @@ -83,12 +88,11 @@ public: mPid = other.mPid; other.mPid = 0; } - Process(const std::function<void(android::base::borrowed_fd /* writeEnd */, - android::base::borrowed_fd /* readEnd */)>& f) { - android::base::unique_fd childWriteEnd; - android::base::unique_fd childReadEnd; - if (!android::base::Pipe(&mReadEnd, &childWriteEnd, 0)) PLOGF("child write pipe failed"); - if (!android::base::Pipe(&childReadEnd, &mWriteEnd, 0)) PLOGF("child read pipe failed"); + Process(const std::function<void(borrowed_fd /* writeEnd */, borrowed_fd /* readEnd */)>& f) { + unique_fd childWriteEnd; + unique_fd childReadEnd; + if (!binder::Pipe(&mReadEnd, &childWriteEnd, 0)) PLOGF("child write pipe failed"); + if (!binder::Pipe(&childReadEnd, &mWriteEnd, 0)) PLOGF("child read pipe failed"); if (0 == (mPid = fork())) { // racey: assume parent doesn't crash before this is set prctl(PR_SET_PDEATHSIG, SIGHUP); @@ -110,8 +114,8 @@ public: } } } - android::base::borrowed_fd readEnd() { return mReadEnd; } - android::base::borrowed_fd writeEnd() { return mWriteEnd; } + borrowed_fd readEnd() { return mReadEnd; } + borrowed_fd writeEnd() { return mWriteEnd; } void setCustomExitStatusCheck(std::function<void(int wstatus)> f) { mCustomExitStatusCheck = std::move(f); @@ -125,8 +129,8 @@ public: private: std::function<void(int wstatus)> mCustomExitStatusCheck; pid_t mPid = 0; - android::base::unique_fd mReadEnd; - android::base::unique_fd mWriteEnd; + unique_fd mReadEnd; + unique_fd mWriteEnd; }; static std::string allocateSocketAddress() { @@ -142,10 +146,9 @@ static unsigned int allocateVsockPort() { return vsockPort++; } -static base::unique_fd initUnixSocket(std::string addr) { +static unique_fd initUnixSocket(std::string addr) { auto socket_addr = UnixSocketAddress(addr.c_str()); - base::unique_fd fd( - TEMP_FAILURE_RETRY(socket(socket_addr.addr()->sa_family, SOCK_STREAM, AF_UNIX))); + unique_fd fd(TEMP_FAILURE_RETRY(socket(socket_addr.addr()->sa_family, SOCK_STREAM, AF_UNIX))); if (!fd.ok()) PLOGF("initUnixSocket failed to create socket"); if (0 != TEMP_FAILURE_RETRY(bind(fd.get(), socket_addr.addr(), socket_addr.addrSize()))) { PLOGF("initUnixSocket failed to bind"); @@ -204,8 +207,8 @@ public: void terminate() override { host.terminate(); } }; -static base::unique_fd connectTo(const RpcSocketAddress& addr) { - base::unique_fd serverFd( +static unique_fd connectTo(const RpcSocketAddress& addr) { + unique_fd serverFd( TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0))); if (!serverFd.ok()) { PLOGF("Could not create socket %s", addr.toString().c_str()); @@ -218,15 +221,15 @@ static base::unique_fd connectTo(const RpcSocketAddress& addr) { } #ifndef BINDER_RPC_TO_TRUSTY_TEST -static base::unique_fd connectToUnixBootstrap(const RpcTransportFd& transportFd) { - base::unique_fd sockClient, sockServer; - if (!base::Socketpair(SOCK_STREAM, &sockClient, &sockServer)) { +static unique_fd connectToUnixBootstrap(const RpcTransportFd& transportFd) { + unique_fd sockClient, sockServer; + if (!binder::Socketpair(SOCK_STREAM, &sockClient, &sockServer)) { PLOGF("Failed socketpair()"); } int zero = 0; iovec iov{&zero, sizeof(zero)}; - std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; + std::vector<std::variant<unique_fd, borrowed_fd>> fds; fds.emplace_back(std::move(sockServer)); if (binder::os::sendMessageOnSocket(transportFd, &iov, 1, &fds) < 0) { @@ -259,12 +262,12 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( bool singleThreaded = GetParam().singleThreaded; bool noKernel = GetParam().noKernel; - std::string path = android::base::GetExecutableDirectory(); + std::string path = GetExecutableDirectory(); auto servicePath = std::format("{}/binder_rpc_test_service{}{}", path, singleThreaded ? "_single_threaded" : "", noKernel ? "_no_kernel" : ""); - base::unique_fd bootstrapClientFd, socketFd; + unique_fd bootstrapClientFd, socketFd; auto addr = allocateSocketAddress(); // Initializes the socket before the fork/exec. @@ -273,13 +276,13 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( } else if (socketType == SocketType::UNIX_BOOTSTRAP) { // Do not set O_CLOEXEC, bootstrapServerFd needs to survive fork/exec. // This is because we cannot pass ParcelFileDescriptor over a pipe. - if (!base::Socketpair(SOCK_STREAM, &bootstrapClientFd, &socketFd)) { + if (!binder::Socketpair(SOCK_STREAM, &bootstrapClientFd, &socketFd)) { PLOGF("Failed socketpair()"); } } auto ret = std::make_unique<LinuxProcessSession>( - Process([=](android::base::borrowed_fd writeEnd, android::base::borrowed_fd readEnd) { + Process([=](borrowed_fd writeEnd, borrowed_fd readEnd) { if (socketType == SocketType::TIPC) { // Trusty has a single persistent service return; @@ -374,7 +377,7 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( break; case SocketType::UNIX_BOOTSTRAP: status = session->setupUnixDomainSocketBootstrapClient( - base::unique_fd(dup(bootstrapClientFd.get()))); + unique_fd(dup(bootstrapClientFd.get()))); break; case SocketType::VSOCK: status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort); @@ -391,14 +394,14 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( // in case the service is slow to start int tipcFd = tipc_connect(kTrustyIpcDevice, port.c_str()); if (tipcFd >= 0) { - return android::base::unique_fd(tipcFd); + return unique_fd(tipcFd); } usleep(50000); } - return android::base::unique_fd(); + return unique_fd(); #else LOG_ALWAYS_FATAL("Tried to connect to Trusty outside of vendor"); - return android::base::unique_fd(); + return unique_fd(); #endif }); break; @@ -590,12 +593,12 @@ TEST_P(BinderRpc, OnewayCallQueueingWithFds) { android::os::ParcelFileDescriptor fdA; EXPECT_OK(proc.rootIface->blockingRecvFd(&fdA)); std::string result; - ASSERT_TRUE(android::base::ReadFdToString(fdA.get(), &result)); + ASSERT_TRUE(ReadFdToString(fdA.get(), &result)); EXPECT_EQ(result, "a"); android::os::ParcelFileDescriptor fdB; EXPECT_OK(proc.rootIface->blockingRecvFd(&fdB)); - ASSERT_TRUE(android::base::ReadFdToString(fdB.get(), &result)); + ASSERT_TRUE(ReadFdToString(fdB.get(), &result)); EXPECT_EQ(result, "b"); saturateThreadPool(kNumServerThreads, proc.rootIface); @@ -952,7 +955,7 @@ TEST_P(BinderRpc, ReceiveFile) { ASSERT_TRUE(status.isOk()) << status; std::string result; - ASSERT_TRUE(android::base::ReadFdToString(out.get(), &result)); + ASSERT_TRUE(ReadFdToString(out.get(), &result)); ASSERT_EQ(result, "hello"); } @@ -982,7 +985,7 @@ TEST_P(BinderRpc, SendFiles) { ASSERT_TRUE(status.isOk()) << status; std::string result; - EXPECT_TRUE(android::base::ReadFdToString(out.get(), &result)); + EXPECT_TRUE(ReadFdToString(out.get(), &result)); EXPECT_EQ(result, "123abcd"); } @@ -1007,7 +1010,7 @@ TEST_P(BinderRpc, SendMaxFiles) { ASSERT_TRUE(status.isOk()) << status; std::string result; - EXPECT_TRUE(android::base::ReadFdToString(out.get(), &result)); + EXPECT_TRUE(ReadFdToString(out.get(), &result)); EXPECT_EQ(result, std::string(253, 'a')); } @@ -1152,7 +1155,7 @@ bool testSupportVsockLoopback() { // We don't need to enable TLS to know if vsock is supported. unsigned int vsockPort = allocateVsockPort(); - android::base::unique_fd serverFd( + unique_fd serverFd( TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0))); if (errno == EAFNOSUPPORT) { @@ -1179,7 +1182,7 @@ bool testSupportVsockLoopback() { // to see if the kernel supports it. It's safe to use a blocking // connect because vsock sockets have a 2 second connection timeout, // and they return ETIMEDOUT after that. - android::base::unique_fd connectFd( + unique_fd connectFd( TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0))); LOG_ALWAYS_FATAL_IF(!connectFd.ok(), "Could not create socket for port %u: %s", vsockPort, strerror(errno)); @@ -1193,7 +1196,7 @@ bool testSupportVsockLoopback() { ret = TEMP_FAILURE_RETRY(connect(connectFd.get(), reinterpret_cast<sockaddr*>(&connectAddr), sizeof(connectAddr))); if (ret != 0 && (errno == EAGAIN || errno == EINPROGRESS)) { - android::base::unique_fd acceptFd; + unique_fd acceptFd; while (true) { pollfd pfd[]{ {.fd = serverFd.get(), .events = POLLIN, .revents = 0}, @@ -1423,14 +1426,14 @@ public: }; TEST_P(BinderRpcServerOnly, SetExternalServerTest) { - base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR))); + unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR))); int sinkFd = sink.get(); auto server = RpcServer::make(newTlsFactory(std::get<0>(GetParam()))); ASSERT_TRUE(server->setProtocolVersion(std::get<1>(GetParam()))); ASSERT_FALSE(server->hasServer()); ASSERT_EQ(OK, server->setupExternalServer(std::move(sink))); ASSERT_TRUE(server->hasServer()); - base::unique_fd retrieved = server->releaseServer(); + unique_fd retrieved = server->releaseServer(); ASSERT_FALSE(server->hasServer()); ASSERT_EQ(sinkFd, retrieved.get()); } @@ -1476,12 +1479,12 @@ public: // in the client half of the tests. using Param = std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>, uint32_t>; - using ConnectToServer = std::function<base::unique_fd()>; + using ConnectToServer = std::function<unique_fd()>; // A server that handles client socket connections. class Server { public: - using AcceptConnection = std::function<base::unique_fd(Server*)>; + using AcceptConnection = std::function<unique_fd(Server*)>; explicit Server() {} Server(Server&&) = default; @@ -1510,8 +1513,8 @@ public: }; } break; case SocketType::UNIX_BOOTSTRAP: { - base::unique_fd bootstrapFdClient, bootstrapFdServer; - if (!base::Socketpair(SOCK_STREAM, &bootstrapFdClient, &bootstrapFdServer)) { + unique_fd bootstrapFdClient, bootstrapFdServer; + if (!binder::Socketpair(SOCK_STREAM, &bootstrapFdClient, &bootstrapFdServer)) { return AssertionFailure() << "Socketpair() failed"; } auto status = rpcServer->setupUnixDomainSocketBootstrapServer( @@ -1554,7 +1557,7 @@ public: mConnectToServer = [port] { const char* addr = kLocalInetAddress; auto aiStart = InetSocketAddress::getAddrInfo(addr, port); - if (aiStart == nullptr) return base::unique_fd{}; + if (aiStart == nullptr) return unique_fd{}; for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) { auto fd = connectTo( InetSocketAddress(ai->ai_addr, ai->ai_addrlen, addr, port)); @@ -1562,7 +1565,7 @@ public: } ALOGE("None of the socket address resolved for %s:%u can be connected", addr, port); - return base::unique_fd{}; + return unique_fd{}; }; } break; case SocketType::TIPC: { @@ -1586,13 +1589,13 @@ public: mThread = std::make_unique<std::thread>(&Server::run, this); } - base::unique_fd acceptServerConnection() { - return base::unique_fd(TEMP_FAILURE_RETRY( + unique_fd acceptServerConnection() { + return unique_fd(TEMP_FAILURE_RETRY( accept4(mFd.fd.get(), nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK))); } - base::unique_fd recvmsgServerConnection() { - std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; + unique_fd recvmsgServerConnection() { + std::vector<std::variant<unique_fd, borrowed_fd>> fds; int buf; iovec iov{&buf, sizeof(buf)}; @@ -1601,7 +1604,7 @@ public: } LOG_ALWAYS_FATAL_IF(fds.size() != 1, "Expected one FD from receiveMessage(), got %zu", fds.size()); - return std::move(std::get<base::unique_fd>(fds[0])); + return std::move(std::get<unique_fd>(fds[0])); } void run() { @@ -1609,13 +1612,13 @@ public: std::vector<std::thread> threads; while (OK == mFdTrigger->triggerablePoll(mFd, POLLIN)) { - base::unique_fd acceptedFd = mAcceptConnection(this); + unique_fd acceptedFd = mAcceptConnection(this); threads.emplace_back(&Server::handleOne, this, std::move(acceptedFd)); } for (auto& thread : threads) thread.join(); } - void handleOne(android::base::unique_fd acceptedFd) { + void handleOne(unique_fd acceptedFd) { ASSERT_TRUE(acceptedFd.ok()); RpcTransportFd transportFd(std::move(acceptedFd)); auto serverTransport = mCtx->newTransport(std::move(transportFd), mFdTrigger.get()); diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h index b2b63e4bf3..a55edd273e 100644 --- a/libs/binder/tests/binderRpcTestCommon.h +++ b/libs/binder/tests/binderRpcTestCommon.h @@ -41,7 +41,6 @@ #endif #ifndef __TRUSTY__ -#include <android-base/file.h> #include <android/binder_auto_utils.h> #include <android/binder_libbinder.h> #include <binder/ProcessState.h> @@ -58,7 +57,9 @@ #include "../BuildFlags.h" #include "../FdTrigger.h" +#include "../FdUtils.h" #include "../RpcState.h" // for debugging +#include "FileUtils.h" #include "format.h" #include "utils/Errors.h" @@ -156,28 +157,28 @@ struct BinderRpcOptions { }; #ifndef __TRUSTY__ -static inline void writeString(android::base::borrowed_fd fd, std::string_view str) { +static inline void writeString(binder::borrowed_fd fd, std::string_view str) { uint64_t length = str.length(); - LOG_ALWAYS_FATAL_IF(!android::base::WriteFully(fd, &length, sizeof(length))); - LOG_ALWAYS_FATAL_IF(!android::base::WriteFully(fd, str.data(), str.length())); + LOG_ALWAYS_FATAL_IF(!android::binder::WriteFully(fd, &length, sizeof(length))); + LOG_ALWAYS_FATAL_IF(!android::binder::WriteFully(fd, str.data(), str.length())); } -static inline std::string readString(android::base::borrowed_fd fd) { +static inline std::string readString(binder::borrowed_fd fd) { uint64_t length; - LOG_ALWAYS_FATAL_IF(!android::base::ReadFully(fd, &length, sizeof(length))); + LOG_ALWAYS_FATAL_IF(!android::binder::ReadFully(fd, &length, sizeof(length))); std::string ret(length, '\0'); - LOG_ALWAYS_FATAL_IF(!android::base::ReadFully(fd, ret.data(), length)); + LOG_ALWAYS_FATAL_IF(!android::binder::ReadFully(fd, ret.data(), length)); return ret; } -static inline void writeToFd(android::base::borrowed_fd fd, const Parcelable& parcelable) { +static inline void writeToFd(binder::borrowed_fd fd, const Parcelable& parcelable) { Parcel parcel; LOG_ALWAYS_FATAL_IF(OK != parcelable.writeToParcel(&parcel)); writeString(fd, std::string(reinterpret_cast<const char*>(parcel.data()), parcel.dataSize())); } template <typename T> -static inline T readFromFd(android::base::borrowed_fd fd) { +static inline T readFromFd(binder::borrowed_fd fd) { std::string data = readString(fd); Parcel parcel; LOG_ALWAYS_FATAL_IF(OK != @@ -208,12 +209,12 @@ static inline std::unique_ptr<RpcTransportCtxFactory> newTlsFactory( } // Create an FD that returns `contents` when read. -static inline base::unique_fd mockFileDescriptor(std::string contents) { - android::base::unique_fd readFd, writeFd; - LOG_ALWAYS_FATAL_IF(!android::base::Pipe(&readFd, &writeFd), "%s", strerror(errno)); +static inline binder::unique_fd mockFileDescriptor(std::string contents) { + binder::unique_fd readFd, writeFd; + LOG_ALWAYS_FATAL_IF(!binder::Pipe(&readFd, &writeFd), "%s", strerror(errno)); RpcMaybeThread([writeFd = std::move(writeFd), contents = std::move(contents)]() { signal(SIGPIPE, SIG_IGN); // ignore possible SIGPIPE from the write - if (!WriteStringToFd(contents, writeFd)) { + if (!android::binder::WriteStringToFd(contents, writeFd)) { int savedErrno = errno; LOG_ALWAYS_FATAL_IF(EPIPE != savedErrno, "mockFileDescriptor write failed: %s", strerror(savedErrno)); diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp index 5025bd617f..28125f169c 100644 --- a/libs/binder/tests/binderRpcTestService.cpp +++ b/libs/binder/tests/binderRpcTestService.cpp @@ -17,6 +17,8 @@ #include "binderRpcTestCommon.h" using namespace android; +using android::binder::ReadFdToString; +using android::binder::unique_fd; class MyBinderRpcTestAndroid : public MyBinderRpcTestBase { public: @@ -65,17 +67,17 @@ public: std::string acc; for (const auto& file : files) { std::string result; - LOG_ALWAYS_FATAL_IF(!android::base::ReadFdToString(file.get(), &result)); + LOG_ALWAYS_FATAL_IF(!ReadFdToString(file.get(), &result)); acc.append(result); } out->reset(mockFileDescriptor(acc)); return Status::ok(); } - HandoffChannel<android::base::unique_fd> mFdChannel; + HandoffChannel<unique_fd> mFdChannel; Status blockingSendFdOneway(const android::os::ParcelFileDescriptor& fd) override { - mFdChannel.write(android::base::unique_fd(fcntl(fd.get(), F_DUPFD_CLOEXEC, 0))); + mFdChannel.write(unique_fd(fcntl(fd.get(), F_DUPFD_CLOEXEC, 0))); return Status::ok(); } @@ -101,8 +103,8 @@ int main(int argc, char* argv[]) { __android_log_set_logger(__android_log_stderr_logger); LOG_ALWAYS_FATAL_IF(argc != 3, "Invalid number of arguments: %d", argc); - base::unique_fd writeEnd(atoi(argv[1])); - base::unique_fd readEnd(atoi(argv[2])); + unique_fd writeEnd(atoi(argv[1])); + unique_fd readEnd(atoi(argv[2])); auto serverConfig = readFromFd<BinderRpcTestServerConfig>(readEnd); auto socketType = static_cast<SocketType>(serverConfig.socketType); @@ -123,7 +125,7 @@ int main(int argc, char* argv[]) { server->setSupportedFileDescriptorTransportModes(serverSupportedFileDescriptorTransportModes); unsigned int outPort = 0; - base::unique_fd socketFd(serverConfig.socketFd); + unique_fd socketFd(serverConfig.socketFd); switch (socketType) { case SocketType::PRECONNECTED: diff --git a/libs/binder/tests/binderRpcTestTrusty.cpp b/libs/binder/tests/binderRpcTestTrusty.cpp index 8acaae6e95..18751cc089 100644 --- a/libs/binder/tests/binderRpcTestTrusty.cpp +++ b/libs/binder/tests/binderRpcTestTrusty.cpp @@ -22,6 +22,8 @@ #include "binderRpcTestFixture.h" +using android::binder::unique_fd; + namespace android { // Destructors need to be defined, even if pure virtual @@ -74,7 +76,7 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( auto port = trustyIpcPort(serverVersion); int rc = connect(port.c_str(), IPC_CONNECT_WAIT_FOR_PORT); LOG_ALWAYS_FATAL_IF(rc < 0, "Failed to connect to service: %d", rc); - return base::unique_fd(rc); + return unique_fd(rc); }); if (options.allowConnectFailure && status != OK) { ret->sessions.clear(); diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp index cbbbe74bb5..41cb552e4c 100644 --- a/libs/binder/tests/binderSafeInterfaceTest.cpp +++ b/libs/binder/tests/binderSafeInterfaceTest.cpp @@ -41,6 +41,7 @@ #include <sys/prctl.h> using namespace std::chrono_literals; // NOLINT - google-build-using-namespace +using android::binder::unique_fd; namespace android { namespace tests { @@ -685,7 +686,7 @@ bool fdsAreEquivalent(int a, int b) { TEST_F(SafeInterfaceTest, TestIncrementNativeHandle) { // Create an fd we can use to send and receive from the remote process - base::unique_fd eventFd{eventfd(0 /*initval*/, 0 /*flags*/)}; + unique_fd eventFd{eventfd(0 /*initval*/, 0 /*flags*/)}; ASSERT_NE(-1, eventFd); // Determine the maximum number of fds this process can have open diff --git a/libs/binder/tests/binderTextOutputTest.cpp b/libs/binder/tests/binderTextOutputTest.cpp index b37030e7d7..a648c0886d 100644 --- a/libs/binder/tests/binderTextOutputTest.cpp +++ b/libs/binder/tests/binderTextOutputTest.cpp @@ -20,13 +20,14 @@ #include <limits> #include <cstddef> -#include "android-base/file.h" #include "android-base/test_utils.h" #include <gtest/gtest.h> #include <binder/Parcel.h> #include <binder/TextOutput.h> +#include "../file.h" + static void CheckMessage(CapturedStderr& cap, const char* expected, bool singleline) { diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp index ffeca2d13e..08fe071bfb 100644 --- a/libs/binder/tests/parcel_fuzzer/binder.cpp +++ b/libs/binder/tests/parcel_fuzzer/binder.cpp @@ -29,8 +29,9 @@ #include "../../Utils.h" -using ::android::status_t; using ::android::HexString; +using ::android::status_t; +using ::android::binder::unique_fd; enum ByteEnum : int8_t {}; enum IntEnum : int32_t {}; @@ -307,11 +308,12 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS { }, PARCEL_READ_NO_STATUS(int, readFileDescriptor), PARCEL_READ_NO_STATUS(int, readParcelFileDescriptor), - PARCEL_READ_WITH_STATUS(android::base::unique_fd, readUniqueFileDescriptor), + PARCEL_READ_WITH_STATUS(unique_fd, readUniqueFileDescriptor), - PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector), - PARCEL_READ_WITH_STATUS(std::optional<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector), - PARCEL_READ_WITH_STATUS(std::vector<android::base::unique_fd>, readUniqueFileDescriptorVector), + PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<unique_fd>>, + readUniqueFileDescriptorVector), + PARCEL_READ_WITH_STATUS(std::optional<std::vector<unique_fd>>, readUniqueFileDescriptorVector), + PARCEL_READ_WITH_STATUS(std::vector<unique_fd>, readUniqueFileDescriptorVector), [] (const ::android::Parcel& p, FuzzedDataProvider& provider) { size_t len = provider.ConsumeIntegral<size_t>(); diff --git a/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp b/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp index c0fdaea0a8..57521f4a73 100644 --- a/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp +++ b/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp @@ -14,18 +14,20 @@ * limitations under the License. */ -#include <android-base/file.h> +#include "../../FileUtils.h" + #include <android-base/logging.h> -#include <android-base/unique_fd.h> #include <binder/RecordedTransaction.h> +#include <binder/unique_fd.h> #include <fuzzseeds/random_parcel_seeds.h> #include <sys/prctl.h> +#include <sys/stat.h> using android::generateSeedsFromRecording; using android::status_t; -using android::base::unique_fd; +using android::binder::unique_fd; using android::binder::debug::RecordedTransaction; status_t generateCorpus(const char* recordingPath, const char* corpusDir) { @@ -49,7 +51,7 @@ status_t generateCorpus(const char* recordingPath, const char* corpusDir) { std::string filePath = std::string(corpusDir) + std::string("transaction_") + std::to_string(transactionNumber); constexpr int openFlags = O_WRONLY | O_CREAT | O_BINARY | O_CLOEXEC; - android::base::unique_fd corpusFd(open(filePath.c_str(), openFlags, 0666)); + unique_fd corpusFd(open(filePath.c_str(), openFlags, 0666)); if (!corpusFd.ok()) { std::cerr << "Failed to open fd. Path " << filePath << " with error: " << strerror(errno) << std::endl; diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h index 6ea970825b..8d1299d92a 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h @@ -16,7 +16,7 @@ #pragma once -#include <android-base/unique_fd.h> +#include <binder/unique_fd.h> #include <fuzzer/FuzzedDataProvider.h> #include <vector> @@ -27,6 +27,6 @@ namespace android { // get a random FD for use in fuzzing, of a few different specific types // // may return multiple FDs (e.g. pipe), but will always return at least one -std::vector<base::unique_fd> getRandomFds(FuzzedDataProvider* provider); +std::vector<binder::unique_fd> getRandomFds(FuzzedDataProvider* provider); } // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h index 27587a9162..2812da79fa 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h @@ -27,7 +27,7 @@ namespace android { struct RandomParcelOptions { std::function<void(Parcel* p, FuzzedDataProvider& provider)> writeHeader; std::vector<sp<IBinder>> extraBinders; - std::vector<base::unique_fd> extraFds; + std::vector<binder::unique_fd> extraFds; }; /** diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h index 071250ddf1..694b68d25e 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h @@ -14,7 +14,8 @@ * limitations under the License. */ -#include <android-base/file.h> +#include "../../../../file.h" + #include <android-base/logging.h> #include <binder/Binder.h> @@ -40,6 +41,6 @@ void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T min, T max, T template <typename T> void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T val); } // namespace impl -void generateSeedsFromRecording(base::borrowed_fd fd, +void generateSeedsFromRecording(binder::borrowed_fd fd, const binder::debug::RecordedTransaction& transaction); } // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index 38e6f32cb9..02e69cc371 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -23,6 +23,8 @@ #include <private/android_filesystem_config.h> +using android::binder::unique_fd; + namespace android { void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) { @@ -103,7 +105,7 @@ void fuzzService(const std::vector<sp<IBinder>>& binders, FuzzedDataProvider&& p retBinders.end()); auto retFds = reply.debugReadAllFileDescriptors(); for (size_t i = 0; i < retFds.size(); i++) { - options.extraFds.push_back(base::unique_fd(dup(retFds[i]))); + options.extraFds.push_back(unique_fd(dup(retFds[i]))); } } diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp index 4a9bd07c6e..c7d15337b5 100644 --- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp @@ -23,7 +23,7 @@ namespace android { -using base::unique_fd; +using binder::unique_fd; std::vector<unique_fd> getRandomFds(FuzzedDataProvider* provider) { const char* fdType; diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp index f367b419af..4e58dc4899 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp @@ -23,6 +23,8 @@ #include <fuzzbinder/random_fd.h> #include <utils/String16.h> +using android::binder::unique_fd; + namespace android { static void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) { @@ -72,7 +74,7 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti } if (options->extraFds.size() > 0 && provider.ConsumeBool()) { - const base::unique_fd& fd = options->extraFds.at( + const unique_fd& fd = options->extraFds.at( provider.ConsumeIntegralInRange<size_t>(0, options->extraFds.size() - 1)); @@ -83,7 +85,7 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti return; } - std::vector<base::unique_fd> fds = getRandomFds(&provider); + std::vector<unique_fd> fds = getRandomFds(&provider); CHECK(OK == p->writeFileDescriptor(fds.begin()->release(), true /*takeOwnership*/)); diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp index 9e3e2aba77..7b3c80642b 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp @@ -14,14 +14,16 @@ * limitations under the License. */ -#include <android-base/file.h> #include <android-base/logging.h> #include <binder/RecordedTransaction.h> #include <fuzzseeds/random_parcel_seeds.h> -using android::base::WriteFully; +#include "../../file.h" + +using android::binder::borrowed_fd; +using android::binder::WriteFully; namespace android { namespace impl { @@ -64,7 +66,7 @@ void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T val) { } // namespace impl -void generateSeedsFromRecording(base::borrowed_fd fd, +void generateSeedsFromRecording(borrowed_fd fd, const binder::debug::RecordedTransaction& transaction) { // Write Reserved bytes for future use std::vector<uint8_t> reservedBytes(8); diff --git a/libs/binder/tests/rpc_fuzzer/Android.bp b/libs/binder/tests/rpc_fuzzer/Android.bp index 71e847fd1e..ab72bfd2b5 100644 --- a/libs/binder/tests/rpc_fuzzer/Android.bp +++ b/libs/binder/tests/rpc_fuzzer/Android.bp @@ -25,13 +25,14 @@ cc_fuzz { "libbase", "libcutils", "liblog", + "libbinder_test_utils", "libbinder_tls_static", "libbinder_tls_test_utils", "libssl_fuzz_unsafe", "libcrypto_fuzz_unsafe", ], cflags: [ - "-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE" // for RAND_reset_for_fuzzing + "-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE", // for RAND_reset_for_fuzzing ], target: { android: { diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp index dcc8b8ebf7..50fc2f21f1 100644 --- a/libs/binder/tests/rpc_fuzzer/main.cpp +++ b/libs/binder/tests/rpc_fuzzer/main.cpp @@ -14,9 +14,9 @@ * limitations under the License. */ -#include <android-base/file.h> +#include "../FileUtils.h" + #include <android-base/logging.h> -#include <android-base/unique_fd.h> #include <binder/Binder.h> #include <binder/Parcel.h> #include <binder/RpcServer.h> @@ -24,13 +24,18 @@ #include <binder/RpcTransport.h> #include <binder/RpcTransportRaw.h> #include <binder/RpcTransportTls.h> +#include <binder/unique_fd.h> #include <fuzzer/FuzzedDataProvider.h> #include <openssl/rand.h> #include <openssl/ssl.h> #include <sys/resource.h> +#include <sys/socket.h> #include <sys/un.h> +using android::binder::GetExecutableDirectory; +using android::binder::unique_fd; + namespace android { static const std::string kSock = std::string(getenv("TMPDIR") ?: "/tmp") + @@ -76,12 +81,12 @@ struct ServerAuth { ServerAuth readServerKeyAndCert() { ServerAuth ret; - auto keyPath = android::base::GetExecutableDirectory() + "/data/server.key"; + auto keyPath = GetExecutableDirectory() + "/data/server.key"; bssl::UniquePtr<BIO> keyBio(BIO_new_file(keyPath.c_str(), "r")); ret.pkey.reset(PEM_read_bio_PrivateKey(keyBio.get(), nullptr, passwordCallback, nullptr)); CHECK_NE(ret.pkey.get(), nullptr); - auto certPath = android::base::GetExecutableDirectory() + "/data/server.crt"; + auto certPath = GetExecutableDirectory() + "/data/server.crt"; bssl::UniquePtr<BIO> certBio(BIO_new_file(certPath.c_str(), "r")); ret.cert.reset(PEM_read_bio_X509(certBio.get(), nullptr, nullptr, nullptr)); CHECK_NE(ret.cert.get(), nullptr); @@ -129,7 +134,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { CHECK_LT(kSock.size(), sizeof(addr.sun_path)); memcpy(&addr.sun_path, kSock.c_str(), kSock.size()); - std::vector<base::unique_fd> connections; + std::vector<unique_fd> connections; bool hangupBeforeShutdown = provider.ConsumeBool(); @@ -140,7 +145,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { while (provider.remaining_bytes() > 0) { if (connections.empty() || (connections.size() < kMaxConnections && provider.ConsumeBool())) { - base::unique_fd fd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0))); + unique_fd fd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0))); CHECK_NE(fd.get(), -1); CHECK_EQ(0, TEMP_FAILURE_RETRY( diff --git a/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h index 8d2b714b5c..993418adcc 100644 --- a/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h +++ b/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h @@ -74,7 +74,7 @@ static const std::vector<std::function<void(FuzzedDataProvider*, const sp<BBinde bbinder->getDebugPid(); }, [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void { - (void)bbinder->setRpcClientDebug(android::base::unique_fd(), + (void)bbinder->setRpcClientDebug(binder::unique_fd(), sp<BBinder>::make()); }}; diff --git a/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp b/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp index 070618294f..87b0fb6662 100644 --- a/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp +++ b/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp @@ -19,13 +19,15 @@ #include "fuzzer/FuzzedDataProvider.h" +using android::binder::unique_fd; + extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { std::FILE* intermediateFile = std::tmpfile(); fwrite(data, sizeof(uint8_t), size, intermediateFile); rewind(intermediateFile); int fileNumber = fileno(intermediateFile); - android::base::unique_fd fd(dup(fileNumber)); + unique_fd fd(dup(fileNumber)); auto transaction = android::binder::debug::RecordedTransaction::fromFile(fd); @@ -34,7 +36,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (transaction.has_value()) { intermediateFile = std::tmpfile(); - android::base::unique_fd fdForWriting(dup(fileno(intermediateFile))); + unique_fd fdForWriting(dup(fileno(intermediateFile))); auto writeStatus [[maybe_unused]] = transaction.value().dumpToFile(fdForWriting); std::fclose(intermediateFile); diff --git a/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp b/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp index 9289f6ac90..fa939e68e4 100644 --- a/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp +++ b/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp @@ -22,6 +22,7 @@ #include "fuzzer/FuzzedDataProvider.h" using android::fillRandomParcel; +using android::binder::unique_fd; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider provider = FuzzedDataProvider(data, size); @@ -53,7 +54,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (transaction.has_value()) { std::FILE* intermediateFile = std::tmpfile(); - android::base::unique_fd fdForWriting(dup(fileno(intermediateFile))); + unique_fd fdForWriting(dup(fileno(intermediateFile))); auto writeStatus [[maybe_unused]] = transaction.value().dumpToFile(fdForWriting); std::fclose(intermediateFile); diff --git a/libs/binder/tests/unit_fuzzers/TextOutputFuzz.cpp b/libs/binder/tests/unit_fuzzers/TextOutputFuzz.cpp index 5e3502aace..fe099782c0 100644 --- a/libs/binder/tests/unit_fuzzers/TextOutputFuzz.cpp +++ b/libs/binder/tests/unit_fuzzers/TextOutputFuzz.cpp @@ -14,11 +14,12 @@ * limitations under the License. */ +#include "../../file.h" + #include <fuzzer/FuzzedDataProvider.h> #include <binder/Parcel.h> #include <binder/TextOutput.h> -#include "android-base/file.h" #include "android-base/test_utils.h" #include <fcntl.h> diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp index 0d18b0b94d..ca14286d74 100644 --- a/libs/binder/trusty/OS.cpp +++ b/libs/binder/trusty/OS.cpp @@ -26,9 +26,12 @@ #include "../OS.h" #include "TrustyStatus.h" +using android::binder::borrowed_fd; +using android::binder::unique_fd; + namespace android::binder::os { -status_t setNonBlocking(android::base::borrowed_fd /*fd*/) { +status_t setNonBlocking(borrowed_fd /*fd*/) { // Trusty IPC syscalls are all non-blocking by default. return OK; } @@ -59,14 +62,14 @@ std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory() { ssize_t sendMessageOnSocket( const RpcTransportFd& /* socket */, iovec* /* iovs */, int /* niovs */, - const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /* ancillaryFds */) { + const std::vector<std::variant<unique_fd, borrowed_fd>>* /* ancillaryFds */) { errno = ENOTSUP; return -1; } ssize_t receiveMessageFromSocket( const RpcTransportFd& /* socket */, iovec* /* iovs */, int /* niovs */, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /* ancillaryFds */) { + std::vector<std::variant<unique_fd, borrowed_fd>>* /* ancillaryFds */) { errno = ENOTSUP; return -1; } diff --git a/libs/binder/trusty/RpcServerTrusty.cpp b/libs/binder/trusty/RpcServerTrusty.cpp index 8f643230d1..0872b9014c 100644 --- a/libs/binder/trusty/RpcServerTrusty.cpp +++ b/libs/binder/trusty/RpcServerTrusty.cpp @@ -28,6 +28,7 @@ #include "TrustyStatus.h" using android::base::unexpected; +using android::binder::unique_fd; namespace android { @@ -129,7 +130,7 @@ int RpcServerTrusty::handleConnect(const tipc_port* port, handle_t chan, const u if (chanDup < 0) { return chanDup; } - base::unique_fd clientFd(chanDup); + unique_fd clientFd(chanDup); android::RpcTransportFd transportFd(std::move(clientFd)); std::array<uint8_t, RpcServer::kRpcAddressSize> addr; diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp index 6bb45e2e11..c74ba0a65e 100644 --- a/libs/binder/trusty/RpcTransportTipcTrusty.cpp +++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp @@ -30,6 +30,8 @@ namespace android { using namespace android::binder::impl; +using android::binder::borrowed_fd; +using android::binder::unique_fd; // RpcTransport for Trusty. class RpcTransportTipcTrusty : public RpcTransport { @@ -48,8 +50,7 @@ public: status_t interruptableWriteFully( FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs, const std::optional<SmallFunction<status_t()>>& /*altPoll*/, - const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) - override { + const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override { if (niovs < 0) { return BAD_VALUE; } @@ -118,7 +119,7 @@ public: status_t interruptableReadFully( FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs, const std::optional<SmallFunction<status_t()>>& /*altPoll*/, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override { + std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override { if (niovs < 0) { return BAD_VALUE; } @@ -170,7 +171,7 @@ public: if (ancillaryFds != nullptr) { ancillaryFds->reserve(ancillaryFds->size() + mMessageInfo.num_handles); for (size_t i = 0; i < mMessageInfo.num_handles; i++) { - ancillaryFds->emplace_back(base::unique_fd(msgHandles[i])); + ancillaryFds->emplace_back(unique_fd(msgHandles[i])); } // Clear the saved number of handles so we don't accidentally diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h index aa476f946a..7382a303fe 100644 --- a/libs/binder/trusty/include/binder/RpcServerTrusty.h +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -17,11 +17,11 @@ #pragma once #include <android-base/expected.h> -#include <android-base/unique_fd.h> #include <binder/IBinder.h> #include <binder/RpcServer.h> #include <binder/RpcSession.h> #include <binder/RpcTransport.h> +#include <binder/unique_fd.h> #include <utils/Errors.h> #include <utils/RefBase.h> diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk index 9cad556711..dbddbe16e2 100644 --- a/libs/binder/trusty/rules.mk +++ b/libs/binder/trusty/rules.mk @@ -43,6 +43,7 @@ MODULE_SRCS := \ $(LIBBINDER_DIR)/Stability.cpp \ $(LIBBINDER_DIR)/Status.cpp \ $(LIBBINDER_DIR)/Utils.cpp \ + $(LIBBINDER_DIR)/file.cpp \ $(LIBBASE_DIR)/hex.cpp \ $(LIBBASE_DIR)/stringprintf.cpp \ $(LIBUTILS_DIR)/binder/Errors.cpp \ diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 30cedb02c9..09e98d0515 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -446,7 +446,7 @@ status_t InputChannel::sendMessage(const InputMessage* msg) { msg->getSanitizedCopy(&cleanMsg); ssize_t nWrite; do { - nWrite = ::send(getFd(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); + nWrite = ::send(getFd().get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); } while (nWrite == -1 && errno == EINTR); if (nWrite < 0) { @@ -478,7 +478,7 @@ status_t InputChannel::sendMessage(const InputMessage* msg) { status_t InputChannel::receiveMessage(InputMessage* msg) { ssize_t nRead; do { - nRead = ::recv(getFd(), msg, sizeof(InputMessage), MSG_DONTWAIT); + nRead = ::recv(getFd().get(), msg, sizeof(InputMessage), MSG_DONTWAIT); } while (nRead == -1 && errno == EINTR); if (nRead < 0) { @@ -551,7 +551,7 @@ sp<IBinder> InputChannel::getConnectionToken() const { } base::unique_fd InputChannel::dupFd() const { - android::base::unique_fd newFd(::dup(getFd())); + base::unique_fd newFd(::dup(getFd().get())); if (!newFd.ok()) { ALOGE("Could not duplicate fd %i for channel %s: %s", getFd().get(), getName().c_str(), strerror(errno)); diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp index 8821c0e97d..ba20d1f223 100644 --- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp @@ -433,6 +433,10 @@ VulkanInterface initVulkanInterface(bool protectedContent = false) { // Looks like this would slow things down and we can't depend on it on all platforms interface.physicalDeviceFeatures2->features.robustBufferAccess = VK_FALSE; + if (protectedContent && !interface.protectedMemoryFeatures->protectedMemory) { + BAIL("Protected memory not supported"); + } + float queuePriorities[1] = {0.0f}; void* queueNextPtr = nullptr; diff --git a/libs/ui/include/ui/DisplayMap.h b/libs/ui/include/ui/DisplayMap.h index 7eacb0a7f0..65d2b8fa31 100644 --- a/libs/ui/include/ui/DisplayMap.h +++ b/libs/ui/include/ui/DisplayMap.h @@ -23,13 +23,18 @@ namespace android::ui { // The static capacities were chosen to exceed a typical number of physical and/or virtual displays. +constexpr size_t kDisplayCapacity = 5; template <typename Key, typename Value> -using DisplayMap = ftl::SmallMap<Key, Value, 5>; +using DisplayMap = ftl::SmallMap<Key, Value, kDisplayCapacity>; +constexpr size_t kPhysicalDisplayCapacity = 3; template <typename Key, typename Value> -using PhysicalDisplayMap = ftl::SmallMap<Key, Value, 3>; +using PhysicalDisplayMap = ftl::SmallMap<Key, Value, kPhysicalDisplayCapacity>; template <typename T> -using PhysicalDisplayVector = ftl::SmallVector<T, 3>; +using DisplayVector = ftl::SmallVector<T, kDisplayCapacity>; + +template <typename T> +using PhysicalDisplayVector = ftl::SmallVector<T, kPhysicalDisplayCapacity>; } // namespace android::ui diff --git a/libs/vibrator/fuzzer/Android.bp b/libs/vibrator/fuzzer/Android.bp index f2a313cb8a..cb063af2f6 100644 --- a/libs/vibrator/fuzzer/Android.bp +++ b/libs/vibrator/fuzzer/Android.bp @@ -47,6 +47,17 @@ cc_fuzz { ], fuzz_config: { - componentid: 155276, + cc: [ + "android-haptics@google.com", + ], + componentid: 345036, + hotlists: [ + "4593311", + ], + description: "The fuzzer targets the APIs of libvibrator", + vector: "local_no_privileges_required", + service_privilege: "privileged", + users: "multi_user", + fuzzed_code_usage: "shipped", }, } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index d5761d7995..6ad3de0015 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2305,6 +2305,13 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( } if (isHoverAction) { + if (wasDown) { + // Started hovering, but the device is already down: reject the hover event + LOG(ERROR) << "Got hover event " << entry.getDescription() + << " but the device is already down " << oldState->dump(); + outInjectionResult = InputEventInjectionResult::FAILED; + return {}; + } // For hover actions, we will treat 'tempTouchState' as a new state, so let's erase // all of the existing hovering pointers and recompute. tempTouchState.clearHoveringPointers(entry.deviceId); @@ -2687,15 +2694,7 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( } // Update final pieces of touch state if the injector had permission. - if (isHoverAction) { - if (oldState && oldState->isDown(entry.deviceId)) { - // Started hovering, but the device is already down: reject the hover event - LOG(ERROR) << "Got hover event " << entry.getDescription() - << " but the device is already down " << oldState->dump(); - outInjectionResult = InputEventInjectionResult::FAILED; - return {}; - } - } else if (maskedAction == AMOTION_EVENT_ACTION_UP) { + if (maskedAction == AMOTION_EVENT_ACTION_UP) { // Pointer went up. tempTouchState.removeTouchingPointer(entry.deviceId, entry.pointerProperties[0].id); } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) { @@ -5887,7 +5886,7 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const { // acquire lock std::scoped_lock _l(mLock); const sp<IBinder>& token = serverChannel->getConnectionToken(); - int fd = serverChannel->getFd(); + auto&& fd = serverChannel->getFd(); std::shared_ptr<Connection> connection = std::make_shared<Connection>(std::move(serverChannel), /*monitor=*/false, mIdGenerator); @@ -5900,7 +5899,7 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback, this, std::placeholders::_1, token); - mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback), + mLooper->addFd(fd.get(), 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback), nullptr); } // release lock @@ -5930,7 +5929,7 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor(int32_ std::shared_ptr<Connection> connection = std::make_shared<Connection>(serverChannel, /*monitor=*/true, mIdGenerator); const sp<IBinder>& token = serverChannel->getConnectionToken(); - const int fd = serverChannel->getFd(); + auto&& fd = serverChannel->getFd(); if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) { ALOGE("Created a new connection, but the token %p is already known", token.get()); @@ -5941,7 +5940,7 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor(int32_ mGlobalMonitorsByDisplay[displayId].emplace_back(serverChannel, pid); - mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback), + mLooper->addFd(fd.get(), 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback), nullptr); } @@ -5980,7 +5979,7 @@ status_t InputDispatcher::removeInputChannelLocked(const sp<IBinder>& connection removeMonitorChannelLocked(connectionToken); } - mLooper->removeFd(connection->inputChannel->getFd()); + mLooper->removeFd(connection->inputChannel->getFd().get()); nsecs_t currentTime = now(); abortBrokenDispatchCycleLocked(currentTime, connection, notify); diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp index 536775100a..cd0500c872 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.cpp +++ b/services/inputflinger/dispatcher/TouchedWindow.cpp @@ -128,20 +128,14 @@ void TouchedWindow::removeTouchingPointers(DeviceId deviceId, std::set<DeviceId> TouchedWindow::getTouchingDeviceIds() const { std::set<DeviceId> deviceIds; - for (const auto& [deviceId, _] : mDeviceStates) { - deviceIds.insert(deviceId); + for (const auto& [deviceId, deviceState] : mDeviceStates) { + if (deviceState.touchingPointerIds.any()) { + deviceIds.insert(deviceId); + } } return deviceIds; } -std::set<DeviceId> TouchedWindow::getActiveDeviceIds() const { - std::set<DeviceId> out; - for (const auto& [deviceId, _] : mDeviceStates) { - out.emplace(deviceId); - } - return out; -} - bool TouchedWindow::hasPilferingPointers(DeviceId deviceId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index 6d2283e0af..9a31678955 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -48,15 +48,7 @@ struct TouchedWindow { void addTouchingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointers); void removeTouchingPointer(DeviceId deviceId, int32_t pointerId); void removeTouchingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointers); - /** - * Get the currently active touching device id. If there isn't exactly 1 touching device, return - * nullopt. - */ std::set<DeviceId> getTouchingDeviceIds() const; - /** - * The ids of devices that are currently touching or hovering. - */ - std::set<DeviceId> getActiveDeviceIds() const; // Pilfering pointers bool hasPilferingPointers(DeviceId deviceId) const; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 26c77d514c..e22013327f 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1052,12 +1052,10 @@ public: } if (event->getType() == InputEventType::KEY) { KeyEvent& keyEvent = static_cast<KeyEvent&>(*event); - ADD_FAILURE() << "Received key event " - << KeyEvent::actionToString(keyEvent.getAction()); + ADD_FAILURE() << "Received key event " << keyEvent; } else if (event->getType() == InputEventType::MOTION) { MotionEvent& motionEvent = static_cast<MotionEvent&>(*event); - ADD_FAILURE() << "Received motion event " - << MotionEvent::actionToString(motionEvent.getAction()); + ADD_FAILURE() << "Received motion event " << motionEvent; } else if (event->getType() == InputEventType::FOCUS) { FocusEvent& focusEvent = static_cast<FocusEvent&>(*event); ADD_FAILURE() << "Received focus event, hasFocus = " @@ -1784,8 +1782,10 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance mDispatcher->onWindowInfosChanged( {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {100, 200})) + injectMotionEvent(*mDispatcher, + MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(200)) + .build())) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; // Both foreground window and its wallpaper should receive the touch down @@ -1793,11 +1793,13 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {110, 200})) + injectMotionEvent(*mDispatcher, + MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(110).y(200)) + .build())) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - foregroundWindow->consumeMotionMove(); + foregroundWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); // Now the foreground window goes away, but the wallpaper stays @@ -7740,12 +7742,15 @@ protected: static constexpr PointF WINDOW_LOCATION = {20, 20}; void tapOnWindow() { - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - WINDOW_LOCATION)); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - WINDOW_LOCATION)); + const auto touchingPointer = PointerBuilder(/*id=*/0, ToolType::FINGER) + .x(WINDOW_LOCATION.x) + .y(WINDOW_LOCATION.y); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(touchingPointer) + .build()); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(touchingPointer) + .build()); } sp<FakeWindowHandle> addSpyWindow() { @@ -8182,11 +8187,10 @@ TEST_F(InputDispatcherSingleWindowAnr, std::optional<uint32_t> upSequenceNum = mWindow->receiveEvent(); ASSERT_TRUE(upSequenceNum); // Don't finish the events yet, and send a key - // Injection is async, so it will succeed - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, - ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, - /*allowKeyRepeat=*/false)); + mDispatcher->notifyKey( + KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD) + .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT) + .build()); // At this point, key is still pending, and should not be sent to the application yet. // Make sure the `assertNoEvents` check doesn't take too long. It uses // CONSUME_TIMEOUT_NO_EVENT_EXPECTED under the hood. @@ -8195,12 +8199,12 @@ TEST_F(InputDispatcherSingleWindowAnr, // Now tap down again. It should cause the pending key to go to the focused window right away. tapOnWindow(); - mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); // it doesn't matter that we haven't ack'd - // the other events yet. We can finish events in any order. + mWindow->consumeKeyEvent(WithKeyAction(AKEY_EVENT_ACTION_DOWN)); // it doesn't matter that we + // haven't ack'd the other events yet. We can finish events in any order. mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP - mWindow->consumeMotionDown(); - mWindow->consumeMotionUp(); + mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + mWindow->consumeMotionEvent(WithMotionAction(ACTION_UP)); mWindow->assertNoEvents(); } @@ -10037,6 +10041,19 @@ TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) { ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp()); } +TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) { + // Start hovering over the window. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE, + ADISPLAY_ID_DEFAULT, {50, 50})); + + ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER))); + ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER))); + + ASSERT_FALSE(startDrag(/*sendDown=*/false)) + << "Drag and drop should not work with a hovering pointer"; +} + class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {}; TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { @@ -10058,6 +10075,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); + mDispatcher->waitForIdle(); window->assertNoEvents(); // With the flag cleared, the window should get input @@ -10935,6 +10953,25 @@ TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) { rightWindow->assertNoEvents(); } +TEST_F(InputDispatcherPilferPointersTest, NoPilferingWithHoveringPointers) { + auto window = createForeground(); + auto spy = createSpy(); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); + + mDispatcher->notifyMotion( + MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .deviceId(1) + .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(100).y(200)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + + // Pilfer pointers from the spy window should fail. + EXPECT_NE(OK, mDispatcher->pilferPointers(spy->getToken())); + spy->assertNoEvents(); + window->assertNoEvents(); +} + class InputDispatcherStylusInterceptorTest : public InputDispatcherTest { public: std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() { diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 2740a979f3..455e623c37 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -91,6 +91,9 @@ cc_library { ], local_include_dirs: ["include"], export_include_dirs: ["include"], + shared_libs: [ + "server_configurable_flags", + ], } cc_library { @@ -114,6 +117,9 @@ cc_library { "libsurfaceflinger_common_test", "libsurfaceflingerflags_test", ], + shared_libs: [ + "server_configurable_flags", + ], local_include_dirs: ["include"], export_include_dirs: ["include"], } @@ -150,10 +156,11 @@ cc_test { "libsurfaceflinger_common_test", "libsurfaceflingerflags_test", ], - // For some reason, libvulkan isn't picked up from librenderengine - // Probably ASAN related? shared_libs: [ + // For some reason, libvulkan isn't picked up from librenderengine + // Probably ASAN related? "libvulkan", + "server_configurable_flags", ], sanitize: { hwaddress: true, diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h index 9c80cacf6f..a74c5fe207 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h @@ -36,7 +36,7 @@ class HdrCapabilities; namespace compositionengine { /** - * Encapsulates all the state and functionality for how colors should be + * Encapsulates all the states and functionality for how colors should be * transformed for a display */ class DisplayColorProfile { diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 40ebf4414d..f1d6f52eb8 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -26,6 +26,7 @@ #include <vector> #include <compositionengine/LayerFE.h> +#include <ftl/future.h> #include <renderengine/LayerSettings.h> #include <ui/Fence.h> #include <ui/FenceTime.h> @@ -61,7 +62,7 @@ struct GpuCompositionResult; } // namespace impl /** - * Encapsulates all the state involved with composing layers for an output + * Encapsulates all the states involved with composing layers for an output */ class Output { public: @@ -263,8 +264,15 @@ public: // Prepare the output, updating the OutputLayers used in the output virtual void prepare(const CompositionRefreshArgs&, LayerFESet&) = 0; - // Presents the output, finalizing all composition details - virtual void present(const CompositionRefreshArgs&) = 0; + // Presents the output, finalizing all composition details. This may happen + // asynchronously, in which case the returned future must be waited upon. + virtual ftl::Future<std::monostate> present(const CompositionRefreshArgs&) = 0; + + // Whether this output can be presented from another thread. + virtual bool supportsOffloadPresent() const = 0; + + // Make the next call to `present` run asynchronously. + virtual void offloadPresentNextFrame() = 0; // Enables predicting composition strategy to run client composition earlier virtual void setPredictCompositionStrategy(bool) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index de8293151b..eac5d97df3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -62,6 +62,7 @@ public: compositionengine::Output::FrameFences presentFrame() override; void setExpensiveRenderingExpected(bool) override; void finishFrame(GpuCompositionResult&&) override; + bool supportsOffloadPresent() const override; // compositionengine::Display overrides DisplayId getId() const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index d95fbeab92..ec6a4e9c63 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -80,7 +80,9 @@ public: void setReleasedLayers(ReleasedLayers&&) override; void prepare(const CompositionRefreshArgs&, LayerFESet&) override; - void present(const CompositionRefreshArgs&) override; + ftl::Future<std::monostate> present(const CompositionRefreshArgs&) override; + bool supportsOffloadPresent() const override { return false; } + void offloadPresentNextFrame() override; void uncacheBuffers(const std::vector<uint64_t>& bufferIdsToUncache) override; void rebuildLayerStacks(const CompositionRefreshArgs&, LayerFESet&) override; @@ -121,6 +123,7 @@ public: virtual std::future<bool> chooseCompositionStrategyAsync( std::optional<android::HWComposer::DeviceRequestedChanges>*); virtual void resetCompositionStrategy(); + virtual ftl::Future<std::monostate> presentFrameAndReleaseLayersAsync(); protected: std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const; @@ -164,6 +167,7 @@ private: ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const; compositionengine::Output::ColorProfile pickColorProfile( const compositionengine::CompositionRefreshArgs&) const; + void updateHwcAsyncWorker(); std::string mName; std::string mNamePlusId; @@ -177,6 +181,9 @@ private: std::unique_ptr<planner::Planner> mPlanner; std::unique_ptr<HwcAsyncWorker> mHwComposerAsyncWorker; + bool mPredictCompositionStrategy = false; + bool mOffloadPresent = false; + // Whether the content must be recomposed this frame. bool mMustRecompose = false; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index 7b0af3a248..6c419da716 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -90,7 +90,7 @@ struct OutputLayerCompositionState { // The source crop for this layer on this output FloatRect sourceCrop; - // The buffer transform to use for this layer o on this output. + // The buffer transform to use for this layer on this output. Hwc2::Transform bufferTransform{static_cast<Hwc2::Transform>(0)}; // The dataspace for this layer diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index c88fbd6d0f..95ea3a4ed7 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -80,7 +80,10 @@ public: MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&)); MOCK_METHOD2(prepare, void(const compositionengine::CompositionRefreshArgs&, LayerFESet&)); - MOCK_METHOD1(present, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_METHOD1(present, + ftl::Future<std::monostate>(const compositionengine::CompositionRefreshArgs&)); + MOCK_CONST_METHOD0(supportsOffloadPresent, bool()); + MOCK_METHOD(void, offloadPresentNextFrame, ()); MOCK_METHOD1(uncacheBuffers, void(const std::vector<uint64_t>&)); MOCK_METHOD2(rebuildLayerStacks, diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp index 002177b572..748d87bdc3 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -20,6 +20,7 @@ #include <compositionengine/OutputLayer.h> #include <compositionengine/impl/CompositionEngine.h> #include <compositionengine/impl/Display.h> +#include <ui/DisplayMap.h> #include <renderengine/RenderEngine.h> #include <utils/Trace.h> @@ -88,6 +89,33 @@ nsecs_t CompositionEngine::getLastFrameRefreshTimestamp() const { return mRefreshStartTime; } +namespace { +int numDisplaysWithOffloadPresentSupport(const CompositionRefreshArgs& args) { + if (!FlagManager::getInstance().multithreaded_present() || args.outputs.size() < 2) { + return 0; + } + + int numEligibleDisplays = 0; + // Only run present in multiple threads if all HWC-enabled displays + // being refreshed support it. + if (!std::all_of(args.outputs.begin(), args.outputs.end(), + [&numEligibleDisplays](const auto& output) { + if (!ftl::Optional(output->getDisplayId()) + .and_then(HalDisplayId::tryCast)) { + // Not HWC-enabled, so it is always + // client-composited. + return true; + } + const bool support = output->supportsOffloadPresent(); + numEligibleDisplays += static_cast<int>(support); + return support; + })) { + return 0; + } + return numEligibleDisplays; +} +} // namespace + void CompositionEngine::present(CompositionRefreshArgs& args) { ATRACE_CALL(); ALOGV(__FUNCTION__); @@ -105,8 +133,36 @@ void CompositionEngine::present(CompositionRefreshArgs& args) { } } + // Offloading the HWC call for `present` allows us to simultaneously call it + // on multiple displays. This is desirable because these calls block and can + // be slow. + if (const int numEligibleDisplays = numDisplaysWithOffloadPresentSupport(args); + numEligibleDisplays > 1) { + // Leave the last eligible display on the main thread, which will + // allow it to run concurrently without an extra thread hop. + int numToOffload = numEligibleDisplays - 1; + for (auto& output : args.outputs) { + if (output->supportsOffloadPresent()) { + output->offloadPresentNextFrame(); + if (--numToOffload == 0) { + break; + } + } + } + } + + ui::DisplayVector<ftl::Future<std::monostate>> presentFutures; for (const auto& output : args.outputs) { - output->present(args); + presentFutures.push_back(output->present(args)); + } + + { + ATRACE_NAME("Waiting on HWC"); + for (auto& future : presentFutures) { + // TODO(b/185536303): Call ftl::Future::wait() once it exists, since + // we do not need the return value of get(). + future.get(); + } } } diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 469fb386fc..0475881bae 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -430,4 +430,13 @@ void Display::finishFrame(GpuCompositionResult&& result) { impl::Output::finishFrame(std::move(result)); } +bool Display::supportsOffloadPresent() const { + if (const auto halDisplayId = HalDisplayId::tryCast(mId)) { + const auto& hwc = getCompositionEngine().getHwComposer(); + return hwc.hasDisplayCapability(*halDisplayId, DisplayCapability::MULTI_THREADED_PRESENT); + } + + return false; +} + } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 2ae80de42a..e4d757810a 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -427,7 +427,8 @@ void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArg uncacheBuffers(refreshArgs.bufferIdsToUncache); } -void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) { +ftl::Future<std::monostate> Output::present( + const compositionengine::CompositionRefreshArgs& refreshArgs) { ATRACE_FORMAT("%s for %s", __func__, mNamePlusId.c_str()); ALOGV(__FUNCTION__); @@ -448,8 +449,26 @@ void Output::present(const compositionengine::CompositionRefreshArgs& refreshArg devOptRepaintFlash(refreshArgs); finishFrame(std::move(result)); - presentFrameAndReleaseLayers(); + ftl::Future<std::monostate> future; + if (mOffloadPresent) { + future = presentFrameAndReleaseLayersAsync(); + + // Only offload for this frame. The next frame will determine whether it + // needs to be offloaded. Leave the HwcAsyncWorker in place. For one thing, + // it is currently presenting. Further, it may be needed next frame, and + // we don't want to churn. + mOffloadPresent = false; + } else { + presentFrameAndReleaseLayers(); + future = ftl::yield<std::monostate>({}); + } renderCachedSets(refreshArgs); + return future; +} + +void Output::offloadPresentNextFrame() { + mOffloadPresent = true; + updateHwcAsyncWorker(); } void Output::uncacheBuffers(std::vector<uint64_t> const& bufferIdsToUncache) { @@ -1084,6 +1103,14 @@ void Output::prepareFrame() { finishPrepareFrame(); } +ftl::Future<std::monostate> Output::presentFrameAndReleaseLayersAsync() { + return ftl::Future<bool>(std::move(mHwComposerAsyncWorker->send([&]() { + presentFrameAndReleaseLayers(); + return true; + }))) + .then([](bool) { return std::monostate{}; }); +} + std::future<bool> Output::chooseCompositionStrategyAsync( std::optional<android::HWComposer::DeviceRequestedChanges>* changes) { return mHwComposerAsyncWorker->send( @@ -1600,8 +1627,15 @@ compositionengine::Output::FrameFences Output::presentFrame() { } void Output::setPredictCompositionStrategy(bool predict) { - if (predict) { - mHwComposerAsyncWorker = std::make_unique<HwcAsyncWorker>(); + mPredictCompositionStrategy = predict; + updateHwcAsyncWorker(); +} + +void Output::updateHwcAsyncWorker() { + if (mPredictCompositionStrategy || mOffloadPresent) { + if (!mHwComposerAsyncWorker) { + mHwComposerAsyncWorker = std::make_unique<HwcAsyncWorker>(); + } } else { mHwComposerAsyncWorker.reset(nullptr); } @@ -1616,7 +1650,7 @@ bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refresh uint64_t outputLayerHash = getState().outputLayerHash; editState().lastOutputLayerHash = outputLayerHash; - if (!getState().isEnabled || !mHwComposerAsyncWorker) { + if (!getState().isEnabled || !mPredictCompositionStrategy) { ALOGV("canPredictCompositionStrategy disabled"); return false; } diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp index 60ed660c7a..a451ab2b77 100644 --- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp @@ -20,12 +20,15 @@ #include <compositionengine/mock/LayerFE.h> #include <compositionengine/mock/Output.h> #include <compositionengine/mock/OutputLayer.h> +#include <ftl/future.h> #include <gtest/gtest.h> #include <renderengine/mock/RenderEngine.h> #include "MockHWComposer.h" #include "TimeStats/TimeStats.h" +#include <variant> + namespace android::compositionengine { namespace { @@ -107,10 +110,19 @@ TEST_F(CompositionEnginePresentTest, worksAsExpected) { EXPECT_CALL(*mOutput2, prepare(Ref(mRefreshArgs), _)); EXPECT_CALL(*mOutput3, prepare(Ref(mRefreshArgs), _)); + if (FlagManager::getInstance().multithreaded_present()) { + EXPECT_CALL(*mOutput1, getDisplayId()).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*mOutput2, getDisplayId()).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*mOutput3, getDisplayId()).WillOnce(Return(std::nullopt)); + } + // The last step is to actually present each output. - EXPECT_CALL(*mOutput1, present(Ref(mRefreshArgs))); - EXPECT_CALL(*mOutput2, present(Ref(mRefreshArgs))); - EXPECT_CALL(*mOutput3, present(Ref(mRefreshArgs))); + EXPECT_CALL(*mOutput1, present(Ref(mRefreshArgs))) + .WillOnce(Return(ftl::yield<std::monostate>({}))); + EXPECT_CALL(*mOutput2, present(Ref(mRefreshArgs))) + .WillOnce(Return(ftl::yield<std::monostate>({}))); + EXPECT_CALL(*mOutput3, present(Ref(mRefreshArgs))) + .WillOnce(Return(ftl::yield<std::monostate>({}))); mRefreshArgs.outputs = {mOutput1, mOutput2, mOutput3}; mEngine.present(mRefreshArgs); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 5537fcdcb5..5006e7d94a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -35,6 +35,7 @@ #include <cmath> #include <cstdint> +#include <variant> #include "CallOrderStateMachineHelper.h" #include "MockHWC2.h" @@ -54,6 +55,7 @@ using testing::InSequence; using testing::Invoke; using testing::IsEmpty; using testing::Mock; +using testing::NiceMock; using testing::Pointee; using testing::Property; using testing::Ref; @@ -4900,5 +4902,54 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, EXPECT_EQ(mLayers[2].mLayerSettings, requests[0]); } +struct OutputPresentFrameAndReleaseLayersAsyncTest : public ::testing::Test { + // Piggy-back on OutputPrepareFrameAsyncTest's version to avoid some boilerplate. + struct OutputPartialMock : public OutputPrepareFrameAsyncTest::OutputPartialMock { + // Set up the helper functions called by the function under test to use + // mock implementations. + MOCK_METHOD0(presentFrameAndReleaseLayers, void()); + MOCK_METHOD0(presentFrameAndReleaseLayersAsync, ftl::Future<std::monostate>()); + }; + OutputPresentFrameAndReleaseLayersAsyncTest() { + mOutput->setDisplayColorProfileForTest( + std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile)); + mOutput->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface)); + mOutput->setCompositionEnabled(true); + mRefreshArgs.outputs = {mOutput}; + } + + mock::DisplayColorProfile* mDisplayColorProfile = new NiceMock<mock::DisplayColorProfile>(); + mock::RenderSurface* mRenderSurface = new NiceMock<mock::RenderSurface>(); + std::shared_ptr<OutputPartialMock> mOutput{std::make_shared<NiceMock<OutputPartialMock>>()}; + CompositionRefreshArgs mRefreshArgs; +}; + +TEST_F(OutputPresentFrameAndReleaseLayersAsyncTest, notCalledWhenNotRequested) { + EXPECT_CALL(*mOutput, presentFrameAndReleaseLayersAsync()).Times(0); + EXPECT_CALL(*mOutput, presentFrameAndReleaseLayers()).Times(1); + + mOutput->present(mRefreshArgs); +} + +TEST_F(OutputPresentFrameAndReleaseLayersAsyncTest, calledWhenRequested) { + EXPECT_CALL(*mOutput, presentFrameAndReleaseLayersAsync()) + .WillOnce(Return(ftl::yield<std::monostate>({}))); + EXPECT_CALL(*mOutput, presentFrameAndReleaseLayers()).Times(0); + + mOutput->offloadPresentNextFrame(); + mOutput->present(mRefreshArgs); +} + +TEST_F(OutputPresentFrameAndReleaseLayersAsyncTest, calledForOneFrame) { + ::testing::InSequence inseq; + EXPECT_CALL(*mOutput, presentFrameAndReleaseLayersAsync()) + .WillOnce(Return(ftl::yield<std::monostate>({}))); + EXPECT_CALL(*mOutput, presentFrameAndReleaseLayers()).Times(1); + + mOutput->offloadPresentNextFrame(); + mOutput->present(mRefreshArgs); + mOutput->present(mRefreshArgs); +} + } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 2ffe92b028..7fdf9e7672 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -63,14 +63,14 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mDisplayToken(args.displayToken), mSequenceId(args.sequenceId), mCompositionDisplay{args.compositionDisplay}, - mActiveModeFPSTrace(concatId("ActiveModeFPS")), - mActiveModeFPSHwcTrace(concatId("ActiveModeFPS_HWC")), - mRenderFrameRateFPSTrace(concatId("RenderRateFPS")), + mPendingModeFpsTrace(concatId("PendingModeFps")), + mActiveModeFpsTrace(concatId("ActiveModeFps")), + mRenderRateFpsTrace(concatId("RenderRateFps")), mPhysicalOrientation(args.physicalOrientation), mIsPrimary(args.isPrimary), mRequestedRefreshRate(args.requestedRefreshRate), mRefreshRateSelector(std::move(args.refreshRateSelector)), - mDesiredActiveModeChanged(concatId("DesiredActiveModeChanged"), false) { + mDesiredModeChanged(concatId("DesiredModeChanged"), false) { mCompositionDisplay->editState().isSecure = args.isSecure; mCompositionDisplay->createRenderSurface( compositionengine::RenderSurfaceCreationArgsBuilder() @@ -210,16 +210,16 @@ bool DisplayDevice::isPoweredOn() const { } void DisplayDevice::setActiveMode(DisplayModeId modeId, Fps vsyncRate, Fps renderFps) { - ATRACE_INT(mActiveModeFPSTrace.c_str(), vsyncRate.getIntValue()); - ATRACE_INT(mRenderFrameRateFPSTrace.c_str(), renderFps.getIntValue()); + ATRACE_INT(mActiveModeFpsTrace.c_str(), vsyncRate.getIntValue()); + ATRACE_INT(mRenderRateFpsTrace.c_str(), renderFps.getIntValue()); mRefreshRateSelector->setActiveMode(modeId, renderFps); updateRefreshRateOverlayRate(vsyncRate, renderFps); } -status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info, - const hal::VsyncPeriodChangeConstraints& constraints, - hal::VsyncPeriodChangeTimeline* outTimeline) { +bool DisplayDevice::initiateModeChange(const ActiveModeInfo& info, + const hal::VsyncPeriodChangeConstraints& constraints, + hal::VsyncPeriodChangeTimeline& outTimeline) { if (!info.modeOpt || info.modeOpt->modePtr->getPhysicalDisplayId() != getPhysicalId()) { ALOGE("Trying to initiate a mode change to invalid mode %s on display %s", info.modeOpt ? std::to_string(info.modeOpt->modePtr->getId().value()).c_str() @@ -227,14 +227,18 @@ status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info, to_string(getId()).c_str()); return BAD_VALUE; } - mUpcomingActiveMode = info; + mPendingMode = info; mIsModeSetPending = true; - const auto& pendingMode = *info.modeOpt->modePtr; - ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), pendingMode.getVsyncRate().getIntValue()); + const auto& mode = *info.modeOpt->modePtr; - return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), pendingMode.getHwcId(), - constraints, outTimeline); + if (mHwComposer.setActiveModeWithConstraints(getPhysicalId(), mode.getHwcId(), constraints, + &outTimeline) != OK) { + return false; + } + + ATRACE_INT(mPendingModeFpsTrace.c_str(), mode.getVsyncRate().getIntValue()); + return true; } void DisplayDevice::finalizeModeChange(DisplayModeId modeId, Fps vsyncRate, Fps renderFps) { @@ -524,8 +528,7 @@ void DisplayDevice::animateOverlay() { } } -auto DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info, bool force) - -> DesiredActiveModeAction { +auto DisplayDevice::setDesiredMode(const ActiveModeInfo& info, bool force) -> DesiredModeAction { ATRACE_CALL(); LOG_ALWAYS_FATAL_IF(!info.modeOpt, "desired mode not provided"); @@ -534,49 +537,50 @@ auto DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info, bool force) ALOGV("%s(%s)", __func__, to_string(*info.modeOpt->modePtr).c_str()); - std::scoped_lock lock(mActiveModeLock); - if (mDesiredActiveModeChanged) { - // If a mode change is pending, just cache the latest request in mDesiredActiveMode - const auto prevConfig = mDesiredActiveMode.event; - mDesiredActiveMode = info; - mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig; - return DesiredActiveModeAction::None; + std::scoped_lock lock(mDesiredModeLock); + if (mDesiredModeChanged) { + // A mode transition was already scheduled, so just override the desired mode. + const auto event = mDesiredMode.event; + mDesiredMode = info; + mDesiredMode.event = mDesiredMode.event | event; + return DesiredModeAction::None; } const auto& desiredMode = *info.modeOpt->modePtr; - // Check if we are already at the desired mode - const auto currentMode = refreshRateSelector().getActiveMode(); - if (!force && currentMode.modePtr->getId() == desiredMode.getId()) { - if (currentMode == info.modeOpt) { - return DesiredActiveModeAction::None; + // If the desired mode is already active... + const auto activeMode = refreshRateSelector().getActiveMode(); + if (!force && activeMode.modePtr->getId() == desiredMode.getId()) { + if (activeMode == info.modeOpt) { + return DesiredModeAction::None; } + // ...but the render rate changed: setActiveMode(desiredMode.getId(), desiredMode.getVsyncRate(), info.modeOpt->fps); - return DesiredActiveModeAction::InitiateRenderRateSwitch; + return DesiredModeAction::InitiateRenderRateSwitch; } - // Set the render frame rate to the current physical refresh rate to schedule the next + // Set the render frame rate to the active physical refresh rate to schedule the next // frame as soon as possible. - setActiveMode(currentMode.modePtr->getId(), currentMode.modePtr->getVsyncRate(), - currentMode.modePtr->getVsyncRate()); + setActiveMode(activeMode.modePtr->getId(), activeMode.modePtr->getVsyncRate(), + activeMode.modePtr->getVsyncRate()); // Initiate a mode change. - mDesiredActiveModeChanged = true; - mDesiredActiveMode = info; - return DesiredActiveModeAction::InitiateDisplayModeSwitch; + mDesiredModeChanged = true; + mDesiredMode = info; + return DesiredModeAction::InitiateDisplayModeSwitch; } -std::optional<DisplayDevice::ActiveModeInfo> DisplayDevice::getDesiredActiveMode() const { - std::scoped_lock lock(mActiveModeLock); - if (mDesiredActiveModeChanged) return mDesiredActiveMode; +auto DisplayDevice::getDesiredMode() const -> ftl::Optional<ActiveModeInfo> { + std::scoped_lock lock(mDesiredModeLock); + if (mDesiredModeChanged) return mDesiredMode; return std::nullopt; } -void DisplayDevice::clearDesiredActiveModeState() { - std::scoped_lock lock(mActiveModeLock); - mDesiredActiveMode.event = scheduler::DisplayModeEvent::None; - mDesiredActiveModeChanged = false; +void DisplayDevice::clearDesiredMode() { + std::scoped_lock lock(mDesiredModeLock); + mDesiredMode.event = scheduler::DisplayModeEvent::None; + mDesiredModeChanged = false; } void DisplayDevice::adjustRefreshRate(Fps pacesetterDisplayRefreshRate) { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index a40f310711..a061fcaa92 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -17,7 +17,6 @@ #pragma once #include <memory> -#include <optional> #include <string> #include <unordered_map> @@ -25,6 +24,7 @@ #include <android/native_window.h> #include <binder/IBinder.h> #include <ftl/concat.h> +#include <ftl/optional.h> #include <gui/LayerState.h> #include <math/mat4.h> #include <renderengine/RenderEngine.h> @@ -51,6 +51,7 @@ #include "ThreadContext.h" #include "TracedOrdinal.h" #include "Utils/Dumper.h" + namespace android { class Fence; @@ -205,19 +206,15 @@ public: } }; - enum class DesiredActiveModeAction { - None, - InitiateDisplayModeSwitch, - InitiateRenderRateSwitch - }; - DesiredActiveModeAction setDesiredActiveMode(const ActiveModeInfo&, bool force = false) - EXCLUDES(mActiveModeLock); - std::optional<ActiveModeInfo> getDesiredActiveMode() const EXCLUDES(mActiveModeLock); - void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock); - ActiveModeInfo getUpcomingActiveMode() const REQUIRES(kMainThreadContext) { - return mUpcomingActiveMode; - } + enum class DesiredModeAction { None, InitiateDisplayModeSwitch, InitiateRenderRateSwitch }; + + DesiredModeAction setDesiredMode(const ActiveModeInfo&, bool force = false) + EXCLUDES(mDesiredModeLock); + + ftl::Optional<ActiveModeInfo> getDesiredMode() const EXCLUDES(mDesiredModeLock); + void clearDesiredMode() EXCLUDES(mDesiredModeLock); + ActiveModeInfo getPendingMode() const REQUIRES(kMainThreadContext) { return mPendingMode; } bool isModeSetPending() const REQUIRES(kMainThreadContext) { return mIsModeSetPending; } scheduler::FrameRateMode getActiveMode() const REQUIRES(kMainThreadContext) { @@ -226,9 +223,8 @@ public: void setActiveMode(DisplayModeId, Fps vsyncRate, Fps renderFps); - status_t initiateModeChange(const ActiveModeInfo&, - const hal::VsyncPeriodChangeConstraints& constraints, - hal::VsyncPeriodChangeTimeline* outTimeline) + bool initiateModeChange(const ActiveModeInfo&, const hal::VsyncPeriodChangeConstraints&, + hal::VsyncPeriodChangeTimeline& outTimeline) REQUIRES(kMainThreadContext); void finalizeModeChange(DisplayModeId, Fps vsyncRate, Fps renderFps) @@ -282,9 +278,9 @@ private: const std::shared_ptr<compositionengine::Display> mCompositionDisplay; std::string mDisplayName; - std::string mActiveModeFPSTrace; - std::string mActiveModeFPSHwcTrace; - std::string mRenderFrameRateFPSTrace; + std::string mPendingModeFpsTrace; + std::string mActiveModeFpsTrace; + std::string mRenderRateFpsTrace; const ui::Rotation mPhysicalOrientation; ui::Rotation mOrientation = ui::ROTATION_0; @@ -319,11 +315,11 @@ private: // This parameter is only used for hdr/sdr ratio overlay float mHdrSdrRatio = 1.0f; - mutable std::mutex mActiveModeLock; - ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock); - TracedOrdinal<bool> mDesiredActiveModeChanged GUARDED_BY(mActiveModeLock); + mutable std::mutex mDesiredModeLock; + ActiveModeInfo mDesiredMode GUARDED_BY(mDesiredModeLock); + TracedOrdinal<bool> mDesiredModeChanged GUARDED_BY(mDesiredModeLock); - ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext); + ActiveModeInfo mPendingMode GUARDED_BY(kMainThreadContext); bool mIsModeSetPending GUARDED_BY(kMainThreadContext) = false; }; diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 2d957e6334..cc2f6c7cb3 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -1575,8 +1575,7 @@ void AidlComposer::onHotplugDisconnect(Display display) { } bool AidlComposer::hasMultiThreadedPresentSupport(Display display) { -#if 0 - // TODO (b/259132483): Reenable + if (!FlagManager::getInstance().multithreaded_present()) return false; const auto displayId = translate<int64_t>(display); std::vector<AidlDisplayCapability> capabilities; const auto status = mAidlComposerClient->getDisplayCapabilities(displayId, &capabilities); @@ -1586,10 +1585,6 @@ bool AidlComposer::hasMultiThreadedPresentSupport(Display display) { } return std::find(capabilities.begin(), capabilities.end(), AidlDisplayCapability::MULTI_THREADED_PRESENT) != capabilities.end(); -#else - (void) display; - return false; -#endif } void AidlComposer::addReader(Display display) { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 9aaaa95a66..26c0d67af9 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -945,6 +945,10 @@ status_t HWComposer::notifyExpectedPresentIfRequired(PhysicalDisplayId displayId std::optional<Period> timeoutOpt) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); auto& displayData = mDisplayData[displayId]; + if (!displayData.hwcDisplay) { + // Display setup has not completed yet + return BAD_INDEX; + } { std::scoped_lock lock{displayData.expectedPresentLock}; const auto lastExpectedPresentTimestamp = displayData.lastExpectedPresentTimestamp; diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp index a826ec18a1..0983e7c1ac 100644 --- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp +++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp @@ -433,4 +433,15 @@ void LayerLifecycleManager::updateDisplayMirrorLayers(RequestedLayerState& rootL } } +bool LayerLifecycleManager::isLayerSecure(uint32_t layerId) const { + if (layerId == UNASSIGNED_LAYER_ID) { + return false; + } + + if (getLayerFromId(layerId)->flags & layer_state_t::eLayerSecure) { + return true; + } + return isLayerSecure(getLayerFromId(layerId)->parentId); +} + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h index 9aff78e463..330da9a3d3 100644 --- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h +++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h @@ -80,6 +80,7 @@ public: const std::vector<RequestedLayerState*>& getChangedLayers() const; const ftl::Flags<RequestedLayerState::Changes> getGlobalChanges() const; const RequestedLayerState* getLayerFromId(uint32_t) const; + bool isLayerSecure(uint32_t) const; private: friend class LayerLifecycleManagerTest; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 9476ff4932..743cbf3cb1 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -365,7 +365,7 @@ LayerSnapshot LayerSnapshotBuilder::getRootSnapshot() { return snapshot; } -LayerSnapshotBuilder::LayerSnapshotBuilder() : mRootSnapshot(getRootSnapshot()) {} +LayerSnapshotBuilder::LayerSnapshotBuilder() {} LayerSnapshotBuilder::LayerSnapshotBuilder(Args args) : LayerSnapshotBuilder() { args.forceUpdate = ForceUpdateFlags::ALL; @@ -417,19 +417,20 @@ bool LayerSnapshotBuilder::tryFastUpdate(const Args& args) { void LayerSnapshotBuilder::updateSnapshots(const Args& args) { ATRACE_NAME("UpdateSnapshots"); + LayerSnapshot rootSnapshot = args.rootSnapshot; if (args.parentCrop) { - mRootSnapshot.geomLayerBounds = *args.parentCrop; + rootSnapshot.geomLayerBounds = *args.parentCrop; } else if (args.forceUpdate == ForceUpdateFlags::ALL || args.displayChanges) { - mRootSnapshot.geomLayerBounds = getMaxDisplayBounds(args.displays); + rootSnapshot.geomLayerBounds = getMaxDisplayBounds(args.displays); } if (args.displayChanges) { - mRootSnapshot.changes = RequestedLayerState::Changes::AffectsChildren | + rootSnapshot.changes = RequestedLayerState::Changes::AffectsChildren | RequestedLayerState::Changes::Geometry; } if (args.forceUpdate == ForceUpdateFlags::HIERARCHY) { - mRootSnapshot.changes |= + rootSnapshot.changes |= RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Visibility; - mRootSnapshot.clientChanges |= layer_state_t::eReparent; + rootSnapshot.clientChanges |= layer_state_t::eReparent; } for (auto& snapshot : mSnapshots) { @@ -444,13 +445,13 @@ void LayerSnapshotBuilder::updateSnapshots(const Args& args) { // multiple children. LayerHierarchy::ScopedAddToTraversalPath addChildToPath(root, args.root.getLayer()->id, LayerHierarchy::Variant::Attached); - updateSnapshotsInHierarchy(args, args.root, root, mRootSnapshot, /*depth=*/0); + updateSnapshotsInHierarchy(args, args.root, root, rootSnapshot, /*depth=*/0); } else { for (auto& [childHierarchy, variant] : args.root.mChildren) { LayerHierarchy::ScopedAddToTraversalPath addChildToPath(root, childHierarchy->getLayer()->id, variant); - updateSnapshotsInHierarchy(args, *childHierarchy, root, mRootSnapshot, /*depth=*/0); + updateSnapshotsInHierarchy(args, *childHierarchy, root, rootSnapshot, /*depth=*/0); } } @@ -459,7 +460,6 @@ void LayerSnapshotBuilder::updateSnapshots(const Args& args) { updateTouchableRegionCrop(args); const bool hasUnreachableSnapshots = sortSnapshotsByZ(args); - clearChanges(mRootSnapshot); // Destroy unreachable snapshots for clone layers. And destroy snapshots for non-clone // layers if the layer have been destroyed. diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h index 1506913e15..1cec0183b9 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h @@ -33,6 +33,9 @@ namespace android::surfaceflinger::frontend { // The builder also uses a fast path to update // snapshots when there are only buffer updates. class LayerSnapshotBuilder { +private: + static LayerSnapshot getRootSnapshot(); + public: enum class ForceUpdateFlags { NONE, @@ -55,6 +58,7 @@ public: const std::unordered_map<std::string, bool>& supportedLayerGenericMetadata; const std::unordered_map<std::string, uint32_t>& genericLayerMetadataKeyMap; bool skipRoundCornersWhenProtected = false; + LayerSnapshot rootSnapshot = getRootSnapshot(); }; LayerSnapshotBuilder(); @@ -87,7 +91,6 @@ public: private: friend class LayerSnapshotTest; - static LayerSnapshot getRootSnapshot(); // return true if we were able to successfully update the snapshots via // the fast path. @@ -130,7 +133,6 @@ private: std::unordered_set<LayerHierarchy::TraversalPath, LayerHierarchy::TraversalPathHash> mNeedsTouchableRegionCrop; std::vector<std::unique_ptr<LayerSnapshot>> mSnapshots; - LayerSnapshot mRootSnapshot; bool mResortSnapshots = false; int mNumInterestingSnapshots = 0; }; diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 0e49b754f5..b1a18aefb5 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -98,7 +98,6 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) z = 0; layerStack = ui::DEFAULT_LAYER_STACK; transformToDisplayInverse = false; - dataspace = ui::Dataspace::UNKNOWN; desiredHdrSdrRatio = 1.f; currentHdrSdrRatio = 1.f; dataspaceRequested = false; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 4c2da91afe..9195b57886 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1718,10 +1718,18 @@ void Layer::miniDump(std::string& result, const frontend::LayerSnapshot& snapsho StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f | ", crop.left, crop.top, crop.right, crop.bottom); const auto frameRate = snapshot.frameRate; + std::string frameRateStr; + if (frameRate.vote.rate.isValid()) { + StringAppendF(&frameRateStr, "%.2f", frameRate.vote.rate.getValue()); + } if (frameRate.vote.rate.isValid() || frameRate.vote.type != FrameRateCompatibility::Default) { - StringAppendF(&result, "%s %15s %17s", to_string(frameRate.vote.rate).c_str(), + StringAppendF(&result, "%6s %15s %17s", frameRateStr.c_str(), ftl::enum_string(frameRate.vote.type).c_str(), ftl::enum_string(frameRate.vote.seamlessness).c_str()); + } else if (frameRate.category != FrameRateCategory::Default) { + StringAppendF(&result, "%6s %15s %17s", frameRateStr.c_str(), + (std::string("Cat::") + ftl::enum_string(frameRate.category)).c_str(), + ftl::enum_string(frameRate.vote.seamlessness).c_str()); } else { result.append(41, ' '); } @@ -4326,7 +4334,6 @@ void Layer::updateSnapshot(bool updateGeometry) { prepareBasicGeometryCompositionState(); prepareGeometryCompositionState(); snapshot->roundedCorner = getRoundedCornerState(); - snapshot->stretchEffect = getStretchEffect(); snapshot->transformedBounds = mScreenBounds; if (mEffectiveShadowRadius > 0.f) { snapshot->shadowSettings = mFlinger->mDrawingState.globalShadowSettings; diff --git a/services/surfaceflinger/Scheduler/Android.bp b/services/surfaceflinger/Scheduler/Android.bp index 6d2586ae9c..d71484889d 100644 --- a/services/surfaceflinger/Scheduler/Android.bp +++ b/services/surfaceflinger/Scheduler/Android.bp @@ -21,6 +21,7 @@ cc_defaults { "libui", "libutils", ], + static_libs: ["libsurfaceflinger_common"], } cc_library_headers { @@ -61,5 +62,9 @@ cc_test { "libgmock", "libgtest", "libscheduler", + "libsurfaceflingerflags_test", + ], + shared_libs: [ + "server_configurable_flags", ], } diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index 47c8ef9f16..6a7063e40f 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -36,7 +36,6 @@ #include <scheduler/FrameRateMode.h> #include <utils/Trace.h> -#include "../SurfaceFlingerProperties.h" #include "RefreshRateSelector.h" #include <com_android_graphics_surfaceflinger_flags.h> @@ -971,17 +970,21 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme } ftl::Optional<FrameRateMode> RefreshRateSelector::onKernelTimerChanged( - std::optional<DisplayModeId> desiredActiveModeId, bool timerExpired) const { + ftl::Optional<DisplayModeId> desiredModeIdOpt, bool timerExpired) const { std::lock_guard lock(mLock); - const auto current = [&]() REQUIRES(mLock) -> FrameRateMode { - if (desiredActiveModeId) { - const auto& modePtr = mDisplayModes.get(*desiredActiveModeId)->get(); - return FrameRateMode{modePtr->getPeakFps(), ftl::as_non_null(modePtr)}; - } - - return getActiveModeLocked(); - }(); + const auto current = + desiredModeIdOpt + .and_then([this](DisplayModeId modeId) + REQUIRES(mLock) { return mDisplayModes.get(modeId); }) + .transform([](const DisplayModePtr& modePtr) { + return FrameRateMode{modePtr->getPeakFps(), ftl::as_non_null(modePtr)}; + }) + .or_else([this] { + ftl::FakeGuard guard(mLock); + return std::make_optional(getActiveModeLocked()); + }) + .value(); const DisplayModePtr& min = mMinRefreshRateModeIt->second; if (current.modePtr->getId() == min->getId()) { diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index 545b939b3d..40e9a8310f 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -16,9 +16,6 @@ #pragma once -#include <algorithm> -#include <numeric> -#include <set> #include <type_traits> #include <utility> #include <variant> @@ -258,9 +255,8 @@ public: mMaxRefreshRateModeIt->second->getPeakFps()}; } - ftl::Optional<FrameRateMode> onKernelTimerChanged( - std::optional<DisplayModeId> desiredActiveModeId, bool timerExpired) const - EXCLUDES(mLock); + ftl::Optional<FrameRateMode> onKernelTimerChanged(ftl::Optional<DisplayModeId> desiredModeIdOpt, + bool timerExpired) const EXCLUDES(mLock); void setActiveMode(DisplayModeId, Fps renderFrameRate) EXCLUDES(mLock); diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index b54f33451b..6437b4eb94 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -118,7 +118,7 @@ void Scheduler::setPacesetterDisplay(std::optional<PhysicalDisplayId> pacesetter void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) { auto schedulePtr = std::make_shared<VsyncSchedule>( - displayId, mFeatures, + selectorPtr->getActiveMode().modePtr, mFeatures, [this](PhysicalDisplayId id, bool enable) { onHardwareVsyncRequest(id, enable); }, mVsyncTrackerCallback); @@ -223,6 +223,19 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, mPacesetterFrameDurationFractionToSkip = 0.f; } + if (FlagManager::getInstance().vrr_config()) { + const auto minFramePeriod = pacesetterOpt->get().schedulePtr->minFramePeriod(); + const auto presentFenceForPastVsync = + pacesetterTargeter.target().presentFenceForPastVsync(minFramePeriod); + const auto lastConfirmedPresentTime = presentFenceForPastVsync->getSignalTime(); + if (lastConfirmedPresentTime != Fence::SIGNAL_TIME_PENDING && + lastConfirmedPresentTime != Fence::SIGNAL_TIME_INVALID) { + pacesetterOpt->get() + .schedulePtr->getTracker() + .onFrameBegin(expectedVsyncTime, TimePoint::fromNs(lastConfirmedPresentTime)); + } + } + const auto resultsPerDisplay = compositor.composite(pacesetterId, targeters); compositor.sample(); @@ -503,7 +516,7 @@ void Scheduler::resyncAllToHardwareVsync(bool allowToEnable) { } void Scheduler::resyncToHardwareVsyncLocked(PhysicalDisplayId id, bool allowToEnable, - std::optional<Fps> refreshRate) { + DisplayModePtr modePtr) { const auto displayOpt = mDisplays.get(id); if (!displayOpt) { ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str()); @@ -512,12 +525,12 @@ void Scheduler::resyncToHardwareVsyncLocked(PhysicalDisplayId id, bool allowToEn const Display& display = *displayOpt; if (display.schedulePtr->isHardwareVsyncAllowed(allowToEnable)) { - if (!refreshRate) { - refreshRate = display.selectorPtr->getActiveMode().modePtr->getVsyncRate(); + if (!modePtr) { + modePtr = display.selectorPtr->getActiveMode().modePtr.get(); } - if (refreshRate->isValid()) { + if (modePtr->getVsyncRate().isValid()) { constexpr bool kForce = false; - display.schedulePtr->startPeriodTransition(refreshRate->getPeriod(), kForce); + display.schedulePtr->onDisplayModeChanged(ftl::as_non_null(modePtr), kForce); } } } @@ -563,19 +576,7 @@ void Scheduler::setRenderRate(PhysicalDisplayId id, Fps renderFrameRate) { ALOGV("%s %s (%s)", __func__, to_string(mode.fps).c_str(), to_string(mode.modePtr->getVsyncRate()).c_str()); - display.schedulePtr->getTracker().setDisplayModeData( - {.renderRate = renderFrameRate, - .notifyExpectedPresentTimeoutOpt = getNotifyExpectedPresentTimeout(mode)}); -} - -std::optional<Period> Scheduler::getNotifyExpectedPresentTimeout(const FrameRateMode& mode) { - if (mode.modePtr->getVrrConfig() && mode.modePtr->getVrrConfig()->notifyExpectedPresentConfig) { - return Period::fromNs( - mode.modePtr->getVrrConfig() - ->notifyExpectedPresentConfig->notifyExpectedPresentTimeoutNs); - } else { - return std::nullopt; - } + display.schedulePtr->getTracker().setRenderRate(renderFrameRate); } void Scheduler::resync() { @@ -913,9 +914,9 @@ std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked( newVsyncSchedulePtr = pacesetter.schedulePtr; - const Fps refreshRate = pacesetter.selectorPtr->getActiveMode().modePtr->getVsyncRate(); constexpr bool kForce = true; - newVsyncSchedulePtr->startPeriodTransition(refreshRate.getPeriod(), kForce); + newVsyncSchedulePtr->onDisplayModeChanged(pacesetter.selectorPtr->getActiveMode().modePtr, + kForce); } return newVsyncSchedulePtr; } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index c78051a278..0615b31c10 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -210,13 +210,12 @@ public: // If allowToEnable is true, then hardware vsync will be turned on. // Otherwise, if hardware vsync is not already enabled then this method will // no-op. - // If refreshRate is nullopt, use the existing refresh rate of the display. + // If modePtr is nullopt, use the active display mode. void resyncToHardwareVsync(PhysicalDisplayId id, bool allowToEnable, - std::optional<Fps> refreshRate = std::nullopt) - EXCLUDES(mDisplayLock) { + DisplayModePtr modePtr = nullptr) EXCLUDES(mDisplayLock) { std::scoped_lock lock(mDisplayLock); ftl::FakeGuard guard(kMainThreadContext); - resyncToHardwareVsyncLocked(id, allowToEnable, refreshRate); + resyncToHardwareVsyncLocked(id, allowToEnable, modePtr); } void forceNextResync() { mLastResyncTime = 0; } @@ -354,7 +353,7 @@ private: void onHardwareVsyncRequest(PhysicalDisplayId, bool enable); void resyncToHardwareVsyncLocked(PhysicalDisplayId, bool allowToEnable, - std::optional<Fps> refreshRate = std::nullopt) + DisplayModePtr modePtr = nullptr) REQUIRES(kMainThreadContext, mDisplayLock); void resyncAllToHardwareVsync(bool allowToEnable) EXCLUDES(mDisplayLock); void setVsyncConfig(const VsyncConfig&, Period vsyncPeriod); @@ -431,9 +430,6 @@ private: Period getVsyncPeriod(uid_t) override EXCLUDES(mDisplayLock); void resync() override EXCLUDES(mDisplayLock); - std::optional<Period> getNotifyExpectedPresentTimeout(const FrameRateMode&) - REQUIRES(mDisplayLock); - // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection. struct Connection { sp<EventThreadConnection> connection; diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index f5f93ce2f1..7379a4605d 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -47,16 +47,16 @@ static auto constexpr kMaxPercent = 100u; VSyncPredictor::~VSyncPredictor() = default; -VSyncPredictor::VSyncPredictor(PhysicalDisplayId id, nsecs_t idealPeriod, size_t historySize, +VSyncPredictor::VSyncPredictor(ftl::NonNull<DisplayModePtr> modePtr, size_t historySize, size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent, IVsyncTrackerCallback& callback) - : mId(id), + : mId(modePtr->getPhysicalDisplayId()), mTraceOn(property_get_bool("debug.sf.vsp_trace", false)), kHistorySize(historySize), kMinimumSamplesForPrediction(minimumSamplesForPrediction), kOutlierTolerancePercent(std::min(outlierTolerancePercent, kMaxPercent)), mVsyncTrackerCallback(callback), - mIdealPeriod(idealPeriod) { + mDisplayModePtr(modePtr) { resetModel(); } @@ -74,13 +74,18 @@ inline size_t VSyncPredictor::next(size_t i) const { return (i + 1) % mTimestamps.size(); } +nsecs_t VSyncPredictor::idealPeriod() const { + return mDisplayModePtr->getVsyncRate().getPeriodNsecs(); +} + bool VSyncPredictor::validate(nsecs_t timestamp) const { if (mLastTimestampIndex < 0 || mTimestamps.empty()) { return true; } - auto const aValidTimestamp = mTimestamps[mLastTimestampIndex]; - auto const percent = (timestamp - aValidTimestamp) % mIdealPeriod * kMaxPercent / mIdealPeriod; + const auto aValidTimestamp = mTimestamps[mLastTimestampIndex]; + const auto percent = + (timestamp - aValidTimestamp) % idealPeriod() * kMaxPercent / idealPeriod(); if (percent >= kOutlierTolerancePercent && percent <= (kMaxPercent - kOutlierTolerancePercent)) { return false; @@ -90,7 +95,7 @@ bool VSyncPredictor::validate(nsecs_t timestamp) const { [timestamp](nsecs_t a, nsecs_t b) { return std::abs(timestamp - a) < std::abs(timestamp - b); }); - const auto distancePercent = std::abs(*iter - timestamp) * kMaxPercent / mIdealPeriod; + const auto distancePercent = std::abs(*iter - timestamp) * kMaxPercent / idealPeriod(); if (distancePercent < kOutlierTolerancePercent) { // duplicate timestamp return false; @@ -100,7 +105,24 @@ bool VSyncPredictor::validate(nsecs_t timestamp) const { nsecs_t VSyncPredictor::currentPeriod() const { std::lock_guard lock(mMutex); - return mRateMap.find(mIdealPeriod)->second.slope; + return mRateMap.find(idealPeriod())->second.slope; +} + +Period VSyncPredictor::minFramePeriod() const { + if (!FlagManager::getInstance().vrr_config()) { + return Period::fromNs(currentPeriod()); + } + + std::lock_guard lock(mMutex); + return minFramePeriodLocked(); +} + +Period VSyncPredictor::minFramePeriodLocked() const { + const auto idealPeakRefreshPeriod = mDisplayModePtr->getPeakFps().getPeriodNsecs(); + const auto numPeriods = static_cast<int>(std::round(static_cast<float>(idealPeakRefreshPeriod) / + static_cast<float>(idealPeriod()))); + const auto slope = mRateMap.find(idealPeriod())->second.slope; + return Period::fromNs(slope * numPeriods); } bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { @@ -137,7 +159,7 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { const size_t numSamples = mTimestamps.size(); if (numSamples < kMinimumSamplesForPrediction) { - mRateMap[mIdealPeriod] = {mIdealPeriod, 0}; + mRateMap[idealPeriod()] = {idealPeriod(), 0}; return true; } @@ -161,7 +183,7 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { // Normalizing to the oldest timestamp cuts down on error in calculating the intercept. const auto oldestTS = *std::min_element(mTimestamps.begin(), mTimestamps.end()); - auto it = mRateMap.find(mIdealPeriod); + auto it = mRateMap.find(idealPeriod()); auto const currentPeriod = it->second.slope; // The mean of the ordinals must be precise for the intercept calculation, so scale them up for @@ -199,7 +221,7 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { } if (CC_UNLIKELY(bottom == 0)) { - it->second = {mIdealPeriod, 0}; + it->second = {idealPeriod(), 0}; clearTimestamps(); return false; } @@ -207,9 +229,9 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { nsecs_t const anticipatedPeriod = top * kScalingFactor / bottom; nsecs_t const intercept = meanTS - (anticipatedPeriod * meanOrdinal / kScalingFactor); - auto const percent = std::abs(anticipatedPeriod - mIdealPeriod) * kMaxPercent / mIdealPeriod; + auto const percent = std::abs(anticipatedPeriod - idealPeriod()) * kMaxPercent / idealPeriod(); if (percent >= kOutlierTolerancePercent) { - it->second = {mIdealPeriod, 0}; + it->second = {idealPeriod(), 0}; clearTimestamps(); return false; } @@ -241,8 +263,8 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFromLocked(nsecs_t timePoint) co if (mTimestamps.empty()) { traceInt64("VSP-mode", 1); auto const knownTimestamp = mKnownTimestamp ? *mKnownTimestamp : timePoint; - auto const numPeriodsOut = ((timePoint - knownTimestamp) / mIdealPeriod) + 1; - return knownTimestamp + numPeriodsOut * mIdealPeriod; + auto const numPeriodsOut = ((timePoint - knownTimestamp) / idealPeriod()) + 1; + return knownTimestamp + numPeriodsOut * idealPeriod(); } auto const oldest = *std::min_element(mTimestamps.begin(), mTimestamps.end()); @@ -278,27 +300,32 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { mLastVsyncSequence = getVsyncSequenceLocked(timePoint); const auto renderRatePhase = [&]() REQUIRES(mMutex) -> int { - if (!mDisplayModeDataOpt) return 0; - + if (!mRenderRateOpt) return 0; const auto divisor = - RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod), - mDisplayModeDataOpt->renderRate); + RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(idealPeriod()), + *mRenderRateOpt); if (divisor <= 1) return 0; - const int mod = mLastVsyncSequence->seq % divisor; + int mod = mLastVsyncSequence->seq % divisor; if (mod == 0) return 0; + // This is actually a bug fix, but guarded with vrr_config since we found it with this + // config + if (FlagManager::getInstance().vrr_config()) { + if (mod < 0) mod += divisor; + } + return divisor - mod; }(); if (renderRatePhase == 0) { const auto vsyncTime = mLastVsyncSequence->vsyncTime; - if (FlagManager::getInstance().vrr_config() && mDisplayModeDataOpt) { + if (FlagManager::getInstance().vrr_config()) { const auto vsyncTimePoint = TimePoint::fromNs(vsyncTime); ATRACE_FORMAT("%s InPhase vsyncIn %.2fms", __func__, ticks<std::milli, float>(vsyncTimePoint - TimePoint::now())); - mVsyncTrackerCallback.onVsyncGenerated(mId, vsyncTimePoint, *mDisplayModeDataOpt, - Period::fromNs(mIdealPeriod)); + const Fps renderRate = mRenderRateOpt ? *mRenderRateOpt : mDisplayModePtr->getPeakFps(); + mVsyncTrackerCallback.onVsyncGenerated(vsyncTimePoint, mDisplayModePtr, renderRate); } return vsyncTime; } @@ -307,12 +334,13 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { const auto approximateNextVsync = mLastVsyncSequence->vsyncTime + slope * renderRatePhase; const auto nextAnticipatedVsyncTime = nextAnticipatedVSyncTimeFromLocked(approximateNextVsync - slope / 2); - if (FlagManager::getInstance().vrr_config() && mDisplayModeDataOpt) { + if (FlagManager::getInstance().vrr_config()) { const auto nextAnticipatedVsyncTimePoint = TimePoint::fromNs(nextAnticipatedVsyncTime); ATRACE_FORMAT("%s outOfPhase vsyncIn %.2fms", __func__, ticks<std::milli, float>(nextAnticipatedVsyncTimePoint - TimePoint::now())); - mVsyncTrackerCallback.onVsyncGenerated(mId, nextAnticipatedVsyncTimePoint, - *mDisplayModeDataOpt, Period::fromNs(mIdealPeriod)); + const Fps renderRate = mRenderRateOpt ? *mRenderRateOpt : mDisplayModePtr->getPeakFps(); + mVsyncTrackerCallback.onVsyncGenerated(nextAnticipatedVsyncTimePoint, mDisplayModePtr, + renderRate); } return nextAnticipatedVsyncTime; } @@ -328,7 +356,8 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { bool VSyncPredictor::isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const { std::lock_guard lock(mMutex); const auto divisor = - RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod), frameRate); + RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(idealPeriod()), + frameRate); return isVSyncInPhaseLocked(timePoint, static_cast<unsigned>(divisor)); } @@ -344,7 +373,7 @@ bool VSyncPredictor::isVSyncInPhaseLocked(nsecs_t timePoint, unsigned divisor) c return true; } - const nsecs_t period = mRateMap[mIdealPeriod].slope; + const nsecs_t period = mRateMap[idealPeriod()].slope; const nsecs_t justBeforeTimePoint = timePoint - period / 2; const auto vsyncSequence = getVsyncSequenceLocked(justBeforeTimePoint); ATRACE_FORMAT_INSTANT("vsync in: %.2f sequence: %" PRId64, @@ -352,45 +381,139 @@ bool VSyncPredictor::isVSyncInPhaseLocked(nsecs_t timePoint, unsigned divisor) c return vsyncSequence.seq % divisor == 0; } -void VSyncPredictor::setDisplayModeData(const DisplayModeData& displayModeData) { - ALOGV("%s %s: RenderRate %s notifyExpectedPresentTimeout %s", __func__, to_string(mId).c_str(), - to_string(displayModeData.renderRate).c_str(), - displayModeData.notifyExpectedPresentTimeoutOpt - ? std::to_string(displayModeData.notifyExpectedPresentTimeoutOpt->ns()).c_str() - : "N/A"); +void VSyncPredictor::setRenderRate(Fps renderRate) { + ATRACE_FORMAT("%s %s", __func__, to_string(renderRate).c_str()); + ALOGV("%s %s: RenderRate %s ", __func__, to_string(mId).c_str(), to_string(renderRate).c_str()); std::lock_guard lock(mMutex); - mDisplayModeDataOpt = displayModeData; + mRenderRateOpt = renderRate; } -VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const { +void VSyncPredictor::setDisplayModePtr(ftl::NonNull<DisplayModePtr> modePtr) { + LOG_ALWAYS_FATAL_IF(mId != modePtr->getPhysicalDisplayId(), + "mode does not belong to the display"); + ATRACE_FORMAT("%s %s", __func__, to_string(*modePtr).c_str()); + const auto timeout = modePtr->getVrrConfig() + ? modePtr->getVrrConfig()->notifyExpectedPresentConfig + : std::nullopt; + ALOGV("%s %s: DisplayMode %s notifyExpectedPresentTimeout %s", __func__, to_string(mId).c_str(), + to_string(*modePtr).c_str(), + timeout ? std::to_string(timeout->notifyExpectedPresentTimeoutNs).c_str() : "N/A"); std::lock_guard lock(mMutex); - const auto model = VSyncPredictor::getVSyncPredictionModelLocked(); - return {model.slope, model.intercept}; -} -VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModelLocked() const { - return mRateMap.find(mIdealPeriod)->second; -} + mDisplayModePtr = modePtr; + traceInt64("VSP-setPeriod", modePtr->getVsyncRate().getPeriodNsecs()); -void VSyncPredictor::setPeriod(nsecs_t period) { - ATRACE_FORMAT("%s %s", __func__, to_string(mId).c_str()); - traceInt64("VSP-setPeriod", period); - - std::lock_guard lock(mMutex); static constexpr size_t kSizeLimit = 30; if (CC_UNLIKELY(mRateMap.size() == kSizeLimit)) { mRateMap.erase(mRateMap.begin()); } - // TODO(b/308610306) mIdealPeriod to be updated with setDisplayModeData - mIdealPeriod = period; - if (mRateMap.find(period) == mRateMap.end()) { - mRateMap[mIdealPeriod] = {period, 0}; + if (mRateMap.find(idealPeriod()) == mRateMap.end()) { + mRateMap[idealPeriod()] = {idealPeriod(), 0}; } clearTimestamps(); } +void VSyncPredictor::ensureMinFrameDurationIsKept(TimePoint expectedPresentTime, + TimePoint lastConfirmedPresentTime) { + const auto currentPeriod = mRateMap.find(idealPeriod())->second.slope; + const auto threshold = currentPeriod / 2; + const auto minFramePeriod = minFramePeriodLocked().ns(); + + auto prev = lastConfirmedPresentTime.ns(); + for (auto& current : mPastExpectedPresentTimes) { + if (CC_UNLIKELY(mTraceOn)) { + ATRACE_FORMAT_INSTANT("current %.2f past last signaled fence", + static_cast<float>(current.ns() - lastConfirmedPresentTime.ns()) / + 1e6f); + } + + const auto minPeriodViolation = current.ns() - prev + threshold < minFramePeriod; + if (minPeriodViolation) { + ATRACE_NAME("minPeriodViolation"); + current = TimePoint::fromNs(prev + minFramePeriod); + prev = current.ns(); + } else { + break; + } + } + + if (!mPastExpectedPresentTimes.empty()) { + const auto phase = Duration(mPastExpectedPresentTimes.back() - expectedPresentTime); + if (phase > 0ns) { + if (mLastVsyncSequence) { + mLastVsyncSequence->vsyncTime += phase.ns(); + } + } + } +} + +void VSyncPredictor::onFrameBegin(TimePoint expectedPresentTime, + TimePoint lastConfirmedPresentTime) { + ATRACE_CALL(); + std::lock_guard lock(mMutex); + + if (!mDisplayModePtr->getVrrConfig()) return; + + if (CC_UNLIKELY(mTraceOn)) { + ATRACE_FORMAT_INSTANT("vsync is %.2f past last signaled fence", + static_cast<float>(expectedPresentTime.ns() - + lastConfirmedPresentTime.ns()) / + 1e6f); + } + mPastExpectedPresentTimes.push_back(expectedPresentTime); + + const auto currentPeriod = mRateMap.find(idealPeriod())->second.slope; + const auto threshold = currentPeriod / 2; + + const auto minFramePeriod = minFramePeriodLocked().ns(); + while (!mPastExpectedPresentTimes.empty()) { + const auto front = mPastExpectedPresentTimes.front().ns(); + const bool frontIsLastConfirmed = + std::abs(front - lastConfirmedPresentTime.ns()) < threshold; + const bool frontIsBeforeConfirmed = + front < lastConfirmedPresentTime.ns() - minFramePeriod + threshold; + if (frontIsLastConfirmed || frontIsBeforeConfirmed) { + if (CC_UNLIKELY(mTraceOn)) { + ATRACE_FORMAT_INSTANT("Discarding old vsync - %.2f before last signaled fence", + static_cast<float>(lastConfirmedPresentTime.ns() - + mPastExpectedPresentTimes.front().ns()) / + 1e6f); + } + mPastExpectedPresentTimes.pop_front(); + } else { + break; + } + } + + ensureMinFrameDurationIsKept(expectedPresentTime, lastConfirmedPresentTime); +} + +void VSyncPredictor::onFrameMissed(TimePoint expectedPresentTime) { + ATRACE_CALL(); + + std::lock_guard lock(mMutex); + if (!mDisplayModePtr->getVrrConfig()) return; + + // We don't know when the frame is going to be presented, so we assume it missed one vsync + const auto currentPeriod = mRateMap.find(idealPeriod())->second.slope; + const auto lastConfirmedPresentTime = + TimePoint::fromNs(expectedPresentTime.ns() + currentPeriod); + + ensureMinFrameDurationIsKept(expectedPresentTime, lastConfirmedPresentTime); +} + +VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const { + std::lock_guard lock(mMutex); + const auto model = VSyncPredictor::getVSyncPredictionModelLocked(); + return {model.slope, model.intercept}; +} + +VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModelLocked() const { + return mRateMap.find(idealPeriod())->second; +} + void VSyncPredictor::clearTimestamps() { if (!mTimestamps.empty()) { auto const maxRb = *std::max_element(mTimestamps.begin(), mTimestamps.end()); @@ -412,18 +535,18 @@ bool VSyncPredictor::needsMoreSamples() const { void VSyncPredictor::resetModel() { std::lock_guard lock(mMutex); - mRateMap[mIdealPeriod] = {mIdealPeriod, 0}; + mRateMap[idealPeriod()] = {idealPeriod(), 0}; clearTimestamps(); } void VSyncPredictor::dump(std::string& result) const { std::lock_guard lock(mMutex); - StringAppendF(&result, "\tmIdealPeriod=%.2f\n", mIdealPeriod / 1e6f); + StringAppendF(&result, "\tmDisplayModePtr=%s\n", to_string(*mDisplayModePtr).c_str()); StringAppendF(&result, "\tRefresh Rate Map:\n"); - for (const auto& [idealPeriod, periodInterceptTuple] : mRateMap) { + for (const auto& [period, periodInterceptTuple] : mRateMap) { StringAppendF(&result, "\t\tFor ideal period %.2fms: period = %.2fms, intercept = %" PRId64 "\n", - idealPeriod / 1e6f, periodInterceptTuple.slope / 1e6f, + period / 1e6f, periodInterceptTuple.slope / 1e6f, periodInterceptTuple.intercept); } } diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h index c271eb738e..72a343112a 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.h +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h @@ -16,6 +16,7 @@ #pragma once +#include <deque> #include <mutex> #include <unordered_map> #include <vector> @@ -31,14 +32,14 @@ class VSyncPredictor : public VSyncTracker { public: /* * \param [in] PhysicalDisplayid The display this corresponds to. - * \param [in] idealPeriod The initial ideal period to use. + * \param [in] modePtr The initial display mode * \param [in] historySize The internal amount of entries to store in the model. * \param [in] minimumSamplesForPrediction The minimum number of samples to collect before * predicting. \param [in] outlierTolerancePercent a number 0 to 100 that will be used to filter * samples that fall outlierTolerancePercent from an anticipated vsync event. * \param [in] IVsyncTrackerCallback The callback for the VSyncTracker. */ - VSyncPredictor(PhysicalDisplayId, nsecs_t idealPeriod, size_t historySize, + VSyncPredictor(ftl::NonNull<DisplayModePtr> modePtr, size_t historySize, size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent, IVsyncTrackerCallback&); ~VSyncPredictor(); @@ -46,17 +47,9 @@ public: bool addVsyncTimestamp(nsecs_t timestamp) final EXCLUDES(mMutex); nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final EXCLUDES(mMutex); nsecs_t currentPeriod() const final EXCLUDES(mMutex); + Period minFramePeriod() const final EXCLUDES(mMutex); void resetModel() final EXCLUDES(mMutex); - /* - * Inform the model that the period is anticipated to change to a new value. - * model will use the period parameter to predict vsync events until enough - * timestamps with the new period have been collected. - * - * \param [in] period The new period that should be used. - */ - void setPeriod(nsecs_t period) final EXCLUDES(mMutex); - /* Query if the model is in need of more samples to make a prediction. * \return True, if model would benefit from more samples, False if not. */ @@ -71,7 +64,13 @@ public: bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const final EXCLUDES(mMutex); - void setDisplayModeData(const DisplayModeData&) final EXCLUDES(mMutex); + void setDisplayModePtr(ftl::NonNull<DisplayModePtr>) final EXCLUDES(mMutex); + + void setRenderRate(Fps) final EXCLUDES(mMutex); + + void onFrameBegin(TimePoint expectedPresentTime, TimePoint lastConfirmedPresentTime) final + EXCLUDES(mMutex); + void onFrameMissed(TimePoint expectedPresentTime) final EXCLUDES(mMutex); void dump(std::string& result) const final EXCLUDES(mMutex); @@ -90,12 +89,15 @@ private: Model getVSyncPredictionModelLocked() const REQUIRES(mMutex); nsecs_t nextAnticipatedVSyncTimeFromLocked(nsecs_t timePoint) const REQUIRES(mMutex); bool isVSyncInPhaseLocked(nsecs_t timePoint, unsigned divisor) const REQUIRES(mMutex); + Period minFramePeriodLocked() const REQUIRES(mMutex); + void ensureMinFrameDurationIsKept(TimePoint, TimePoint) REQUIRES(mMutex); struct VsyncSequence { nsecs_t vsyncTime; int64_t seq; }; VsyncSequence getVsyncSequenceLocked(nsecs_t timestamp) const REQUIRES(mMutex); + nsecs_t idealPeriod() const REQUIRES(mMutex); bool const mTraceOn; size_t const kHistorySize; @@ -104,7 +106,6 @@ private: IVsyncTrackerCallback& mVsyncTrackerCallback; std::mutex mutable mMutex; - nsecs_t mIdealPeriod GUARDED_BY(mMutex); std::optional<nsecs_t> mKnownTimestamp GUARDED_BY(mMutex); // Map between ideal vsync period and the calculated model @@ -113,9 +114,12 @@ private: size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0; std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex); - std::optional<DisplayModeData> mDisplayModeDataOpt GUARDED_BY(mMutex); + ftl::NonNull<DisplayModePtr> mDisplayModePtr GUARDED_BY(mMutex); + std::optional<Fps> mRenderRateOpt GUARDED_BY(mMutex); mutable std::optional<VsyncSequence> mLastVsyncSequence GUARDED_BY(mMutex); + + std::deque<TimePoint> mPastExpectedPresentTimes GUARDED_BY(mMutex); }; } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index 2938aa3fb3..24737e4fb2 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -116,32 +116,34 @@ void VSyncReactor::updateIgnorePresentFencesInternal() { } } -void VSyncReactor::startPeriodTransitionInternal(nsecs_t newPeriod) { +void VSyncReactor::startPeriodTransitionInternal(ftl::NonNull<DisplayModePtr> modePtr) { ATRACE_FORMAT("%s %" PRIu64, __func__, mId.value); mPeriodConfirmationInProgress = true; - mPeriodTransitioningTo = newPeriod; + mModePtrTransitioningTo = modePtr.get(); mMoreSamplesNeeded = true; setIgnorePresentFencesInternal(true); } void VSyncReactor::endPeriodTransition() { ATRACE_FORMAT("%s %" PRIu64, __func__, mId.value); - mPeriodTransitioningTo.reset(); + mModePtrTransitioningTo.reset(); mPeriodConfirmationInProgress = false; mLastHwVsync.reset(); } -void VSyncReactor::startPeriodTransition(nsecs_t period, bool force) { - ATRACE_INT64(ftl::Concat("VSR-", __func__, " ", mId.value).c_str(), period); +void VSyncReactor::onDisplayModeChanged(ftl::NonNull<DisplayModePtr> modePtr, bool force) { + ATRACE_INT64(ftl::Concat("VSR-", __func__, " ", mId.value).c_str(), + modePtr->getVsyncRate().getPeriodNsecs()); std::lock_guard lock(mMutex); mLastHwVsync.reset(); - if (!mSupportKernelIdleTimer && period == mTracker.currentPeriod() && !force) { + if (!mSupportKernelIdleTimer && + modePtr->getVsyncRate().getPeriodNsecs() == mTracker.currentPeriod() && !force) { endPeriodTransition(); setIgnorePresentFencesInternal(false); mMoreSamplesNeeded = false; } else { - startPeriodTransitionInternal(period); + startPeriodTransitionInternal(modePtr); } } @@ -159,14 +161,16 @@ bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp, std::optional<nsecs_ return false; } - const bool periodIsChanging = - mPeriodTransitioningTo && (*mPeriodTransitioningTo != mTracker.currentPeriod()); + const std::optional<Period> newPeriod = mModePtrTransitioningTo + ? mModePtrTransitioningTo->getVsyncRate().getPeriod() + : std::optional<Period>{}; + const bool periodIsChanging = newPeriod && (newPeriod->ns() != mTracker.currentPeriod()); if (mSupportKernelIdleTimer && !periodIsChanging) { // Clear out the Composer-provided period and use the allowance logic below HwcVsyncPeriod = {}; } - auto const period = mPeriodTransitioningTo ? *mPeriodTransitioningTo : mTracker.currentPeriod(); + auto const period = newPeriod ? newPeriod->ns() : mTracker.currentPeriod(); static constexpr int allowancePercent = 10; static constexpr std::ratio<allowancePercent, 100> allowancePercentRatio; auto const allowance = period * allowancePercentRatio.num / allowancePercentRatio.den; @@ -185,8 +189,8 @@ bool VSyncReactor::addHwVsyncTimestamp(nsecs_t timestamp, std::optional<nsecs_t> std::lock_guard lock(mMutex); if (periodConfirmed(timestamp, hwcVsyncPeriod)) { ATRACE_FORMAT("VSR %" PRIu64 ": period confirmed", mId.value); - if (mPeriodTransitioningTo) { - mTracker.setPeriod(*mPeriodTransitioningTo); + if (mModePtrTransitioningTo) { + mTracker.setDisplayModePtr(ftl::as_non_null(mModePtrTransitioningTo)); *periodFlushed = true; } @@ -228,10 +232,11 @@ void VSyncReactor::dump(std::string& result) const { mInternalIgnoreFences, mExternalIgnoreFences); StringAppendF(&result, "mMoreSamplesNeeded=%d mPeriodConfirmationInProgress=%d\n", mMoreSamplesNeeded, mPeriodConfirmationInProgress); - if (mPeriodTransitioningTo) { - StringAppendF(&result, "mPeriodTransitioningTo=%" PRId64 "\n", *mPeriodTransitioningTo); + if (mModePtrTransitioningTo) { + StringAppendF(&result, "mModePtrTransitioningTo=%s\n", + to_string(*mModePtrTransitioningTo).c_str()); } else { - StringAppendF(&result, "mPeriodTransitioningTo=nullptr\n"); + StringAppendF(&result, "mModePtrTransitioningTo=nullptr\n"); } if (mLastHwVsync) { diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index f2302422ad..2415a66a64 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -27,6 +27,7 @@ #include <scheduler/TimeKeeper.h> +#include "VSyncTracker.h" #include "VsyncController.h" namespace android::scheduler { @@ -45,7 +46,7 @@ public: bool addPresentFence(std::shared_ptr<FenceTime>) final; void setIgnorePresentFences(bool ignore) final; - void startPeriodTransition(nsecs_t period, bool force) final; + void onDisplayModeChanged(ftl::NonNull<DisplayModePtr>, bool force) final; bool addHwVsyncTimestamp(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod, bool* periodFlushed) final; @@ -57,7 +58,7 @@ public: private: void setIgnorePresentFencesInternal(bool ignore) REQUIRES(mMutex); void updateIgnorePresentFencesInternal() REQUIRES(mMutex); - void startPeriodTransitionInternal(nsecs_t newPeriod) REQUIRES(mMutex); + void startPeriodTransitionInternal(ftl::NonNull<DisplayModePtr>) REQUIRES(mMutex); void endPeriodTransition() REQUIRES(mMutex); bool periodConfirmed(nsecs_t vsync_timestamp, std::optional<nsecs_t> hwcVsyncPeriod) REQUIRES(mMutex); @@ -74,7 +75,7 @@ private: bool mMoreSamplesNeeded GUARDED_BY(mMutex) = false; bool mPeriodConfirmationInProgress GUARDED_BY(mMutex) = false; - std::optional<nsecs_t> mPeriodTransitioningTo GUARDED_BY(mMutex); + DisplayModePtr mModePtrTransitioningTo GUARDED_BY(mMutex); std::optional<nsecs_t> mLastHwVsync GUARDED_BY(mMutex); hal::PowerMode mDisplayPowerMode GUARDED_BY(mMutex) = hal::PowerMode::ON; diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h index 7eedc312e2..1ed863cf7d 100644 --- a/services/surfaceflinger/Scheduler/VSyncTracker.h +++ b/services/surfaceflinger/Scheduler/VSyncTracker.h @@ -20,25 +20,16 @@ #include <utils/Timers.h> #include <scheduler/Fps.h> +#include <scheduler/FrameRateMode.h> #include "VSyncDispatch.h" namespace android::scheduler { -struct DisplayModeData { - Fps renderRate; - std::optional<Period> notifyExpectedPresentTimeoutOpt; - - bool operator==(const DisplayModeData& other) const { - return isApproxEqual(renderRate, other.renderRate) && - notifyExpectedPresentTimeoutOpt == other.notifyExpectedPresentTimeoutOpt; - } -}; - struct IVsyncTrackerCallback { virtual ~IVsyncTrackerCallback() = default; - virtual void onVsyncGenerated(PhysicalDisplayId, TimePoint expectedPresentTime, - const DisplayModeData&, Period vsyncPeriod) = 0; + virtual void onVsyncGenerated(TimePoint expectedPresentTime, ftl::NonNull<DisplayModePtr>, + Fps renderRate) = 0; }; /* @@ -78,11 +69,9 @@ public: virtual nsecs_t currentPeriod() const = 0; /* - * Inform the tracker that the period is changing and the tracker needs to recalibrate itself. - * - * \param [in] period The period that the system is changing into. + * The minimal period frames can be displayed. */ - virtual void setPeriod(nsecs_t period) = 0; + virtual Period minFramePeriod() const = 0; /* Inform the tracker that the samples it has are not accurate for prediction. */ virtual void resetModel() = 0; @@ -98,20 +87,30 @@ public: virtual bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const = 0; /* - * Sets the metadata about the currently active display mode such as VRR - * timeout period, vsyncPeriod and framework property such as render rate. - * If the render rate is not a divisor of the period, the render rate is - * ignored until the period changes. + * Sets the active mode of the display which includes the vsync period and other VRR attributes. + * This will inform the tracker that the period is changing and the tracker needs to recalibrate + * itself. + * + * \param [in] DisplayModePtr The display mode the tracker will use. + */ + virtual void setDisplayModePtr(ftl::NonNull<DisplayModePtr>) = 0; + + /* + * Sets a render rate on the tracker. If the render rate is not a divisor + * of the period, the render rate is ignored until the period changes. * The tracker will continue to track the vsync timeline and expect it * to match the current period, however, nextAnticipatedVSyncTimeFrom will * return vsyncs according to the render rate set. Setting a render rate is useful * when a display is running at 120Hz but the render frame rate is 60Hz. - * When IVsyncTrackerCallback::onVsyncGenerated callback is made we will pass along - * the vsyncPeriod, render rate and timeoutNs. * - * \param [in] DisplayModeData The DisplayModeData the tracker will use. + * \param [in] Fps The render rate the tracker should operate at. */ - virtual void setDisplayModeData(const DisplayModeData&) = 0; + virtual void setRenderRate(Fps) = 0; + + virtual void onFrameBegin(TimePoint expectedPresentTime, + TimePoint lastConfirmedPresentTime) = 0; + + virtual void onFrameMissed(TimePoint expectedPresentTime) = 0; virtual void dump(std::string& result) const = 0; diff --git a/services/surfaceflinger/Scheduler/VsyncController.h b/services/surfaceflinger/Scheduler/VsyncController.h index 917789934a..807a7fba53 100644 --- a/services/surfaceflinger/Scheduler/VsyncController.h +++ b/services/surfaceflinger/Scheduler/VsyncController.h @@ -22,6 +22,7 @@ #include <DisplayHardware/HWComposer.h> #include <DisplayHardware/Hal.h> +#include <scheduler/FrameRateMode.h> #include <ui/FenceTime.h> #include <utils/Mutex.h> #include <utils/RefBase.h> @@ -59,13 +60,14 @@ public: bool* periodFlushed) = 0; /* - * Inform the controller that the period is changing and the controller needs to recalibrate - * itself. The controller will end the period transition internally. + * Inform the controller that the display mode is changing and the controller needs to + * recalibrate itself to the new vsync period. The controller will end the period transition + * internally. * - * \param [in] period The period that the system is changing into. + * \param [in] DisplayModePtr The new mode the display is changing to. * \param [in] force True to recalibrate even if period matches the existing period. */ - virtual void startPeriodTransition(nsecs_t period, bool force) = 0; + virtual void onDisplayModeChanged(ftl::NonNull<DisplayModePtr>, bool force) = 0; /* * Tells the tracker to stop using present fences to get a vsync signal. diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp index 5fb53f9e20..ff1c9e909a 100644 --- a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp @@ -16,6 +16,8 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include <common/FlagManager.h> + #include <ftl/fake_guard.h> #include <scheduler/Fps.h> #include <scheduler/Timer.h> @@ -53,14 +55,14 @@ private: VSyncCallbackRegistration mRegistration; }; -VsyncSchedule::VsyncSchedule(PhysicalDisplayId id, FeatureFlags features, +VsyncSchedule::VsyncSchedule(ftl::NonNull<DisplayModePtr> modePtr, FeatureFlags features, RequestHardwareVsync requestHardwareVsync, IVsyncTrackerCallback& callback) - : mId(id), + : mId(modePtr->getPhysicalDisplayId()), mRequestHardwareVsync(std::move(requestHardwareVsync)), - mTracker(createTracker(id, callback)), + mTracker(createTracker(modePtr, callback)), mDispatch(createDispatch(mTracker)), - mController(createController(id, *mTracker, features)), + mController(createController(modePtr->getPhysicalDisplayId(), *mTracker, features)), mTracer(features.test(Feature::kTracePredictedVsync) ? std::make_unique<PredictedVsyncTracer>(mDispatch) : nullptr) {} @@ -79,6 +81,13 @@ Period VsyncSchedule::period() const { return Period::fromNs(mTracker->currentPeriod()); } +Period VsyncSchedule::minFramePeriod() const { + if (FlagManager::getInstance().vrr_config()) { + return mTracker->minFramePeriod(); + } + return period(); +} + TimePoint VsyncSchedule::vsyncDeadlineAfter(TimePoint timePoint) const { return TimePoint::fromNs(mTracker->nextAnticipatedVSyncTimeFrom(timePoint.ns())); } @@ -101,17 +110,15 @@ void VsyncSchedule::dump(std::string& out) const { mDispatch->dump(out); } -VsyncSchedule::TrackerPtr VsyncSchedule::createTracker(PhysicalDisplayId id, +VsyncSchedule::TrackerPtr VsyncSchedule::createTracker(ftl::NonNull<DisplayModePtr> modePtr, IVsyncTrackerCallback& callback) { // TODO(b/144707443): Tune constants. - constexpr nsecs_t kInitialPeriod = (60_Hz).getPeriodNsecs(); constexpr size_t kHistorySize = 20; constexpr size_t kMinSamplesForPrediction = 6; constexpr uint32_t kDiscardOutlierPercent = 20; - return std::make_unique<VSyncPredictor>(id, kInitialPeriod, kHistorySize, - kMinSamplesForPrediction, kDiscardOutlierPercent, - callback); + return std::make_unique<VSyncPredictor>(modePtr, kHistorySize, kMinSamplesForPrediction, + kDiscardOutlierPercent, callback); } VsyncSchedule::DispatchPtr VsyncSchedule::createDispatch(TrackerPtr tracker) { @@ -140,9 +147,9 @@ VsyncSchedule::ControllerPtr VsyncSchedule::createController(PhysicalDisplayId i return reactor; } -void VsyncSchedule::startPeriodTransition(Period period, bool force) { +void VsyncSchedule::onDisplayModeChanged(ftl::NonNull<DisplayModePtr> modePtr, bool force) { std::lock_guard<std::mutex> lock(mHwVsyncLock); - mController->startPeriodTransition(period.ns(), force); + mController->onDisplayModeChanged(modePtr, force); enableHardwareVsyncLocked(); } diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h index ca61f875c3..722ea0b836 100644 --- a/services/surfaceflinger/Scheduler/VsyncSchedule.h +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h @@ -57,21 +57,23 @@ class VsyncSchedule final : public IVsyncSource { public: using RequestHardwareVsync = std::function<void(PhysicalDisplayId, bool enabled)>; - VsyncSchedule(PhysicalDisplayId, FeatureFlags, RequestHardwareVsync, IVsyncTrackerCallback&); + VsyncSchedule(ftl::NonNull<DisplayModePtr> modePtr, FeatureFlags, RequestHardwareVsync, + IVsyncTrackerCallback&); ~VsyncSchedule(); // IVsyncSource overrides: Period period() const override; TimePoint vsyncDeadlineAfter(TimePoint) const override; + Period minFramePeriod() const override; - // Inform the schedule that the period is changing and the schedule needs to recalibrate - // itself. The schedule will end the period transition internally. This will - // enable hardware VSYNCs in order to calibrate. + // Inform the schedule that the display mode changed the schedule needs to recalibrate + // itself to the new vsync period. The schedule will end the period transition internally. + // This will enable hardware VSYNCs in order to calibrate. // - // \param [in] period The period that the system is changing into. + // \param [in] DisplayModePtr The mode that the display is changing to. // \param [in] force True to force a transition even if it is not a // change. - void startPeriodTransition(Period period, bool force); + void onDisplayModeChanged(ftl::NonNull<DisplayModePtr>, bool force); // Pass a VSYNC sample to VsyncController. Return true if // VsyncController detected that the VSYNC period changed. Enable or disable @@ -125,7 +127,7 @@ private: friend class android::VsyncScheduleTest; friend class android::fuzz::SchedulerFuzzer; - static TrackerPtr createTracker(PhysicalDisplayId, IVsyncTrackerCallback&); + static TrackerPtr createTracker(ftl::NonNull<DisplayModePtr> modePtr, IVsyncTrackerCallback&); static DispatchPtr createDispatch(TrackerPtr); static ControllerPtr createController(PhysicalDisplayId, VsyncTracker&, FeatureFlags); diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h index ae74205720..70d4846070 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h @@ -50,11 +50,11 @@ public: TimePoint expectedPresentTime() const { return mExpectedPresentTime; } // The time of the VSYNC that preceded this frame. See `presentFenceForPastVsync` for details. - TimePoint pastVsyncTime(Period vsyncPeriod) const; + TimePoint pastVsyncTime(Period minFramePeriod) const; // Equivalent to `pastVsyncTime` unless running N VSYNCs ahead. - TimePoint previousFrameVsyncTime(Period vsyncPeriod) const { - return mExpectedPresentTime - vsyncPeriod; + TimePoint previousFrameVsyncTime(Period minFramePeriod) const { + return mExpectedPresentTime - minFramePeriod; } // The present fence for the frame that had targeted the most recent VSYNC before this frame. @@ -62,14 +62,14 @@ public: // VSYNC of at least one previous frame has not yet passed. In other words, this is NOT the // `presentFenceForPreviousFrame` if running N VSYNCs ahead, but the one that should have been // signaled by now (unless that frame missed). - const FenceTimePtr& presentFenceForPastVsync(Period vsyncPeriod) const; + const FenceTimePtr& presentFenceForPastVsync(Period minFramePeriod) const; // Equivalent to `presentFenceForPastVsync` unless running N VSYNCs ahead. const FenceTimePtr& presentFenceForPreviousFrame() const { return mPresentFences.front().fenceTime; } - bool wouldPresentEarly(Period vsyncPeriod) const; + bool wouldPresentEarly(Period minFramePeriod) const; bool isFramePending() const { return mFramePending; } bool didMissFrame() const { return mFrameMissed; } @@ -96,9 +96,9 @@ protected: private: template <int N> - inline bool targetsVsyncsAhead(Period vsyncPeriod) const { + inline bool targetsVsyncsAhead(Period minFramePeriod) const { static_assert(N > 1); - return expectedFrameDuration() > (N - 1) * vsyncPeriod; + return expectedFrameDuration() > (N - 1) * minFramePeriod; } }; diff --git a/services/surfaceflinger/Scheduler/include/scheduler/IVsyncSource.h b/services/surfaceflinger/Scheduler/include/scheduler/IVsyncSource.h index bb2de75ac4..0154060f36 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/IVsyncSource.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/IVsyncSource.h @@ -23,6 +23,7 @@ namespace android::scheduler { struct IVsyncSource { virtual Period period() const = 0; virtual TimePoint vsyncDeadlineAfter(TimePoint) const = 0; + virtual Period minFramePeriod() const = 0; protected: ~IVsyncSource() = default; diff --git a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp index 7a18654346..e80372be31 100644 --- a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp +++ b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp @@ -27,28 +27,28 @@ FrameTarget::FrameTarget(const std::string& displayLabel) mHwcFrameMissed("PrevHwcFrameMissed " + displayLabel, false), mGpuFrameMissed("PrevGpuFrameMissed " + displayLabel, false) {} -TimePoint FrameTarget::pastVsyncTime(Period vsyncPeriod) const { +TimePoint FrameTarget::pastVsyncTime(Period minFramePeriod) const { // TODO(b/267315508): Generalize to N VSYNCs. - const int shift = static_cast<int>(targetsVsyncsAhead<2>(vsyncPeriod)); - return mExpectedPresentTime - Period::fromNs(vsyncPeriod.ns() << shift); + const int shift = static_cast<int>(targetsVsyncsAhead<2>(minFramePeriod)); + return mExpectedPresentTime - Period::fromNs(minFramePeriod.ns() << shift); } -const FenceTimePtr& FrameTarget::presentFenceForPastVsync(Period vsyncPeriod) const { +const FenceTimePtr& FrameTarget::presentFenceForPastVsync(Period minFramePeriod) const { // TODO(b/267315508): Generalize to N VSYNCs. - const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(vsyncPeriod)); + const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(minFramePeriod)); return mPresentFences[i].fenceTime; } -bool FrameTarget::wouldPresentEarly(Period vsyncPeriod) const { +bool FrameTarget::wouldPresentEarly(Period minFramePeriod) const { // TODO(b/241285475): Since this is called during `composite`, the calls to `targetsVsyncsAhead` // should use `TimePoint::now()` in case of delays since `mFrameBeginTime`. // TODO(b/267315508): Generalize to N VSYNCs. - if (targetsVsyncsAhead<3>(vsyncPeriod)) { + if (targetsVsyncsAhead<3>(minFramePeriod)) { return true; } - const auto fence = presentFenceForPastVsync(vsyncPeriod); + const auto fence = presentFenceForPastVsync(minFramePeriod); return fence->isValid() && fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING; } @@ -68,6 +68,7 @@ void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& v mScheduledPresentTime = args.expectedVsyncTime; const Period vsyncPeriod = vsyncSource.period(); + const Period minFramePeriod = vsyncSource.minFramePeriod(); // Calculate the expected present time once and use the cached value throughout this frame to // make sure all layers are seeing this same value. @@ -85,7 +86,7 @@ void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& v ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()), mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)"); - const FenceTimePtr& pastPresentFence = presentFenceForPastVsync(vsyncPeriod); + const FenceTimePtr& pastPresentFence = presentFenceForPastVsync(minFramePeriod); // In cases where the present fence is about to fire, give it a small grace period instead of // giving up on the frame. diff --git a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp index 1e038d1753..c883385755 100644 --- a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp +++ b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp @@ -17,23 +17,29 @@ #include <ftl/optional.h> #include <gtest/gtest.h> +#include <common/test/FlagUtils.h> #include <scheduler/Fps.h> #include <scheduler/FrameTargeter.h> #include <scheduler/IVsyncSource.h> +#include <com_android_graphics_surfaceflinger_flags.h> + using namespace std::chrono_literals; namespace android::scheduler { namespace { struct VsyncSource final : IVsyncSource { - VsyncSource(Period period, TimePoint deadline) : vsyncPeriod(period), vsyncDeadline(deadline) {} + VsyncSource(Period period, Period minFramePeriod, TimePoint deadline) + : vsyncPeriod(period), framePeriod(minFramePeriod), vsyncDeadline(deadline) {} const Period vsyncPeriod; + const Period framePeriod; const TimePoint vsyncDeadline; Period period() const override { return vsyncPeriod; } TimePoint vsyncDeadlineAfter(TimePoint) const override { return vsyncDeadline; } + Period minFramePeriod() const override { return framePeriod; } }; } // namespace @@ -44,10 +50,13 @@ public: struct Frame { Frame(FrameTargeterTest* testPtr, VsyncId vsyncId, TimePoint& frameBeginTime, - Duration frameDuration, Fps refreshRate, + Duration frameDuration, Fps refreshRate, Fps peakRefreshRate, FrameTargeter::IsFencePendingFuncPtr isFencePendingFuncPtr = Frame::fenceSignaled, const ftl::Optional<VsyncSource>& vsyncSourceOpt = std::nullopt) - : testPtr(testPtr), frameBeginTime(frameBeginTime), period(refreshRate.getPeriod()) { + : testPtr(testPtr), + frameBeginTime(frameBeginTime), + period(refreshRate.getPeriod()), + minFramePeriod(peakRefreshRate.getPeriod()) { const FrameTargeter::BeginFrameArgs args{.frameBeginTime = frameBeginTime, .vsyncId = vsyncId, .expectedVsyncTime = @@ -58,7 +67,7 @@ public: vsyncSourceOpt .or_else([&] { return std::make_optional( - VsyncSource(period, + VsyncSource(period, period, args.expectedVsyncTime)); }) .value(), @@ -88,6 +97,7 @@ public: TimePoint& frameBeginTime; const Period period; + const Period minFramePeriod; bool ended = false; }; @@ -103,7 +113,7 @@ TEST_F(FrameTargeterTest, targetsFrames) { VsyncId vsyncId{42}; { TimePoint frameBeginTime(989ms); - const Frame frame(this, vsyncId++, frameBeginTime, 10ms, 60_Hz); + const Frame frame(this, vsyncId++, frameBeginTime, 10ms, 60_Hz, 60_Hz); EXPECT_EQ(target().vsyncId(), VsyncId{42}); EXPECT_EQ(target().frameBeginTime(), TimePoint(989ms)); @@ -112,7 +122,7 @@ TEST_F(FrameTargeterTest, targetsFrames) { } { TimePoint frameBeginTime(1100ms); - const Frame frame(this, vsyncId++, frameBeginTime, 11ms, 60_Hz); + const Frame frame(this, vsyncId++, frameBeginTime, 11ms, 60_Hz, 60_Hz); EXPECT_EQ(target().vsyncId(), VsyncId{43}); EXPECT_EQ(target().frameBeginTime(), TimePoint(1100ms)); @@ -127,9 +137,10 @@ TEST_F(FrameTargeterTest, inflatesExpectedPresentTime) { TimePoint frameBeginTime(777ms); constexpr Fps kRefreshRate = 120_Hz; - const VsyncSource vsyncSource(kRefreshRate.getPeriod(), frameBeginTime + 5ms); + const VsyncSource vsyncSource(kRefreshRate.getPeriod(), kRefreshRate.getPeriod(), + frameBeginTime + 5ms); const Frame frame(this, VsyncId{123}, frameBeginTime, kFrameDuration, kRefreshRate, - Frame::fenceSignaled, vsyncSource); + kRefreshRate, Frame::fenceSignaled, vsyncSource); EXPECT_EQ(target().expectedPresentTime(), vsyncSource.vsyncDeadline + vsyncSource.vsyncPeriod); } @@ -142,7 +153,7 @@ TEST_F(FrameTargeterTest, recallsPastVsync) { constexpr Duration kFrameDuration = 13ms; for (int n = 5; n-- > 0;) { - Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate); + Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate); const auto fence = frame.end(); EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - kPeriod); @@ -160,7 +171,31 @@ TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAhead) { FenceTimePtr previousFence = FenceTime::NO_FENCE; for (int n = 5; n-- > 0;) { - Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate); + Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate); + const auto fence = frame.end(); + + EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod); + EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), previousFence); + + previousFence = fence; + } +} + +TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAheadVrr) { + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::vrr_config, true); + + VsyncId vsyncId{222}; + TimePoint frameBeginTime(2000ms); + constexpr Fps kRefreshRate = 120_Hz; + constexpr Fps kPeakRefreshRate = 240_Hz; + constexpr Period kPeriod = kRefreshRate.getPeriod(); + constexpr Duration kFrameDuration = 10ms; + + FenceTimePtr previousFence = FenceTime::NO_FENCE; + + for (int n = 5; n-- > 0;) { + Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, + kPeakRefreshRate); const auto fence = frame.end(); EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod); @@ -184,12 +219,12 @@ TEST_F(FrameTargeterTest, detectsEarlyPresent) { // The target is not early while past present fences are pending. for (int n = 3; n-- > 0;) { - const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate); + const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); EXPECT_FALSE(target().wouldPresentEarly(kPeriod)); } // The target is early if the past present fence was signaled. - Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate); + Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); const auto fence = frame.end(); fence->signalForTest(frameBeginTime.ns()); @@ -204,18 +239,18 @@ TEST_F(FrameTargeterTest, detectsEarlyPresentTwoVsyncsAhead) { // The target is not early while past present fences are pending. for (int n = 3; n-- > 0;) { - const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate); + const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); EXPECT_FALSE(target().wouldPresentEarly(kPeriod)); } - Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate); + Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); const auto fence = frame.end(); fence->signalForTest(frameBeginTime.ns()); // The target is two VSYNCs ahead, so the past present fence is still pending. EXPECT_FALSE(target().wouldPresentEarly(kPeriod)); - { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate); } + { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); } // The target is early if the past present fence was signaled. EXPECT_TRUE(target().wouldPresentEarly(kPeriod)); @@ -226,7 +261,7 @@ TEST_F(FrameTargeterTest, detectsEarlyPresentThreeVsyncsAhead) { constexpr Fps kRefreshRate = 144_Hz; constexpr Period kPeriod = kRefreshRate.getPeriod(); - const Frame frame(this, VsyncId{555}, frameBeginTime, 16ms, kRefreshRate); + const Frame frame(this, VsyncId{555}, frameBeginTime, 16ms, kRefreshRate, kRefreshRate); // The target is more than two VSYNCs ahead, but present fences are not tracked that far back. EXPECT_TRUE(target().wouldPresentEarly(kPeriod)); @@ -243,7 +278,7 @@ TEST_F(FrameTargeterTest, detectsMissedFrames) { EXPECT_FALSE(target().didMissHwcFrame()); { - const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate); + const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); EXPECT_FALSE(target().isFramePending()); // The frame did not miss if the past present fence is invalid. @@ -251,7 +286,8 @@ TEST_F(FrameTargeterTest, detectsMissedFrames) { EXPECT_FALSE(target().didMissHwcFrame()); } { - Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, Frame::fencePending); + Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate, + Frame::fencePending); EXPECT_TRUE(target().isFramePending()); // The frame missed if the past present fence is pending. @@ -261,7 +297,8 @@ TEST_F(FrameTargeterTest, detectsMissedFrames) { frame.end(CompositionCoverage::Gpu); } { - const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, Frame::fencePending); + const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate, + Frame::fencePending); EXPECT_TRUE(target().isFramePending()); // The GPU frame missed if the past present fence is pending. @@ -269,7 +306,7 @@ TEST_F(FrameTargeterTest, detectsMissedFrames) { EXPECT_FALSE(target().didMissHwcFrame()); } { - Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate); + Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); EXPECT_FALSE(target().isFramePending()); const auto fence = frame.end(); @@ -277,7 +314,7 @@ TEST_F(FrameTargeterTest, detectsMissedFrames) { fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2 + 1); } { - Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate); + Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); EXPECT_FALSE(target().isFramePending()); const auto fence = frame.end(); @@ -289,7 +326,7 @@ TEST_F(FrameTargeterTest, detectsMissedFrames) { EXPECT_TRUE(target().didMissHwcFrame()); } { - Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate); + Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); EXPECT_FALSE(target().isFramePending()); // The frame did not miss if the past present fence was signaled within slop. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 644b6ef30e..6e6229ac4c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1177,7 +1177,7 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& displayToken, return NO_ERROR; } -void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request, bool force) { +void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& request, bool force) { const auto displayId = request.mode.modePtr->getPhysicalDisplayId(); ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str()); @@ -1190,10 +1190,9 @@ void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request, const auto mode = request.mode; const bool emitEvent = request.emitEvent; - switch (display->setDesiredActiveMode(DisplayDevice::ActiveModeInfo(std::move(request)), - force)) { - case DisplayDevice::DesiredActiveModeAction::InitiateDisplayModeSwitch: - // Set the render rate as setDesiredActiveMode updated it. + switch (display->setDesiredMode(DisplayDevice::ActiveModeInfo(std::move(request)), force)) { + case DisplayDevice::DesiredModeAction::InitiateDisplayModeSwitch: + // DisplayDevice::setDesiredMode updated the render rate, so inform Scheduler. mScheduler->setRenderRate(displayId, display->refreshRateSelector().getActiveMode().fps); @@ -1203,7 +1202,7 @@ void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request, // Start receiving vsync samples now, so that we can detect a period // switch. mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */, - mode.modePtr->getVsyncRate()); + mode.modePtr.get()); // As we called to set period, we will call to onRefreshRateChangeCompleted once // VsyncController model is locked. @@ -1215,7 +1214,7 @@ void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request, mScheduler->setModeChangePending(true); break; - case DisplayDevice::DesiredActiveModeAction::InitiateRenderRateSwitch: + case DisplayDevice::DesiredModeAction::InitiateRenderRateSwitch: mScheduler->setRenderRate(displayId, mode.fps); if (displayId == mActiveDisplayId) { @@ -1227,7 +1226,7 @@ void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request, dispatchDisplayModeChangeEvent(displayId, mode); } break; - case DisplayDevice::DesiredActiveModeAction::None: + case DisplayDevice::DesiredModeAction::None: break; } } @@ -1287,27 +1286,27 @@ void SurfaceFlinger::finalizeDisplayModeChange(DisplayDevice& display) { const auto displayId = display.getPhysicalId(); ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str()); - const auto upcomingModeInfo = display.getUpcomingActiveMode(); - if (!upcomingModeInfo.modeOpt) { + const auto pendingMode = display.getPendingMode(); + if (!pendingMode.modeOpt) { // There is no pending mode change. This can happen if the active // display changed and the mode change happened on a different display. return; } if (display.getActiveMode().modePtr->getResolution() != - upcomingModeInfo.modeOpt->modePtr->getResolution()) { + pendingMode.modeOpt->modePtr->getResolution()) { auto& state = mCurrentState.displays.editValueFor(display.getDisplayToken()); // We need to generate new sequenceId in order to recreate the display (and this // way the framebuffer). state.sequenceId = DisplayDeviceState{}.sequenceId; - state.physical->activeMode = upcomingModeInfo.modeOpt->modePtr.get(); + state.physical->activeMode = pendingMode.modeOpt->modePtr.get(); processDisplayChangesLocked(); // processDisplayChangesLocked will update all necessary components so we're done here. return; } - const auto& activeMode = *upcomingModeInfo.modeOpt; + const auto& activeMode = *pendingMode.modeOpt; display.finalizeModeChange(activeMode.modePtr->getId(), activeMode.modePtr->getVsyncRate(), activeMode.fps); @@ -1316,27 +1315,26 @@ void SurfaceFlinger::finalizeDisplayModeChange(DisplayDevice& display) { updatePhaseConfiguration(activeMode.fps); } - if (upcomingModeInfo.event != scheduler::DisplayModeEvent::None) { + if (pendingMode.event != scheduler::DisplayModeEvent::None) { dispatchDisplayModeChangeEvent(displayId, activeMode); } } -void SurfaceFlinger::clearDesiredActiveModeState(const sp<DisplayDevice>& display) { - display->clearDesiredActiveModeState(); +void SurfaceFlinger::dropModeRequest(const sp<DisplayDevice>& display) { + display->clearDesiredMode(); if (display->getPhysicalId() == mActiveDisplayId) { // TODO(b/255635711): Check for pending mode changes on other displays. mScheduler->setModeChangePending(false); } } -void SurfaceFlinger::desiredActiveModeChangeDone(const sp<DisplayDevice>& display) { - const auto desiredActiveMode = display->getDesiredActiveMode(); - const auto& modeOpt = desiredActiveMode->modeOpt; +void SurfaceFlinger::applyActiveMode(const sp<DisplayDevice>& display) { + const auto desiredModeOpt = display->getDesiredMode(); + const auto& modeOpt = desiredModeOpt->modeOpt; const auto displayId = modeOpt->modePtr->getPhysicalDisplayId(); - const auto vsyncRate = modeOpt->modePtr->getVsyncRate(); const auto renderFps = modeOpt->fps; - clearDesiredActiveModeState(display); - mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */, vsyncRate); + dropModeRequest(display); + mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */, modeOpt->modePtr.get()); mScheduler->setRenderRate(displayId, renderFps); if (displayId == mActiveDisplayId) { @@ -1353,25 +1351,23 @@ void SurfaceFlinger::initiateDisplayModeChanges() { const auto display = getDisplayDeviceLocked(id); if (!display) continue; - // Store the local variable to release the lock. - const auto desiredActiveMode = display->getDesiredActiveMode(); - if (!desiredActiveMode) { - // No desired active mode pending to be applied. + const auto desiredModeOpt = display->getDesiredMode(); + if (!desiredModeOpt) { continue; } if (!shouldApplyRefreshRateSelectorPolicy(*display)) { - clearDesiredActiveModeState(display); + dropModeRequest(display); continue; } - const auto desiredModeId = desiredActiveMode->modeOpt->modePtr->getId(); + const auto desiredModeId = desiredModeOpt->modeOpt->modePtr->getId(); const auto displayModePtrOpt = physical.snapshot().displayModes().get(desiredModeId); if (!displayModePtrOpt) { ALOGW("Desired display mode is no longer supported. Mode ID = %d", desiredModeId.value()); - clearDesiredActiveModeState(display); + dropModeRequest(display); continue; } @@ -1379,9 +1375,8 @@ void SurfaceFlinger::initiateDisplayModeChanges() { to_string(displayModePtrOpt->get()->getVsyncRate()).c_str(), to_string(display->getId()).c_str()); - if (display->getActiveMode() == desiredActiveMode->modeOpt) { - // we are already in the requested mode, there is nothing left to do - desiredActiveModeChangeDone(display); + if (display->getActiveMode() == desiredModeOpt->modeOpt) { + applyActiveMode(display); continue; } @@ -1389,9 +1384,9 @@ void SurfaceFlinger::initiateDisplayModeChanges() { // allowed modes might have changed by the time we process the refresh. // Make sure the desired mode is still allowed const auto displayModeAllowed = - display->refreshRateSelector().isModeAllowed(*desiredActiveMode->modeOpt); + display->refreshRateSelector().isModeAllowed(*desiredModeOpt->modeOpt); if (!displayModeAllowed) { - clearDesiredActiveModeState(display); + dropModeRequest(display); continue; } @@ -1401,13 +1396,7 @@ void SurfaceFlinger::initiateDisplayModeChanges() { constraints.seamlessRequired = false; hal::VsyncPeriodChangeTimeline outTimeline; - const auto status = - display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline); - - if (status != NO_ERROR) { - // initiateModeChange may fail if a hotplug event is just about - // to be sent. We just log the error in this case. - ALOGW("initiateModeChange failed: %d", status); + if (!display->initiateModeChange(*desiredModeOpt, constraints, outTimeline)) { continue; } @@ -1428,9 +1417,9 @@ void SurfaceFlinger::initiateDisplayModeChanges() { const auto display = getDisplayDeviceLocked(*displayToUpdateImmediately); finalizeDisplayModeChange(*display); - const auto desiredActiveMode = display->getDesiredActiveMode(); - if (desiredActiveMode && display->getActiveMode() == desiredActiveMode->modeOpt) { - desiredActiveModeChangeDone(display); + const auto desiredModeOpt = display->getDesiredMode(); + if (desiredModeOpt && display->getActiveMode() == desiredModeOpt->modeOpt) { + applyActiveMode(display); } } } @@ -2487,6 +2476,10 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, if (pacesetterFrameTarget.isFramePending()) { if (mBackpressureGpuComposition || pacesetterFrameTarget.didMissHwcFrame()) { + if (FlagManager::getInstance().vrr_config()) { + mScheduler->getVsyncSchedule()->getTracker().onFrameMissed( + pacesetterFrameTarget.expectedPresentTime()); + } scheduleCommit(FrameHint::kNone); return false; } @@ -2682,16 +2675,16 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay); } - const Period vsyncPeriod = mScheduler->getVsyncSchedule()->period(); + const Period minFramePeriod = mScheduler->getVsyncSchedule()->minFramePeriod(); if (!getHwComposer().getComposer()->isSupported( Hwc2::Composer::OptionalFeature::ExpectedPresentTime) && - pacesetterTarget.wouldPresentEarly(vsyncPeriod)) { + pacesetterTarget.wouldPresentEarly(minFramePeriod)) { const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration; // TODO(b/255601557): Calculate and pass per-display values for each FrameTarget. refreshArgs.earliestPresentTime = - pacesetterTarget.previousFrameVsyncTime(vsyncPeriod) - hwcMinWorkDuration; + pacesetterTarget.previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration; } refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime(); @@ -4016,7 +4009,7 @@ void SurfaceFlinger::requestDisplayModes(std::vector<display::DisplayModeRequest } if (display->refreshRateSelector().isModeAllowed(request.mode)) { - setDesiredActiveMode(std::move(request)); + setDesiredMode(std::move(request)); } else { ALOGV("%s: Mode %d is disallowed for display %s", __func__, modePtr->getId().value(), to_string(displayId).c_str()); @@ -4045,15 +4038,23 @@ void SurfaceFlinger::onChoreographerAttached() { } } -void SurfaceFlinger::onVsyncGenerated(PhysicalDisplayId displayId, TimePoint expectedPresentTime, - const scheduler::DisplayModeData& displayModeData, - Period vsyncPeriod) { - const auto status = - getHwComposer() - .notifyExpectedPresentIfRequired(displayId, vsyncPeriod, expectedPresentTime, - displayModeData.renderRate, - displayModeData - .notifyExpectedPresentTimeoutOpt); +void SurfaceFlinger::onVsyncGenerated(TimePoint expectedPresentTime, + ftl::NonNull<DisplayModePtr> modePtr, Fps renderRate) { + const auto vsyncPeriod = modePtr->getVsyncRate().getPeriod(); + const auto timeout = [&]() -> std::optional<Period> { + const auto vrrConfig = modePtr->getVrrConfig(); + if (!vrrConfig) return std::nullopt; + + const auto notifyExpectedPresentConfig = + modePtr->getVrrConfig()->notifyExpectedPresentConfig; + if (!notifyExpectedPresentConfig) return std::nullopt; + return Period::fromNs(notifyExpectedPresentConfig->notifyExpectedPresentTimeoutNs); + }(); + + const auto displayId = modePtr->getPhysicalDisplayId(); + const auto status = getHwComposer().notifyExpectedPresentIfRequired(displayId, vsyncPeriod, + expectedPresentTime, + renderRate, timeout); if (status != NO_ERROR) { ALOGE("%s failed to notifyExpectedPresentHint for display %" PRId64, __func__, displayId.value); @@ -4706,7 +4707,7 @@ bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId return false; } - const Duration earlyLatchVsyncThreshold = mScheduler->getVsyncSchedule()->period() / 2; + const Duration earlyLatchVsyncThreshold = mScheduler->getVsyncSchedule()->minFramePeriod() / 2; return predictedPresentTime >= expectedPresentTime && predictedPresentTime - expectedPresentTime >= earlyLatchVsyncThreshold; @@ -5775,7 +5776,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: display->setPowerMode(mode); - const auto refreshRate = display->refreshRateSelector().getActiveMode().modePtr->getVsyncRate(); + const auto activeMode = display->refreshRateSelector().getActiveMode().modePtr; if (!currentModeOpt || *currentModeOpt == hal::PowerMode::OFF) { // Turn on the display @@ -5812,7 +5813,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: mScheduler->enableSyntheticVsync(false); constexpr bool kAllowToEnable = true; - mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, refreshRate); + mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, activeMode.get()); } mVisibleRegionsDirty = true; @@ -5854,7 +5855,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: mVisibleRegionsDirty = true; scheduleRepaint(); mScheduler->enableSyntheticVsync(false); - mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */, refreshRate); + mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */, + activeMode.get()); } } else if (mode == hal::PowerMode::DOZE_SUSPEND) { // Leave display going to doze @@ -7283,15 +7285,14 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { } if (!display->isRefreshRateOverlayEnabled()) return; - const auto desiredActiveMode = display->getDesiredActiveMode(); - const std::optional<DisplayModeId> desiredModeId = desiredActiveMode - ? std::make_optional(desiredActiveMode->modeOpt->modePtr->getId()) - - : std::nullopt; + const auto desiredModeIdOpt = + display->getDesiredMode().transform([](const DisplayDevice::ActiveModeInfo& info) { + return info.modeOpt->modePtr->getId(); + }); const bool timerExpired = mKernelIdleTimerEnabled && expired; - if (display->onKernelTimerChanged(desiredModeId, timerExpired)) { + if (display->onKernelTimerChanged(desiredModeIdOpt, timerExpired)) { mScheduler->scheduleFrame(); } })); @@ -8239,18 +8240,19 @@ status_t SurfaceFlinger::applyRefreshRateSelectorPolicy( auto preferredMode = std::move(*preferredModeOpt); const auto preferredModeId = preferredMode.modePtr->getId(); + const Fps preferredFps = preferredMode.fps; ALOGV("Switching to Scheduler preferred mode %d (%s)", preferredModeId.value(), - to_string(preferredMode.fps).c_str()); + to_string(preferredFps).c_str()); if (!selector.isModeAllowed(preferredMode)) { ALOGE("%s: Preferred mode %d is disallowed", __func__, preferredModeId.value()); return INVALID_OPERATION; } - setDesiredActiveMode({preferredMode, .emitEvent = true}, force); + setDesiredMode({std::move(preferredMode), .emitEvent = true}, force); // Update the frameRateOverride list as the display render rate might have changed - if (mScheduler->updateFrameRateOverrides(/*consideredSignals*/ {}, preferredMode.fps)) { + if (mScheduler->updateFrameRateOverrides(scheduler::GlobalSignals{}, preferredFps)) { triggerOnFrameRateOverridesChanged(); } @@ -8587,7 +8589,7 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveD const DisplayDevice& activeDisplay) { ATRACE_CALL(); - // For the first display activated during boot, there is no need to force setDesiredActiveMode, + // For the first display activated during boot, there is no need to force setDesiredMode, // because DM is about to send its policy via setDesiredDisplayModeSpecs. bool forceApplyPolicy = false; @@ -8611,9 +8613,9 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveD sActiveDisplayRotationFlags = ui::Transform::toRotationFlags(activeDisplay.getOrientation()); // The policy of the new active/pacesetter display may have changed while it was inactive. In - // that case, its preferred mode has not been propagated to HWC (via setDesiredActiveMode). In - // either case, the Scheduler's cachedModeChangedParams must be initialized to the newly active - // mode, and the kernel idle timer of the newly active display must be toggled. + // that case, its preferred mode has not been propagated to HWC (via setDesiredMode). In either + // case, the Scheduler's cachedModeChangedParams must be initialized to the newly active mode, + // and the kernel idle timer of the newly active display must be toggled. applyRefreshRateSelectorPolicy(mActiveDisplayId, activeDisplay.refreshRateSelector(), forceApplyPolicy); } @@ -8958,6 +8960,10 @@ SurfaceFlinger::getLayerSnapshotsForScreenshots(uint32_t rootLayerId, uint32_t u .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap(), .skipRoundCornersWhenProtected = !getRenderEngine().supportsProtectedContent()}; + // The layer may not exist if it was just created and a screenshot was requested immediately + // after. In this case, the hierarchy will be empty so we will not render any layers. + args.rootSnapshot.isSecure = mLayerLifecycleManager.getLayerFromId(rootLayerId) && + mLayerLifecycleManager.isLayerSecure(rootLayerId); mLayerSnapshotBuilder.update(args); auto getLayerSnapshotsFn = diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 9e6da3f80b..e90f8feb6e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -658,8 +658,8 @@ private: void notifyCpuLoadUp() override; // IVsyncTrackerCallback overrides - void onVsyncGenerated(PhysicalDisplayId, TimePoint expectedPresentTime, - const scheduler::DisplayModeData&, Period vsyncPeriod) override; + void onVsyncGenerated(TimePoint expectedPresentTime, ftl::NonNull<DisplayModePtr>, + Fps renderRate) override; // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates. void toggleKernelIdleTimer() REQUIRES(mStateLock); @@ -686,8 +686,7 @@ private: // Show hdr sdr ratio overlay bool mHdrSdrRatioOverlay = false; - void setDesiredActiveMode(display::DisplayModeRequest&&, bool force = false) - REQUIRES(mStateLock); + void setDesiredMode(display::DisplayModeRequest&&, bool force = false) REQUIRES(mStateLock); status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId, Fps minFps, Fps maxFps); @@ -695,9 +694,10 @@ private: void initiateDisplayModeChanges() REQUIRES(mStateLock, kMainThreadContext); void finalizeDisplayModeChange(DisplayDevice&) REQUIRES(mStateLock, kMainThreadContext); - void clearDesiredActiveModeState(const sp<DisplayDevice>&) REQUIRES(mStateLock); - // Called when active mode is no longer is progress - void desiredActiveModeChangeDone(const sp<DisplayDevice>&) REQUIRES(mStateLock); + // TODO(b/241285191): Replace DisplayDevice with DisplayModeRequest, and move to Scheduler. + void dropModeRequest(const sp<DisplayDevice>&) REQUIRES(mStateLock); + void applyActiveMode(const sp<DisplayDevice>&) REQUIRES(mStateLock); + // Called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) REQUIRES(mStateLock, kMainThreadContext); diff --git a/services/surfaceflinger/tests/unittests/FlagUtils.h b/services/surfaceflinger/common/include/common/test/FlagUtils.h index 550c70d98f..550c70d98f 100644 --- a/services/surfaceflinger/tests/unittests/FlagUtils.h +++ b/services/surfaceflinger/common/include/common/test/FlagUtils.h diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 9b2d4536cd..4fc39cc912 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -806,8 +806,7 @@ private: void onChoreographerAttached() override {} // IVsyncTrackerCallback overrides - void onVsyncGenerated(PhysicalDisplayId, TimePoint, const scheduler::DisplayModeData&, - Period) override {} + void onVsyncGenerated(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {} surfaceflinger::test::Factory mFactory; sp<SurfaceFlinger> mFlinger = diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp index 8fcfd8131a..b690d8d98e 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp @@ -28,6 +28,7 @@ #include "Scheduler/VSyncPredictor.h" #include "Scheduler/VSyncReactor.h" +#include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/MockVSyncDispatch.h" #include "mock/MockVSyncTracker.h" @@ -179,8 +180,7 @@ void SchedulerFuzzer::fuzzVSyncDispatchTimerQueue() { } struct VsyncTrackerCallback : public scheduler::IVsyncTrackerCallback { - void onVsyncGenerated(PhysicalDisplayId, TimePoint, const scheduler::DisplayModeData&, - Period) override {} + void onVsyncGenerated(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {} }; void SchedulerFuzzer::fuzzVSyncPredictor() { @@ -189,14 +189,14 @@ void SchedulerFuzzer::fuzzVSyncPredictor() { uint16_t minimumSamplesForPrediction = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX); nsecs_t idealPeriod = mFdp.ConsumeIntegralInRange<nsecs_t>(1, UINT32_MAX); VsyncTrackerCallback callback; - scheduler::VSyncPredictor tracker{kDisplayId, - idealPeriod, - historySize, - minimumSamplesForPrediction, + const auto mode = ftl::as_non_null( + mock::createDisplayMode(DisplayModeId(0), Fps::fromPeriodNsecs(idealPeriod))); + scheduler::VSyncPredictor tracker{mode, historySize, minimumSamplesForPrediction, mFdp.ConsumeIntegral<uint32_t>() /*outlierTolerancePercent*/, callback}; uint16_t period = mFdp.ConsumeIntegral<uint16_t>(); - tracker.setPeriod(period); + tracker.setDisplayModePtr(ftl::as_non_null( + mock::createDisplayMode(DisplayModeId(0), Fps::fromPeriodNsecs(period)))); for (uint16_t i = 0; i < minimumSamplesForPrediction; ++i) { if (!tracker.needsMoreSamples()) { break; @@ -271,7 +271,10 @@ void SchedulerFuzzer::fuzzVSyncReactor() { *vSyncTracker, mFdp.ConsumeIntegral<uint8_t>() /*pendingLimit*/, false); - reactor.startPeriodTransition(mFdp.ConsumeIntegral<nsecs_t>(), mFdp.ConsumeBool()); + const auto mode = ftl::as_non_null( + mock::createDisplayMode(DisplayModeId(0), + Fps::fromPeriodNsecs(mFdp.ConsumeIntegral<nsecs_t>()))); + reactor.onDisplayModeChanged(mode, mFdp.ConsumeBool()); bool periodFlushed = false; // Value does not matter, since this is an out // param from addHwVsyncTimestamp. reactor.addHwVsyncTimestamp(0, std::nullopt, &periodFlushed); @@ -430,6 +433,7 @@ void SchedulerFuzzer::fuzzFrameTargeter() { Period period() const { return getFuzzedDuration(fuzzer); } TimePoint vsyncDeadlineAfter(TimePoint) const { return getFuzzedTimePoint(fuzzer); } + Period minFramePeriod() const { return period(); } } vsyncSource{mFdp}; int i = 10; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h index 728708f05c..fa307e9bb4 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h @@ -89,8 +89,7 @@ public: nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t /* timePoint */) const override { return 1; } nsecs_t currentPeriod() const override { return 1; } - - void setPeriod(nsecs_t /* period */) override {} + Period minFramePeriod() const override { return Period::fromNs(currentPeriod()); } void resetModel() override {} @@ -100,7 +99,7 @@ public: return true; } - void setDisplayModeData(const scheduler::DisplayModeData&) override {} + void setDisplayModePtr(ftl::NonNull<DisplayModePtr>) override {} nsecs_t nextVSyncTime(nsecs_t timePoint) const { if (timePoint % mPeriod == 0) { @@ -109,6 +108,12 @@ public: return (timePoint - (timePoint % mPeriod) + mPeriod); } + void setRenderRate(Fps) override {} + + void onFrameBegin(TimePoint, TimePoint) override {} + + void onFrameMissed(TimePoint) override {} + void dump(std::string& /* result */) const override {} protected: diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index 79864e05af..061e121950 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -154,6 +154,133 @@ TEST_F(ScreenCaptureTest, CaptureChildSetParentFlagsSecureEUidSystem) { sc.expectColor(Rect(0, 0, 10, 10), Color::BLUE); } +/** + * If a parent layer sets the secure flag, but the screenshot requests is for the child hierarchy, + * we need to ensure the secure flag is respected from the parent even though the parent isn't + * in the captured sub-hierarchy + */ +TEST_F(ScreenCaptureTest, CaptureChildRespectsParentSecureFlag) { + Rect size(0, 0, 100, 100); + Transaction().hide(mBGSurfaceControl).hide(mFGSurfaceControl).apply(); + sp<SurfaceControl> parentLayer; + ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent-test", 0, 0, + ISurfaceComposerClient::eHidden, + mRootSurfaceControl.get())); + + sp<SurfaceControl> childLayer; + ASSERT_NO_FATAL_FAILURE(childLayer = createLayer("child-test", 0, 0, + ISurfaceComposerClient::eFXSurfaceBufferState, + parentLayer.get())); + ASSERT_NO_FATAL_FAILURE( + fillBufferLayerColor(childLayer, Color::GREEN, size.width(), size.height())); + + // hide the parent layer to ensure secure flag is passed down to child when screenshotting + Transaction().setLayer(parentLayer, INT32_MAX).show(childLayer).apply(true); + Transaction() + .setFlags(parentLayer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure) + .apply(); + LayerCaptureArgs captureArgs; + captureArgs.layerHandle = childLayer->getHandle(); + captureArgs.sourceCrop = size; + captureArgs.captureSecureLayers = false; + { + SCOPED_TRACE("parent hidden"); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); + ASSERT_TRUE(mCaptureResults.capturedSecureLayers); + ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers); + sc.expectColor(size, Color::BLACK); + } + + captureArgs.captureSecureLayers = true; + { + SCOPED_TRACE("capture secure parent not visible"); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); + ASSERT_TRUE(mCaptureResults.capturedSecureLayers); + ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers); + sc.expectColor(size, Color::GREEN); + } + + Transaction().show(parentLayer).apply(); + captureArgs.captureSecureLayers = false; + { + SCOPED_TRACE("parent visible"); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); + ASSERT_TRUE(mCaptureResults.capturedSecureLayers); + ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers); + sc.expectColor(size, Color::BLACK); + } + + captureArgs.captureSecureLayers = true; + { + SCOPED_TRACE("capture secure parent visible"); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); + ASSERT_TRUE(mCaptureResults.capturedSecureLayers); + ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers); + sc.expectColor(size, Color::GREEN); + } +} + +TEST_F(ScreenCaptureTest, CaptureOffscreenChildRespectsParentSecureFlag) { + Rect size(0, 0, 100, 100); + Transaction().hide(mBGSurfaceControl).hide(mFGSurfaceControl).apply(); + // Parent layer should be offscreen. + sp<SurfaceControl> parentLayer; + ASSERT_NO_FATAL_FAILURE( + parentLayer = createLayer("parent-test", 0, 0, ISurfaceComposerClient::eHidden)); + + sp<SurfaceControl> childLayer; + ASSERT_NO_FATAL_FAILURE(childLayer = createLayer("child-test", 0, 0, + ISurfaceComposerClient::eFXSurfaceBufferState, + parentLayer.get())); + ASSERT_NO_FATAL_FAILURE( + fillBufferLayerColor(childLayer, Color::GREEN, size.width(), size.height())); + + // hide the parent layer to ensure secure flag is passed down to child when screenshotting + Transaction().setLayer(parentLayer, INT32_MAX).show(childLayer).apply(true); + Transaction() + .setFlags(parentLayer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure) + .apply(); + LayerCaptureArgs captureArgs; + captureArgs.layerHandle = childLayer->getHandle(); + captureArgs.sourceCrop = size; + captureArgs.captureSecureLayers = false; + { + SCOPED_TRACE("parent hidden"); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); + ASSERT_TRUE(mCaptureResults.capturedSecureLayers); + ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers); + sc.expectColor(size, Color::BLACK); + } + + captureArgs.captureSecureLayers = true; + { + SCOPED_TRACE("capture secure parent not visible"); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); + ASSERT_TRUE(mCaptureResults.capturedSecureLayers); + ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers); + sc.expectColor(size, Color::GREEN); + } + + Transaction().show(parentLayer).apply(); + captureArgs.captureSecureLayers = false; + { + SCOPED_TRACE("parent visible"); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); + ASSERT_TRUE(mCaptureResults.capturedSecureLayers); + ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers); + sc.expectColor(size, Color::BLACK); + } + + captureArgs.captureSecureLayers = true; + { + SCOPED_TRACE("capture secure parent visible"); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); + ASSERT_TRUE(mCaptureResults.capturedSecureLayers); + ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers); + sc.expectColor(size, Color::GREEN); + } +} + TEST_F(ScreenCaptureTest, CaptureSingleLayer) { LayerCaptureArgs captureArgs; captureArgs.layerHandle = mBGSurfaceControl->getHandle(); diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp index 2d87ddd488..3873b0c076 100644 --- a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp @@ -30,7 +30,7 @@ using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjec class InitiateModeChangeTest : public DisplayTransactionTest { public: - using Action = DisplayDevice::DesiredActiveModeAction; + using Action = DisplayDevice::DesiredModeAction; using Event = scheduler::DisplayModeEvent; void SetUp() override { @@ -66,108 +66,93 @@ protected: ftl::as_non_null(createDisplayMode(kModeId120, 120_Hz)); }; -TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setCurrentMode) { +TEST_F(InitiateModeChangeTest, setDesiredModeToActiveMode) { EXPECT_EQ(Action::None, - mDisplay->setDesiredActiveMode( - {scheduler::FrameRateMode{60_Hz, kMode60}, Event::None})); - EXPECT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); + mDisplay->setDesiredMode({scheduler::FrameRateMode{60_Hz, kMode60}, Event::None})); + EXPECT_FALSE(mDisplay->getDesiredMode()); } -TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setNewMode) { +TEST_F(InitiateModeChangeTest, setDesiredMode) { EXPECT_EQ(Action::InitiateDisplayModeSwitch, - mDisplay->setDesiredActiveMode( - {scheduler::FrameRateMode{90_Hz, kMode90}, Event::None})); - ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getDesiredActiveMode()->modeOpt); - EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); + mDisplay->setDesiredMode({scheduler::FrameRateMode{90_Hz, kMode90}, Event::None})); + ASSERT_TRUE(mDisplay->getDesiredMode()); + EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getDesiredMode()->modeOpt); + EXPECT_EQ(Event::None, mDisplay->getDesiredMode()->event); - // Setting another mode should be cached but return None + // Setting another mode should be cached but return None. EXPECT_EQ(Action::None, - mDisplay->setDesiredActiveMode( - {scheduler::FrameRateMode{120_Hz, kMode120}, Event::None})); - ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, *mDisplay->getDesiredActiveMode()->modeOpt); - EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); + mDisplay->setDesiredMode({scheduler::FrameRateMode{120_Hz, kMode120}, Event::None})); + ASSERT_TRUE(mDisplay->getDesiredMode()); + EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, *mDisplay->getDesiredMode()->modeOpt); + EXPECT_EQ(Event::None, mDisplay->getDesiredMode()->event); } -TEST_F(InitiateModeChangeTest, clearDesiredActiveModeState) { +TEST_F(InitiateModeChangeTest, clearDesiredMode) { EXPECT_EQ(Action::InitiateDisplayModeSwitch, - mDisplay->setDesiredActiveMode( - {scheduler::FrameRateMode{90_Hz, kMode90}, Event::None})); - ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + mDisplay->setDesiredMode({scheduler::FrameRateMode{90_Hz, kMode90}, Event::None})); + EXPECT_TRUE(mDisplay->getDesiredMode()); - mDisplay->clearDesiredActiveModeState(); - ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); + mDisplay->clearDesiredMode(); + EXPECT_FALSE(mDisplay->getDesiredMode()); } -TEST_F(InitiateModeChangeTest, initiateModeChange) NO_THREAD_SAFETY_ANALYSIS { +TEST_F(InitiateModeChangeTest, initiateModeChange) REQUIRES(kMainThreadContext) { EXPECT_EQ(Action::InitiateDisplayModeSwitch, - mDisplay->setDesiredActiveMode( - {scheduler::FrameRateMode{90_Hz, kMode90}, Event::None})); - ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getDesiredActiveMode()->modeOpt); - EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); + mDisplay->setDesiredMode({scheduler::FrameRateMode{90_Hz, kMode90}, Event::None})); + ASSERT_TRUE(mDisplay->getDesiredMode()); + EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getDesiredMode()->modeOpt); + EXPECT_EQ(Event::None, mDisplay->getDesiredMode()->event); - hal::VsyncPeriodChangeConstraints constraints{ + const hal::VsyncPeriodChangeConstraints constraints{ .desiredTimeNanos = systemTime(), .seamlessRequired = false, }; hal::VsyncPeriodChangeTimeline timeline; - EXPECT_EQ(OK, - mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints, - &timeline)); - EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getUpcomingActiveMode().modeOpt); - EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); - - mDisplay->clearDesiredActiveModeState(); - ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); + EXPECT_TRUE(mDisplay->initiateModeChange(*mDisplay->getDesiredMode(), constraints, timeline)); + EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getPendingMode().modeOpt); + EXPECT_EQ(Event::None, mDisplay->getPendingMode().event); + + mDisplay->clearDesiredMode(); + EXPECT_FALSE(mDisplay->getDesiredMode()); } -TEST_F(InitiateModeChangeTest, initiateRenderRateChange) { +TEST_F(InitiateModeChangeTest, initiateRenderRateSwitch) { EXPECT_EQ(Action::InitiateRenderRateSwitch, - mDisplay->setDesiredActiveMode( - {scheduler::FrameRateMode{30_Hz, kMode60}, Event::None})); - EXPECT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); + mDisplay->setDesiredMode({scheduler::FrameRateMode{30_Hz, kMode60}, Event::None})); + EXPECT_FALSE(mDisplay->getDesiredMode()); } -TEST_F(InitiateModeChangeTest, getUpcomingActiveMode_desiredActiveModeChanged) -NO_THREAD_SAFETY_ANALYSIS { +TEST_F(InitiateModeChangeTest, initiateDisplayModeSwitch) FTL_FAKE_GUARD(kMainThreadContext) { EXPECT_EQ(Action::InitiateDisplayModeSwitch, - mDisplay->setDesiredActiveMode( - {scheduler::FrameRateMode{90_Hz, kMode90}, Event::None})); - ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getDesiredActiveMode()->modeOpt); - EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); + mDisplay->setDesiredMode({scheduler::FrameRateMode{90_Hz, kMode90}, Event::None})); + ASSERT_TRUE(mDisplay->getDesiredMode()); + EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getDesiredMode()->modeOpt); + EXPECT_EQ(Event::None, mDisplay->getDesiredMode()->event); - hal::VsyncPeriodChangeConstraints constraints{ + const hal::VsyncPeriodChangeConstraints constraints{ .desiredTimeNanos = systemTime(), .seamlessRequired = false, }; hal::VsyncPeriodChangeTimeline timeline; - EXPECT_EQ(OK, - mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints, - &timeline)); - EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getUpcomingActiveMode().modeOpt); - EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); + EXPECT_TRUE(mDisplay->initiateModeChange(*mDisplay->getDesiredMode(), constraints, timeline)); + EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getPendingMode().modeOpt); + EXPECT_EQ(Event::None, mDisplay->getPendingMode().event); EXPECT_EQ(Action::None, - mDisplay->setDesiredActiveMode( - {scheduler::FrameRateMode{120_Hz, kMode120}, Event::None})); - ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, *mDisplay->getDesiredActiveMode()->modeOpt); - EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); - - EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getUpcomingActiveMode().modeOpt); - EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); - - EXPECT_EQ(OK, - mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints, - &timeline)); - EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, *mDisplay->getUpcomingActiveMode().modeOpt); - EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); - - mDisplay->clearDesiredActiveModeState(); - ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); + mDisplay->setDesiredMode({scheduler::FrameRateMode{120_Hz, kMode120}, Event::None})); + ASSERT_TRUE(mDisplay->getDesiredMode()); + EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, *mDisplay->getDesiredMode()->modeOpt); + EXPECT_EQ(Event::None, mDisplay->getDesiredMode()->event); + + EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getPendingMode().modeOpt); + EXPECT_EQ(Event::None, mDisplay->getPendingMode().event); + + EXPECT_TRUE(mDisplay->initiateModeChange(*mDisplay->getDesiredMode(), constraints, timeline)); + EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, *mDisplay->getPendingMode().modeOpt); + EXPECT_EQ(Event::None, mDisplay->getPendingMode().event); + + mDisplay->clearDesiredMode(); + EXPECT_FALSE(mDisplay->getDesiredMode()); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp index c040f29fec..803710d5d6 100644 --- a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp +++ b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp @@ -18,7 +18,7 @@ #define LOG_TAG "FlagManagerTest" #include <common/FlagManager.h> -#include "FlagUtils.h" +#include <common/test/FlagUtils.h> #include <gmock/gmock.h> #include <gtest/gtest.h> diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index 6d87717404..9dd14317ef 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "FlagUtils.h" +#include <common/test/FlagUtils.h> #include "com_android_graphics_surfaceflinger_flags.h" #include "gmock/gmock-spec-builders.h" #include "mock/MockTimeStats.h" diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index f1e841b88f..4a2273182e 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -35,11 +35,11 @@ #include <log/log.h> #include <chrono> +#include <common/test/FlagUtils.h> #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/Hal.h" #include "DisplayIdentificationTestHelpers.h" -#include "FlagUtils.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/DisplayHardware/MockHWC2.h" diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp index befef482b9..c1059d7733 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp @@ -25,7 +25,7 @@ #include <renderengine/mock/FakeExternalTexture.h> -#include "FlagUtils.h" +#include <common/test/FlagUtils.h> #include "FpsOps.h" #include "LayerHierarchyTest.h" #include "Scheduler/LayerHistory.h" diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 1adf14f587..c24d397e31 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -27,7 +27,7 @@ #include <gtest/gtest.h> #include <log/log.h> -#include "FlagUtils.h" +#include <common/test/FlagUtils.h> #include "FpsOps.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/LayerInfo.h" diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp index 047ef5a928..07a522ac4e 100644 --- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp @@ -21,7 +21,7 @@ #include <scheduler/Fps.h> -#include "FlagUtils.h" +#include <common/test/FlagUtils.h> #include "FpsOps.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/LayerInfo.h" diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 2cc6dc7721..16143e3a7f 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -1055,4 +1055,23 @@ TEST_F(LayerSnapshotTest, isFrontBuffered) { EXPECT_FALSE(getSnapshot(1)->isFrontBuffered()); } +TEST_F(LayerSnapshotTest, setSecureRootSnapshot) { + setFlags(1, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure); + LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(), + .layerLifecycleManager = mLifecycleManager, + .includeMetadata = false, + .displays = mFrontEndDisplayInfos, + .displayChanges = false, + .globalShadowSettings = globalShadowSettings, + .supportsBlur = true, + .supportedLayerGenericMetadata = {}, + .genericLayerMetadataKeyMap = {}}; + args.rootSnapshot.isSecure = true; + update(mSnapshotBuilder, args); + + EXPECT_TRUE(getSnapshot(1)->isSecure); + // Ensure child is also marked as secure + EXPECT_TRUE(getSnapshot(11)->isSecure); +} + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index a00e8864dd..a9567b2881 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -26,6 +26,7 @@ #include <log/log.h> #include <ui/Size.h> +#include <common/test/FlagUtils.h> #include <scheduler/Fps.h> #include <scheduler/FrameRateMode.h> #include "DisplayHardware/HWC2.h" @@ -1543,6 +1544,7 @@ TEST_P(RefreshRateSelectorTest, return; } + SET_FLAG_FOR_TEST(flags::vrr_config, false); // VRR compatibility is determined by the presence of a vrr config in the DisplayMode. auto selector = createSelector(makeModes(kMode60, kMode120), kModeId120); @@ -1610,6 +1612,7 @@ TEST_P(RefreshRateSelectorTest, return; } + SET_FLAG_FOR_TEST(flags::vrr_config, true); // VRR compatibility is determined by the presence of a vrr config in the DisplayMode. auto selector = createSelector(kVrrModes_60_120, kModeId120); @@ -1624,15 +1627,15 @@ TEST_P(RefreshRateSelectorTest, // Note that `smoothSwitchOnly` should not have an effect. const std::initializer_list<Case> testCases = { - {FrameRateCategory::Default, false, 240_Hz}, + {FrameRateCategory::Default, false, 120_Hz}, // TODO(b/266481656): Once this bug is fixed, NoPreference should be a lower frame rate. - {FrameRateCategory::NoPreference, false, 240_Hz}, + {FrameRateCategory::NoPreference, false, 120_Hz}, {FrameRateCategory::Low, false, 30_Hz}, {FrameRateCategory::Normal, false, 60_Hz}, {FrameRateCategory::High, false, 120_Hz}, - {FrameRateCategory::Default, true, 240_Hz}, + {FrameRateCategory::Default, true, 120_Hz}, // TODO(b/266481656): Once this bug is fixed, NoPreference should be a lower frame rate. - {FrameRateCategory::NoPreference, true, 240_Hz}, + {FrameRateCategory::NoPreference, true, 120_Hz}, {FrameRateCategory::Low, true, 30_Hz}, {FrameRateCategory::Normal, true, 60_Hz}, {FrameRateCategory::High, true, 120_Hz}, @@ -3486,10 +3489,11 @@ TEST_P(RefreshRateSelectorTest, frameRateOverrideInBlockingZone60_90_NonDivisor) // VRR tests TEST_P(RefreshRateSelectorTest, singleMinMaxRateForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { + if (GetParam() != Config::FrameRateOverride::Enabled) { return; } + SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrMode_120, kModeId120); EXPECT_TRUE(selector.supportsFrameRateOverride()); @@ -3505,10 +3509,11 @@ TEST_P(RefreshRateSelectorTest, singleMinMaxRateForVrr) { } TEST_P(RefreshRateSelectorTest, renderRateChangesWithPolicyChangeForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { + if (GetParam() != Config::FrameRateOverride::Enabled) { return; } + SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrModes_60_120, kModeId120); const FpsRange only120 = {120_Hz, 120_Hz}; @@ -3562,10 +3567,11 @@ TEST_P(RefreshRateSelectorTest, renderRateChangesWithPolicyChangeForVrr) { } TEST_P(RefreshRateSelectorTest, modeChangesWithPolicyChangeForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { + if (GetParam() != Config::FrameRateOverride::Enabled) { return; } + SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrModes_60_120, kModeId120); const FpsRange range120 = {0_Hz, 120_Hz}; @@ -3585,10 +3591,11 @@ TEST_P(RefreshRateSelectorTest, modeChangesWithPolicyChangeForVrr) { } TEST_P(RefreshRateSelectorTest, getFrameRateOverridesForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { + if (GetParam() != Config::FrameRateOverride::Enabled) { return; } + SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrMode_120, kModeId120); // TODO(b/297600226) Run at lower than 30 Fps for dVRR const std::vector<Fps> desiredRefreshRates = {30_Hz, 34.285_Hz, 40_Hz, 48_Hz, @@ -3614,10 +3621,11 @@ TEST_P(RefreshRateSelectorTest, getFrameRateOverridesForVrr) { } TEST_P(RefreshRateSelectorTest, renderFrameRatesForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { + if (GetParam() != Config::FrameRateOverride::Enabled) { return; } + SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrMode_120, kModeId120); const FpsRange only120 = {120_Hz, 120_Hz}; const FpsRange range120 = {0_Hz, 120_Hz}; diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index aeac80dc62..3558ba6f09 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -56,6 +56,9 @@ public: EXPECT_CALL(*vsyncTracker, currentPeriod()) .WillRepeatedly(Return( TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + EXPECT_CALL(*vsyncTracker, minFramePeriod()) + .WillRepeatedly(Return(Period::fromNs( + TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD))); mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this) .setRefreshRateSelector(std::move(selectorPtr)) @@ -138,6 +141,9 @@ void DisplayModeSwitchingTest::setupScheduler( EXPECT_CALL(*vsyncTracker, currentPeriod()) .WillRepeatedly( Return(TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + EXPECT_CALL(*vsyncTracker, minFramePeriod()) + .WillRepeatedly(Return(Period::fromNs( + TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD))); EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread), @@ -145,11 +151,11 @@ void DisplayModeSwitchingTest::setupScheduler( TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp); } -TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRequired) { +TEST_F(DisplayModeSwitchingTest, changeRefreshRateOnActiveDisplayWithRefreshRequired) { ftl::FakeGuard guard(kMainThreadContext); - ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); + EXPECT_FALSE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); mFlinger.onActiveDisplayChanged(nullptr, *mDisplay); @@ -157,9 +163,9 @@ TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRe mock::createDisplayModeSpecs(kModeId90.value(), false, 0, 120)); - ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90); - ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); + ASSERT_TRUE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getDesiredMode()->modeOpt->modePtr->getId(), kModeId90); + EXPECT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); // Verify that next commit will call setActiveConfigWithConstraints in HWC const VsyncPeriodChangeTimeline timeline{.refreshRequired = true}; @@ -171,8 +177,9 @@ TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRe mFlinger.commit(); Mock::VerifyAndClearExpectations(mComposer); - ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); + + EXPECT_TRUE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); // Verify that the next commit will complete the mode change and send // a onModeChanged event to the framework. @@ -182,14 +189,14 @@ TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRe mFlinger.commit(); Mock::VerifyAndClearExpectations(mAppEventThread); - ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90); + EXPECT_FALSE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90); } -TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefreshRequired) { +TEST_F(DisplayModeSwitchingTest, changeRefreshRateOnActiveDisplayWithoutRefreshRequired) { ftl::FakeGuard guard(kMainThreadContext); - ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); + EXPECT_FALSE(mDisplay->getDesiredMode()); mFlinger.onActiveDisplayChanged(nullptr, *mDisplay); @@ -197,9 +204,9 @@ TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefres mock::createDisplayModeSpecs(kModeId90.value(), true, 0, 120)); - ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90); - ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); + ASSERT_TRUE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getDesiredMode()->modeOpt->modePtr->getId(), kModeId90); + EXPECT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); // Verify that next commit will call setActiveConfigWithConstraints in HWC // and complete the mode change. @@ -214,8 +221,8 @@ TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefres mFlinger.commit(); - ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90); + EXPECT_FALSE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90); } TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) { @@ -224,8 +231,8 @@ TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) { // Test that if we call setDesiredDisplayModeSpecs while a previous mode change // is still being processed the later call will be respected. - ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); + EXPECT_FALSE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); mFlinger.onActiveDisplayChanged(nullptr, *mDisplay); @@ -245,8 +252,8 @@ TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) { mock::createDisplayModeSpecs(kModeId120.value(), false, 0, 180)); - ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId120); + ASSERT_TRUE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getDesiredMode()->modeOpt->modePtr->getId(), kModeId120); EXPECT_CALL(*mComposer, setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID, @@ -255,20 +262,20 @@ TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) { mFlinger.commit(); - ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId120); + ASSERT_TRUE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getDesiredMode()->modeOpt->modePtr->getId(), kModeId120); mFlinger.commit(); - ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId120); + EXPECT_FALSE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId120); } -TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefreshRequired) { +TEST_F(DisplayModeSwitchingTest, changeResolutionOnActiveDisplayWithoutRefreshRequired) { ftl::FakeGuard guard(kMainThreadContext); - ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); + EXPECT_FALSE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); mFlinger.onActiveDisplayChanged(nullptr, *mDisplay); @@ -276,9 +283,9 @@ TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefresh mock::createDisplayModeSpecs(kModeId90_4K.value(), false, 0, 120)); - ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90_4K); - ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); + ASSERT_TRUE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getDesiredMode()->modeOpt->modePtr->getId(), kModeId90_4K); + EXPECT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60); // Verify that next commit will call setActiveConfigWithConstraints in HWC // and complete the mode change. @@ -312,18 +319,18 @@ TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefresh // so we need to update with the new instance. mDisplay = mFlinger.getDisplay(displayToken); - ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90_4K); + EXPECT_FALSE(mDisplay->getDesiredMode()); + EXPECT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90_4K); } MATCHER_P2(ModeSwitchingTo, flinger, modeId, "") { - if (!arg->getDesiredActiveMode()) { - *result_listener << "No desired active mode"; + if (!arg->getDesiredMode()) { + *result_listener << "No desired mode"; return false; } - if (arg->getDesiredActiveMode()->modeOpt->modePtr->getId() != modeId) { - *result_listener << "Unexpected desired active mode " << modeId; + if (arg->getDesiredMode()->modeOpt->modePtr->getId() != modeId) { + *result_listener << "Unexpected desired mode " << modeId; return false; } @@ -336,9 +343,8 @@ MATCHER_P2(ModeSwitchingTo, flinger, modeId, "") { } MATCHER_P(ModeSettledTo, modeId, "") { - if (const auto desiredOpt = arg->getDesiredActiveMode()) { - *result_listener << "Unsettled desired active mode " - << desiredOpt->modeOpt->modePtr->getId(); + if (const auto desiredOpt = arg->getDesiredMode()) { + *result_listener << "Unsettled desired mode " << desiredOpt->modeOpt->modePtr->getId(); return false; } diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp index cf3fab3aa3..31e13305a4 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp @@ -25,6 +25,11 @@ namespace android { namespace { +MATCHER_P(DisplayModeFps, value, "equals") { + using fps_approx_ops::operator==; + return arg->getVsyncRate() == value; +} + // Used when we simulate a display that supports doze. template <typename Display> struct DozeIsSupportedVariant { @@ -94,7 +99,8 @@ struct DispSyncIsSupportedVariant { static void setupResetModelCallExpectations(DisplayTransactionTest* test) { auto vsyncSchedule = test->mFlinger.scheduler()->getVsyncSchedule(); EXPECT_CALL(static_cast<mock::VsyncController&>(vsyncSchedule->getController()), - startPeriodTransition(DEFAULT_VSYNC_PERIOD, false)) + onDisplayModeChanged(DisplayModeFps(Fps::fromPeriodNsecs(DEFAULT_VSYNC_PERIOD)), + false)) .Times(1); EXPECT_CALL(static_cast<mock::VSyncTracker&>(vsyncSchedule->getTracker()), resetModel()) .Times(1); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index bca14f5217..cf48c76a5b 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -306,6 +306,9 @@ public: EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); EXPECT_CALL(*vsyncTracker, currentPeriod()) .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + EXPECT_CALL(*vsyncTracker, minFramePeriod()) + .WillRepeatedly( + Return(Period::fromNs(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD))); EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread), DefaultDisplayMode{options.displayId}, diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp index 4be07a1ddb..6a5635305a 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp @@ -34,38 +34,48 @@ constexpr nsecs_t toNs(std::chrono::duration<Rep, Per> const& tp) { return std::chrono::duration_cast<std::chrono::nanoseconds>(tp).count(); } -class FixedRateIdealStubTracker : public VSyncTracker { +class StubTracker : public VSyncTracker { public: - FixedRateIdealStubTracker() : mPeriod{toNs(3ms)} {} + StubTracker(nsecs_t period) : mPeriod(period) {} bool addVsyncTimestamp(nsecs_t) final { return true; } - nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final { - auto const floor = timePoint % mPeriod; - if (floor == 0) { - return timePoint; - } - return timePoint - floor + mPeriod; + nsecs_t currentPeriod() const final { + std::lock_guard lock(mMutex); + return mPeriod; } - nsecs_t currentPeriod() const final { return mPeriod; } - - void setPeriod(nsecs_t) final {} + Period minFramePeriod() const final { return Period::fromNs(currentPeriod()); } void resetModel() final {} bool needsMoreSamples() const final { return false; } bool isVSyncInPhase(nsecs_t, Fps) const final { return false; } - void setDisplayModeData(const DisplayModeData&) final {} + void setDisplayModePtr(ftl::NonNull<DisplayModePtr>) final {} + void setRenderRate(Fps) final {} + void onFrameBegin(TimePoint, TimePoint) final {} + void onFrameMissed(TimePoint) final {} void dump(std::string&) const final {} -private: - nsecs_t const mPeriod; +protected: + std::mutex mutable mMutex; + nsecs_t mPeriod; }; -class VRRStubTracker : public VSyncTracker { +class FixedRateIdealStubTracker : public StubTracker { public: - VRRStubTracker(nsecs_t period) : mPeriod{period} {} + FixedRateIdealStubTracker() : StubTracker{toNs(3ms)} {} - bool addVsyncTimestamp(nsecs_t) final { return true; } + nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final { + auto const floor = timePoint % mPeriod; + if (floor == 0) { + return timePoint; + } + return timePoint - floor + mPeriod; + } +}; + +class VRRStubTracker : public StubTracker { +public: + VRRStubTracker(nsecs_t period) : StubTracker(period) {} nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t time_point) const final { std::lock_guard lock(mMutex); @@ -83,21 +93,7 @@ public: mBase = last_known; } - nsecs_t currentPeriod() const final { - std::lock_guard lock(mMutex); - return mPeriod; - } - - void setPeriod(nsecs_t) final {} - void resetModel() final {} - bool needsMoreSamples() const final { return false; } - bool isVSyncInPhase(nsecs_t, Fps) const final { return false; } - void setDisplayModeData(const DisplayModeData&) final {} - void dump(std::string&) const final {} - private: - std::mutex mutable mMutex; - nsecs_t mPeriod; nsecs_t mBase = 0; }; diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index 83108662b9..2047018a15 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -30,9 +30,10 @@ #include <scheduler/TimeKeeper.h> -#include "FlagUtils.h" +#include <common/test/FlagUtils.h> #include "Scheduler/VSyncDispatchTimerQueue.h" #include "Scheduler/VSyncTracker.h" +#include "mock/MockVSyncTracker.h" #include <com_android_graphics_surfaceflinger_flags.h> @@ -42,7 +43,7 @@ using namespace std::literals; namespace android::scheduler { using namespace com::android::graphics::surfaceflinger; -class MockVSyncTracker : public VSyncTracker { +class MockVSyncTracker : public mock::VSyncTracker { public: MockVSyncTracker(nsecs_t period) : mPeriod{period} { ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_)) @@ -52,16 +53,6 @@ public: .WillByDefault(Invoke(this, &MockVSyncTracker::getCurrentPeriod)); } - MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t)); - MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t)); - MOCK_CONST_METHOD0(currentPeriod, nsecs_t()); - MOCK_METHOD1(setPeriod, void(nsecs_t)); - MOCK_METHOD0(resetModel, void()); - MOCK_CONST_METHOD0(needsMoreSamples, bool()); - MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps)); - MOCK_METHOD(void, setDisplayModeData, (const DisplayModeData&), (override)); - MOCK_CONST_METHOD1(dump, void(std::string&)); - nsecs_t nextVSyncTime(nsecs_t timePoint) const { if (timePoint % mPeriod == 0) { return timePoint; diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp index 30a2855955..7a498c9d29 100644 --- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp @@ -23,8 +23,9 @@ #define LOG_TAG "LibSurfaceFlingerUnittests" #define LOG_NDEBUG 0 -#include "FlagUtils.h" +#include <common/test/FlagUtils.h> #include "Scheduler/VSyncPredictor.h" +#include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/MockVsyncTrackerCallback.h" #include <gmock/gmock.h> @@ -39,12 +40,25 @@ using namespace testing; using namespace std::literals; using namespace com::android::graphics::surfaceflinger; +using NotifyExpectedPresentConfig = + ::aidl::android::hardware::graphics::composer3::VrrConfig::NotifyExpectedPresentConfig; + +using android::mock::createDisplayMode; +using android::mock::createDisplayModeBuilder; +using android::mock::createVrrDisplayMode; + namespace android::scheduler { +namespace { MATCHER_P2(IsCloseTo, value, tolerance, "is within tolerance") { return arg <= value + tolerance && arg >= value - tolerance; } +MATCHER_P(FpsMatcher, value, "equals") { + using fps_approx_ops::operator==; + return arg == value; +} + std::vector<nsecs_t> generateVsyncTimestamps(size_t count, nsecs_t period, nsecs_t bias) { std::vector<nsecs_t> vsyncs(count); std::generate(vsyncs.begin(), vsyncs.end(), @@ -54,21 +68,27 @@ std::vector<nsecs_t> generateVsyncTimestamps(size_t count, nsecs_t period, nsecs constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u); +ftl::NonNull<DisplayModePtr> displayMode(nsecs_t period) { + const int32_t kGroup = 0; + const auto kResolution = ui::Size(1920, 1080); + const auto refreshRate = Fps::fromPeriodNsecs(period); + return ftl::as_non_null(createDisplayMode(DisplayModeId(0), refreshRate, kGroup, kResolution, + DEFAULT_DISPLAY_ID)); +} +} // namespace + struct VSyncPredictorTest : testing::Test { nsecs_t mNow = 0; nsecs_t mPeriod = 1000; + ftl::NonNull<DisplayModePtr> mMode = displayMode(mPeriod); scheduler::mock::VsyncTrackerCallback mVsyncTrackerCallback; static constexpr size_t kHistorySize = 10; static constexpr size_t kMinimumSamplesForPrediction = 6; static constexpr size_t kOutlierTolerancePercent = 25; static constexpr nsecs_t mMaxRoundingError = 100; - VSyncPredictor tracker{DEFAULT_DISPLAY_ID, - mPeriod, - kHistorySize, - kMinimumSamplesForPrediction, - kOutlierTolerancePercent, - mVsyncTrackerCallback}; + VSyncPredictor tracker{mMode, kHistorySize, kMinimumSamplesForPrediction, + kOutlierTolerancePercent, mVsyncTrackerCallback}; }; TEST_F(VSyncPredictorTest, reportsAnticipatedPeriod) { @@ -78,7 +98,7 @@ TEST_F(VSyncPredictorTest, reportsAnticipatedPeriod) { EXPECT_THAT(model.intercept, Eq(0)); auto const changedPeriod = 2000; - tracker.setPeriod(changedPeriod); + tracker.setDisplayModePtr(displayMode(changedPeriod)); model = tracker.getVSyncPredictionModel(); EXPECT_THAT(model.slope, Eq(changedPeriod)); EXPECT_THAT(model.intercept, Eq(0)); @@ -99,7 +119,7 @@ TEST_F(VSyncPredictorTest, reportsSamplesNeededAfterExplicitRateChange) { EXPECT_FALSE(tracker.needsMoreSamples()); auto const changedPeriod = mPeriod * 2; - tracker.setPeriod(changedPeriod); + tracker.setDisplayModePtr(displayMode(changedPeriod)); EXPECT_TRUE(tracker.needsMoreSamples()); for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) { @@ -133,7 +153,7 @@ TEST_F(VSyncPredictorTest, uponNotifiedOfInaccuracyUsesSynthetic) { } EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + slightlyLessPeriod)); - tracker.setPeriod(changedPeriod); + tracker.setDisplayModePtr(displayMode(changedPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + changedPeriod)); } @@ -179,7 +199,7 @@ TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_60hzHighVariance) { auto constexpr expectedPeriod = 16639242; auto constexpr expectedIntercept = 1049341; - tracker.setPeriod(idealPeriod); + tracker.setDisplayModePtr(displayMode(idealPeriod)); for (auto const& timestamp : simulatedVsyncs) { tracker.addVsyncTimestamp(timestamp); } @@ -198,7 +218,7 @@ TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_90hzLowVariance) { auto expectedPeriod = 11089413; auto expectedIntercept = 94421; - tracker.setPeriod(idealPeriod); + tracker.setDisplayModePtr(displayMode(idealPeriod)); for (auto const& timestamp : simulatedVsyncs) { tracker.addVsyncTimestamp(timestamp); } @@ -225,7 +245,7 @@ TEST_F(VSyncPredictorTest, adaptsToFenceTimelinesDiscontinuous_22hzLowVariance) auto expectedPeriod = 45450152; auto expectedIntercept = 469647; - tracker.setPeriod(idealPeriod); + tracker.setDisplayModePtr(displayMode(idealPeriod)); for (auto const& timestamp : simulatedVsyncs) { tracker.addVsyncTimestamp(timestamp); } @@ -251,7 +271,7 @@ TEST_F(VSyncPredictorTest, againstOutliersDiscontinuous_500hzLowVariance) { auto expectedPeriod = 1999892; auto expectedIntercept = 86342; - tracker.setPeriod(idealPeriod); + tracker.setDisplayModePtr(displayMode(idealPeriod)); for (auto const& timestamp : simulatedVsyncs) { tracker.addVsyncTimestamp(timestamp); } @@ -271,7 +291,7 @@ TEST_F(VSyncPredictorTest, handlesVsyncChange) { auto const simulatedVsyncsSlow = generateVsyncTimestamps(kMinimumSamplesForPrediction, slowPeriod, slowTimeBase); - tracker.setPeriod(fastPeriod); + tracker.setDisplayModePtr(displayMode(fastPeriod)); for (auto const& timestamp : simulatedVsyncsFast) { tracker.addVsyncTimestamp(timestamp); } @@ -281,7 +301,7 @@ TEST_F(VSyncPredictorTest, handlesVsyncChange) { EXPECT_THAT(model.slope, IsCloseTo(fastPeriod, mMaxRoundingError)); EXPECT_THAT(model.intercept, IsCloseTo(0, mMaxRoundingError)); - tracker.setPeriod(slowPeriod); + tracker.setDisplayModePtr(displayMode(slowPeriod)); for (auto const& timestamp : simulatedVsyncsSlow) { tracker.addVsyncTimestamp(timestamp); } @@ -305,7 +325,7 @@ TEST_F(VSyncPredictorTest, willBeAccurateUsingPriorResultsForRate) { generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod2, fastTimeBase); auto idealPeriod = 100000; - tracker.setPeriod(idealPeriod); + tracker.setDisplayModePtr(displayMode(idealPeriod)); for (auto const& timestamp : simulatedVsyncsFast) { tracker.addVsyncTimestamp(timestamp); } @@ -313,14 +333,14 @@ TEST_F(VSyncPredictorTest, willBeAccurateUsingPriorResultsForRate) { EXPECT_THAT(model.slope, Eq(fastPeriod)); EXPECT_THAT(model.intercept, Eq(0)); - tracker.setPeriod(slowPeriod); + tracker.setDisplayModePtr(displayMode(slowPeriod)); for (auto const& timestamp : simulatedVsyncsSlow) { tracker.addVsyncTimestamp(timestamp); } // we had a model for 100ns mPeriod before, use that until the new samples are // sufficiently built up - tracker.setPeriod(idealPeriod); + tracker.setDisplayModePtr(displayMode(idealPeriod)); model = tracker.getVSyncPredictionModel(); EXPECT_THAT(model.slope, Eq(fastPeriod)); EXPECT_THAT(model.intercept, Eq(0)); @@ -369,7 +389,7 @@ TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) { auto const expectedPeriod = 11113919; auto const expectedIntercept = -1195945; - tracker.setPeriod(idealPeriod); + tracker.setDisplayModePtr(displayMode(idealPeriod)); for (auto const& timestamp : simulatedVsyncs) { tracker.addVsyncTimestamp(timestamp); } @@ -388,11 +408,8 @@ TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) { // See b/151146131 TEST_F(VSyncPredictorTest, hasEnoughPrecision) { - VSyncPredictor tracker{DEFAULT_DISPLAY_ID, - mPeriod, - 20, - kMinimumSamplesForPrediction, - kOutlierTolerancePercent, + const auto mode = displayMode(mPeriod); + VSyncPredictor tracker{mode, 20, kMinimumSamplesForPrediction, kOutlierTolerancePercent, mVsyncTrackerCallback}; std::vector<nsecs_t> const simulatedVsyncs{840873348817, 840890049444, 840906762675, 840923581635, 840940161584, 840956868096, @@ -407,7 +424,7 @@ TEST_F(VSyncPredictorTest, hasEnoughPrecision) { auto const expectedPeriod = 16698426; auto const expectedIntercept = 58055; - tracker.setPeriod(idealPeriod); + tracker.setDisplayModePtr(displayMode(idealPeriod)); for (auto const& timestamp : simulatedVsyncs) { tracker.addVsyncTimestamp(timestamp); } @@ -420,7 +437,7 @@ TEST_F(VSyncPredictorTest, hasEnoughPrecision) { TEST_F(VSyncPredictorTest, resetsWhenInstructed) { auto const idealPeriod = 10000; auto const realPeriod = 10500; - tracker.setPeriod(idealPeriod); + tracker.setDisplayModePtr(displayMode(idealPeriod)); for (auto i = 0; i < kMinimumSamplesForPrediction; i++) { tracker.addVsyncTimestamp(i * realPeriod); } @@ -562,7 +579,7 @@ TEST_F(VSyncPredictorTest, robustToDuplicateTimestamps_60hzRealTraceData) { auto constexpr expectedPeriod = 16'644'742; auto constexpr expectedIntercept = 125'626; - tracker.setPeriod(idealPeriod); + tracker.setDisplayModePtr(displayMode(idealPeriod)); for (auto const& timestamp : simulatedVsyncs) { tracker.addVsyncTimestamp(timestamp); } @@ -580,7 +597,7 @@ TEST_F(VSyncPredictorTest, setRenderRateIsRespected) { tracker.addVsyncTimestamp(mNow); } - tracker.setDisplayModeData({.renderRate = Fps::fromPeriodNsecs(3 * mPeriod)}); + tracker.setRenderRate(Fps::fromPeriodNsecs(3 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod)); @@ -602,12 +619,12 @@ TEST_F(VSyncPredictorTest, setRenderRateOfDivisorIsInPhase) { const auto refreshRate = Fps::fromPeriodNsecs(mPeriod); - tracker.setDisplayModeData({.renderRate = refreshRate / 4}); + tracker.setRenderRate(refreshRate / 4); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + 3 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 3 * mPeriod), Eq(mNow + 7 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 7 * mPeriod), Eq(mNow + 11 * mPeriod)); - tracker.setDisplayModeData({.renderRate = refreshRate / 2}); + tracker.setRenderRate(refreshRate / 2); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + 1 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1 * mPeriod), Eq(mNow + 3 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 3 * mPeriod), Eq(mNow + 5 * mPeriod)); @@ -615,7 +632,7 @@ TEST_F(VSyncPredictorTest, setRenderRateOfDivisorIsInPhase) { EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 7 * mPeriod), Eq(mNow + 9 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 9 * mPeriod), Eq(mNow + 11 * mPeriod)); - tracker.setDisplayModeData({.renderRate = refreshRate / 6}); + tracker.setRenderRate(refreshRate / 6); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + 1 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1 * mPeriod), Eq(mNow + 7 * mPeriod)); } @@ -629,7 +646,7 @@ TEST_F(VSyncPredictorTest, setRenderRateIsIgnoredIfNotDivisor) { tracker.addVsyncTimestamp(mNow); } - tracker.setDisplayModeData({.renderRate = Fps::fromPeriodNsecs(3.5f * mPeriod)}); + tracker.setRenderRate(Fps::fromPeriodNsecs(3.5f * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod)); @@ -642,16 +659,27 @@ TEST_F(VSyncPredictorTest, setRenderRateIsIgnoredIfNotDivisor) { TEST_F(VSyncPredictorTest, vsyncTrackerCallback) { SET_FLAG_FOR_TEST(flags::vrr_config, true); + const auto refreshRate = Fps::fromPeriodNsecs(mPeriod); - DisplayModeData displayModeData = - DisplayModeData{.renderRate = refreshRate, - .notifyExpectedPresentTimeoutOpt = Period::fromNs(30)}; - tracker.setDisplayModeData(displayModeData); + NotifyExpectedPresentConfig notifyExpectedPresentConfig; + notifyExpectedPresentConfig.notifyExpectedPresentTimeoutNs = Period::fromNs(30).ns(); + + hal::VrrConfig vrrConfig; + vrrConfig.notifyExpectedPresentConfig = notifyExpectedPresentConfig; + vrrConfig.minFrameIntervalNs = refreshRate.getPeriodNsecs(); + + const int32_t kGroup = 0; + const auto kResolution = ui::Size(1920, 1080); + const auto mode = + ftl::as_non_null(createVrrDisplayMode(DisplayModeId(0), refreshRate, vrrConfig, kGroup, + kResolution, DEFAULT_DISPLAY_ID)); + + tracker.setDisplayModePtr(mode); auto last = mNow; for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) { EXPECT_CALL(mVsyncTrackerCallback, - onVsyncGenerated(DEFAULT_DISPLAY_ID, TimePoint::fromNs(last + mPeriod), - displayModeData, Period::fromNs(mPeriod))) + onVsyncGenerated(TimePoint::fromNs(last + mPeriod), mode, + FpsMatcher(refreshRate))) .Times(1); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod)); mNow += mPeriod; @@ -659,20 +687,50 @@ TEST_F(VSyncPredictorTest, vsyncTrackerCallback) { tracker.addVsyncTimestamp(mNow); } - displayModeData = DisplayModeData{.renderRate = refreshRate / 2, - .notifyExpectedPresentTimeoutOpt = Period::fromNs(30)}; - tracker.setDisplayModeData(displayModeData); + tracker.setRenderRate(refreshRate / 2); { // out of render rate phase EXPECT_CALL(mVsyncTrackerCallback, - onVsyncGenerated(DEFAULT_DISPLAY_ID, TimePoint::fromNs(mNow + 3 * mPeriod), - displayModeData, Period::fromNs(mPeriod))) + onVsyncGenerated(TimePoint::fromNs(mNow + 3 * mPeriod), mode, + FpsMatcher(refreshRate / 2))) .Times(1); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1 * mPeriod), Eq(mNow + 3 * mPeriod)); } } +TEST_F(VSyncPredictorTest, adjustsVrrTimeline) { + SET_FLAG_FOR_TEST(flags::vrr_config, true); + + const int32_t kGroup = 0; + const auto kResolution = ui::Size(1920, 1080); + const auto refreshRate = Fps::fromPeriodNsecs(500); + const auto minFrameRate = Fps::fromPeriodNsecs(1000); + hal::VrrConfig vrrConfig; + vrrConfig.minFrameIntervalNs = minFrameRate.getPeriodNsecs(); + const ftl::NonNull<DisplayModePtr> kMode = + ftl::as_non_null(createDisplayModeBuilder(DisplayModeId(0), refreshRate, kGroup, + kResolution, DEFAULT_DISPLAY_ID) + .setVrrConfig(std::move(vrrConfig)) + .build()); + + VSyncPredictor vrrTracker{kMode, kHistorySize, kMinimumSamplesForPrediction, + kOutlierTolerancePercent, mVsyncTrackerCallback}; + + vrrTracker.setRenderRate(minFrameRate); + vrrTracker.addVsyncTimestamp(0); + EXPECT_EQ(1000, vrrTracker.nextAnticipatedVSyncTimeFrom(700)); + EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1300)); + + vrrTracker.onFrameBegin(TimePoint::fromNs(2000), TimePoint::fromNs(1500)); + EXPECT_EQ(1500, vrrTracker.nextAnticipatedVSyncTimeFrom(1300)); + EXPECT_EQ(2500, vrrTracker.nextAnticipatedVSyncTimeFrom(2300)); + + vrrTracker.onFrameMissed(TimePoint::fromNs(2500)); + EXPECT_EQ(3000, vrrTracker.nextAnticipatedVSyncTimeFrom(2300)); + EXPECT_EQ(4000, vrrTracker.nextAnticipatedVSyncTimeFrom(3300)); +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index aca3ccca6d..8d9623de1c 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -31,6 +31,9 @@ #include <scheduler/TimeKeeper.h> +#include "mock/DisplayHardware/MockDisplayMode.h" +#include "mock/MockVSyncTracker.h" + #include "Scheduler/VSyncDispatch.h" #include "Scheduler/VSyncReactor.h" #include "Scheduler/VSyncTracker.h" @@ -40,20 +43,7 @@ using namespace std::literals; namespace android::scheduler { -class MockVSyncTracker : public VSyncTracker { -public: - MockVSyncTracker() { ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true)); } - MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t)); - MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t)); - MOCK_CONST_METHOD0(currentPeriod, nsecs_t()); - MOCK_METHOD1(setPeriod, void(nsecs_t)); - MOCK_METHOD0(resetModel, void()); - MOCK_CONST_METHOD0(needsMoreSamples, bool()); - MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps)); - MOCK_METHOD(void, setDisplayModeData, (const DisplayModeData&), (override)); - MOCK_CONST_METHOD1(dump, void(std::string&)); -}; - +namespace { class MockClock : public Clock { public: MOCK_CONST_METHOD0(now, nsecs_t()); @@ -93,18 +83,33 @@ std::shared_ptr<android::FenceTime> generateSignalledFenceWithTime(nsecs_t time) constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u); +ftl::NonNull<DisplayModePtr> displayMode(nsecs_t vsyncPeriod) { + const int32_t kGroup = 0; + const auto kResolution = ui::Size(1920, 1080); + const auto refreshRate = Fps::fromPeriodNsecs(vsyncPeriod); + return ftl::as_non_null(mock::createDisplayMode(DisplayModeId(0), refreshRate, kGroup, + kResolution, DEFAULT_DISPLAY_ID)); +} + +MATCHER_P(DisplayModeMatcher, value, "display mode equals") { + return arg->getId() == value->getId() && equalsExceptDisplayModeId(*arg, *value); +} + +} // namespace + class VSyncReactorTest : public testing::Test { protected: VSyncReactorTest() - : mMockTracker(std::make_shared<NiceMock<MockVSyncTracker>>()), + : mMockTracker(std::make_shared<NiceMock<mock::VSyncTracker>>()), mMockClock(std::make_shared<NiceMock<MockClock>>()), mReactor(DEFAULT_DISPLAY_ID, std::make_unique<ClockWrapper>(mMockClock), *mMockTracker, kPendingLimit, false /* supportKernelIdleTimer */) { ON_CALL(*mMockClock, now()).WillByDefault(Return(mFakeNow)); ON_CALL(*mMockTracker, currentPeriod()).WillByDefault(Return(period)); + ON_CALL(*mMockTracker, addVsyncTimestamp(_)).WillByDefault(Return(true)); } - std::shared_ptr<MockVSyncTracker> mMockTracker; + std::shared_ptr<mock::VSyncTracker> mMockTracker; std::shared_ptr<MockClock> mMockClock; static constexpr size_t kPendingLimit = 3; static constexpr nsecs_t mDummyTime = 47; @@ -194,7 +199,8 @@ TEST_F(VSyncReactorTest, ignoresProperlyAfterAPeriodConfirmation) { mReactor.setIgnorePresentFences(true); nsecs_t const newPeriod = 5000; - mReactor.startPeriodTransition(newPeriod, false); + + mReactor.onDisplayModeChanged(displayMode(newPeriod), false); EXPECT_TRUE(mReactor.addHwVsyncTimestamp(0, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); @@ -206,8 +212,8 @@ TEST_F(VSyncReactorTest, ignoresProperlyAfterAPeriodConfirmation) { TEST_F(VSyncReactorTest, setPeriodCalledOnceConfirmedChange) { nsecs_t const newPeriod = 5000; - EXPECT_CALL(*mMockTracker, setPeriod(_)).Times(0); - mReactor.startPeriodTransition(newPeriod, false); + EXPECT_CALL(*mMockTracker, setDisplayModePtr(_)).Times(0); + mReactor.onDisplayModeChanged(displayMode(newPeriod), false); bool periodFlushed = true; EXPECT_TRUE(mReactor.addHwVsyncTimestamp(10000, std::nullopt, &periodFlushed)); @@ -217,7 +223,7 @@ TEST_F(VSyncReactorTest, setPeriodCalledOnceConfirmedChange) { EXPECT_FALSE(periodFlushed); Mock::VerifyAndClearExpectations(mMockTracker.get()); - EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1); + EXPECT_CALL(*mMockTracker, setDisplayModePtr(/*displayMode(newPeriod)*/ _)).Times(1); EXPECT_FALSE(mReactor.addHwVsyncTimestamp(25000, std::nullopt, &periodFlushed)); EXPECT_TRUE(periodFlushed); @@ -226,7 +232,7 @@ TEST_F(VSyncReactorTest, setPeriodCalledOnceConfirmedChange) { TEST_F(VSyncReactorTest, changingPeriodBackAbortsConfirmationProcess) { nsecs_t sampleTime = 0; nsecs_t const newPeriod = 5000; - mReactor.startPeriodTransition(newPeriod, false); + mReactor.onDisplayModeChanged(displayMode(newPeriod), false); bool periodFlushed = true; EXPECT_TRUE(mReactor.addHwVsyncTimestamp(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); @@ -234,7 +240,7 @@ TEST_F(VSyncReactorTest, changingPeriodBackAbortsConfirmationProcess) { EXPECT_TRUE(mReactor.addHwVsyncTimestamp(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - mReactor.startPeriodTransition(period, false); + mReactor.onDisplayModeChanged(displayMode(period), false); EXPECT_FALSE(mReactor.addHwVsyncTimestamp(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); } @@ -244,13 +250,13 @@ TEST_F(VSyncReactorTest, changingToAThirdPeriodWillWaitForLastPeriod) { nsecs_t const secondPeriod = 5000; nsecs_t const thirdPeriod = 2000; - mReactor.startPeriodTransition(secondPeriod, false); + mReactor.onDisplayModeChanged(displayMode(secondPeriod), false); bool periodFlushed = true; EXPECT_TRUE(mReactor.addHwVsyncTimestamp(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); EXPECT_TRUE(mReactor.addHwVsyncTimestamp(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - mReactor.startPeriodTransition(thirdPeriod, false); + mReactor.onDisplayModeChanged(displayMode(thirdPeriod), false); EXPECT_TRUE( mReactor.addHwVsyncTimestamp(sampleTime += secondPeriod, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); @@ -291,21 +297,22 @@ TEST_F(VSyncReactorTest, reportedBadTimestampFromPredictorWillReactivateHwVSyncP TEST_F(VSyncReactorTest, presentFenceAdditionDoesNotInterruptConfirmationProcess) { nsecs_t const newPeriod = 5000; - mReactor.startPeriodTransition(newPeriod, false); + mReactor.onDisplayModeChanged(displayMode(newPeriod), false); EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); } TEST_F(VSyncReactorTest, setPeriodCalledFirstTwoEventsNewPeriod) { nsecs_t const newPeriod = 5000; - EXPECT_CALL(*mMockTracker, setPeriod(_)).Times(0); - mReactor.startPeriodTransition(newPeriod, false); + EXPECT_CALL(*mMockTracker, setDisplayModePtr(_)).Times(0); + mReactor.onDisplayModeChanged(displayMode(newPeriod), false); bool periodFlushed = true; EXPECT_TRUE(mReactor.addHwVsyncTimestamp(5000, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); Mock::VerifyAndClearExpectations(mMockTracker.get()); - EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1); + EXPECT_CALL(*mMockTracker, setDisplayModePtr(DisplayModeMatcher(displayMode(newPeriod)))) + .Times(1); EXPECT_FALSE(mReactor.addHwVsyncTimestamp(10000, std::nullopt, &periodFlushed)); EXPECT_TRUE(periodFlushed); } @@ -323,7 +330,7 @@ TEST_F(VSyncReactorTest, addResyncSamplePeriodChanges) { bool periodFlushed = false; nsecs_t const newPeriod = 4000; - mReactor.startPeriodTransition(newPeriod, false); + mReactor.onDisplayModeChanged(displayMode(newPeriod), false); auto time = 0; auto constexpr numTimestampSubmissions = 10; @@ -348,7 +355,7 @@ TEST_F(VSyncReactorTest, addHwVsyncTimestampDozePreempt) { bool periodFlushed = false; nsecs_t const newPeriod = 4000; - mReactor.startPeriodTransition(newPeriod, false); + mReactor.onDisplayModeChanged(displayMode(newPeriod), false); auto time = 0; // If the power mode is not DOZE or DOZE_SUSPEND, it is still collecting timestamps. @@ -365,7 +372,7 @@ TEST_F(VSyncReactorTest, addPresentFenceWhileAwaitingPeriodConfirmationRequestsH auto time = 0; bool periodFlushed = false; nsecs_t const newPeriod = 4000; - mReactor.startPeriodTransition(newPeriod, false); + mReactor.onDisplayModeChanged(displayMode(newPeriod), false); time += period; mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed); @@ -381,7 +388,7 @@ TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTracker) { auto time = 0; bool periodFlushed = false; nsecs_t const newPeriod = 4000; - mReactor.startPeriodTransition(newPeriod, false); + mReactor.onDisplayModeChanged(displayMode(newPeriod), false); static auto constexpr numSamplesWithNewPeriod = 4; Sequence seq; @@ -408,7 +415,7 @@ TEST_F(VSyncReactorTest, hwVsyncturnsOffOnConfirmationWhenTrackerDoesntRequest) auto time = 0; bool periodFlushed = false; nsecs_t const newPeriod = 4000; - mReactor.startPeriodTransition(newPeriod, false); + mReactor.onDisplayModeChanged(displayMode(newPeriod), false); Sequence seq; EXPECT_CALL(*mMockTracker, needsMoreSamples()) @@ -428,7 +435,7 @@ TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTrackerMultiplePeriodChanges) { nsecs_t const newPeriod1 = 4000; nsecs_t const newPeriod2 = 7000; - mReactor.startPeriodTransition(newPeriod1, false); + mReactor.onDisplayModeChanged(displayMode(newPeriod1), false); Sequence seq; EXPECT_CALL(*mMockTracker, needsMoreSamples()) @@ -447,7 +454,7 @@ TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTrackerMultiplePeriodChanges) { EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += newPeriod1, std::nullopt, &periodFlushed)); EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += newPeriod1, std::nullopt, &periodFlushed)); - mReactor.startPeriodTransition(newPeriod2, false); + mReactor.onDisplayModeChanged(displayMode(newPeriod2), false); EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += newPeriod1, std::nullopt, &periodFlushed)); EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += newPeriod2, std::nullopt, &periodFlushed)); EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += newPeriod2, std::nullopt, &periodFlushed)); @@ -460,7 +467,7 @@ TEST_F(VSyncReactorTest, periodChangeWithGivenVsyncPeriod) { mReactor.setIgnorePresentFences(true); nsecs_t const newPeriod = 5000; - mReactor.startPeriodTransition(newPeriod, false); + mReactor.onDisplayModeChanged(displayMode(newPeriod), false); EXPECT_TRUE(mReactor.addHwVsyncTimestamp(0, 0, &periodFlushed)); EXPECT_FALSE(periodFlushed); @@ -484,7 +491,7 @@ TEST_F(VSyncReactorTest, periodIsMeasuredIfIgnoringComposer) { // First, set the same period, which should only be confirmed when we receive two // matching callbacks - idleReactor.startPeriodTransition(10000, false); + idleReactor.onDisplayModeChanged(displayMode(10000), false); EXPECT_TRUE(idleReactor.addHwVsyncTimestamp(0, 0, &periodFlushed)); EXPECT_FALSE(periodFlushed); // Correct period but incorrect timestamp delta @@ -497,7 +504,7 @@ TEST_F(VSyncReactorTest, periodIsMeasuredIfIgnoringComposer) { // Then, set a new period, which should be confirmed as soon as we receive a callback // reporting the new period nsecs_t const newPeriod = 5000; - idleReactor.startPeriodTransition(newPeriod, false); + idleReactor.onDisplayModeChanged(displayMode(newPeriod), false); // Incorrect timestamp delta and period EXPECT_TRUE(idleReactor.addHwVsyncTimestamp(20000, 10000, &periodFlushed)); EXPECT_FALSE(periodFlushed); diff --git a/services/surfaceflinger/tests/unittests/VsyncScheduleTest.cpp b/services/surfaceflinger/tests/unittests/VsyncScheduleTest.cpp index a8a3cd0293..bfdd5963f3 100644 --- a/services/surfaceflinger/tests/unittests/VsyncScheduleTest.cpp +++ b/services/surfaceflinger/tests/unittests/VsyncScheduleTest.cpp @@ -25,10 +25,12 @@ #include <scheduler/Fps.h> #include "Scheduler/VsyncSchedule.h" #include "ThreadContext.h" +#include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/MockVSyncDispatch.h" #include "mock/MockVSyncTracker.h" #include "mock/MockVsyncController.h" +using android::mock::createDisplayMode; using testing::_; namespace android { @@ -157,35 +159,35 @@ TEST_F(VsyncScheduleTest, StartPeriodTransition) { // allowed. ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); - const Period period = (60_Hz).getPeriod(); + const auto mode = ftl::as_non_null(createDisplayMode(DisplayModeId(0), 60_Hz)); EXPECT_CALL(mRequestHardwareVsync, Call(kDisplayId, true)); - EXPECT_CALL(getController(), startPeriodTransition(period.ns(), false)); + EXPECT_CALL(getController(), onDisplayModeChanged(mode, false)); - mVsyncSchedule->startPeriodTransition(period, false); + mVsyncSchedule->onDisplayModeChanged(mode, false); } TEST_F(VsyncScheduleTest, StartPeriodTransitionAlreadyEnabled) { ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); mVsyncSchedule->enableHardwareVsync(); - const Period period = (60_Hz).getPeriod(); + const auto mode = ftl::as_non_null(createDisplayMode(DisplayModeId(0), 60_Hz)); EXPECT_CALL(mRequestHardwareVsync, Call(_, _)).Times(0); - EXPECT_CALL(getController(), startPeriodTransition(period.ns(), false)); + EXPECT_CALL(getController(), onDisplayModeChanged(mode, false)); - mVsyncSchedule->startPeriodTransition(period, false); + mVsyncSchedule->onDisplayModeChanged(mode, false); } TEST_F(VsyncScheduleTest, StartPeriodTransitionForce) { ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); - const Period period = (60_Hz).getPeriod(); + const auto mode = ftl::as_non_null(createDisplayMode(DisplayModeId(0), 60_Hz)); EXPECT_CALL(mRequestHardwareVsync, Call(kDisplayId, true)); - EXPECT_CALL(getController(), startPeriodTransition(period.ns(), true)); + EXPECT_CALL(getController(), onDisplayModeChanged(mode, true)); - mVsyncSchedule->startPeriodTransition(period, true); + mVsyncSchedule->onDisplayModeChanged(mode, true); } TEST_F(VsyncScheduleTest, AddResyncSampleDisallowed) { diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h index cb05c00699..5bcce501e6 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h @@ -52,6 +52,7 @@ inline DisplayModePtr createVrrDisplayMode( .setVrrConfig(std::move(vrrConfig)) .build(); } + inline DisplayModePtr cloneForDisplay(PhysicalDisplayId displayId, const DisplayModePtr& modePtr) { return DisplayMode::Builder(modePtr->getHwcId()) .setId(modePtr->getId()) diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.cpp b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.cpp index bcccae5b1b..cc24f42d2e 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.cpp +++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.cpp @@ -17,9 +17,13 @@ #include "mock/MockVSyncTracker.h" namespace android::mock { +using testing::Return; // Explicit default instantiation is recommended. -VSyncTracker::VSyncTracker() = default; VSyncTracker::~VSyncTracker() = default; +VSyncTracker::VSyncTracker() { + ON_CALL(*this, minFramePeriod()).WillByDefault(Return(Period::fromNs(0))); +} + } // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h index 31eb86e4c5..e588bb9a3f 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h +++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h @@ -27,15 +27,18 @@ public: VSyncTracker(); ~VSyncTracker() override; - MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t)); - MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t)); - MOCK_CONST_METHOD0(currentPeriod, nsecs_t()); - MOCK_METHOD1(setPeriod, void(nsecs_t)); - MOCK_METHOD0(resetModel, void()); - MOCK_CONST_METHOD0(needsMoreSamples, bool()); - MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps)); - MOCK_METHOD(void, setDisplayModeData, (const scheduler::DisplayModeData&), (override)); - MOCK_CONST_METHOD1(dump, void(std::string&)); + MOCK_METHOD(bool, addVsyncTimestamp, (nsecs_t), (override)); + MOCK_METHOD(nsecs_t, nextAnticipatedVSyncTimeFrom, (nsecs_t), (const, override)); + MOCK_METHOD(nsecs_t, currentPeriod, (), (const, override)); + MOCK_METHOD(Period, minFramePeriod, (), (const, override)); + MOCK_METHOD(void, resetModel, (), (override)); + MOCK_METHOD(bool, needsMoreSamples, (), (const, override)); + MOCK_METHOD(bool, isVSyncInPhase, (nsecs_t, Fps), (const, override)); + MOCK_METHOD(void, setDisplayModePtr, (ftl::NonNull<DisplayModePtr>), (override)); + MOCK_METHOD(void, setRenderRate, (Fps), (override)); + MOCK_METHOD(void, onFrameBegin, (TimePoint, TimePoint), (override)); + MOCK_METHOD(void, onFrameMissed, (TimePoint), (override)); + MOCK_METHOD(void, dump, (std::string&), (const, override)); }; } // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h index 69ec60acd4..f7433908b0 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h +++ b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h @@ -29,7 +29,7 @@ public: MOCK_METHOD(bool, addPresentFence, (std::shared_ptr<FenceTime>), (override)); MOCK_METHOD(bool, addHwVsyncTimestamp, (nsecs_t, std::optional<nsecs_t>, bool*), (override)); - MOCK_METHOD(void, startPeriodTransition, (nsecs_t, bool), (override)); + MOCK_METHOD(void, onDisplayModeChanged, (ftl::NonNull<DisplayModePtr>, bool), (override)); MOCK_METHOD(void, setIgnorePresentFences, (bool), (override)); MOCK_METHOD(void, setDisplayPowerMode, (hal::PowerMode), (override)); diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncTrackerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncTrackerCallback.h index b8e24e0593..b48529f4ac 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVsyncTrackerCallback.h +++ b/services/surfaceflinger/tests/unittests/mock/MockVsyncTrackerCallback.h @@ -23,13 +23,10 @@ namespace android::scheduler::mock { struct VsyncTrackerCallback final : IVsyncTrackerCallback { - MOCK_METHOD(void, onVsyncGenerated, - (PhysicalDisplayId, TimePoint, const scheduler::DisplayModeData&, Period), - (override)); + MOCK_METHOD(void, onVsyncGenerated, (TimePoint, ftl::NonNull<DisplayModePtr>, Fps), (override)); }; struct NoOpVsyncTrackerCallback final : IVsyncTrackerCallback { - void onVsyncGenerated(PhysicalDisplayId, TimePoint, const scheduler::DisplayModeData&, - Period) override{}; + void onVsyncGenerated(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override{}; }; } // namespace android::scheduler::mock diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp index 5403baf2e7..2002bdf628 100644 --- a/services/vibratorservice/Android.bp +++ b/services/vibratorservice/Android.bp @@ -59,12 +59,6 @@ cc_library_shared { "-Wunreachable-code", ], - // FIXME: Workaround LTO build breakage - // http://b/241699694 - lto: { - never: true, - }, - local_include_dirs: ["include"], export_include_dirs: ["include"], |